summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.mailmap1
-rw-r--r--CONTRIBUTING.md11
-rw-r--r--Cargo.lock157
-rw-r--r--README.md5
-rw-r--r--RELEASES.md114
-rw-r--r--compiler/rustc_apfloat/src/lib.rs1
-rw-r--r--compiler/rustc_ast/src/ast.rs31
-rw-r--r--compiler/rustc_ast/src/ast_like.rs4
-rw-r--r--compiler/rustc_ast/src/lib.rs1
-rw-r--r--compiler/rustc_ast/src/mut_visit.rs39
-rw-r--r--compiler/rustc_ast/src/util/literal.rs2
-rw-r--r--compiler/rustc_ast/src/visit.rs3
-rw-r--r--compiler/rustc_ast_lowering/src/asm.rs18
-rw-r--r--compiler/rustc_ast_lowering/src/block.rs32
-rw-r--r--compiler/rustc_ast_lowering/src/expr.rs119
-rw-r--r--compiler/rustc_ast_lowering/src/item.rs14
-rw-r--r--compiler/rustc_ast_lowering/src/lib.rs281
-rw-r--r--compiler/rustc_ast_lowering/src/path.rs110
-rw-r--r--compiler/rustc_ast_passes/src/ast_validation.rs77
-rw-r--r--compiler/rustc_ast_passes/src/feature_gate.rs22
-rw-r--r--compiler/rustc_ast_passes/src/lib.rs1
-rw-r--r--compiler/rustc_ast_pretty/src/helpers.rs10
-rw-r--r--compiler/rustc_ast_pretty/src/pprust/mod.rs9
-rw-r--r--compiler/rustc_ast_pretty/src/pprust/state.rs478
-rw-r--r--compiler/rustc_attr/src/builtin.rs6
-rw-r--r--compiler/rustc_borrowck/src/borrow_set.rs2
-rw-r--r--compiler/rustc_borrowck/src/dataflow.rs6
-rw-r--r--compiler/rustc_borrowck/src/def_use.rs3
-rw-r--r--compiler/rustc_borrowck/src/diagnostics/bound_region_errors.rs9
-rw-r--r--compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs97
-rw-r--r--compiler/rustc_borrowck/src/diagnostics/find_all_local_uses.rs26
-rw-r--r--compiler/rustc_borrowck/src/diagnostics/mod.rs40
-rw-r--r--compiler/rustc_borrowck/src/diagnostics/mutability_errors.rs96
-rw-r--r--compiler/rustc_borrowck/src/diagnostics/region_name.rs34
-rw-r--r--compiler/rustc_borrowck/src/invalidation.rs1
-rw-r--r--compiler/rustc_borrowck/src/lib.rs4
-rw-r--r--compiler/rustc_borrowck/src/member_constraints.rs6
-rw-r--r--compiler/rustc_borrowck/src/path_utils.rs2
-rw-r--r--compiler/rustc_borrowck/src/region_infer/opaque_types.rs2
-rw-r--r--compiler/rustc_borrowck/src/region_infer/values.rs28
-rw-r--r--compiler/rustc_borrowck/src/renumber.rs18
-rw-r--r--compiler/rustc_borrowck/src/type_check/constraint_conversion.rs15
-rw-r--r--compiler/rustc_borrowck/src/type_check/free_region_relations.rs14
-rw-r--r--compiler/rustc_borrowck/src/type_check/input_output.rs26
-rw-r--r--compiler/rustc_borrowck/src/type_check/liveness/local_use_map.rs2
-rw-r--r--compiler/rustc_borrowck/src/type_check/liveness/mod.rs4
-rw-r--r--compiler/rustc_borrowck/src/type_check/liveness/polonius.rs8
-rw-r--r--compiler/rustc_borrowck/src/type_check/liveness/trace.rs46
-rw-r--r--compiler/rustc_borrowck/src/type_check/mod.rs12
-rw-r--r--compiler/rustc_borrowck/src/type_check/relate_tys.rs4
-rw-r--r--compiler/rustc_builtin_macros/Cargo.toml1
-rw-r--r--compiler/rustc_builtin_macros/src/asm.rs89
-rw-r--r--compiler/rustc_builtin_macros/src/cfg_eval.rs60
-rw-r--r--compiler/rustc_builtin_macros/src/concat_bytes.rs167
-rw-r--r--compiler/rustc_builtin_macros/src/deriving/generic/mod.rs174
-rw-r--r--compiler/rustc_builtin_macros/src/deriving/generic/ty.rs16
-rw-r--r--compiler/rustc_builtin_macros/src/format.rs24
-rw-r--r--compiler/rustc_builtin_macros/src/lib.rs3
-rw-r--r--compiler/rustc_builtin_macros/src/test.rs5
-rw-r--r--compiler/rustc_builtin_macros/src/test_harness.rs58
-rw-r--r--compiler/rustc_builtin_macros/src/util.rs35
-rw-r--r--compiler/rustc_codegen_cranelift/scripts/cargo.rs4
-rw-r--r--compiler/rustc_codegen_cranelift/src/abi/pass_mode.rs2
-rw-r--r--compiler/rustc_codegen_cranelift/src/base.rs22
-rw-r--r--compiler/rustc_codegen_cranelift/src/inline_asm.rs2
-rw-r--r--compiler/rustc_codegen_cranelift/src/lib.rs1
-rw-r--r--compiler/rustc_codegen_gcc/src/abi.rs6
-rw-r--r--compiler/rustc_codegen_gcc/src/asm.rs19
-rw-r--r--compiler/rustc_codegen_gcc/src/back/write.rs4
-rw-r--r--compiler/rustc_codegen_gcc/src/base.rs39
-rw-r--r--compiler/rustc_codegen_gcc/src/lib.rs7
-rw-r--r--compiler/rustc_codegen_gcc/tests/run/asm.rs2
-rw-r--r--compiler/rustc_codegen_llvm/Cargo.toml2
-rw-r--r--compiler/rustc_codegen_llvm/src/abi.rs46
-rw-r--r--compiler/rustc_codegen_llvm/src/asm.rs83
-rw-r--r--compiler/rustc_codegen_llvm/src/attributes.rs42
-rw-r--r--compiler/rustc_codegen_llvm/src/back/lto.rs6
-rw-r--r--compiler/rustc_codegen_llvm/src/back/write.rs184
-rw-r--r--compiler/rustc_codegen_llvm/src/base.rs62
-rw-r--r--compiler/rustc_codegen_llvm/src/builder.rs24
-rw-r--r--compiler/rustc_codegen_llvm/src/callee.rs2
-rw-r--r--compiler/rustc_codegen_llvm/src/common.rs18
-rw-r--r--compiler/rustc_codegen_llvm/src/consts.rs16
-rw-r--r--compiler/rustc_codegen_llvm/src/context.rs32
-rw-r--r--compiler/rustc_codegen_llvm/src/coverageinfo/mapgen.rs55
-rw-r--r--compiler/rustc_codegen_llvm/src/coverageinfo/mod.rs18
-rw-r--r--compiler/rustc_codegen_llvm/src/debuginfo/create_scope_map.rs4
-rw-r--r--compiler/rustc_codegen_llvm/src/debuginfo/gdb.rs2
-rw-r--r--compiler/rustc_codegen_llvm/src/debuginfo/metadata.rs149
-rw-r--r--compiler/rustc_codegen_llvm/src/debuginfo/mod.rs10
-rw-r--r--compiler/rustc_codegen_llvm/src/debuginfo/namespace.rs2
-rw-r--r--compiler/rustc_codegen_llvm/src/debuginfo/utils.rs13
-rw-r--r--compiler/rustc_codegen_llvm/src/declare.rs4
-rw-r--r--compiler/rustc_codegen_llvm/src/intrinsic.rs37
-rw-r--r--compiler/rustc_codegen_llvm/src/lib.rs40
-rw-r--r--compiler/rustc_codegen_llvm/src/llvm/diagnostic.rs8
-rw-r--r--compiler/rustc_codegen_llvm/src/llvm/ffi.rs466
-rw-r--r--compiler/rustc_codegen_llvm/src/llvm/mod.rs20
-rw-r--r--compiler/rustc_codegen_llvm/src/llvm_util.rs21
-rw-r--r--compiler/rustc_codegen_llvm/src/mono_item.rs4
-rw-r--r--compiler/rustc_codegen_llvm/src/type_.rs6
-rw-r--r--compiler/rustc_codegen_llvm/src/va_arg.rs20
-rw-r--r--compiler/rustc_codegen_ssa/Cargo.toml1
-rw-r--r--compiler/rustc_codegen_ssa/src/back/link.rs162
-rw-r--r--compiler/rustc_codegen_ssa/src/back/metadata.rs197
-rw-r--r--compiler/rustc_codegen_ssa/src/back/rpath.rs5
-rw-r--r--compiler/rustc_codegen_ssa/src/back/symbol_export.rs2
-rw-r--r--compiler/rustc_codegen_ssa/src/back/write.rs23
-rw-r--r--compiler/rustc_codegen_ssa/src/base.rs68
-rw-r--r--compiler/rustc_codegen_ssa/src/common.rs4
-rw-r--r--compiler/rustc_codegen_ssa/src/coverageinfo/ffi.rs8
-rw-r--r--compiler/rustc_codegen_ssa/src/coverageinfo/map.rs14
-rw-r--r--compiler/rustc_codegen_ssa/src/debuginfo/type_names.rs6
-rw-r--r--compiler/rustc_codegen_ssa/src/glue.rs18
-rw-r--r--compiler/rustc_codegen_ssa/src/lib.rs1
-rw-r--r--compiler/rustc_codegen_ssa/src/mir/analyze.rs7
-rw-r--r--compiler/rustc_codegen_ssa/src/mir/block.rs61
-rw-r--r--compiler/rustc_codegen_ssa/src/mir/operand.rs2
-rw-r--r--compiler/rustc_codegen_ssa/src/target_features.rs2
-rw-r--r--compiler/rustc_codegen_ssa/src/traits/abi.rs2
-rw-r--r--compiler/rustc_codegen_ssa/src/traits/asm.rs1
-rw-r--r--compiler/rustc_codegen_ssa/src/traits/backend.rs7
-rw-r--r--compiler/rustc_codegen_ssa/src/traits/type_.rs4
-rw-r--r--compiler/rustc_const_eval/src/const_eval/eval_queries.rs3
-rw-r--r--compiler/rustc_const_eval/src/const_eval/machine.rs4
-rw-r--r--compiler/rustc_const_eval/src/const_eval/mod.rs4
-rw-r--r--compiler/rustc_const_eval/src/interpret/eval_context.rs40
-rw-r--r--compiler/rustc_const_eval/src/interpret/intern.rs11
-rw-r--r--compiler/rustc_const_eval/src/interpret/intrinsics.rs52
-rw-r--r--compiler/rustc_const_eval/src/interpret/intrinsics/type_name.rs2
-rw-r--r--compiler/rustc_const_eval/src/interpret/machine.rs4
-rw-r--r--compiler/rustc_const_eval/src/interpret/operand.rs6
-rw-r--r--compiler/rustc_const_eval/src/interpret/operator.rs12
-rw-r--r--compiler/rustc_const_eval/src/interpret/place.rs30
-rw-r--r--compiler/rustc_const_eval/src/interpret/step.rs11
-rw-r--r--compiler/rustc_const_eval/src/interpret/terminator.rs2
-rw-r--r--compiler/rustc_const_eval/src/lib.rs2
-rw-r--r--compiler/rustc_const_eval/src/transform/check_consts/check.rs59
-rw-r--r--compiler/rustc_const_eval/src/transform/check_consts/mod.rs10
-rw-r--r--compiler/rustc_const_eval/src/transform/check_consts/ops.rs148
-rw-r--r--compiler/rustc_const_eval/src/transform/check_consts/post_drop_elaboration.rs16
-rw-r--r--compiler/rustc_const_eval/src/transform/check_consts/qualifs.rs51
-rw-r--r--compiler/rustc_const_eval/src/transform/check_consts/resolver.rs35
-rw-r--r--compiler/rustc_const_eval/src/transform/mod.rs2
-rw-r--r--compiler/rustc_const_eval/src/transform/promote_consts.rs11
-rw-r--r--compiler/rustc_const_eval/src/transform/validate.rs12
-rw-r--r--compiler/rustc_data_structures/src/binary_search_util/mod.rs2
-rw-r--r--compiler/rustc_data_structures/src/fingerprint.rs4
-rw-r--r--compiler/rustc_data_structures/src/functor.rs79
-rw-r--r--compiler/rustc_data_structures/src/graph/dominators/mod.rs275
-rw-r--r--compiler/rustc_data_structures/src/graph/dominators/tests.rs11
-rw-r--r--compiler/rustc_data_structures/src/graph/iterate/mod.rs6
-rw-r--r--compiler/rustc_data_structures/src/graph/scc/mod.rs2
-rw-r--r--compiler/rustc_data_structures/src/graph/vec_graph/mod.rs2
-rw-r--r--compiler/rustc_data_structures/src/lib.rs3
-rw-r--r--compiler/rustc_data_structures/src/profiling.rs2
-rw-r--r--compiler/rustc_data_structures/src/small_c_str.rs2
-rw-r--r--compiler/rustc_data_structures/src/sorted_map/index_map.rs4
-rw-r--r--compiler/rustc_data_structures/src/sso/map.rs4
-rw-r--r--compiler/rustc_data_structures/src/sso/set.rs2
-rw-r--r--compiler/rustc_data_structures/src/stable_hasher.rs65
-rw-r--r--compiler/rustc_data_structures/src/tagged_ptr/copy.rs2
-rw-r--r--compiler/rustc_data_structures/src/vec_linked_list.rs4
-rw-r--r--compiler/rustc_driver/src/lib.rs17
-rw-r--r--compiler/rustc_error_codes/src/error_codes/E0038.md97
-rw-r--r--compiler/rustc_errors/src/emitter.rs54
-rw-r--r--compiler/rustc_errors/src/lib.rs11
-rw-r--r--compiler/rustc_expand/src/base.rs19
-rw-r--r--compiler/rustc_expand/src/config.rs19
-rw-r--r--compiler/rustc_expand/src/expand.rs138
-rw-r--r--compiler/rustc_expand/src/lib.rs4
-rw-r--r--compiler/rustc_expand/src/mbe/macro_parser.rs4
-rw-r--r--compiler/rustc_expand/src/mbe/macro_rules.rs28
-rw-r--r--compiler/rustc_expand/src/mbe/transcribe.rs4
-rw-r--r--compiler/rustc_expand/src/parse/tests.rs29
-rw-r--r--compiler/rustc_expand/src/placeholders.rs14
-rw-r--r--compiler/rustc_expand/src/proc_macro_server.rs5
-rw-r--r--compiler/rustc_feature/src/accepted.rs4
-rw-r--r--compiler/rustc_feature/src/active.rs20
-rw-r--r--compiler/rustc_feature/src/removed.rs6
-rw-r--r--compiler/rustc_graphviz/src/lib.rs6
-rw-r--r--compiler/rustc_hir/src/arena.rs1
-rw-r--r--compiler/rustc_hir/src/def.rs8
-rw-r--r--compiler/rustc_hir/src/definitions.rs7
-rw-r--r--compiler/rustc_hir/src/hir.rs159
-rw-r--r--compiler/rustc_hir/src/intravisit.rs20
-rw-r--r--compiler/rustc_hir/src/lang_items.rs2
-rw-r--r--compiler/rustc_hir/src/lib.rs1
-rw-r--r--compiler/rustc_hir/src/stable_hash_impls.rs4
-rw-r--r--compiler/rustc_hir_pretty/src/lib.rs469
-rw-r--r--compiler/rustc_incremental/src/assert_dep_graph.rs6
-rw-r--r--compiler/rustc_incremental/src/assert_module_sources.rs3
-rw-r--r--compiler/rustc_incremental/src/lib.rs2
-rw-r--r--compiler/rustc_incremental/src/persist/dirty_clean.rs8
-rw-r--r--compiler/rustc_incremental/src/persist/fs.rs34
-rw-r--r--compiler/rustc_incremental/src/persist/load.rs19
-rw-r--r--compiler/rustc_incremental/src/persist/save.rs15
-rw-r--r--compiler/rustc_incremental/src/persist/work_product.rs6
-rw-r--r--compiler/rustc_index/src/bit_set.rs142
-rw-r--r--compiler/rustc_index/src/bit_set/tests.rs95
-rw-r--r--compiler/rustc_index/src/lib.rs3
-rw-r--r--compiler/rustc_infer/src/infer/combine.rs8
-rw-r--r--compiler/rustc_infer/src/infer/error_reporting/mod.rs44
-rw-r--r--compiler/rustc_infer/src/infer/error_reporting/need_type_info.rs225
-rw-r--r--compiler/rustc_infer/src/infer/error_reporting/nice_region_error/mod.rs2
-rw-r--r--compiler/rustc_infer/src/infer/error_reporting/nice_region_error/placeholder_error.rs4
-rw-r--r--compiler/rustc_infer/src/infer/error_reporting/nice_region_error/static_impl_trait.rs139
-rw-r--r--compiler/rustc_infer/src/infer/error_reporting/nice_region_error/trait_impl_difference.rs1
-rw-r--r--compiler/rustc_infer/src/infer/error_reporting/nice_region_error/util.rs2
-rw-r--r--compiler/rustc_infer/src/infer/free_regions.rs2
-rw-r--r--compiler/rustc_infer/src/infer/lexical_region_resolve/mod.rs32
-rw-r--r--compiler/rustc_infer/src/infer/mod.rs32
-rw-r--r--compiler/rustc_infer/src/infer/opaque_types.rs44
-rw-r--r--compiler/rustc_infer/src/infer/resolve.rs55
-rw-r--r--compiler/rustc_infer/src/lib.rs2
-rw-r--r--compiler/rustc_infer/src/traits/engine.rs20
-rw-r--r--compiler/rustc_infer/src/traits/mod.rs10
-rw-r--r--compiler/rustc_infer/src/traits/project.rs72
-rw-r--r--compiler/rustc_infer/src/traits/structural_impls.rs18
-rw-r--r--compiler/rustc_infer/src/traits/util.rs10
-rw-r--r--compiler/rustc_interface/Cargo.toml1
-rw-r--r--compiler/rustc_interface/src/passes.rs37
-rw-r--r--compiler/rustc_interface/src/queries.rs7
-rw-r--r--compiler/rustc_interface/src/tests.rs15
-rw-r--r--compiler/rustc_interface/src/util.rs46
-rw-r--r--compiler/rustc_lexer/Cargo.toml1
-rw-r--r--compiler/rustc_lexer/src/cursor.rs33
-rw-r--r--compiler/rustc_lexer/src/lib.rs44
-rw-r--r--compiler/rustc_lint/src/array_into_iter.rs7
-rw-r--r--compiler/rustc_lint/src/builtin.rs76
-rw-r--r--compiler/rustc_lint/src/context.rs36
-rw-r--r--compiler/rustc_lint/src/enum_intrinsics_non_enums.rs18
-rw-r--r--compiler/rustc_lint/src/levels.rs15
-rw-r--r--compiler/rustc_lint/src/lib.rs3
-rw-r--r--compiler/rustc_lint/src/non_fmt_panic.rs21
-rw-r--r--compiler/rustc_lint/src/noop_method_call.rs72
-rw-r--r--compiler/rustc_lint/src/traits.rs20
-rw-r--r--compiler/rustc_lint/src/types.rs11
-rw-r--r--compiler/rustc_lint/src/unused.rs9
-rw-r--r--compiler/rustc_lint_defs/src/builtin.rs114
-rw-r--r--compiler/rustc_lint_defs/src/lib.rs2
-rw-r--r--compiler/rustc_llvm/build.rs7
-rw-r--r--compiler/rustc_llvm/llvm-wrapper/CoverageMappingWrapper.cpp9
-rw-r--r--compiler/rustc_llvm/llvm-wrapper/LLVMWrapper.h3
-rw-r--r--compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp112
-rw-r--r--compiler/rustc_macros/src/query.rs20
-rw-r--r--compiler/rustc_macros/src/serialize.rs25
-rw-r--r--compiler/rustc_macros/src/type_foldable.rs8
-rw-r--r--compiler/rustc_metadata/Cargo.toml5
-rw-r--r--compiler/rustc_metadata/src/creader.rs53
-rw-r--r--compiler/rustc_metadata/src/dynamic_lib.rs194
-rw-r--r--compiler/rustc_metadata/src/dynamic_lib/tests.rs18
-rw-r--r--compiler/rustc_metadata/src/foreign_modules.rs2
-rw-r--r--compiler/rustc_metadata/src/lib.rs2
-rw-r--r--compiler/rustc_metadata/src/locator.rs20
-rw-r--r--compiler/rustc_metadata/src/native_libs.rs6
-rw-r--r--compiler/rustc_metadata/src/rmeta/decoder.rs4
-rw-r--r--compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs2
-rw-r--r--compiler/rustc_metadata/src/rmeta/def_path_hash_map.rs2
-rw-r--r--compiler/rustc_metadata/src/rmeta/encoder.rs32
-rw-r--r--compiler/rustc_metadata/src/rmeta/mod.rs4
-rw-r--r--compiler/rustc_middle/src/hir/map/mod.rs29
-rw-r--r--compiler/rustc_middle/src/infer/canonical.rs8
-rw-r--r--compiler/rustc_middle/src/lib.rs5
-rw-r--r--compiler/rustc_middle/src/lint.rs4
-rw-r--r--compiler/rustc_middle/src/macros.rs18
-rw-r--r--compiler/rustc_middle/src/middle/region.rs16
-rw-r--r--compiler/rustc_middle/src/middle/stability.rs61
-rw-r--r--compiler/rustc_middle/src/mir/coverage.rs6
-rw-r--r--compiler/rustc_middle/src/mir/generic_graphviz.rs4
-rw-r--r--compiler/rustc_middle/src/mir/interpret/error.rs3
-rw-r--r--compiler/rustc_middle/src/mir/interpret/queries.rs2
-rw-r--r--compiler/rustc_middle/src/mir/mod.rs63
-rw-r--r--compiler/rustc_middle/src/mir/mono.rs2
-rw-r--r--compiler/rustc_middle/src/mir/spanview.rs12
-rw-r--r--compiler/rustc_middle/src/mir/terminator.rs55
-rw-r--r--compiler/rustc_middle/src/mir/type_foldable.rs230
-rw-r--r--compiler/rustc_middle/src/mir/visit.rs18
-rw-r--r--compiler/rustc_middle/src/query/mod.rs72
-rw-r--r--compiler/rustc_middle/src/traits/mod.rs25
-rw-r--r--compiler/rustc_middle/src/traits/select.rs10
-rw-r--r--compiler/rustc_middle/src/traits/util.rs49
-rw-r--r--compiler/rustc_middle/src/ty/adt.rs42
-rw-r--r--compiler/rustc_middle/src/ty/context.rs47
-rw-r--r--compiler/rustc_middle/src/ty/diagnostics.rs88
-rw-r--r--compiler/rustc_middle/src/ty/error.rs10
-rw-r--r--compiler/rustc_middle/src/ty/fast_reject.rs82
-rw-r--r--compiler/rustc_middle/src/ty/fold.rs156
-rw-r--r--compiler/rustc_middle/src/ty/generics.rs6
-rw-r--r--compiler/rustc_middle/src/ty/instance.rs18
-rw-r--r--compiler/rustc_middle/src/ty/layout.rs33
-rw-r--r--compiler/rustc_middle/src/ty/list.rs140
-rw-r--r--compiler/rustc_middle/src/ty/mod.rs196
-rw-r--r--compiler/rustc_middle/src/ty/normalize_erasing_regions.rs154
-rw-r--r--compiler/rustc_middle/src/ty/print/pretty.rs331
-rw-r--r--compiler/rustc_middle/src/ty/query.rs14
-rw-r--r--compiler/rustc_middle/src/ty/relate.rs23
-rw-r--r--compiler/rustc_middle/src/ty/structural_impls.rs337
-rw-r--r--compiler/rustc_middle/src/ty/sty.rs48
-rw-r--r--compiler/rustc_middle/src/ty/subst.rs41
-rw-r--r--compiler/rustc_middle/src/ty/trait_def.rs45
-rw-r--r--compiler/rustc_middle/src/ty/util.rs42
-rw-r--r--compiler/rustc_mir_build/src/build/expr/into.rs4
-rw-r--r--compiler/rustc_mir_build/src/build/scope.rs7
-rw-r--r--compiler/rustc_mir_build/src/lib.rs1
-rw-r--r--compiler/rustc_mir_build/src/thir/cx/expr.rs7
-rw-r--r--compiler/rustc_mir_build/src/thir/pattern/check_match.rs8
-rw-r--r--compiler/rustc_mir_build/src/thir/pattern/mod.rs83
-rw-r--r--compiler/rustc_mir_build/src/thir/pattern/usefulness.rs11
-rw-r--r--compiler/rustc_mir_dataflow/src/framework/direction.rs91
-rw-r--r--compiler/rustc_mir_dataflow/src/framework/engine.rs21
-rw-r--r--compiler/rustc_mir_dataflow/src/framework/graphviz.rs66
-rw-r--r--compiler/rustc_mir_dataflow/src/framework/mod.rs52
-rw-r--r--compiler/rustc_mir_dataflow/src/framework/tests.rs12
-rw-r--r--compiler/rustc_mir_dataflow/src/framework/visitor.rs2
-rw-r--r--compiler/rustc_mir_dataflow/src/impls/borrowed_locals.rs12
-rw-r--r--compiler/rustc_mir_dataflow/src/impls/init_locals.rs20
-rw-r--r--compiler/rustc_mir_dataflow/src/impls/liveness.rs28
-rw-r--r--compiler/rustc_mir_dataflow/src/impls/mod.rs165
-rw-r--r--compiler/rustc_mir_dataflow/src/impls/storage_liveness.rs24
-rw-r--r--compiler/rustc_mir_dataflow/src/lib.rs8
-rw-r--r--compiler/rustc_mir_dataflow/src/move_paths/builder.rs1
-rw-r--r--compiler/rustc_mir_dataflow/src/rustc_peek.rs1
-rw-r--r--compiler/rustc_mir_dataflow/src/storage.rs2
-rw-r--r--compiler/rustc_mir_transform/src/add_retag.rs10
-rw-r--r--compiler/rustc_mir_transform/src/check_const_item_mutation.rs10
-rw-r--r--compiler/rustc_mir_transform/src/check_packed_ref.rs13
-rw-r--r--compiler/rustc_mir_transform/src/check_unsafety.rs7
-rw-r--r--compiler/rustc_mir_transform/src/const_debuginfo.rs10
-rw-r--r--compiler/rustc_mir_transform/src/const_goto.rs24
-rw-r--r--compiler/rustc_mir_transform/src/const_prop.rs116
-rw-r--r--compiler/rustc_mir_transform/src/coverage/debug.rs12
-rw-r--r--compiler/rustc_mir_transform/src/coverage/graph.rs6
-rw-r--r--compiler/rustc_mir_transform/src/coverage/mod.rs10
-rw-r--r--compiler/rustc_mir_transform/src/coverage/query.rs2
-rw-r--r--compiler/rustc_mir_transform/src/coverage/spans.rs20
-rw-r--r--compiler/rustc_mir_transform/src/coverage/tests.rs8
-rw-r--r--compiler/rustc_mir_transform/src/deduplicate_blocks.rs25
-rw-r--r--compiler/rustc_mir_transform/src/dest_prop.rs51
-rw-r--r--compiler/rustc_mir_transform/src/early_otherwise_branch.rs16
-rw-r--r--compiler/rustc_mir_transform/src/elaborate_drops.rs8
-rw-r--r--compiler/rustc_mir_transform/src/function_item_references.rs10
-rw-r--r--compiler/rustc_mir_transform/src/generator.rs22
-rw-r--r--compiler/rustc_mir_transform/src/inline.rs54
-rw-r--r--compiler/rustc_mir_transform/src/inline/cycle.rs4
-rw-r--r--compiler/rustc_mir_transform/src/instcombine.rs6
-rw-r--r--compiler/rustc_mir_transform/src/lib.rs273
-rw-r--r--compiler/rustc_mir_transform/src/lower_intrinsics.rs4
-rw-r--r--compiler/rustc_mir_transform/src/lower_slice_len.rs4
-rw-r--r--compiler/rustc_mir_transform/src/marker.rs20
-rw-r--r--compiler/rustc_mir_transform/src/match_branches.rs8
-rw-r--r--compiler/rustc_mir_transform/src/multiple_return_terminators.rs8
-rw-r--r--compiler/rustc_mir_transform/src/normalize_array_len.rs10
-rw-r--r--compiler/rustc_mir_transform/src/nrvo.rs12
-rw-r--r--compiler/rustc_mir_transform/src/pass_manager.rs144
-rw-r--r--compiler/rustc_mir_transform/src/remove_false_edges.rs29
-rw-r--r--compiler/rustc_mir_transform/src/remove_noop_landing_pads.rs16
-rw-r--r--compiler/rustc_mir_transform/src/remove_storage_markers.rs4
-rw-r--r--compiler/rustc_mir_transform/src/remove_uninit_drops.rs171
-rw-r--r--compiler/rustc_mir_transform/src/remove_unneeded_drops.rs6
-rw-r--r--compiler/rustc_mir_transform/src/remove_zsts.rs4
-rw-r--r--compiler/rustc_mir_transform/src/required_consts.rs2
-rw-r--r--compiler/rustc_mir_transform/src/reveal_all.rs40
-rw-r--r--compiler/rustc_mir_transform/src/separate_const_switch.rs10
-rw-r--r--compiler/rustc_mir_transform/src/shim.rs36
-rw-r--r--compiler/rustc_mir_transform/src/simplify.rs16
-rw-r--r--compiler/rustc_mir_transform/src/simplify_branches.rs28
-rw-r--r--compiler/rustc_mir_transform/src/simplify_comparison_integral.rs6
-rw-r--r--compiler/rustc_mir_transform/src/simplify_try.rs24
-rw-r--r--compiler/rustc_mir_transform/src/uninhabited_enum_branching.rs4
-rw-r--r--compiler/rustc_mir_transform/src/unreachable_prop.rs14
-rw-r--r--compiler/rustc_parse/src/lexer/mod.rs19
-rw-r--r--compiler/rustc_parse/src/lexer/unicode_chars.rs2
-rw-r--r--compiler/rustc_parse/src/lib.rs6
-rw-r--r--compiler/rustc_parse/src/parser/attr.rs4
-rw-r--r--compiler/rustc_parse/src/parser/diagnostics.rs272
-rw-r--r--compiler/rustc_parse/src/parser/expr.rs138
-rw-r--r--compiler/rustc_parse/src/parser/generics.rs35
-rw-r--r--compiler/rustc_parse/src/parser/item.rs261
-rw-r--r--compiler/rustc_parse/src/parser/mod.rs9
-rw-r--r--compiler/rustc_parse/src/parser/pat.rs117
-rw-r--r--compiler/rustc_parse/src/parser/path.rs88
-rw-r--r--compiler/rustc_parse/src/parser/stmt.rs14
-rw-r--r--compiler/rustc_parse/src/parser/ty.rs46
-rw-r--r--compiler/rustc_passes/src/check_attr.rs54
-rw-r--r--compiler/rustc_passes/src/check_const.rs14
-rw-r--r--compiler/rustc_passes/src/dead.rs6
-rw-r--r--compiler/rustc_passes/src/intrinsicck.rs6
-rw-r--r--compiler/rustc_passes/src/lang_items.rs4
-rw-r--r--compiler/rustc_passes/src/layout_test.rs12
-rw-r--r--compiler/rustc_passes/src/lib.rs3
-rw-r--r--compiler/rustc_passes/src/lib_features.rs8
-rw-r--r--compiler/rustc_passes/src/liveness.rs16
-rw-r--r--compiler/rustc_passes/src/naked_functions.rs2
-rw-r--r--compiler/rustc_passes/src/reachable.rs5
-rw-r--r--compiler/rustc_passes/src/region.rs25
-rw-r--r--compiler/rustc_passes/src/stability.rs8
-rw-r--r--compiler/rustc_passes/src/upvars.rs4
-rw-r--r--compiler/rustc_passes/src/weak_lang_items.rs10
-rw-r--r--compiler/rustc_plugin_impl/Cargo.toml1
-rw-r--r--compiler/rustc_plugin_impl/src/load.rs42
-rw-r--r--compiler/rustc_privacy/src/lib.rs27
-rw-r--r--compiler/rustc_query_impl/src/keys.rs2
-rw-r--r--compiler/rustc_query_impl/src/lib.rs1
-rw-r--r--compiler/rustc_query_impl/src/on_disk_cache.rs4
-rw-r--r--compiler/rustc_query_impl/src/plumbing.rs20
-rw-r--r--compiler/rustc_query_impl/src/profiling_support.rs2
-rw-r--r--compiler/rustc_query_system/src/lib.rs3
-rw-r--r--compiler/rustc_query_system/src/query/plumbing.rs97
-rw-r--r--compiler/rustc_resolve/src/build_reduced_graph.rs171
-rw-r--r--compiler/rustc_resolve/src/def_collector.rs16
-rw-r--r--compiler/rustc_resolve/src/diagnostics.rs2
-rw-r--r--compiler/rustc_resolve/src/late.rs4
-rw-r--r--compiler/rustc_resolve/src/late/diagnostics.rs147
-rw-r--r--compiler/rustc_resolve/src/late/lifetimes.rs219
-rw-r--r--compiler/rustc_resolve/src/lib.rs15
-rw-r--r--compiler/rustc_resolve/src/macros.rs1
-rw-r--r--compiler/rustc_save_analysis/src/lib.rs2
-rw-r--r--compiler/rustc_save_analysis/src/sig.rs2
-rw-r--r--compiler/rustc_serialize/src/json.rs20
-rw-r--r--compiler/rustc_serialize/src/opaque.rs21
-rw-r--r--compiler/rustc_serialize/src/serialize.rs14
-rw-r--r--compiler/rustc_session/src/config.rs49
-rw-r--r--compiler/rustc_session/src/filesearch.rs4
-rw-r--r--compiler/rustc_session/src/lib.rs1
-rw-r--r--compiler/rustc_session/src/options.rs52
-rw-r--r--compiler/rustc_session/src/output.rs2
-rw-r--r--compiler/rustc_session/src/parse.rs8
-rw-r--r--compiler/rustc_session/src/session.rs48
-rw-r--r--compiler/rustc_span/src/def_id.rs63
-rw-r--r--compiler/rustc_span/src/hygiene.rs22
-rw-r--r--compiler/rustc_span/src/lib.rs15
-rw-r--r--compiler/rustc_span/src/symbol.rs35
-rw-r--r--compiler/rustc_symbol_mangling/src/legacy.rs10
-rw-r--r--compiler/rustc_symbol_mangling/src/lib.rs10
-rw-r--r--compiler/rustc_symbol_mangling/src/test.rs4
-rw-r--r--compiler/rustc_symbol_mangling/src/v0.rs12
-rw-r--r--compiler/rustc_target/src/abi/call/mips64.rs15
-rw-r--r--compiler/rustc_target/src/abi/call/mod.rs39
-rw-r--r--compiler/rustc_target/src/abi/call/sparc64.rs126
-rw-r--r--compiler/rustc_target/src/asm/aarch64.rs20
-rw-r--r--compiler/rustc_target/src/asm/arm.rs56
-rw-r--r--compiler/rustc_target/src/asm/avr.rs196
-rw-r--r--compiler/rustc_target/src/asm/mod.rs59
-rw-r--r--compiler/rustc_target/src/lib.rs4
-rw-r--r--compiler/rustc_target/src/spec/aarch64_apple_darwin.rs5
-rw-r--r--compiler/rustc_target/src/spec/aarch64_unknown_linux_musl.rs6
-rw-r--r--compiler/rustc_target/src/spec/apple_base.rs19
-rw-r--r--compiler/rustc_target/src/spec/m68k_unknown_linux_gnu.rs2
-rw-r--r--compiler/rustc_target/src/spec/mod.rs67
-rw-r--r--compiler/rustc_target/src/spec/nvptx64_nvidia_cuda.rs4
-rw-r--r--compiler/rustc_target/src/spec/riscv64gc_unknown_freebsd.rs18
-rw-r--r--compiler/rustc_trait_selection/src/autoderef.rs2
-rw-r--r--compiler/rustc_trait_selection/src/infer.rs1
-rw-r--r--compiler/rustc_trait_selection/src/lib.rs4
-rw-r--r--compiler/rustc_trait_selection/src/opaque_types.rs6
-rw-r--r--compiler/rustc_trait_selection/src/traits/auto_trait.rs9
-rw-r--r--compiler/rustc_trait_selection/src/traits/chalk_fulfill.rs4
-rw-r--r--compiler/rustc_trait_selection/src/traits/codegen.rs2
-rw-r--r--compiler/rustc_trait_selection/src/traits/coherence.rs34
-rw-r--r--compiler/rustc_trait_selection/src/traits/const_evaluatable.rs22
-rw-r--r--compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs109
-rw-r--r--compiler/rustc_trait_selection/src/traits/error_reporting/on_unimplemented.rs2
-rw-r--r--compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs267
-rw-r--r--compiler/rustc_trait_selection/src/traits/fulfill.rs58
-rw-r--r--compiler/rustc_trait_selection/src/traits/misc.rs2
-rw-r--r--compiler/rustc_trait_selection/src/traits/mod.rs54
-rw-r--r--compiler/rustc_trait_selection/src/traits/object_safety.rs23
-rw-r--r--compiler/rustc_trait_selection/src/traits/project.rs18
-rw-r--r--compiler/rustc_trait_selection/src/traits/query/evaluate_obligation.rs21
-rw-r--r--compiler/rustc_trait_selection/src/traits/query/normalize.rs165
-rw-r--r--compiler/rustc_trait_selection/src/traits/query/type_op/normalize.rs8
-rw-r--r--compiler/rustc_trait_selection/src/traits/query/type_op/outlives.rs2
-rw-r--r--compiler/rustc_trait_selection/src/traits/query/type_op/prove_predicate.rs8
-rw-r--r--compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs54
-rw-r--r--compiler/rustc_trait_selection/src/traits/select/confirmation.rs16
-rw-r--r--compiler/rustc_trait_selection/src/traits/select/mod.rs315
-rw-r--r--compiler/rustc_trait_selection/src/traits/specialize/mod.rs6
-rw-r--r--compiler/rustc_trait_selection/src/traits/specialize/specialization_graph.rs41
-rw-r--r--compiler/rustc_trait_selection/src/traits/structural_match.rs4
-rw-r--r--compiler/rustc_trait_selection/src/traits/util.rs27
-rw-r--r--compiler/rustc_trait_selection/src/traits/wf.rs7
-rw-r--r--compiler/rustc_traits/src/normalize_erasing_regions.rs19
-rw-r--r--compiler/rustc_ty_utils/src/needs_drop.rs6
-rw-r--r--compiler/rustc_ty_utils/src/ty.rs108
-rw-r--r--compiler/rustc_type_ir/src/lib.rs1
-rw-r--r--compiler/rustc_typeck/src/astconv/errors.rs2
-rw-r--r--compiler/rustc_typeck/src/astconv/generics.rs36
-rw-r--r--compiler/rustc_typeck/src/astconv/mod.rs187
-rw-r--r--compiler/rustc_typeck/src/bounds.rs2
-rw-r--r--compiler/rustc_typeck/src/check/_match.rs2
-rw-r--r--compiler/rustc_typeck/src/check/callee.rs2
-rw-r--r--compiler/rustc_typeck/src/check/cast.rs6
-rw-r--r--compiler/rustc_typeck/src/check/check.rs38
-rw-r--r--compiler/rustc_typeck/src/check/closure.rs2
-rw-r--r--compiler/rustc_typeck/src/check/coercion.rs33
-rw-r--r--compiler/rustc_typeck/src/check/compare_method.rs85
-rw-r--r--compiler/rustc_typeck/src/check/demand.rs119
-rw-r--r--compiler/rustc_typeck/src/check/dropck.rs2
-rw-r--r--compiler/rustc_typeck/src/check/expr.rs108
-rw-r--r--compiler/rustc_typeck/src/check/fn_ctxt/_impl.rs141
-rw-r--r--compiler/rustc_typeck/src/check/fn_ctxt/checks.rs73
-rw-r--r--compiler/rustc_typeck/src/check/gather_locals.rs65
-rw-r--r--compiler/rustc_typeck/src/check/generator_interior.rs24
-rw-r--r--compiler/rustc_typeck/src/check/inherited.rs18
-rw-r--r--compiler/rustc_typeck/src/check/method/mod.rs2
-rw-r--r--compiler/rustc_typeck/src/check/method/prelude2021.rs5
-rw-r--r--compiler/rustc_typeck/src/check/method/probe.rs4
-rw-r--r--compiler/rustc_typeck/src/check/method/suggest.rs45
-rw-r--r--compiler/rustc_typeck/src/check/mod.rs10
-rw-r--r--compiler/rustc_typeck/src/check/op.rs31
-rw-r--r--compiler/rustc_typeck/src/check/pat.rs4
-rw-r--r--compiler/rustc_typeck/src/check/place_op.rs7
-rw-r--r--compiler/rustc_typeck/src/check/regionck.rs4
-rw-r--r--compiler/rustc_typeck/src/check/upvar.rs33
-rw-r--r--compiler/rustc_typeck/src/check/wfcheck.rs102
-rw-r--r--compiler/rustc_typeck/src/check_unused.rs9
-rw-r--r--compiler/rustc_typeck/src/coherence/builtin.rs28
-rw-r--r--compiler/rustc_typeck/src/coherence/inherent_impls.rs4
-rw-r--r--compiler/rustc_typeck/src/coherence/inherent_impls_overlap.rs12
-rw-r--r--compiler/rustc_typeck/src/coherence/orphan.rs2
-rw-r--r--compiler/rustc_typeck/src/coherence/unsafety.rs8
-rw-r--r--compiler/rustc_typeck/src/collect.rs150
-rw-r--r--compiler/rustc_typeck/src/collect/type_of.rs25
-rw-r--r--compiler/rustc_typeck/src/expr_use_visitor.rs10
-rw-r--r--compiler/rustc_typeck/src/impl_wf_check.rs2
-rw-r--r--compiler/rustc_typeck/src/lib.rs3
-rw-r--r--compiler/rustc_typeck/src/outlives/test.rs2
-rw-r--r--compiler/rustc_typeck/src/variance/test.rs2
-rw-r--r--library/alloc/benches/vec.rs19
-rw-r--r--library/alloc/src/borrow.rs2
-rw-r--r--library/alloc/src/boxed.rs173
-rw-r--r--library/alloc/src/collections/binary_heap.rs81
-rw-r--r--library/alloc/src/collections/btree/map.rs17
-rw-r--r--library/alloc/src/collections/btree/map/tests.rs6
-rw-r--r--library/alloc/src/collections/btree/set.rs148
-rw-r--r--library/alloc/src/collections/btree/set/tests.rs38
-rw-r--r--library/alloc/src/collections/btree/testing/crash_test.rs4
-rw-r--r--library/alloc/src/collections/linked_list.rs4
-rw-r--r--library/alloc/src/collections/vec_deque/iter_mut.rs8
-rw-r--r--library/alloc/src/collections/vec_deque/mod.rs65
-rw-r--r--library/alloc/src/lib.rs4
-rw-r--r--library/alloc/src/raw_vec.rs8
-rw-r--r--library/alloc/src/raw_vec/tests.rs84
-rw-r--r--library/alloc/src/rc.rs2
-rw-r--r--library/alloc/src/str.rs12
-rw-r--r--library/alloc/src/string.rs16
-rw-r--r--library/alloc/src/sync.rs2
-rw-r--r--library/alloc/src/vec/drain.rs55
-rw-r--r--library/alloc/src/vec/mod.rs71
-rw-r--r--library/alloc/tests/boxed.rs2
-rw-r--r--library/alloc/tests/slice.rs8
-rw-r--r--library/alloc/tests/str.rs2
-rw-r--r--library/alloc/tests/vec.rs3
-rw-r--r--library/core/src/alloc/layout.rs22
-rw-r--r--library/core/src/any.rs174
-rw-r--r--library/core/src/array/equality.rs95
-rw-r--r--library/core/src/array/iter.rs223
-rw-r--r--library/core/src/array/mod.rs238
-rw-r--r--library/core/src/bool.rs13
-rw-r--r--library/core/src/borrow.rs15
-rw-r--r--library/core/src/cell.rs6
-rw-r--r--library/core/src/cmp.rs5
-rw-r--r--library/core/src/convert/mod.rs5
-rw-r--r--library/core/src/fmt/mod.rs42
-rw-r--r--library/core/src/future/future.rs6
-rw-r--r--library/core/src/future/into_future.rs1
-rw-r--r--library/core/src/future/join.rs193
-rw-r--r--library/core/src/future/mod.rs4
-rw-r--r--library/core/src/future/ready.rs2
-rw-r--r--library/core/src/hash/mod.rs13
-rw-r--r--library/core/src/hint.rs5
-rw-r--r--library/core/src/intrinsics.rs78
-rw-r--r--library/core/src/iter/adapters/mod.rs2
-rw-r--r--library/core/src/iter/adapters/skip.rs4
-rw-r--r--library/core/src/iter/adapters/take.rs29
-rw-r--r--library/core/src/iter/adapters/zip.rs25
-rw-r--r--library/core/src/iter/mod.rs2
-rw-r--r--library/core/src/iter/range.rs4
-rw-r--r--library/core/src/iter/traits/double_ended.rs3
-rw-r--r--library/core/src/iter/traits/iterator.rs137
-rw-r--r--library/core/src/lib.rs35
-rw-r--r--library/core/src/macros/mod.rs28
-rw-r--r--library/core/src/mem/manually_drop.rs4
-rw-r--r--library/core/src/mem/maybe_uninit.rs17
-rw-r--r--library/core/src/num/dec2flt/fpu.rs1
-rw-r--r--library/core/src/num/dec2flt/number.rs2
-rw-r--r--library/core/src/num/fmt.rs2
-rw-r--r--library/core/src/num/nonzero.rs4
-rw-r--r--library/core/src/num/saturating.rs2
-rw-r--r--library/core/src/num/uint_macros.rs2
-rw-r--r--library/core/src/ops/control_flow.rs9
-rw-r--r--library/core/src/ops/generator.rs1
-rw-r--r--library/core/src/ops/mod.rs8
-rw-r--r--library/core/src/ops/range.rs18
-rw-r--r--library/core/src/ops/try_trait.rs76
-rw-r--r--library/core/src/option.rs309
-rw-r--r--library/core/src/prelude/v1.rs17
-rw-r--r--library/core/src/primitive_docs.rs3
-rw-r--r--library/core/src/ptr/const_ptr.rs56
-rw-r--r--library/core/src/ptr/mut_ptr.rs64
-rw-r--r--library/core/src/ptr/non_null.rs12
-rw-r--r--library/core/src/ptr/unique.rs6
-rw-r--r--library/core/src/result.rs74
-rw-r--r--library/core/src/slice/index.rs15
-rw-r--r--library/core/src/slice/iter.rs8
-rw-r--r--library/core/src/slice/mod.rs465
-rw-r--r--library/core/src/slice/raw.rs8
-rw-r--r--library/core/src/slice/rotate.rs6
-rw-r--r--library/core/src/slice/sort.rs37
-rw-r--r--library/core/src/str/iter.rs18
-rw-r--r--library/core/src/str/lossy.rs80
-rw-r--r--library/core/src/str/mod.rs8
-rw-r--r--library/core/src/str/validations.rs33
-rw-r--r--library/core/src/stream/mod.rs6
-rw-r--r--library/core/src/stream/stream.rs (renamed from library/core/src/stream/stream/mod.rs)4
-rw-r--r--library/core/src/time.rs36
-rw-r--r--library/core/tests/array.rs200
-rw-r--r--library/core/tests/bool.rs14
-rw-r--r--library/core/tests/cmp.rs33
-rw-r--r--library/core/tests/convert.rs16
-rw-r--r--library/core/tests/future.rs119
-rw-r--r--library/core/tests/intrinsics.rs30
-rw-r--r--library/core/tests/iter/adapters/chain.rs8
-rw-r--r--library/core/tests/iter/adapters/flatten.rs14
-rw-r--r--library/core/tests/iter/adapters/skip.rs11
-rw-r--r--library/core/tests/iter/adapters/take.rs22
-rw-r--r--library/core/tests/iter/range.rs3
-rw-r--r--library/core/tests/iter/traits/iterator.rs28
-rw-r--r--library/core/tests/lib.rs19
-rw-r--r--library/core/tests/mem.rs32
-rw-r--r--library/core/tests/option.rs98
-rw-r--r--library/core/tests/ptr.rs15
-rw-r--r--library/core/tests/simd.rs2
-rw-r--r--library/core/tests/slice.rs146
-rw-r--r--library/panic_abort/src/lib.rs7
-rw-r--r--library/panic_unwind/src/emcc.rs2
-rw-r--r--library/portable-simd/CONTRIBUTING.md2
-rw-r--r--library/portable-simd/README.md2
-rw-r--r--library/portable-simd/crates/core_simd/examples/nbody.rs10
-rw-r--r--library/portable-simd/crates/core_simd/src/comparisons.rs6
-rw-r--r--library/portable-simd/crates/core_simd/src/lane_count.rs12
-rw-r--r--library/portable-simd/crates/core_simd/src/masks.rs24
-rw-r--r--library/portable-simd/crates/core_simd/src/masks/bitmask.rs33
-rw-r--r--library/portable-simd/crates/core_simd/src/masks/full_masks.rs34
-rw-r--r--library/portable-simd/crates/core_simd/src/math.rs8
-rw-r--r--library/portable-simd/crates/core_simd/src/ops.rs419
-rw-r--r--library/portable-simd/crates/core_simd/src/ops/assign.rs124
-rw-r--r--library/portable-simd/crates/core_simd/src/ops/deref.rs124
-rw-r--r--library/portable-simd/crates/core_simd/src/ops/unary.rs77
-rw-r--r--library/portable-simd/crates/core_simd/src/reduction.rs66
-rw-r--r--library/portable-simd/crates/core_simd/src/select.rs3
-rw-r--r--library/portable-simd/crates/core_simd/src/swizzle.rs9
-rw-r--r--library/portable-simd/crates/core_simd/src/vector/float.rs20
-rw-r--r--library/portable-simd/crates/core_simd/src/vector/ptr.rs4
-rw-r--r--library/portable-simd/crates/core_simd/src/vendor/x86.rs4
-rw-r--r--library/portable-simd/crates/core_simd/tests/autoderef.rs22
-rw-r--r--library/portable-simd/crates/core_simd/tests/ops_macros.rs48
-rw-r--r--library/portable-simd/crates/test_helpers/src/lib.rs12
-rw-r--r--library/proc_macro/src/bridge/client.rs4
-rw-r--r--library/proc_macro/src/bridge/mod.rs8
-rw-r--r--library/proc_macro/src/bridge/rpc.rs8
-rw-r--r--library/proc_macro/src/lib.rs1
-rw-r--r--library/std/Cargo.toml6
-rw-r--r--library/std/src/collections/hash/map.rs125
-rw-r--r--library/std/src/collections/hash/set.rs77
-rw-r--r--library/std/src/env.rs21
-rw-r--r--library/std/src/ffi/c_str.rs2
-rw-r--r--library/std/src/ffi/mod.rs23
-rw-r--r--library/std/src/fs.rs24
-rw-r--r--library/std/src/fs/tests.rs11
-rw-r--r--library/std/src/io/buffered/bufreader.rs59
-rw-r--r--library/std/src/io/buffered/tests.rs52
-rw-r--r--library/std/src/io/copy.rs81
-rw-r--r--library/std/src/io/cursor.rs17
-rw-r--r--library/std/src/io/error.rs35
-rw-r--r--library/std/src/io/impls.rs38
-rw-r--r--library/std/src/io/mod.rs241
-rw-r--r--library/std/src/io/readbuf.rs245
-rw-r--r--library/std/src/io/readbuf/tests.rs181
-rw-r--r--library/std/src/io/stdio.rs18
-rw-r--r--library/std/src/io/tests.rs45
-rw-r--r--library/std/src/io/util.rs29
-rw-r--r--library/std/src/io/util/tests.rs29
-rw-r--r--library/std/src/lib.rs29
-rw-r--r--library/std/src/net/ip/tests.rs2
-rw-r--r--library/std/src/net/tcp.rs14
-rw-r--r--library/std/src/os/fortanix_sgx/arch.rs1
-rw-r--r--library/std/src/os/raw/mod.rs6
-rw-r--r--library/std/src/os/unix/net/stream.rs12
-rw-r--r--library/std/src/os/windows/fs.rs20
-rw-r--r--library/std/src/panicking.rs6
-rw-r--r--library/std/src/path.rs9
-rw-r--r--library/std/src/prelude/v1.rs17
-rw-r--r--library/std/src/primitive_docs.rs3
-rw-r--r--library/std/src/process.rs15
-rw-r--r--library/std/src/process/tests.rs64
-rw-r--r--library/std/src/sys/hermit/fd.rs2
-rw-r--r--library/std/src/sys/hermit/fs.rs6
-rw-r--r--library/std/src/sys/hermit/mutex.rs11
-rw-r--r--library/std/src/sys/itron/thread.rs4
-rw-r--r--library/std/src/sys/sgx/abi/mem.rs2
-rw-r--r--library/std/src/sys/sgx/abi/mod.rs1
-rw-r--r--library/std/src/sys/solid/abi/mod.rs8
-rw-r--r--library/std/src/sys/unix/android.rs90
-rw-r--r--library/std/src/sys/unix/fd.rs72
-rw-r--r--library/std/src/sys/unix/fs.rs26
-rw-r--r--library/std/src/sys/unix/kernel_copy.rs14
-rw-r--r--library/std/src/sys/unix/net.rs4
-rw-r--r--library/std/src/sys/unix/os.rs30
-rw-r--r--library/std/src/sys/unix/os/tests.rs10
-rw-r--r--library/std/src/sys/unix/process/process_fuchsia.rs2
-rw-r--r--library/std/src/sys/unix/process/process_unix.rs4
-rw-r--r--library/std/src/sys/unix/thread.rs17
-rw-r--r--library/std/src/sys/unix/weak.rs104
-rw-r--r--library/std/src/sys/unsupported/fs.rs6
-rw-r--r--library/std/src/sys/wasi/fs.rs6
-rw-r--r--library/std/src/sys/wasm/alloc.rs8
-rw-r--r--library/std/src/sys/wasm/atomics/mutex.rs6
-rw-r--r--library/std/src/sys/windows/c.rs6
-rw-r--r--library/std/src/sys/windows/fs.rs6
-rw-r--r--library/std/src/sys/windows/handle.rs35
-rw-r--r--library/std/src/sys/windows/mod.rs6
-rw-r--r--library/std/src/sys/windows/os.rs2
-rw-r--r--library/std/src/sys/windows/stdio.rs2
-rw-r--r--library/std/src/sys/windows/thread_parker.rs2
-rw-r--r--library/std/src/sys_common/thread_parker/generic.rs6
-rw-r--r--library/std/src/thread/local.rs19
-rw-r--r--library/std/src/thread/mod.rs16
-rw-r--r--library/std/src/thread/tests.rs15
-rw-r--r--library/std/src/time.rs2
m---------library/stdarch0
-rw-r--r--library/unwind/build.rs3
-rw-r--r--src/bootstrap/bootstrap.py15
-rw-r--r--src/bootstrap/builder.rs7
-rw-r--r--src/bootstrap/clean.rs6
-rw-r--r--src/bootstrap/compile.rs16
-rw-r--r--src/bootstrap/defaults/config.tools.toml4
-rw-r--r--src/bootstrap/dist.rs11
-rw-r--r--src/bootstrap/download-ci-llvm-stamp2
-rw-r--r--src/bootstrap/lib.rs4
-rw-r--r--src/bootstrap/native.rs11
-rw-r--r--src/ci/docker/host-x86_64/dist-aarch64-linux/Dockerfile13
-rw-r--r--src/ci/docker/host-x86_64/dist-arm-linux/Dockerfile13
-rw-r--r--src/ci/docker/host-x86_64/dist-armhf-linux/Dockerfile13
-rw-r--r--src/ci/docker/host-x86_64/dist-armv7-linux/Dockerfile13
-rw-r--r--src/ci/docker/host-x86_64/x86_64-gnu-tools/Dockerfile2
-rwxr-xr-xsrc/ci/docker/scripts/freebsd-toolchain.sh2
m---------src/doc/book0
m---------src/doc/edition-guide0
m---------src/doc/embedded-book0
m---------src/doc/nomicon0
m---------src/doc/reference0
m---------src/doc/rust-by-example0
m---------src/doc/rustc-dev-guide0
-rw-r--r--src/doc/rustc/src/platform-support.md1
-rw-r--r--src/doc/rustdoc/src/command-line-arguments.md4
-rw-r--r--src/doc/rustdoc/src/documentation-tests.md15
-rw-r--r--src/doc/rustdoc/src/unstable-features.md23
-rw-r--r--src/doc/unstable-book/src/compiler-flags/instrument-coverage.md4
-rw-r--r--src/doc/unstable-book/src/compiler-flags/sanitizer.md3
-rw-r--r--src/doc/unstable-book/src/language-features/asm-const.md11
-rw-r--r--src/doc/unstable-book/src/language-features/asm-experimental-arch.md117
-rw-r--r--src/doc/unstable-book/src/language-features/asm-sym.md13
-rw-r--r--src/doc/unstable-book/src/language-features/asm-unwind.md9
-rw-r--r--src/doc/unstable-book/src/language-features/inline-const-pat.md24
-rw-r--r--src/doc/unstable-book/src/language-features/inline-const.md17
-rw-r--r--src/doc/unstable-book/src/library-features/asm.md896
-rw-r--r--src/doc/unstable-book/src/library-features/global-asm.md113
-rw-r--r--src/doc/unstable-book/src/library-features/llvm-asm.md3
-rw-r--r--src/etc/htmldocck.py80
-rw-r--r--src/librustdoc/clean/auto_trait.rs21
-rw-r--r--src/librustdoc/clean/blanket_impl.rs11
-rw-r--r--src/librustdoc/clean/inline.rs40
-rw-r--r--src/librustdoc/clean/mod.rs882
-rw-r--r--src/librustdoc/clean/types.rs142
-rw-r--r--src/librustdoc/clean/utils.rs41
-rw-r--r--src/librustdoc/config.rs48
-rw-r--r--src/librustdoc/doctest.rs145
-rw-r--r--src/librustdoc/doctest/tests.rs49
-rw-r--r--src/librustdoc/error.rs5
-rw-r--r--src/librustdoc/formats/cache.rs12
-rw-r--r--src/librustdoc/html/format.rs49
-rw-r--r--src/librustdoc/html/highlight.rs2
-rw-r--r--src/librustdoc/html/layout.rs26
-rw-r--r--src/librustdoc/html/markdown.rs2
-rw-r--r--src/librustdoc/html/markdown/tests.rs8
-rw-r--r--src/librustdoc/html/mod.rs1
-rw-r--r--src/librustdoc/html/render/cache.rs34
-rw-r--r--src/librustdoc/html/render/context.rs18
-rw-r--r--src/librustdoc/html/render/mod.rs138
-rw-r--r--src/librustdoc/html/render/print_item.rs76
-rw-r--r--src/librustdoc/html/render/write_shared.rs86
-rw-r--r--src/librustdoc/html/static/css/noscript.css2
-rw-r--r--src/librustdoc/html/static/css/rustdoc.css339
-rw-r--r--src/librustdoc/html/static/css/themes/ayu.css23
-rw-r--r--src/librustdoc/html/static/css/themes/dark.css29
-rw-r--r--src/librustdoc/html/static/css/themes/light.css29
-rw-r--r--src/librustdoc/html/static/js/main.js48
-rw-r--r--src/librustdoc/html/static/js/search.js266
-rw-r--r--src/librustdoc/html/static/js/source-script.js33
-rw-r--r--src/librustdoc/html/static/js/storage.js7
-rw-r--r--src/librustdoc/html/templates/page.html119
-rw-r--r--src/librustdoc/html/tests.rs16
-rw-r--r--src/librustdoc/html/url_parts_builder.rs119
-rw-r--r--src/librustdoc/html/url_parts_builder/tests.rs54
-rw-r--r--src/librustdoc/json/conversions.rs24
-rw-r--r--src/librustdoc/lib.rs11
-rw-r--r--src/librustdoc/markdown.rs12
-rw-r--r--src/librustdoc/passes/bare_urls.rs2
-rw-r--r--src/librustdoc/passes/calculate_doc_coverage.rs1
-rw-r--r--src/librustdoc/passes/check_code_block_syntax.rs1
-rw-r--r--src/librustdoc/passes/check_doc_test_visibility.rs2
-rw-r--r--src/librustdoc/passes/collect_intra_doc_links.rs2
-rw-r--r--src/librustdoc/passes/collect_trait_impls.rs3
-rw-r--r--src/librustdoc/passes/html_tags.rs1
-rw-r--r--src/librustdoc/passes/propagate_doc_cfg.rs1
-rw-r--r--src/librustdoc/passes/strip_hidden.rs1
-rw-r--r--src/librustdoc/passes/strip_priv_imports.rs2
-rw-r--r--src/librustdoc/passes/strip_private.rs2
-rw-r--r--src/librustdoc/passes/stripper.rs1
-rw-r--r--src/librustdoc/passes/unindent_comments.rs13
-rw-r--r--src/librustdoc/passes/unindent_comments/tests.rs5
-rw-r--r--src/librustdoc/scrape_examples.rs17
-rw-r--r--src/librustdoc/theme.rs10
-rw-r--r--src/librustdoc/visit_ast.rs9
m---------src/llvm-project0
-rw-r--r--src/stage0.json672
-rw-r--r--src/test/assembly/asm/arm-modifiers.rs6
-rw-r--r--src/test/assembly/asm/arm-types.rs30
-rw-r--r--src/test/assembly/asm/avr-modifiers.rs60
-rw-r--r--src/test/assembly/asm/avr-types.rs222
-rw-r--r--src/test/assembly/asm/global_asm.rs4
-rw-r--r--src/test/assembly/sparc-struct-abi.rs64
-rw-r--r--src/test/assembly/stack-protector/stack-protector-heuristics-effect.rs396
-rw-r--r--src/test/assembly/stack-protector/stack-protector-target-support.rs286
-rw-r--r--src/test/assembly/x86_64-fortanix-unknown-sgx-lvi-inline-assembly.rs16
-rw-r--r--src/test/codegen/asm-clobber_abi.rs3
-rw-r--r--src/test/codegen/asm-clobbers.rs3
-rw-r--r--src/test/codegen/asm-may_unwind.rs27
-rw-r--r--src/test/codegen/asm-multiple-options.rs3
-rw-r--r--src/test/codegen/asm-options.rs3
-rw-r--r--src/test/codegen/asm-target-clobbers.rs3
-rw-r--r--src/test/codegen/auxiliary/thread_local_aux.rs1
-rw-r--r--src/test/codegen/dst-vtable-align-nonzero.rs45
-rw-r--r--src/test/codegen/global_asm.rs9
-rw-r--r--src/test/codegen/global_asm_include.rs3
-rw-r--r--src/test/codegen/global_asm_x2.rs17
-rw-r--r--src/test/codegen/merge-functions.rs14
-rw-r--r--src/test/codegen/naked-noinline.rs23
-rw-r--r--src/test/codegen/slice-ref-equality.rs19
-rw-r--r--src/test/codegen/sparc-struct-abi.rs58
-rw-r--r--src/test/codegen/stack-protector.rs34
-rw-r--r--src/test/codegen/thread-local.rs1
-rw-r--r--src/test/debuginfo/rc_arc.rs2
-rw-r--r--src/test/incremental/const-generics/hash-tyvid-regression-2.rs2
-rw-r--r--src/test/incremental/issue-72386.rs6
-rw-r--r--src/test/incremental/issue-85360-eval-obligation-ice.rs118
-rw-r--r--src/test/mir-opt/const_promotion_extern_static.BAR.PromoteTemps.diff2
-rw-r--r--src/test/mir-opt/const_promotion_extern_static.FOO.PromoteTemps.diff2
-rw-r--r--src/test/mir-opt/const_prop/bad_op_unsafe_oob_for_slices.main.ConstProp.32bit.diff2
-rw-r--r--src/test/mir-opt/const_prop/bad_op_unsafe_oob_for_slices.main.ConstProp.64bit.diff2
-rw-r--r--src/test/mir-opt/const_prop/const_prop_fails_gracefully.main.ConstProp.diff2
-rw-r--r--src/test/mir-opt/const_prop/ref_deref.main.ConstProp.diff2
-rw-r--r--src/test/mir-opt/const_prop/ref_deref.main.PromoteTemps.diff2
-rw-r--r--src/test/mir-opt/const_prop/ref_deref_project.main.ConstProp.diff2
-rw-r--r--src/test/mir-opt/const_prop/ref_deref_project.main.PromoteTemps.diff2
-rw-r--r--src/test/mir-opt/const_prop/slice_len.main.ConstProp.32bit.diff2
-rw-r--r--src/test/mir-opt/const_prop/slice_len.main.ConstProp.64bit.diff2
-rw-r--r--src/test/mir-opt/const_prop/switch_int.main.SimplifyConstCondition-after-const-prop.diff (renamed from src/test/mir-opt/const_prop/switch_int.main.SimplifyBranches-after-const-prop.diff)4
-rw-r--r--src/test/mir-opt/const_prop/switch_int.rs2
-rw-r--r--src/test/mir-opt/early_otherwise_branch_68867.rs2
-rw-r--r--src/test/mir-opt/early_otherwise_branch_68867.try_sum.EarlyOtherwiseBranch.before-SimplifyConstCondition-final.after.diff (renamed from src/test/mir-opt/early_otherwise_branch_68867.try_sum.EarlyOtherwiseBranch.before-SimplifyBranches-final.after.diff)2
-rw-r--r--src/test/mir-opt/early_otherwise_branch_noopt.rs2
-rw-r--r--src/test/mir-opt/generator_drop_cleanup.main-{closure#0}.generator_drop.0.mir15
-rw-r--r--src/test/mir-opt/inline/inline_retag.bar.Inline.after.mir4
-rw-r--r--src/test/mir-opt/inline/issue_78442.bar.Inline.diff6
-rw-r--r--src/test/mir-opt/inline/issue_78442.bar.RevealAll.diff10
-rw-r--r--src/test/mir-opt/issue_73223.main.PreCodegen.32bit.diff2
-rw-r--r--src/test/mir-opt/issue_73223.main.PreCodegen.64bit.diff2
-rw-r--r--src/test/mir-opt/issue_73223.main.SimplifyArmIdentity.32bit.diff2
-rw-r--r--src/test/mir-opt/issue_73223.main.SimplifyArmIdentity.64bit.diff2
-rw-r--r--src/test/mir-opt/lower_intrinsics.discriminant.LowerIntrinsics.diff6
-rw-r--r--src/test/mir-opt/match_false_edges.full_tested_match.PromoteTemps.after.mir2
-rw-r--r--src/test/mir-opt/retag.array_casts.SimplifyCfg-elaborate-drops.after.mir2
-rw-r--r--src/test/mir-opt/retag.main.SimplifyCfg-elaborate-drops.after.mir4
-rw-r--r--src/test/mir-opt/separate_const_switch.identity.ConstProp.diff2
-rw-r--r--src/test/mir-opt/separate_const_switch.identity.PreCodegen.after.mir2
-rw-r--r--src/test/mir-opt/separate_const_switch.identity.SeparateConstSwitch.diff2
-rw-r--r--src/test/mir-opt/simplify_if.main.SimplifyConstCondition-after-const-prop.diff (renamed from src/test/mir-opt/simplify_if.main.SimplifyBranches-after-const-prop.diff)4
-rw-r--r--src/test/mir-opt/simplify_if.rs2
-rw-r--r--src/test/pretty/asm.pp4
-rw-r--r--src/test/pretty/asm.rs10
-rw-r--r--src/test/pretty/ast-stmt-expr-attr.rs12
-rw-r--r--src/test/pretty/async.rs9
-rw-r--r--src/test/pretty/attr-derive.rs2
-rw-r--r--src/test/pretty/auto-trait.rs6
-rw-r--r--src/test/pretty/block-comment-trailing-whitespace2.rs9
-rw-r--r--src/test/pretty/closure-reform-pretty.rs12
-rw-r--r--src/test/pretty/disamb-stmt-expr.rs2
-rw-r--r--src/test/pretty/enum-variant-vis.rs2
-rw-r--r--src/test/pretty/example1.rs2
-rw-r--r--src/test/pretty/example2.pp2
-rw-r--r--src/test/pretty/example2.rs2
-rw-r--r--src/test/pretty/expanded-and-path-remap-80832.pp2
-rw-r--r--src/test/pretty/fn-return.rs6
-rw-r--r--src/test/pretty/fn-types.rs6
-rw-r--r--src/test/pretty/fn-variadic.rs2
-rw-r--r--src/test/pretty/hir-pretty-loop.pp2
-rw-r--r--src/test/pretty/if-attr.rs18
-rw-r--r--src/test/pretty/issue-12590-a.rs2
-rw-r--r--src/test/pretty/issue-12590-c.pp6
-rw-r--r--src/test/pretty/issue-12590-c.rs2
-rw-r--r--src/test/pretty/issue-19077.rs4
-rw-r--r--src/test/pretty/issue-30731.rs2
-rw-r--r--src/test/pretty/issue-68710-field-attr-proc-mac-lost.rs2
-rw-r--r--src/test/pretty/lifetime.rs4
-rw-r--r--src/test/pretty/macro.rs2
-rw-r--r--src/test/pretty/macro_rules.rs12
-rw-r--r--src/test/pretty/nested-item-vis-defaultness.rs2
-rw-r--r--src/test/pretty/path-type-bounds.rs4
-rw-r--r--src/test/pretty/qpath-associated-type-bound.rs4
-rw-r--r--src/test/pretty/stmt_expr_attributes.rs23
-rw-r--r--src/test/pretty/tag-blank-lines.rs2
-rw-r--r--src/test/pretty/trait-inner-attr.rs2
-rw-r--r--src/test/pretty/trait-polarity.rs4
-rw-r--r--src/test/pretty/trait-safety.rs4
-rw-r--r--src/test/pretty/where-clauses.rs2
-rw-r--r--src/test/run-make-fulldeps/coverage-llvmir/Makefile6
-rw-r--r--src/test/run-make-fulldeps/coverage-reports/Makefile7
-rw-r--r--src/test/run-make-fulldeps/coverage-reports/expected_show_coverage.async.txt4
-rw-r--r--src/test/run-make-fulldeps/coverage-reports/expected_show_coverage.issue-85461.txt36
-rw-r--r--src/test/run-make-fulldeps/coverage/issue-85461.rs10
-rw-r--r--src/test/run-make-fulldeps/coverage/lib/inline_always_with_dead_code.rs22
-rw-r--r--src/test/run-make-fulldeps/crate-hash-rustc-version/Makefile37
-rw-r--r--src/test/run-make-fulldeps/crate-hash-rustc-version/a.rs4
-rw-r--r--src/test/run-make-fulldeps/crate-hash-rustc-version/b.rs8
-rw-r--r--src/test/run-make-fulldeps/extern-fn-reachable/Makefile20
-rw-r--r--src/test/run-make-fulldeps/extern-fn-reachable/main.rs18
-rw-r--r--src/test/run-make-fulldeps/hotplug_codegen_backend/the_backend.rs1
-rw-r--r--src/test/run-make-fulldeps/split-dwarf/Makefile11
-rw-r--r--src/test/run-make/rustdoc-with-out-dir-option/Makefile8
-rw-r--r--src/test/run-make/rustdoc-with-out-dir-option/src/lib.rs2
-rw-r--r--src/test/run-make/rustdoc-with-output-option/Makefile8
-rw-r--r--src/test/run-make/rustdoc-with-output-option/src/lib.rs2
-rw-r--r--src/test/run-make/rustdoc-with-short-out-dir-option/Makefile8
-rw-r--r--src/test/run-make/rustdoc-with-short-out-dir-option/src/lib.rs2
-rw-r--r--src/test/run-make/x86_64-fortanix-unknown-sgx-lvi/enclave/src/main.rs67
-rw-r--r--src/test/rustdoc-gui/anchors.goml74
-rw-r--r--src/test/rustdoc-gui/check-code-blocks-margin.goml4
-rw-r--r--src/test/rustdoc-gui/docblock-code-block-line-number.goml2
-rw-r--r--src/test/rustdoc-gui/docblock-table-overflow.goml6
-rw-r--r--src/test/rustdoc-gui/escape-key.goml10
-rw-r--r--src/test/rustdoc-gui/font-weight.goml15
-rw-r--r--src/test/rustdoc-gui/headers-color.goml94
-rw-r--r--src/test/rustdoc-gui/huge-collection-of-constants.goml6
-rw-r--r--src/test/rustdoc-gui/impl-default-expansion.goml2
-rw-r--r--src/test/rustdoc-gui/item-info-width.goml2
-rw-r--r--src/test/rustdoc-gui/jump-to-def-background.goml30
-rw-r--r--src/test/rustdoc-gui/label-next-to-symbol.goml64
-rw-r--r--src/test/rustdoc-gui/module-items-font.goml72
-rw-r--r--src/test/rustdoc-gui/search-filter.goml4
-rw-r--r--src/test/rustdoc-gui/search-result-color.goml57
-rw-r--r--src/test/rustdoc-gui/search-result-colors.goml6
-rw-r--r--src/test/rustdoc-gui/search-result-go-to-first.goml2
-rw-r--r--src/test/rustdoc-gui/sidebar-source-code.goml32
-rw-r--r--src/test/rustdoc-gui/source-code-page.goml2
-rw-r--r--src/test/rustdoc-gui/src/lib2/lib.rs2
-rw-r--r--src/test/rustdoc-gui/src/test_docs/lib.rs4
-rw-r--r--src/test/rustdoc-gui/toggle-click-deadspace.goml12
-rw-r--r--src/test/rustdoc-gui/toggle-docs.goml6
-rw-r--r--src/test/rustdoc-gui/type-declation-overflow.goml4
-rw-r--r--src/test/rustdoc-js/summaries.rs2
-rw-r--r--src/test/rustdoc-json/primitive.rs2
-rw-r--r--src/test/rustdoc-ui/auxiliary/empty-fn.rs3
-rw-r--r--src/test/rustdoc-ui/auxiliary/overflow.rs20
-rw-r--r--src/test/rustdoc-ui/coverage/exotic.rs3
-rw-r--r--src/test/rustdoc-ui/display-output.rs8
-rw-r--r--src/test/rustdoc-ui/display-output.stdout36
-rw-r--r--src/test/rustdoc-ui/intra-doc/auxiliary/through-proc-macro-aux.rs (renamed from src/test/rustdoc/intra-doc/auxiliary/through-proc-macro-aux.rs)0
-rw-r--r--src/test/rustdoc-ui/intra-doc/through-proc-macro.rs (renamed from src/test/rustdoc/intra-doc/through-proc-macro.rs)8
-rw-r--r--src/test/rustdoc-ui/intra-doc/through-proc-macro.stderr15
-rw-r--r--src/test/rustdoc-ui/invalid-keyword.rs2
-rw-r--r--src/test/rustdoc-ui/issue-91134.rs14
-rw-r--r--src/test/rustdoc-ui/issue-91134.stdout6
-rw-r--r--src/test/rustdoc-ui/issue-91713.rs3
-rw-r--r--src/test/rustdoc-ui/issue-91713.stderr4
-rw-r--r--src/test/rustdoc-ui/issue-91713.stdout31
-rw-r--r--src/test/rustdoc-ui/normalize-cycle.rs25
-rw-r--r--src/test/rustdoc-ui/normalize-overflow.rs3
-rw-r--r--src/test/rustdoc-ui/scrape-examples-ice.rs4
-rw-r--r--src/test/rustdoc-ui/use_both_out_dir_and_output_options.rs1
-rw-r--r--src/test/rustdoc-ui/use_both_out_dir_and_output_options.stderr2
-rw-r--r--src/test/rustdoc/asm-foreign.rs2
-rw-r--r--src/test/rustdoc/asm-foreign2.rs2
-rw-r--r--src/test/rustdoc/auto-impl-primitive.rs3
-rw-r--r--src/test/rustdoc/auxiliary/reexports.rs36
-rw-r--r--src/test/rustdoc/bad-codeblock-syntax.rs2
-rw-r--r--src/test/rustdoc/check-source-code-urls-to-def.rs9
-rw-r--r--src/test/rustdoc/const-generics/const-generic-defaults.rs1
-rw-r--r--src/test/rustdoc/const-generics/const-impl.rs14
-rw-r--r--src/test/rustdoc/default-trait-method.rs2
-rw-r--r--src/test/rustdoc/deref-const-fn.rs38
-rw-r--r--src/test/rustdoc/doc-cfg.rs22
-rw-r--r--src/test/rustdoc/doc-notable_trait-mut_t_is_not_an_iterator.rs23
-rw-r--r--src/test/rustdoc/doc-notable_trait-mut_t_is_not_ref_t.rs21
-rw-r--r--src/test/rustdoc/doc-notable_trait-slice.rs20
-rw-r--r--src/test/rustdoc/duplicate_impls/issue-33054.rs2
-rw-r--r--src/test/rustdoc/impl-everywhere.rs12
-rw-r--r--src/test/rustdoc/intra-doc/associated-defaults.rs2
-rw-r--r--src/test/rustdoc/intra-doc/associated-items.rs2
-rw-r--r--src/test/rustdoc/intra-doc/auxiliary/my-core.rs2
-rw-r--r--src/test/rustdoc/intra-doc/cross-crate/additional_doc.rs2
-rw-r--r--src/test/rustdoc/intra-doc/cross-crate/auxiliary/additional_doc.rs2
-rw-r--r--src/test/rustdoc/intra-doc/cross-crate/auxiliary/hidden.rs2
-rw-r--r--src/test/rustdoc/intra-doc/cross-crate/auxiliary/intra-doc-basic.rs2
-rw-r--r--src/test/rustdoc/intra-doc/cross-crate/auxiliary/macro_inner.rs2
-rw-r--r--src/test/rustdoc/intra-doc/cross-crate/auxiliary/module.rs2
-rw-r--r--src/test/rustdoc/intra-doc/cross-crate/auxiliary/submodule-inner.rs2
-rw-r--r--src/test/rustdoc/intra-doc/cross-crate/auxiliary/submodule-outer.rs2
-rw-r--r--src/test/rustdoc/intra-doc/cross-crate/basic.rs2
-rw-r--r--src/test/rustdoc/intra-doc/cross-crate/hidden.rs2
-rw-r--r--src/test/rustdoc/intra-doc/cross-crate/macro.rs2
-rw-r--r--src/test/rustdoc/intra-doc/cross-crate/module.rs2
-rw-r--r--src/test/rustdoc/intra-doc/cross-crate/submodule-inner.rs2
-rw-r--r--src/test/rustdoc/intra-doc/cross-crate/submodule-outer.rs2
-rw-r--r--src/test/rustdoc/intra-doc/cross-crate/traits.rs2
-rw-r--r--src/test/rustdoc/intra-doc/disambiguators-removed.rs2
-rw-r--r--src/test/rustdoc/intra-doc/email-address.rs2
-rw-r--r--src/test/rustdoc/intra-doc/extern-crate.rs2
-rw-r--r--src/test/rustdoc/intra-doc/external-traits.rs2
-rw-r--r--src/test/rustdoc/intra-doc/in-bodies.rs2
-rw-r--r--src/test/rustdoc/intra-doc/issue-82209.rs2
-rw-r--r--src/test/rustdoc/intra-doc/libstd-re-export.rs2
-rw-r--r--src/test/rustdoc/intra-doc/mod-ambiguity.rs2
-rw-r--r--src/test/rustdoc/intra-doc/prim-assoc.rs2
-rw-r--r--src/test/rustdoc/intra-doc/prim-methods-external-core.rs6
-rw-r--r--src/test/rustdoc/intra-doc/prim-methods-local.rs9
-rw-r--r--src/test/rustdoc/intra-doc/prim-methods.rs7
-rw-r--r--src/test/rustdoc/intra-doc/prim-precedence.rs2
-rw-r--r--src/test/rustdoc/intra-doc/primitive-disambiguators.rs2
-rw-r--r--src/test/rustdoc/intra-doc/primitive-non-default-impl.rs2
-rw-r--r--src/test/rustdoc/intra-doc/private-failures-ignored.rs2
-rw-r--r--src/test/rustdoc/intra-doc/private.rs5
-rw-r--r--src/test/rustdoc/intra-doc/proc-macro.rs2
-rw-r--r--src/test/rustdoc/intra-doc/pub-use.rs2
-rw-r--r--src/test/rustdoc/intra-doc/raw-ident-self.rs2
-rw-r--r--src/test/rustdoc/intra-doc/trait-item.rs2
-rw-r--r--src/test/rustdoc/intra-doc/true-false.rs7
-rw-r--r--src/test/rustdoc/intra-doc/type-alias.rs2
-rw-r--r--src/test/rustdoc/intra-link-prim-self.rs3
-rw-r--r--src/test/rustdoc/issue-12834.rs1
-rw-r--r--src/test/rustdoc/issue-15318-3.rs2
-rw-r--r--src/test/rustdoc/issue-23511.rs1
-rw-r--r--src/test/rustdoc/issue-32374.rs9
-rw-r--r--src/test/rustdoc/issue-42760.rs2
-rw-r--r--src/test/rustdoc/issue-43869.rs1
-rw-r--r--src/test/rustdoc/issue-55364.rs32
-rw-r--r--src/test/rustdoc/keyword.rs6
-rw-r--r--src/test/rustdoc/legacy-const-generic.rs16
-rw-r--r--src/test/rustdoc/link-title-escape.rs2
-rw-r--r--src/test/rustdoc/logo-class-default.rs4
-rw-r--r--src/test/rustdoc/logo-class.rs10
-rw-r--r--src/test/rustdoc/mixing-doc-comments-and-attrs.S1_top-doc.html4
-rw-r--r--src/test/rustdoc/mixing-doc-comments-and-attrs.S2_top-doc.html4
-rw-r--r--src/test/rustdoc/mixing-doc-comments-and-attrs.rs18
-rw-r--r--src/test/rustdoc/primitive-generic-impl.rs5
-rw-r--r--src/test/rustdoc/primitive/primitive-generic-impl.rs6
-rw-r--r--src/test/rustdoc/proc-macro.rs2
-rw-r--r--src/test/rustdoc/range-arg-pattern.rs2
-rw-r--r--src/test/rustdoc/raw-ident-eliminate-r-hashtag.rs1
-rw-r--r--src/test/rustdoc/reexports-priv.rs112
-rw-r--r--src/test/rustdoc/reexports.rs82
-rw-r--r--src/test/rustdoc/sidebar-items.rs8
-rw-r--r--src/test/rustdoc/static-root-path.rs2
-rw-r--r--src/test/rustdoc/struct-implementations-title.rs2
-rw-r--r--src/test/rustdoc/tab_title.rs2
-rw-r--r--src/test/rustdoc/titles.rs2
-rw-r--r--src/test/rustdoc/trait_alias.rs6
-rw-r--r--src/test/rustdoc/tuple-struct-fields-doc.rs4
-rw-r--r--src/test/rustdoc/type-layout.rs12
-rw-r--r--src/test/ui-fulldeps/auxiliary/issue-40001-plugin.rs4
-rw-r--r--src/test/ui-fulldeps/internal-lints/existing_doc_keyword.rs2
-rw-r--r--src/test/ui/abi/stack-protector.rs99
-rw-r--r--src/test/ui/array-slice-vec/box-of-array-of-drop-1.rs1
-rw-r--r--src/test/ui/array-slice-vec/box-of-array-of-drop-2.rs1
-rw-r--r--src/test/ui/array-slice-vec/nested-vec-3.rs1
-rw-r--r--src/test/ui/array-slice-vec/slice-panic-1.rs1
-rw-r--r--src/test/ui/array-slice-vec/slice-panic-2.rs1
-rw-r--r--src/test/ui/asm/aarch64/bad-options.rs2
-rw-r--r--src/test/ui/asm/aarch64/bad-options.stderr24
-rw-r--r--src/test/ui/asm/aarch64/bad-reg.rs6
-rw-r--r--src/test/ui/asm/aarch64/bad-reg.stderr28
-rw-r--r--src/test/ui/asm/aarch64/const.rs4
-rw-r--r--src/test/ui/asm/aarch64/duplicate-options.fixed6
-rw-r--r--src/test/ui/asm/aarch64/duplicate-options.rs6
-rw-r--r--src/test/ui/asm/aarch64/interpolated-idents.rs2
-rw-r--r--src/test/ui/asm/aarch64/may_unwind.rs38
-rw-r--r--src/test/ui/asm/aarch64/parse-error.rs4
-rw-r--r--src/test/ui/asm/aarch64/parse-error.stderr148
-rw-r--r--src/test/ui/asm/aarch64/srcloc.rs3
-rw-r--r--src/test/ui/asm/aarch64/srcloc.stderr46
-rw-r--r--src/test/ui/asm/aarch64/sym.rs4
-rw-r--r--src/test/ui/asm/aarch64/type-check-2.rs4
-rw-r--r--src/test/ui/asm/aarch64/type-check-2.stderr28
-rw-r--r--src/test/ui/asm/aarch64/type-check-3.rs3
-rw-r--r--src/test/ui/asm/aarch64/type-check-3.stderr38
-rw-r--r--src/test/ui/asm/issue-72570.rs2
-rw-r--r--src/test/ui/asm/issue-87802.rs2
-rw-r--r--src/test/ui/asm/issue-89305.rs3
-rw-r--r--src/test/ui/asm/issue-89305.stderr4
-rw-r--r--src/test/ui/asm/may_unwind.rs11
-rw-r--r--src/test/ui/asm/naked-functions-ffi.rs7
-rw-r--r--src/test/ui/asm/naked-functions-ffi.stderr4
-rw-r--r--src/test/ui/asm/naked-functions-unused.aarch64.stderr20
-rw-r--r--src/test/ui/asm/naked-functions-unused.rs5
-rw-r--r--src/test/ui/asm/naked-functions-unused.x86_64.stderr20
-rw-r--r--src/test/ui/asm/naked-functions.rs3
-rw-r--r--src/test/ui/asm/naked-functions.stderr66
-rw-r--r--src/test/ui/asm/naked-invalid-attr.rs3
-rw-r--r--src/test/ui/asm/naked-invalid-attr.stderr10
-rw-r--r--src/test/ui/asm/named-asm-labels.rs4
-rw-r--r--src/test/ui/asm/named-asm-labels.stderr110
-rw-r--r--src/test/ui/asm/noreturn.rs4
-rw-r--r--src/test/ui/asm/rustfix-asm.fixed17
-rw-r--r--src/test/ui/asm/rustfix-asm.rs17
-rw-r--r--src/test/ui/asm/rustfix-asm.stderr24
-rw-r--r--src/test/ui/asm/type-check-1.rs4
-rw-r--r--src/test/ui/asm/type-check-1.stderr26
-rw-r--r--src/test/ui/asm/type-check-4.rs2
-rw-r--r--src/test/ui/asm/x86_64/bad-clobber-abi.rs4
-rw-r--r--src/test/ui/asm/x86_64/bad-options.rs2
-rw-r--r--src/test/ui/asm/x86_64/bad-options.stderr24
-rw-r--r--src/test/ui/asm/x86_64/bad-reg.rs4
-rw-r--r--src/test/ui/asm/x86_64/bad-reg.stderr46
-rw-r--r--src/test/ui/asm/x86_64/const.rs4
-rw-r--r--src/test/ui/asm/x86_64/duplicate-options.fixed6
-rw-r--r--src/test/ui/asm/x86_64/duplicate-options.rs6
-rw-r--r--src/test/ui/asm/x86_64/interpolated-idents.rs2
-rw-r--r--src/test/ui/asm/x86_64/issue-82869.rs3
-rw-r--r--src/test/ui/asm/x86_64/issue-82869.stderr6
-rw-r--r--src/test/ui/asm/x86_64/issue-89875.rs4
-rw-r--r--src/test/ui/asm/x86_64/may_unwind.rs38
-rw-r--r--src/test/ui/asm/x86_64/multiple-clobber-abi.rs4
-rw-r--r--src/test/ui/asm/x86_64/parse-error.rs4
-rw-r--r--src/test/ui/asm/x86_64/parse-error.stderr152
-rw-r--r--src/test/ui/asm/x86_64/srcloc.rs3
-rw-r--r--src/test/ui/asm/x86_64/srcloc.stderr48
-rw-r--r--src/test/ui/asm/x86_64/sym.rs4
-rw-r--r--src/test/ui/asm/x86_64/target-feature-attr.rs4
-rw-r--r--src/test/ui/asm/x86_64/target-feature-attr.stderr8
-rw-r--r--src/test/ui/asm/x86_64/type-check-2.rs4
-rw-r--r--src/test/ui/asm/x86_64/type-check-2.stderr28
-rw-r--r--src/test/ui/asm/x86_64/type-check-3.rs4
-rw-r--r--src/test/ui/asm/x86_64/type-check-3.stderr32
-rw-r--r--src/test/ui/associated-consts/associated-const-generic-obligations.stderr8
-rw-r--r--src/test/ui/associated-consts/associated-const-impl-wrong-type.stderr9
-rw-r--r--src/test/ui/associated-types/associated-type-destructuring-assignment.rs1
-rw-r--r--src/test/ui/associated-types/associated-types-binding-to-type-defined-in-supertrait.stderr14
-rw-r--r--src/test/ui/associated-types/associated-types-eq-3.rs2
-rw-r--r--src/test/ui/associated-types/associated-types-eq-3.stderr16
-rw-r--r--src/test/ui/associated-types/associated-types-eq-hr.nll.stderr14
-rw-r--r--src/test/ui/associated-types/associated-types-eq-hr.stderr14
-rw-r--r--src/test/ui/associated-types/associated-types-issue-20346.stderr7
-rw-r--r--src/test/ui/associated-types/cache/project-fn-ret-contravariant.transmute.stderr2
-rw-r--r--src/test/ui/associated-types/cache/project-fn-ret-invariant.transmute.stderr11
-rw-r--r--src/test/ui/associated-types/defaults-in-other-trait-items.rs1
-rw-r--r--src/test/ui/associated-types/defaults-in-other-trait-items.stderr6
-rw-r--r--src/test/ui/associated-types/defaults-specialization.stderr16
-rw-r--r--src/test/ui/associated-types/defaults-suitability.stderr32
-rw-r--r--src/test/ui/associated-types/defaults-unsound-62211-1.stderr16
-rw-r--r--src/test/ui/associated-types/defaults-unsound-62211-2.stderr16
-rw-r--r--src/test/ui/associated-types/issue-43784-associated-type.stderr4
-rw-r--r--src/test/ui/associated-types/issue-43924.stderr4
-rw-r--r--src/test/ui/associated-types/issue-44153.stderr7
-rw-r--r--src/test/ui/associated-types/issue-54108.stderr4
-rw-r--r--src/test/ui/associated-types/issue-59324.rs26
-rw-r--r--src/test/ui/associated-types/issue-59324.stderr69
-rw-r--r--src/test/ui/associated-types/issue-63593.stderr4
-rw-r--r--src/test/ui/associated-types/issue-65774-1.stderr4
-rw-r--r--src/test/ui/associated-types/issue-65774-2.stderr4
-rw-r--r--src/test/ui/associated-types/issue-67684.rs62
-rw-r--r--src/test/ui/associated-types/issue-69398.rs21
-rw-r--r--src/test/ui/associated-types/issue-71113.rs16
-rw-r--r--src/test/ui/associated-types/issue-72806.stderr9
-rw-r--r--src/test/ui/associated-types/issue-82079.rs121
-rw-r--r--src/test/ui/associated-types/issue-85103.rs9
-rw-r--r--src/test/ui/associated-types/issue-85103.stderr8
-rw-r--r--src/test/ui/associated-types/issue-87261.rs8
-rw-r--r--src/test/ui/associated-types/issue-87261.stderr24
-rw-r--r--src/test/ui/associated-types/issue-88856.rs32
-rw-r--r--src/test/ui/associated-types/issue-91231.rs17
-rw-r--r--src/test/ui/associated-types/issue-91234.rs13
-rw-r--r--src/test/ui/associated-types/point-at-type-on-obligation-failure-2.stderr12
-rw-r--r--src/test/ui/associated-types/point-at-type-on-obligation-failure.stderr9
-rw-r--r--src/test/ui/ast-json/ast-json-noexpand-output.stdout2
-rw-r--r--src/test/ui/ast-json/ast-json-output.stdout2
-rw-r--r--src/test/ui/async-await/async-block-control-flow-static-semantics.rs6
-rw-r--r--src/test/ui/async-await/async-block-control-flow-static-semantics.stderr4
-rw-r--r--src/test/ui/async-await/async-error-span.stderr5
-rw-r--r--src/test/ui/async-await/async-fn-nonsend.stderr12
-rw-r--r--src/test/ui/async-await/async-fn-size-moved-locals.rs6
-rw-r--r--src/test/ui/async-await/await-into-future.rs30
-rw-r--r--src/test/ui/async-await/await-keyword/incorrect-syntax-suggestions.stderr32
-rw-r--r--src/test/ui/async-await/generator-desc.stderr4
-rw-r--r--src/test/ui/async-await/generics-and-bounds.rs11
-rw-r--r--src/test/ui/async-await/issue-64130-1-sync.stderr4
-rw-r--r--src/test/ui/async-await/issue-64130-2-send.stderr4
-rw-r--r--src/test/ui/async-await/issue-64130-3-other.stderr4
-rw-r--r--src/test/ui/async-await/issue-64130-4-async-move.stderr4
-rw-r--r--src/test/ui/async-await/issue-64130-non-send-future-diags.stderr4
-rw-r--r--src/test/ui/async-await/issue-67252-unnamed-future.stderr6
-rw-r--r--src/test/ui/async-await/issue-68112.stderr4
-rw-r--r--src/test/ui/async-await/issue-70594.stderr19
-rw-r--r--src/test/ui/async-await/issue-70935-complex-spans.stderr17
-rw-r--r--src/test/ui/async-await/issue-71137.stderr4
-rw-r--r--src/test/ui/async-await/issues/issue-51719.stderr4
-rw-r--r--src/test/ui/async-await/issues/issue-51751.stderr4
-rw-r--r--src/test/ui/async-await/issues/issue-54752-async-block.rs2
-rw-r--r--src/test/ui/async-await/issues/issue-54752-async-block.stderr8
-rw-r--r--src/test/ui/async-await/issues/issue-60674.stdout6
-rw-r--r--src/test/ui/async-await/issues/issue-62009-1.rs4
-rw-r--r--src/test/ui/async-await/issues/issue-62009-1.stderr32
-rw-r--r--src/test/ui/async-await/issues/issue-62009-2.stderr4
-rw-r--r--src/test/ui/async-await/issues/issue-62097.stderr13
-rw-r--r--src/test/ui/async-await/issues/issue-65419/issue-65419-async-fn-resume-after-panic.rs1
-rw-r--r--src/test/ui/async-await/issues/issue-65436-raw-ptr-not-send.stderr12
-rw-r--r--src/test/ui/async-await/issues/issue-72312.nll.stderr21
-rw-r--r--src/test/ui/async-await/issues/issue-72312.rs19
-rw-r--r--src/test/ui/async-await/issues/issue-72312.stderr23
-rw-r--r--src/test/ui/async-await/issues/non-async-enclosing-span.stderr4
-rw-r--r--src/test/ui/async-await/multiple-lifetimes/ret-impl-trait-one.nll.stderr2
-rw-r--r--src/test/ui/async-await/multiple-lifetimes/ret-impl-trait-one.stderr2
-rw-r--r--src/test/ui/async-await/unnecessary-await.rs14
-rw-r--r--src/test/ui/async-await/unnecessary-await.stderr24
-rw-r--r--src/test/ui/async-await/unresolved_type_param.rs8
-rw-r--r--src/test/ui/async-await/unresolved_type_param.stderr34
-rw-r--r--src/test/ui/attributes/duplicated-attributes.rs41
-rw-r--r--src/test/ui/attributes/duplicated-attributes.stderr22
-rw-r--r--src/test/ui/attributes/issue-90873.rs9
-rw-r--r--src/test/ui/attributes/issue-90873.stderr50
-rw-r--r--src/test/ui/auto-traits/typeck-default-trait-impl-precedence.stderr6
-rw-r--r--src/test/ui/binding/fn-arg-incomplete-pattern-drop-order.rs1
-rw-r--r--src/test/ui/binding/issue-53114-safety-checks.stderr4
-rw-r--r--src/test/ui/binop/binary-op-on-fn-ptr-eq.rs9
-rw-r--r--src/test/ui/borrowck/borrowck-and-init.stderr2
-rw-r--r--src/test/ui/borrowck/borrowck-break-uninit-2.stderr2
-rw-r--r--src/test/ui/borrowck/borrowck-break-uninit.stderr2
-rw-r--r--src/test/ui/borrowck/borrowck-or-init.stderr2
-rw-r--r--src/test/ui/borrowck/borrowck-while-break.stderr2
-rw-r--r--src/test/ui/borrowck/issue-24267-flow-exit.stderr4
-rw-r--r--src/test/ui/borrowck/issue-55492-borrowck-migrate-scans-parents.migrate.stderr12
-rw-r--r--src/test/ui/borrowck/issue-55492-borrowck-migrate-scans-parents.nll.stderr12
-rw-r--r--src/test/ui/borrowck/issue-55492-borrowck-migrate-scans-parents.rs4
-rw-r--r--src/test/ui/borrowck/issue-58776-borrowck-scans-children.migrate.stderr32
-rw-r--r--src/test/ui/borrowck/issue-91206.rs15
-rw-r--r--src/test/ui/borrowck/issue-91206.stderr12
-rw-r--r--src/test/ui/borrowck/suggest-local-var-double-mut.rs27
-rw-r--r--src/test/ui/borrowck/suggest-local-var-double-mut.stderr44
-rw-r--r--src/test/ui/borrowck/suggest-local-var-imm-and-mut.nll.stderr33
-rw-r--r--src/test/ui/borrowck/suggest-local-var-imm-and-mut.rs27
-rw-r--r--src/test/ui/borrowck/suggest-local-var-imm-and-mut.stderr22
-rw-r--r--src/test/ui/borrowck/two-phase-cannot-nest-mut-self-calls.stderr17
-rw-r--r--src/test/ui/builtin-clone-unwind.rs1
-rw-r--r--src/test/ui/cast/cast-int-to-char.rs9
-rw-r--r--src/test/ui/cast/cast-int-to-char.stderr53
-rw-r--r--src/test/ui/cast/issue-88621.rs13
-rw-r--r--src/test/ui/cast/issue-88621.stderr9
-rw-r--r--src/test/ui/catch-unwind-bang.rs1
-rw-r--r--src/test/ui/cfg/auxiliary/crate-attributes-using-cfg_attr.rs6
-rw-r--r--src/test/ui/cfg/crate-attributes-using-cfg_attr.rs6
-rw-r--r--src/test/ui/cfg/future-compat-crate-attributes-using-cfg_attr.rs12
-rw-r--r--src/test/ui/cfg/future-compat-crate-attributes-using-cfg_attr.stderr26
-rw-r--r--src/test/ui/chalkify/impl_wf_2.stderr4
-rw-r--r--src/test/ui/cleanup-rvalue-temp-during-incomplete-alloc.rs1
-rw-r--r--src/test/ui/closures/2229_closure_analysis/diagnostics/arrays.stderr2
-rw-r--r--src/test/ui/closures/2229_closure_analysis/diagnostics/box.stderr2
-rw-r--r--src/test/ui/closures/2229_closure_analysis/diagnostics/repr_packed.stderr2
-rw-r--r--src/test/ui/closures/2229_closure_analysis/diagnostics/simple-struct-min-capture.stderr2
-rw-r--r--src/test/ui/closures/2229_closure_analysis/migrations/mir_calls_to_shims.fixed1
-rw-r--r--src/test/ui/closures/2229_closure_analysis/migrations/mir_calls_to_shims.rs1
-rw-r--r--src/test/ui/closures/2229_closure_analysis/migrations/mir_calls_to_shims.stderr4
-rw-r--r--src/test/ui/closures/closure-bounds-static-cant-capture-borrowed.stderr7
-rw-r--r--src/test/ui/closures/closure-expected.stderr4
-rw-r--r--src/test/ui/closures/coerce-unsafe-to-closure.stderr4
-rw-r--r--src/test/ui/codemap_tests/one_line.stderr11
-rw-r--r--src/test/ui/codemap_tests/tab_3.stderr1
-rw-r--r--src/test/ui/coherence/coherence-orphan.stderr22
-rw-r--r--src/test/ui/compare-method/bad-self-type.stderr16
-rw-r--r--src/test/ui/compare-method/reordered-type-param.stderr8
-rw-r--r--src/test/ui/const-generics/argument_order.min.stderr30
-rw-r--r--src/test/ui/const-generics/argument_order.rs5
-rw-r--r--src/test/ui/const-generics/argument_order.stderr (renamed from src/test/ui/const-generics/argument_order.full.stderr)4
-rw-r--r--src/test/ui/const-generics/associated-type-bound-fail.stderr4
-rw-r--r--src/test/ui/const-generics/const-arg-type-arg-misordered.stderr3
-rw-r--r--src/test/ui/const-generics/const-param-before-other-params.min.stderr14
-rw-r--r--src/test/ui/const-generics/const-param-before-other-params.rs5
-rw-r--r--src/test/ui/const-generics/const-param-before-other-params.stderr (renamed from src/test/ui/const-generics/const-param-before-other-params.full.stderr)2
-rw-r--r--src/test/ui/const-generics/defaults/auxiliary/const_defaulty.rs2
-rw-r--r--src/test/ui/const-generics/defaults/auxiliary/trait_object_lt_defaults_lib.rs1
-rw-r--r--src/test/ui/const-generics/defaults/complex-generic-default-expr.min.stderr4
-rw-r--r--src/test/ui/const-generics/defaults/complex-generic-default-expr.rs3
-rw-r--r--src/test/ui/const-generics/defaults/complex-unord-param.rs6
-rw-r--r--src/test/ui/const-generics/defaults/const-default.rs2
-rw-r--r--src/test/ui/const-generics/defaults/const-param-as-default-value.rs1
-rw-r--r--src/test/ui/const-generics/defaults/const-param-in-ty-defaults.rs1
-rw-r--r--src/test/ui/const-generics/defaults/default-annotation.rs1
-rw-r--r--src/test/ui/const-generics/defaults/default-const-param-cannot-reference-self.rs2
-rw-r--r--src/test/ui/const-generics/defaults/default-const-param-cannot-reference-self.stderr6
-rw-r--r--src/test/ui/const-generics/defaults/default-on-impl.rs2
-rw-r--r--src/test/ui/const-generics/defaults/default-on-impl.stderr2
-rw-r--r--src/test/ui/const-generics/defaults/default-param-wf-concrete.rs1
-rw-r--r--src/test/ui/const-generics/defaults/default-param-wf-concrete.stderr2
-rw-r--r--src/test/ui/const-generics/defaults/doesnt_infer.rs2
-rw-r--r--src/test/ui/const-generics/defaults/doesnt_infer.stderr4
-rw-r--r--src/test/ui/const-generics/defaults/external.rs2
-rw-r--r--src/test/ui/const-generics/defaults/forward-declared.rs2
-rw-r--r--src/test/ui/const-generics/defaults/forward-declared.stderr8
-rw-r--r--src/test/ui/const-generics/defaults/generic-expr-default-concrete.rs2
-rw-r--r--src/test/ui/const-generics/defaults/generic-expr-default-mismatched-types.rs2
-rw-r--r--src/test/ui/const-generics/defaults/generic-expr-default.rs2
-rw-r--r--src/test/ui/const-generics/defaults/intermixed-lifetime.min.stderr14
-rw-r--r--src/test/ui/const-generics/defaults/intermixed-lifetime.rs2
-rw-r--r--src/test/ui/const-generics/defaults/intermixed-lifetime.stderr (renamed from src/test/ui/const-generics/defaults/intermixed-lifetime.full.stderr)4
-rw-r--r--src/test/ui/const-generics/defaults/mismatch.rs2
-rw-r--r--src/test/ui/const-generics/defaults/mismatch.stderr10
-rw-r--r--src/test/ui/const-generics/defaults/needs-feature.min.stderr8
-rw-r--r--src/test/ui/const-generics/defaults/needs-feature.rs12
-rw-r--r--src/test/ui/const-generics/defaults/param-order-err-pretty-prints-default.rs1
-rw-r--r--src/test/ui/const-generics/defaults/param-order-err-pretty-prints-default.stderr2
-rw-r--r--src/test/ui/const-generics/defaults/pretty-printing-ast.rs1
-rw-r--r--src/test/ui/const-generics/defaults/pretty-printing-ast.stdout5
-rw-r--r--src/test/ui/const-generics/defaults/repr-c-issue-82792.rs2
-rw-r--r--src/test/ui/const-generics/defaults/rp_impl_trait.rs2
-rw-r--r--src/test/ui/const-generics/defaults/rp_impl_trait_fail.rs2
-rw-r--r--src/test/ui/const-generics/defaults/rp_impl_trait_fail.stderr6
-rw-r--r--src/test/ui/const-generics/defaults/simple-defaults.rs1
-rw-r--r--src/test/ui/const-generics/defaults/trait_object_lt_defaults.rs24
-rw-r--r--src/test/ui/const-generics/defaults/trait_objects.rs2
-rw-r--r--src/test/ui/const-generics/defaults/trait_objects_fail.rs2
-rw-r--r--src/test/ui/const-generics/defaults/trait_objects_fail.stderr4
-rw-r--r--src/test/ui/const-generics/defaults/type-default-const-param-name.rs2
-rw-r--r--src/test/ui/const-generics/defaults/wfness.rs2
-rw-r--r--src/test/ui/const-generics/defaults/wfness.stderr8
-rw-r--r--src/test/ui/const-generics/defaults/wrong-order.rs2
-rw-r--r--src/test/ui/const-generics/defaults/wrong-order.stderr4
-rw-r--r--src/test/ui/const-generics/generic_arg_infer/dont-use-defaults.rs15
-rw-r--r--src/test/ui/const-generics/generic_arg_infer/issue-91614.rs8
-rw-r--r--src/test/ui/const-generics/generic_arg_infer/issue-91614.stderr18
-rw-r--r--src/test/ui/const-generics/generic_const_exprs/closures.stderr2
-rw-r--r--src/test/ui/const-generics/generic_const_exprs/const_eval_resolve_canonical.rs8
-rw-r--r--src/test/ui/const-generics/generic_const_exprs/const_eval_resolve_canonical.stderr33
-rw-r--r--src/test/ui/const-generics/generic_const_exprs/unused-complex-default-expr.rs2
-rw-r--r--src/test/ui/const-generics/invalid-enum.rs2
-rw-r--r--src/test/ui/const-generics/issues/issue-72845.rs49
-rw-r--r--src/test/ui/const-generics/issues/issue-72845.stderr12
-rw-r--r--src/test/ui/const-generics/issues/issue-79674.rs28
-rw-r--r--src/test/ui/const-generics/issues/issue-79674.stderr12
-rw-r--r--src/test/ui/const-generics/issues/issue-83249.rs23
-rw-r--r--src/test/ui/const-generics/issues/issue-83249.stderr11
-rw-r--r--src/test/ui/const-generics/issues/issue-83288.rs69
-rw-r--r--src/test/ui/const-generics/issues/issue-83765.rs115
-rw-r--r--src/test/ui/const-generics/issues/issue-83765.stderr130
-rw-r--r--src/test/ui/const-generics/issues/issue-86033.rs20
-rw-r--r--src/test/ui/const-generics/issues/issue-87470.rs24
-rw-r--r--src/test/ui/const-generics/issues/issue-87964.rs29
-rw-r--r--src/test/ui/const-generics/issues/issue-88468.rs13
-rw-r--r--src/test/ui/const-generics/issues/issue-89146.rs26
-rw-r--r--src/test/ui/const-generics/issues/issue-89320.rs19
-rw-r--r--src/test/ui/const-generics/issues/issue-90318.rs32
-rw-r--r--src/test/ui/const-generics/issues/issue-90318.stderr37
-rw-r--r--src/test/ui/const-generics/issues/issue-90455.rs12
-rw-r--r--src/test/ui/const-generics/issues/issue-90455.stderr10
-rw-r--r--src/test/ui/const-generics/min_const_generics/const-expression-suggest-missing-braces.rs2
-rw-r--r--src/test/ui/const-generics/min_const_generics/const-expression-suggest-missing-braces.stderr32
-rw-r--r--src/test/ui/const-generics/min_const_generics/const_default_first.rs3
-rw-r--r--src/test/ui/const-generics/min_const_generics/const_default_first.stderr2
-rw-r--r--src/test/ui/const-generics/min_const_generics/default_function_param.rs1
-rw-r--r--src/test/ui/const-generics/min_const_generics/default_function_param.stderr2
-rw-r--r--src/test/ui/const-generics/min_const_generics/default_trait_param.rs2
-rw-r--r--src/test/ui/const-generics/min_const_generics/default_trait_param.stderr12
-rw-r--r--src/test/ui/const-generics/min_const_generics/type_and_const_defaults.rs1
-rw-r--r--src/test/ui/const-generics/params-in-ct-in-ty-param-lazy-norm.min.stderr2
-rw-r--r--src/test/ui/const-generics/type-after-const-ok.rs7
-rw-r--r--src/test/ui/consts/assert-type-intrinsics.rs22
-rw-r--r--src/test/ui/consts/assert-type-intrinsics.stderr39
-rw-r--r--src/test/ui/consts/assume-type-intrinsics.rs13
-rw-r--r--src/test/ui/consts/assume-type-intrinsics.stderr15
-rw-r--r--src/test/ui/consts/closure-structural-match-issue-90013.rs1
-rw-r--r--src/test/ui/consts/const-blocks/fn-call-in-const.rs2
-rw-r--r--src/test/ui/consts/const-cast-different-types.rs6
-rw-r--r--src/test/ui/consts/const-cast-different-types.stderr12
-rw-r--r--src/test/ui/consts/const-cast-wrong-type.rs4
-rw-r--r--src/test/ui/consts/const-cast-wrong-type.stderr6
-rw-r--r--src/test/ui/consts/const-err.rs2
-rw-r--r--src/test/ui/consts/const-eval/conditional_array_execution.stderr1
-rw-r--r--src/test/ui/consts/const-eval/const-eval-query-stack.stderr2
-rw-r--r--src/test/ui/consts/const-eval/issue-43197.stderr2
-rw-r--r--src/test/ui/consts/const-eval/issue-91827-extern-types.rs58
-rw-r--r--src/test/ui/consts/drop_zst.rs17
-rw-r--r--src/test/ui/consts/drop_zst.stderr9
-rw-r--r--src/test/ui/consts/inline_asm.rs2
-rw-r--r--src/test/ui/consts/issue-70942-trait-vs-impl-mismatch.stderr9
-rw-r--r--src/test/ui/consts/issue-90870.fixed34
-rw-r--r--src/test/ui/consts/issue-90870.rs34
-rw-r--r--src/test/ui/consts/issue-90870.stderr36
-rw-r--r--src/test/ui/consts/issue-90878-2.rs2
-rw-r--r--src/test/ui/consts/issue-90878-2.stderr18
-rw-r--r--src/test/ui/consts/miri_unleashed/inline_asm.rs4
-rw-r--r--src/test/ui/consts/miri_unleashed/inline_asm.stderr8
-rw-r--r--src/test/ui/consts/miri_unleashed/tls.stderr4
-rw-r--r--src/test/ui/consts/not_const_clusure_in_const.rs9
-rw-r--r--src/test/ui/consts/try-operator.rs23
-rw-r--r--src/test/ui/crate-loading/invalid-rlib.rs2
-rw-r--r--src/test/ui/crate-loading/invalid-rlib.stderr10
-rw-r--r--src/test/ui/crate-loading/missing-std.rs1
-rw-r--r--src/test/ui/crate-loading/missing-std.stderr6
-rw-r--r--src/test/ui/cross/cross-file-errors/main.rs1
-rw-r--r--src/test/ui/cross/cross-file-errors/main.stderr18
-rw-r--r--src/test/ui/derives/derive-macro-const-default.rs2
-rw-r--r--src/test/ui/derives/issue-36617.rs13
-rw-r--r--src/test/ui/derives/issue-36617.stderr89
-rw-r--r--src/test/ui/destructuring-assignment/bad-expr-lhs.rs7
-rw-r--r--src/test/ui/destructuring-assignment/bad-expr-lhs.stderr28
-rw-r--r--src/test/ui/destructuring-assignment/default-match-bindings-forbidden.rs2
-rw-r--r--src/test/ui/destructuring-assignment/default-match-bindings-forbidden.stderr6
-rw-r--r--src/test/ui/destructuring-assignment/drop-order.rs1
-rw-r--r--src/test/ui/destructuring-assignment/nested_destructure.rs2
-rw-r--r--src/test/ui/destructuring-assignment/note-unsupported.rs11
-rw-r--r--src/test/ui/destructuring-assignment/note-unsupported.stderr59
-rw-r--r--src/test/ui/destructuring-assignment/slice_destructure.rs2
-rw-r--r--src/test/ui/destructuring-assignment/slice_destructure_fail.rs2
-rw-r--r--src/test/ui/destructuring-assignment/slice_destructure_fail.stderr6
-rw-r--r--src/test/ui/destructuring-assignment/struct_destructure.rs1
-rw-r--r--src/test/ui/destructuring-assignment/struct_destructure_fail.rs1
-rw-r--r--src/test/ui/destructuring-assignment/struct_destructure_fail.stderr10
-rw-r--r--src/test/ui/destructuring-assignment/tuple_destructure.rs2
-rw-r--r--src/test/ui/destructuring-assignment/tuple_destructure_fail.rs2
-rw-r--r--src/test/ui/destructuring-assignment/tuple_destructure_fail.stderr16
-rw-r--r--src/test/ui/destructuring-assignment/tuple_struct_destructure.rs2
-rw-r--r--src/test/ui/destructuring-assignment/tuple_struct_destructure_fail.rs2
-rw-r--r--src/test/ui/destructuring-assignment/tuple_struct_destructure_fail.stderr18
-rw-r--r--src/test/ui/destructuring-assignment/underscore-range-expr-gating.rs10
-rw-r--r--src/test/ui/destructuring-assignment/underscore-range-expr-gating.stderr21
-rw-r--r--src/test/ui/destructuring-assignment/warn-unused-duplication.rs2
-rw-r--r--src/test/ui/destructuring-assignment/warn-unused-duplication.stderr4
-rw-r--r--src/test/ui/did_you_mean/bad-assoc-ty.rs2
-rw-r--r--src/test/ui/did_you_mean/bad-assoc-ty.stderr42
-rw-r--r--src/test/ui/did_you_mean/issue-38147-2.rs7
-rw-r--r--src/test/ui/did_you_mean/issue-38147-2.stderr23
-rw-r--r--src/test/ui/did_you_mean/issue-38147-3.stderr8
-rw-r--r--src/test/ui/drop/drop-trait-enum.rs1
-rw-r--r--src/test/ui/drop/dynamic-drop-async.rs1
-rw-r--r--src/test/ui/drop/dynamic-drop.rs1
-rw-r--r--src/test/ui/drop/issue-90752-raw-ptr-shenanigans.rs41
-rw-r--r--src/test/ui/drop/issue-90752.rs32
-rw-r--r--src/test/ui/drop/terminate-in-initializer.rs1
-rw-r--r--src/test/ui/dst/dst-bad-assign-3.stderr4
-rw-r--r--src/test/ui/dst/dst-bad-assign.stderr4
-rw-r--r--src/test/ui/dst/dst-bad-deep.stderr5
-rw-r--r--src/test/ui/dyn-keyword/dyn-2018-edition-lint.rs8
-rw-r--r--src/test/ui/dyn-keyword/dyn-2018-edition-lint.stderr81
-rw-r--r--src/test/ui/dyn-keyword/dyn-2021-edition-error.rs1
-rw-r--r--src/test/ui/dyn-keyword/dyn-2021-edition-error.stderr23
-rw-r--r--src/test/ui/dyn-keyword/dyn-angle-brackets.fixed2
-rw-r--r--src/test/ui/dyn-keyword/dyn-angle-brackets.rs2
-rw-r--r--src/test/ui/dyn-keyword/dyn-angle-brackets.stderr16
-rw-r--r--src/test/ui/editions/dyn-trait-sugg-2021.rs4
-rw-r--r--src/test/ui/editions/dyn-trait-sugg-2021.stderr9
-rw-r--r--src/test/ui/empty_global_asm.rs3
-rw-r--r--src/test/ui/entry-point/imported_main_const_fn_item_type_forbidden.stderr2
-rw-r--r--src/test/ui/enum-discriminant/arbitrary_enum_discriminant.rs13
-rw-r--r--src/test/ui/error-codes/E0070.rs1
-rw-r--r--src/test/ui/error-codes/E0070.stderr11
-rw-r--r--src/test/ui/error-codes/E0161.edition.stderr2
-rw-r--r--src/test/ui/error-codes/E0161.migrate.stderr2
-rw-r--r--src/test/ui/error-codes/E0161.nll.stderr2
-rw-r--r--src/test/ui/error-codes/E0161.rs7
-rw-r--r--src/test/ui/error-codes/E0161.zflags.stderr2
-rw-r--r--src/test/ui/error-codes/E0271.stderr7
-rw-r--r--src/test/ui/expr/if/if-without-block.stderr6
-rw-r--r--src/test/ui/expr/malformed_closure/ruby_style_closure.stderr4
-rw-r--r--src/test/ui/extern-flag/empty-extern-arg.rs2
-rw-r--r--src/test/ui/extern-flag/empty-extern-arg.stderr9
-rw-r--r--src/test/ui/extern/extern-crate-multiple-missing.rs10
-rw-r--r--src/test/ui/extern/extern-crate-multiple-missing.stderr15
-rw-r--r--src/test/ui/extern/extern-types-unsized.stderr5
-rw-r--r--src/test/ui/extern/issue-64655-allow-unwind-when-calling-panic-directly.rs1
-rw-r--r--src/test/ui/extern/issue-64655-extern-rust-must-allow-unwind.rs1
-rw-r--r--src/test/ui/feature-gates/feature-gate-asm.rs2
-rw-r--r--src/test/ui/feature-gates/feature-gate-asm.stderr13
-rw-r--r--src/test/ui/feature-gates/feature-gate-asm2.rs2
-rw-r--r--src/test/ui/feature-gates/feature-gate-asm2.stderr13
-rw-r--r--src/test/ui/feature-gates/feature-gate-asm_const.rs2
-rw-r--r--src/test/ui/feature-gates/feature-gate-asm_sym.rs2
-rw-r--r--src/test/ui/feature-gates/feature-gate-asm_unwind.rs10
-rw-r--r--src/test/ui/feature-gates/feature-gate-asm_unwind.stderr12
-rw-r--r--src/test/ui/feature-gates/feature-gate-concat_bytes.rs4
-rw-r--r--src/test/ui/feature-gates/feature-gate-concat_bytes.stderr12
-rw-r--r--src/test/ui/feature-gates/feature-gate-const_generics_defaults.rs9
-rw-r--r--src/test/ui/feature-gates/feature-gate-const_generics_defaults.stderr21
-rw-r--r--src/test/ui/feature-gates/feature-gate-destructuring_assignment.rs4
-rw-r--r--src/test/ui/feature-gates/feature-gate-destructuring_assignment.stderr14
-rw-r--r--src/test/ui/feature-gates/feature-gate-doc_keyword.rs5
-rw-r--r--src/test/ui/feature-gates/feature-gate-doc_keyword.stderr12
-rw-r--r--src/test/ui/feature-gates/feature-gate-generic_associated_types.stderr4
-rw-r--r--src/test/ui/feature-gates/feature-gate-global_asm.rs5
-rw-r--r--src/test/ui/feature-gates/feature-gate-global_asm.stderr12
-rw-r--r--src/test/ui/feature-gates/feature-gate-inline_const_pat.rs4
-rw-r--r--src/test/ui/feature-gates/feature-gate-inline_const_pat.stderr12
-rw-r--r--src/test/ui/feature-gates/feature-gate-naked_functions.rs3
-rw-r--r--src/test/ui/feature-gates/feature-gate-naked_functions.stderr4
-rw-r--r--src/test/ui/feature-gates/feature-gate-rustdoc_internals.rs5
-rw-r--r--src/test/ui/feature-gates/feature-gate-rustdoc_internals.stderr12
-rw-r--r--src/test/ui/feature-gates/issue-43106-gating-of-bench.rs2
-rw-r--r--src/test/ui/feature-gates/issue-43106-gating-of-bench.stderr13
-rw-r--r--src/test/ui/feature-gates/issue-43106-gating-of-builtin-attrs-error.stderr30
-rw-r--r--src/test/ui/feature-gates/issue-43106-gating-of-test.rs2
-rw-r--r--src/test/ui/feature-gates/issue-43106-gating-of-test.stderr13
-rw-r--r--src/test/ui/feature-gates/thread-local-const-init.rs4
-rw-r--r--src/test/ui/feature-gates/thread-local-const-init.stderr13
-rw-r--r--src/test/ui/fmt/issue-91556.rs8
-rw-r--r--src/test/ui/fmt/issue-91556.stderr11
-rw-r--r--src/test/ui/fn/fn-compare-mismatch.stderr4
-rw-r--r--src/test/ui/fn/fn-recover-return-sign2.rs2
-rw-r--r--src/test/ui/fn/fn-recover-return-sign2.stderr4
-rw-r--r--src/test/ui/fn/implied-bounds-unnorm-associated-type-2.rs22
-rw-r--r--src/test/ui/fn/implied-bounds-unnorm-associated-type-3.rs25
-rw-r--r--src/test/ui/fn/implied-bounds-unnorm-associated-type-3.stderr12
-rw-r--r--src/test/ui/fn/implied-bounds-unnorm-associated-type.nll.stderr14
-rw-r--r--src/test/ui/fn/implied-bounds-unnorm-associated-type.rs22
-rw-r--r--src/test/ui/fn/implied-bounds-unnorm-associated-type.stderr13
-rw-r--r--src/test/ui/fully-qualified-type/fully-qualified-type-name1.rs8
-rw-r--r--src/test/ui/fully-qualified-type/fully-qualified-type-name1.stderr6
-rw-r--r--src/test/ui/generator/generator-region-requirements.stderr2
-rw-r--r--src/test/ui/generator/generator-resume-after-panic.rs1
-rw-r--r--src/test/ui/generator/issue-68112.stderr8
-rw-r--r--src/test/ui/generator/issue-91477.rs7
-rw-r--r--src/test/ui/generator/issue-91477.stderr9
-rw-r--r--src/test/ui/generator/panic-drops-resume.rs1
-rw-r--r--src/test/ui/generator/panic-drops.rs1
-rw-r--r--src/test/ui/generator/panic-safe.rs1
-rw-r--r--src/test/ui/generator/print/generator-print-verbose-1.stderr10
-rw-r--r--src/test/ui/generator/resume-after-return.rs1
-rw-r--r--src/test/ui/generator/yield-while-ref-reborrowed.stderr2
-rw-r--r--src/test/ui/generic-associated-types/cross-crate-bounds.stderr4
-rw-r--r--src/test/ui/generic-associated-types/equality-bound.rs15
-rw-r--r--src/test/ui/generic-associated-types/equality-bound.stderr43
-rw-r--r--src/test/ui/generic-associated-types/gat-trait-path-parenthesised-args.rs2
-rw-r--r--src/test/ui/generic-associated-types/gat-trait-path-parenthesised-args.stderr12
-rw-r--r--src/test/ui/generic-associated-types/generic-associated-types-where.stderr4
-rw-r--r--src/test/ui/generic-associated-types/impl_bounds.stderr4
-rw-r--r--src/test/ui/generic-associated-types/issue-68641-check-gat-bounds.stderr4
-rw-r--r--src/test/ui/generic-associated-types/issue-68642-broken-llvm-ir.stderr4
-rw-r--r--src/test/ui/generic-associated-types/issue-68643-broken-mir.stderr4
-rw-r--r--src/test/ui/generic-associated-types/issue-68644-codegen-selection.stderr4
-rw-r--r--src/test/ui/generic-associated-types/issue-68645-codegen-fulfillment.stderr4
-rw-r--r--src/test/ui/generic-associated-types/issue-68656-unsized-values.stderr4
-rw-r--r--src/test/ui/generic-associated-types/issue-74684-2.stderr7
-rw-r--r--src/test/ui/generic-associated-types/issue-74816.stderr8
-rw-r--r--src/test/ui/generic-associated-types/issue-74824.stderr8
-rw-r--r--src/test/ui/generic-associated-types/issue-78113-lifetime-mismatch-dyn-trait-box.stderr12
-rw-r--r--src/test/ui/generic-associated-types/issue-86787.rs2
-rw-r--r--src/test/ui/generic-associated-types/issue-86787.stderr7
-rw-r--r--src/test/ui/generic-associated-types/issue-87429-associated-type-default.stderr4
-rw-r--r--src/test/ui/generic-associated-types/issue-87429-specialization.stderr4
-rw-r--r--src/test/ui/generic-associated-types/issue-87748.rs30
-rw-r--r--src/test/ui/generic-associated-types/issue-88595.stderr4
-rw-r--r--src/test/ui/generic-associated-types/issue-90014.stderr4
-rw-r--r--src/test/ui/generic-associated-types/missing-bounds.fixed5
-rw-r--r--src/test/ui/generic-associated-types/missing-bounds.rs5
-rw-r--r--src/test/ui/generic-associated-types/missing-bounds.stderr30
-rw-r--r--src/test/ui/generic-associated-types/projection-type-lifetime-mismatch.stderr12
-rw-r--r--src/test/ui/generic-associated-types/self-outlives-lint.rs45
-rw-r--r--src/test/ui/generic-associated-types/self-outlives-lint.stderr95
-rw-r--r--src/test/ui/generic-associated-types/unsatisfied-outlives-bound.stderr8
-rw-r--r--src/test/ui/generics/issue-59508-1.rs3
-rw-r--r--src/test/ui/generics/issue-59508-1.stderr2
-rw-r--r--src/test/ui/generics/issue-59508.stderr2
-rw-r--r--src/test/ui/generics/lifetime-before-type-params.stderr8
-rw-r--r--src/test/ui/half-open-range-patterns/exclusive_range_pattern_syntax_collision.stderr2
-rw-r--r--src/test/ui/half-open-range-patterns/exclusive_range_pattern_syntax_collision2.stderr2
-rw-r--r--src/test/ui/half-open-range-patterns/exclusive_range_pattern_syntax_collision3.stderr6
-rw-r--r--src/test/ui/half-open-range-patterns/pat-tuple-5.stderr2
-rw-r--r--src/test/ui/half-open-range-patterns/range_pat_interactions0.rs2
-rw-r--r--src/test/ui/half-open-range-patterns/range_pat_interactions3.rs2
-rw-r--r--src/test/ui/half-open-range-patterns/range_pat_interactions3.stderr4
-rw-r--r--src/test/ui/higher-rank-trait-bounds/issue-88586-hr-self-outlives-in-trait-def.rs11
-rw-r--r--src/test/ui/higher-rank-trait-bounds/issue-88586-hr-self-outlives-in-trait-def.stderr19
-rw-r--r--src/test/ui/higher-rank-trait-bounds/normalize-under-binder/issue-71955.migrate.stderr20
-rw-r--r--src/test/ui/higher-rank-trait-bounds/normalize-under-binder/issue-71955.nll.stderr2
-rw-r--r--src/test/ui/higher-rank-trait-bounds/normalize-under-binder/issue-71955.rs5
-rw-r--r--src/test/ui/hrtb/issue-30786.migrate.stderr28
-rw-r--r--src/test/ui/hrtb/issue-30786.nll.stderr28
-rw-r--r--src/test/ui/hrtb/issue-30786.rs3
-rw-r--r--src/test/ui/hrtb/issue-62203-hrtb-ice.stderr7
-rw-r--r--src/test/ui/hygiene/unpretty-debug.stdout2
-rw-r--r--src/test/ui/impl-header-lifetime-elision/dyn-trait.stderr2
-rw-r--r--src/test/ui/impl-trait/auto-trait-leak2.stderr12
-rw-r--r--src/test/ui/impl-trait/bound-normalization-fail.stderr14
-rw-r--r--src/test/ui/impl-trait/hidden-lifetimes.stderr4
-rw-r--r--src/test/ui/impl-trait/impl-generic-mismatch-ab.stderr8
-rw-r--r--src/test/ui/impl-trait/impl-trait-in-macro.stderr2
-rw-r--r--src/test/ui/impl-trait/issue-55872-2.rs2
-rw-r--r--src/test/ui/impl-trait/issue-55872-2.stderr4
-rw-r--r--src/test/ui/impl-trait/issue-72911.stderr8
-rw-r--r--src/test/ui/impl-trait/issue-87450.stderr4
-rw-r--r--src/test/ui/impl-trait/issues/issue-70877.stderr7
-rw-r--r--src/test/ui/impl-trait/issues/issue-78722.stderr2
-rw-r--r--src/test/ui/impl-trait/issues/issue-86201.rs4
-rw-r--r--src/test/ui/impl-trait/multiple-lifetimes/ordinary-bounds-unrelated.stderr2
-rw-r--r--src/test/ui/impl-trait/multiple-lifetimes/ordinary-bounds-unsuited.stderr2
-rw-r--r--src/test/ui/impl-trait/must_outlive_least_region_or_bound.nll.stderr6
-rw-r--r--src/test/ui/impl-trait/must_outlive_least_region_or_bound.stderr50
-rw-r--r--src/test/ui/impl-trait/projection-mismatch-in-impl-where-clause.stderr7
-rw-r--r--src/test/ui/impl-trait/region-escape-via-bound.stderr2
-rw-r--r--src/test/ui/impl-trait/static-return-lifetime-infered.stderr8
-rw-r--r--src/test/ui/impl-trait/universal-two-impl-traits.stderr1
-rw-r--r--src/test/ui/imports/extern-crate-self/extern-crate-self-fail.stderr7
-rw-r--r--src/test/ui/imports/issue-28134.rs1
-rw-r--r--src/test/ui/imports/issue-28134.stderr13
-rw-r--r--src/test/ui/in-band-lifetimes/elided-lifetimes.fixed56
-rw-r--r--src/test/ui/in-band-lifetimes/elided-lifetimes.rs56
-rw-r--r--src/test/ui/in-band-lifetimes/elided-lifetimes.stderr90
-rw-r--r--src/test/ui/inference/cannot-infer-partial-try-return.rs2
-rw-r--r--src/test/ui/inference/erase-type-params-in-label.rs27
-rw-r--r--src/test/ui/inference/erase-type-params-in-label.stderr41
-rw-r--r--src/test/ui/inference/issue-83606.stderr2
-rw-r--r--src/test/ui/infinite/infinite-struct.stderr2
-rw-r--r--src/test/ui/infinite/infinite-tag-type-recursion.stderr2
-rw-r--r--src/test/ui/inline-const/const-expr-array-init.rs1
-rw-r--r--src/test/ui/inline-const/const-expr-basic.rs2
-rw-r--r--src/test/ui/inline-const/const-expr-inference.rs1
-rw-r--r--src/test/ui/inline-const/const-expr-lifetime-err.rs1
-rw-r--r--src/test/ui/inline-const/const-expr-lifetime-err.stderr2
-rw-r--r--src/test/ui/inline-const/const-expr-lifetime.rs1
-rw-r--r--src/test/ui/inline-const/const-expr-macro.rs2
-rw-r--r--src/test/ui/inline-const/const-expr-reference.rs1
-rw-r--r--src/test/ui/inline-const/const-match-pat-generic.rs27
-rw-r--r--src/test/ui/inline-const/const-match-pat-generic.stderr20
-rw-r--r--src/test/ui/inline-const/const-match-pat-inference.rs2
-rw-r--r--src/test/ui/inline-const/const-match-pat-lifetime-err.rs2
-rw-r--r--src/test/ui/inline-const/const-match-pat-lifetime.rs1
-rw-r--r--src/test/ui/inline-const/const-match-pat-range.rs2
-rw-r--r--src/test/ui/inline-const/const-match-pat.rs2
-rw-r--r--src/test/ui/integral-variable-unification-error.rs6
-rw-r--r--src/test/ui/integral-variable-unification-error.stderr7
-rw-r--r--src/test/ui/intrinsics/panic-uninitialized-zeroed.rs1
-rw-r--r--src/test/ui/issues-71798.stderr1
-rw-r--r--src/test/ui/issues/issue-11844.stderr2
-rw-r--r--src/test/ui/issues/issue-12552.stderr5
-rw-r--r--src/test/ui/issues/issue-13033.stderr8
-rw-r--r--src/test/ui/issues/issue-13407.rs1
-rw-r--r--src/test/ui/issues/issue-13407.stderr10
-rw-r--r--src/test/ui/issues/issue-13466.stderr5
-rw-r--r--src/test/ui/issues/issue-14875.rs1
-rw-r--r--src/test/ui/issues/issue-16538.mir.stderr29
-rw-r--r--src/test/ui/issues/issue-16538.rs5
-rw-r--r--src/test/ui/issues/issue-16538.thir.stderr31
-rw-r--r--src/test/ui/issues/issue-16922.stderr2
-rw-r--r--src/test/ui/issues/issue-17718-static-sync.stderr4
-rw-r--r--src/test/ui/issues/issue-24446.rs1
-rw-r--r--src/test/ui/issues/issue-24446.stderr11
-rw-r--r--src/test/ui/issues/issue-25089.rs1
-rw-r--r--src/test/ui/issues/issue-26655.rs1
-rw-r--r--src/test/ui/issues/issue-28344.rs4
-rw-r--r--src/test/ui/issues/issue-28344.stderr33
-rw-r--r--src/test/ui/issues/issue-29485.rs1
-rw-r--r--src/test/ui/issues/issue-2951.stderr1
-rw-r--r--src/test/ui/issues/issue-29948.rs1
-rw-r--r--src/test/ui/issues/issue-30018-panic.rs1
-rw-r--r--src/test/ui/issues/issue-33941.stderr6
-rw-r--r--src/test/ui/issues/issue-35869.stderr32
-rw-r--r--src/test/ui/issues/issue-3680.stderr2
-rw-r--r--src/test/ui/issues/issue-37131.stderr4
-rw-r--r--src/test/ui/issues/issue-38821.stderr4
-rw-r--r--src/test/ui/issues/issue-39970.stderr7
-rw-r--r--src/test/ui/issues/issue-42796.stderr2
-rw-r--r--src/test/ui/issues/issue-43853.rs1
-rw-r--r--src/test/ui/issues/issue-46519.rs1
-rw-r--r--src/test/ui/issues/issue-46983.stderr2
-rw-r--r--src/test/ui/issues/issue-47646.stderr2
-rw-r--r--src/test/ui/issues/issue-47706-trait.stderr4
-rw-r--r--src/test/ui/issues/issue-47706.stderr4
-rw-r--r--src/test/ui/issues/issue-49851/compiler-builtins-error.rs6
-rw-r--r--src/test/ui/issues/issue-49851/compiler-builtins-error.stderr12
-rw-r--r--src/test/ui/issues/issue-50480.rs11
-rw-r--r--src/test/ui/issues/issue-50480.stderr89
-rw-r--r--src/test/ui/issues/issue-5216.rs4
-rw-r--r--src/test/ui/issues/issue-5216.stderr4
-rw-r--r--src/test/ui/issues/issue-53348.rs2
-rw-r--r--src/test/ui/issues/issue-53348.stderr3
-rw-r--r--src/test/ui/issues/issue-58734.rs2
-rw-r--r--src/test/ui/issues/issue-58734.stderr16
-rw-r--r--src/test/ui/issues/issue-59488.stderr16
-rw-r--r--src/test/ui/issues/issue-59494.rs2
-rw-r--r--src/test/ui/issues/issue-59494.stderr6
-rw-r--r--src/test/ui/issues/issue-66706.stderr6
-rw-r--r--src/test/ui/issues/issue-70724-add_type_neq_err_label-unwrap.stderr5
-rw-r--r--src/test/ui/issues/issue-72574-1.stderr2
-rw-r--r--src/test/ui/issues/issue-7364.rs3
-rw-r--r--src/test/ui/issues/issue-7364.stderr15
-rw-r--r--src/test/ui/issues/issue-77218.rs11
-rw-r--r--src/test/ui/issues/issue-77218.stderr40
-rw-r--r--src/test/ui/issues/issue-77218/issue-77218-2.fixed6
-rw-r--r--src/test/ui/issues/issue-77218/issue-77218-2.rs6
-rw-r--r--src/test/ui/issues/issue-77218/issue-77218-2.stderr16
-rw-r--r--src/test/ui/issues/issue-77218/issue-77218.fixed5
-rw-r--r--src/test/ui/issues/issue-77218/issue-77218.rs5
-rw-r--r--src/test/ui/issues/issue-77218/issue-77218.stderr16
-rw-r--r--src/test/ui/issues/issue-80512-param-reordering-with-defaults.stderr2
-rw-r--r--src/test/ui/issues/issue-85461.rs27
-rw-r--r--src/test/ui/issues/issue-86756.stderr7
-rw-r--r--src/test/ui/issues/issue-87490.rs10
-rw-r--r--src/test/ui/issues/issue-87490.stderr14
-rw-r--r--src/test/ui/issues/issue-88150.rs21
-rw-r--r--src/test/ui/issues/issue-91489.rs40
-rw-r--r--src/test/ui/iterators/iter-count-overflow-debug.rs1
-rw-r--r--src/test/ui/iterators/iter-position-overflow-debug.rs1
-rw-r--r--src/test/ui/iterators/iter-step-overflow-debug.rs1
-rw-r--r--src/test/ui/iterators/iter-sum-overflow-debug.rs1
-rw-r--r--src/test/ui/iterators/iter-sum-overflow-overflow-checks.rs1
-rw-r--r--src/test/ui/keyword/keyword-self-as-type-param.rs6
-rw-r--r--src/test/ui/keyword/keyword-self-as-type-param.stderr29
-rw-r--r--src/test/ui/let-else/issue-89960.rs7
-rw-r--r--src/test/ui/let-else/issue-89960.stderr12
-rw-r--r--src/test/ui/let-else/let-else-allow-unused.rs14
-rw-r--r--src/test/ui/let-else/let-else-binding-explicit-mut-annotated.rs16
-rw-r--r--src/test/ui/let-else/let-else-binding-explicit-mut-annotated.stderr21
-rw-r--r--src/test/ui/let-else/let-else-binding-explicit-mut-borrow.rs13
-rw-r--r--src/test/ui/let-else/let-else-binding-explicit-mut-borrow.stderr9
-rw-r--r--src/test/ui/let-else/let-else-binding-explicit-mut-pass.rs13
-rw-r--r--src/test/ui/let-else/let-else-binding-explicit-mut.rs20
-rw-r--r--src/test/ui/let-else/let-else-binding-explicit-mut.stderr21
-rw-r--r--src/test/ui/let-else/let-else-binding-immutable.rs10
-rw-r--r--src/test/ui/let-else/let-else-binding-immutable.stderr9
-rw-r--r--src/test/ui/let-else/let-else-bindings.rs75
-rw-r--r--src/test/ui/let-else/let-else-deref-coercion-annotated.rs77
-rw-r--r--src/test/ui/let-else/let-else-deref-coercion.rs75
-rw-r--r--src/test/ui/let-else/let-else-deref-coercion.stderr19
-rw-r--r--src/test/ui/let-else/let-else-no-double-error.rs12
-rw-r--r--src/test/ui/let-else/let-else-no-double-error.stderr9
-rw-r--r--src/test/ui/let-else/let-else-non-copy.rs45
-rw-r--r--src/test/ui/let-else/let-else-ref-bindings-pass.rs71
-rw-r--r--src/test/ui/let-else/let-else-ref-bindings.rs62
-rw-r--r--src/test/ui/let-else/let-else-ref-bindings.stderr75
-rw-r--r--src/test/ui/let-else/let-else-source-expr-nomove-pass.rs17
-rw-r--r--src/test/ui/lexer/lex-bad-binary-literal.rs (renamed from src/test/ui/parser/lex-bad-binary-literal.rs)0
-rw-r--r--src/test/ui/lexer/lex-bad-binary-literal.stderr (renamed from src/test/ui/parser/lex-bad-binary-literal.stderr)0
-rw-r--r--src/test/ui/lexer/lex-bad-char-literals-1.rs (renamed from src/test/ui/parser/lex-bad-char-literals-1.rs)0
-rw-r--r--src/test/ui/lexer/lex-bad-char-literals-1.stderr (renamed from src/test/ui/parser/lex-bad-char-literals-1.stderr)0
-rw-r--r--src/test/ui/lexer/lex-bad-char-literals-2.rs (renamed from src/test/ui/parser/lex-bad-char-literals-2.rs)0
-rw-r--r--src/test/ui/lexer/lex-bad-char-literals-2.stderr (renamed from src/test/ui/parser/lex-bad-char-literals-2.stderr)0
-rw-r--r--src/test/ui/lexer/lex-bad-char-literals-3.rs (renamed from src/test/ui/parser/lex-bad-char-literals-3.rs)0
-rw-r--r--src/test/ui/lexer/lex-bad-char-literals-3.stderr (renamed from src/test/ui/parser/lex-bad-char-literals-3.stderr)0
-rw-r--r--src/test/ui/lexer/lex-bad-char-literals-4.rs (renamed from src/test/ui/parser/lex-bad-char-literals-4.rs)0
-rw-r--r--src/test/ui/lexer/lex-bad-char-literals-4.stderr (renamed from src/test/ui/parser/lex-bad-char-literals-4.stderr)0
-rw-r--r--src/test/ui/lexer/lex-bad-char-literals-5.rs (renamed from src/test/ui/parser/lex-bad-char-literals-5.rs)0
-rw-r--r--src/test/ui/lexer/lex-bad-char-literals-5.stderr (renamed from src/test/ui/parser/lex-bad-char-literals-5.stderr)0
-rw-r--r--src/test/ui/lexer/lex-bad-char-literals-6.rs (renamed from src/test/ui/parser/lex-bad-char-literals-6.rs)0
-rw-r--r--src/test/ui/lexer/lex-bad-char-literals-6.stderr (renamed from src/test/ui/parser/lex-bad-char-literals-6.stderr)0
-rw-r--r--src/test/ui/lexer/lex-bad-char-literals-7.rs (renamed from src/test/ui/parser/lex-bad-char-literals-7.rs)0
-rw-r--r--src/test/ui/lexer/lex-bad-char-literals-7.stderr (renamed from src/test/ui/parser/lex-bad-char-literals-7.stderr)0
-rw-r--r--src/test/ui/lexer/lex-bad-numeric-literals.rs (renamed from src/test/ui/parser/lex-bad-numeric-literals.rs)0
-rw-r--r--src/test/ui/lexer/lex-bad-numeric-literals.stderr (renamed from src/test/ui/parser/lex-bad-numeric-literals.stderr)0
-rw-r--r--src/test/ui/lexer/lex-bad-octal-literal.rs (renamed from src/test/ui/parser/lex-bad-octal-literal.rs)0
-rw-r--r--src/test/ui/lexer/lex-bad-octal-literal.stderr (renamed from src/test/ui/parser/lex-bad-octal-literal.stderr)0
-rw-r--r--src/test/ui/lexer/lex-bad-token.rs (renamed from src/test/ui/parser/lex-bad-token.rs)0
-rw-r--r--src/test/ui/lexer/lex-bad-token.stderr (renamed from src/test/ui/parser/lex-bad-token.stderr)0
-rw-r--r--src/test/ui/lexer/lex-bare-cr-nondoc-comment.rs (renamed from src/test/ui/parser/lex-bare-cr-nondoc-comment.rs)0
-rw-r--r--src/test/ui/lexer/lex-bare-cr-string-literal-doc-comment.rs (renamed from src/test/ui/parser/lex-bare-cr-string-literal-doc-comment.rs)0
-rw-r--r--src/test/ui/lexer/lex-bare-cr-string-literal-doc-comment.stderr (renamed from src/test/ui/parser/lex-bare-cr-string-literal-doc-comment.stderr)0
-rw-r--r--src/test/ui/lexer/lex-stray-backslash.rs (renamed from src/test/ui/parser/lex-stray-backslash.rs)0
-rw-r--r--src/test/ui/lexer/lex-stray-backslash.stderr (renamed from src/test/ui/parser/lex-stray-backslash.stderr)0
-rw-r--r--src/test/ui/lexer/lexer-crlf-line-endings-string-literal-doc-comment.rs (renamed from src/test/ui/parser/lexer-crlf-line-endings-string-literal-doc-comment.rs)0
-rw-r--r--src/test/ui/lifetimes/auxiliary/issue-91763-aux.rs47
-rw-r--r--src/test/ui/lifetimes/issue-76168-hr-outlives.rs19
-rw-r--r--src/test/ui/lifetimes/issue-90600-expected-return-static-indirect.stderr2
-rw-r--r--src/test/ui/lifetimes/issue-91763.rs11
-rw-r--r--src/test/ui/lifetimes/issue-91763.stderr14
-rw-r--r--src/test/ui/lifetimes/undeclared-lifetime-used-in-debug-macro-issue-70152.stderr3
-rw-r--r--src/test/ui/limits/issue-55878.stderr1
-rw-r--r--src/test/ui/lint/bare-trait-objects-path.rs2
-rw-r--r--src/test/ui/lint/bare-trait-objects-path.stderr35
-rw-r--r--src/test/ui/lint/dead-code/anon-const-in-pat.rs2
-rw-r--r--src/test/ui/lint/force-warn/allowed-by-default-lint.stderr6
-rw-r--r--src/test/ui/lint/force-warn/allowed-group-warn-by-default-lint.rs4
-rw-r--r--src/test/ui/lint/force-warn/allowed-group-warn-by-default-lint.stderr37
-rw-r--r--src/test/ui/lint/force-warn/cap-lints-allow.rs4
-rw-r--r--src/test/ui/lint/force-warn/cap-lints-allow.stderr37
-rw-r--r--src/test/ui/lint/force-warn/lint-group-allowed-cli-warn-by-default-lint.rs4
-rw-r--r--src/test/ui/lint/force-warn/lint-group-allowed-cli-warn-by-default-lint.stderr37
-rw-r--r--src/test/ui/lint/force-warn/lint-group-allowed-lint-group.rs4
-rw-r--r--src/test/ui/lint/force-warn/lint-group-allowed-lint-group.stderr37
-rw-r--r--src/test/ui/lint/force-warn/lint-group-allowed-warn-by-default-lint.rs4
-rw-r--r--src/test/ui/lint/force-warn/lint-group-allowed-warn-by-default-lint.stderr37
-rw-r--r--src/test/ui/lint/future-incompat-test.rs2
-rw-r--r--src/test/ui/lint/issue-87308.stdout2
-rw-r--r--src/test/ui/lint/lint-ctypes-73251-2.rs2
-rw-r--r--src/test/ui/lint/lint-ctypes-73251-2.stderr2
-rw-r--r--src/test/ui/lint/must_not_suspend/boxed.stderr2
-rw-r--r--src/test/ui/lint/must_not_suspend/dedup.stderr2
-rw-r--r--src/test/ui/lint/must_not_suspend/gated.stderr2
-rw-r--r--src/test/ui/lint/must_not_suspend/mutex.stderr2
-rw-r--r--src/test/ui/lint/must_not_suspend/ref.stderr2
-rw-r--r--src/test/ui/lint/must_not_suspend/trait.stderr4
-rw-r--r--src/test/ui/lint/must_not_suspend/unit.stderr2
-rw-r--r--src/test/ui/lint/must_not_suspend/warn.stderr2
-rw-r--r--src/test/ui/lint/opaque-ty-ffi-unsafe.rs2
-rw-r--r--src/test/ui/lint/opaque-ty-ffi-unsafe.stderr2
-rw-r--r--src/test/ui/lint/reasons.rs4
-rw-r--r--src/test/ui/lint/reasons.stderr12
-rw-r--r--src/test/ui/lint/unaligned_references.stderr7
-rw-r--r--src/test/ui/lint/unaligned_references_external_macro.stderr1
-rw-r--r--src/test/ui/lint/unused/issue-90807-unused-paren-error.rs9
-rw-r--r--src/test/ui/lint/unused/issue-90807-unused-paren-error.stderr31
-rw-r--r--src/test/ui/lint/unused/issue-90807-unused-paren.rs8
-rw-r--r--src/test/ui/lint/unused/unused-doc-comments-edge-cases.rs3
-rw-r--r--src/test/ui/lint/unused/unused-doc-comments-edge-cases.stderr10
-rw-r--r--src/test/ui/lint/unused/unused-result.rs2
-rw-r--r--src/test/ui/lint/unused/unused-result.stderr2
-rw-r--r--src/test/ui/liveness/liveness-asm.rs3
-rw-r--r--src/test/ui/liveness/liveness-asm.stderr6
-rw-r--r--src/test/ui/liveness/liveness-move-in-while.stderr2
-rw-r--r--src/test/ui/liveness/liveness-use-after-move.stderr2
-rw-r--r--src/test/ui/liveness/liveness-use-after-send.stderr2
-rw-r--r--src/test/ui/loops/loop-proper-liveness.stderr2
-rw-r--r--src/test/ui/lto/lto-duplicate-symbols.rs2
-rw-r--r--src/test/ui/lto/lto-duplicate-symbols.stderr2
-rw-r--r--src/test/ui/macros/concat-bytes-error.rs42
-rw-r--r--src/test/ui/macros/concat-bytes-error.stderr131
-rw-r--r--src/test/ui/macros/concat-bytes.rs7
-rw-r--r--src/test/ui/macros/global-asm.rs4
-rw-r--r--src/test/ui/macros/macro-comma-behavior-rpass.rs1
-rw-r--r--src/test/ui/macros/macro-expanded-include/foo/mod.rs2
-rw-r--r--src/test/ui/macros/macro-expanded-include/test.rs6
-rw-r--r--src/test/ui/macros/macro-pat-pattern-followed-by-or-in-2021.stderr12
-rw-r--r--src/test/ui/macros/macro-pat2021-pattern-followed-by-or.stderr12
-rw-r--r--src/test/ui/macros/macros-nonfatal-errors.rs4
-rw-r--r--src/test/ui/macros/macros-nonfatal-errors.stderr58
-rw-r--r--src/test/ui/macros/nonterminal-matching.rs2
-rw-r--r--src/test/ui/macros/nonterminal-matching.stderr2
-rw-r--r--src/test/ui/match/match-type-err-first-arm.stderr5
-rw-r--r--src/test/ui/methods/method-ambig-two-traits-cross-crate.stderr12
-rw-r--r--src/test/ui/mir/issue-91745.rs21
-rw-r--r--src/test/ui/mir/mir_calls_to_shims.rs1
-rw-r--r--src/test/ui/mir/mir_const_prop_identity.rs12
-rw-r--r--src/test/ui/mir/mir_drop_order.rs1
-rw-r--r--src/test/ui/mir/mir_drop_panics.rs1
-rw-r--r--src/test/ui/mir/mir_dynamic_drops_3.rs1
-rw-r--r--src/test/ui/mir/mir_overflow_off.rs2
-rw-r--r--src/test/ui/mir/remove-zsts-query-cycle.rs2
-rw-r--r--src/test/ui/mismatched_types/E0053.stderr16
-rw-r--r--src/test/ui/mismatched_types/E0409.stderr2
-rw-r--r--src/test/ui/mismatched_types/issue-84976.stderr6
-rw-r--r--src/test/ui/mismatched_types/trait-impl-fn-incompatibility.stderr16
-rw-r--r--src/test/ui/missing/missing-alloc_error_handler.stderr2
-rw-r--r--src/test/ui/missing/missing-items/missing-type-parameter2.rs3
-rw-r--r--src/test/ui/missing/missing-items/missing-type-parameter2.stderr16
-rw-r--r--src/test/ui/moves/move-of-addr-of-mut.rs12
-rw-r--r--src/test/ui/moves/move-of-addr-of-mut.stderr11
-rw-r--r--src/test/ui/moves/moves-based-on-type-capture-clause-bad.stderr2
-rw-r--r--src/test/ui/mut/mut-pattern-mismatched.stderr6
-rw-r--r--src/test/ui/never_type/diverging-tuple-parts-39485.stderr6
-rw-r--r--src/test/ui/never_type/issue-51506.stderr4
-rw-r--r--src/test/ui/nll/ty-outlives/impl-trait-captures.stderr6
-rw-r--r--src/test/ui/nll/user-annotations/constant-in-expr-inherent-1.stderr2
-rw-r--r--src/test/ui/numbers-arithmetic/int-abs-overflow.rs3
-rw-r--r--src/test/ui/numbers-arithmetic/next-power-of-two-overflow-debug.rs1
-rw-r--r--src/test/ui/numeric/numeric-cast.stderr20
-rw-r--r--src/test/ui/object-lifetime/object-lifetime-default-from-box-error.stderr10
-rw-r--r--src/test/ui/operator-recovery/less-than-greater-than.rs4
-rw-r--r--src/test/ui/operator-recovery/less-than-greater-than.stderr8
-rw-r--r--src/test/ui/operator-recovery/spaceship.rs4
-rw-r--r--src/test/ui/operator-recovery/spaceship.stderr8
-rw-r--r--src/test/ui/optimization-remark.rs28
-rw-r--r--src/test/ui/or-patterns/already-bound-name.stderr5
-rw-r--r--src/test/ui/or-patterns/inconsistent-modes.stderr5
-rw-r--r--src/test/ui/output-type-mismatch.stderr4
-rw-r--r--src/test/ui/packed/issue-27060.stderr4
-rw-r--r--src/test/ui/packed/packed-struct-borrow-element-64bit.stderr1
-rw-r--r--src/test/ui/packed/packed-struct-borrow-element.stderr2
-rw-r--r--src/test/ui/packed/packed-struct-drop-aligned.rs28
-rw-r--r--src/test/ui/panic-handler/weak-lang-item.stderr3
-rw-r--r--src/test/ui/panics/location-detail-panic-no-column.rs1
-rw-r--r--src/test/ui/panics/location-detail-panic-no-column.run.stderr2
-rw-r--r--src/test/ui/panics/location-detail-panic-no-file.rs1
-rw-r--r--src/test/ui/panics/location-detail-panic-no-file.run.stderr2
-rw-r--r--src/test/ui/panics/location-detail-panic-no-line.rs1
-rw-r--r--src/test/ui/panics/location-detail-unwrap-no-file.rs1
-rw-r--r--src/test/ui/panics/location-detail-unwrap-no-file.run.stderr2
-rw-r--r--src/test/ui/panics/panic-handler-chain.rs1
-rw-r--r--src/test/ui/panics/panic-handler-flail-wildly.rs1
-rw-r--r--src/test/ui/panics/panic-handler-set-twice.rs1
-rw-r--r--src/test/ui/panics/panic-in-dtor-drops-fields.rs1
-rw-r--r--src/test/ui/panics/panic-recover-propagate.rs1
-rw-r--r--src/test/ui/parser/const-param-decl-on-type-instead-of-impl.rs15
-rw-r--r--src/test/ui/parser/const-param-decl-on-type-instead-of-impl.stderr47
-rw-r--r--src/test/ui/parser/duplicate-visibility.rs7
-rw-r--r--src/test/ui/parser/duplicate-visibility.stderr10
-rw-r--r--src/test/ui/parser/emoji-identifiers.rs19
-rw-r--r--src/test/ui/parser/emoji-identifiers.stderr91
-rw-r--r--src/test/ui/parser/fn-header-semantic-fail.stderr16
-rw-r--r--src/test/ui/parser/issue-87694-duplicated-pub.rs5
-rw-r--r--src/test/ui/parser/issue-87694-duplicated-pub.stderr17
-rw-r--r--src/test/ui/parser/issue-87694-misplaced-pub.rs5
-rw-r--r--src/test/ui/parser/issue-87694-misplaced-pub.stderr11
-rw-r--r--src/test/ui/parser/issue-91421.rs10
-rw-r--r--src/test/ui/parser/issue-91421.stderr21
-rw-r--r--src/test/ui/parser/issues/issue-14303-enum.stderr2
-rw-r--r--src/test/ui/parser/issues/issue-14303-fn-def.stderr2
-rw-r--r--src/test/ui/parser/issues/issue-14303-impl.stderr2
-rw-r--r--src/test/ui/parser/issues/issue-14303-struct.stderr2
-rw-r--r--src/test/ui/parser/issues/issue-14303-trait.stderr2
-rw-r--r--src/test/ui/parser/issues/issue-24780.rs2
-rw-r--r--src/test/ui/parser/issues/issue-24780.stderr4
-rw-r--r--src/test/ui/parser/issues/issue-58856-1.rs2
-rw-r--r--src/test/ui/parser/issues/issue-58856-1.stderr4
-rw-r--r--src/test/ui/parser/issues/issue-68890-2.rs2
-rw-r--r--src/test/ui/parser/issues/issue-68890-2.stderr12
-rw-r--r--src/test/ui/parser/issues/issue-73568-lifetime-after-mut.rs4
-rw-r--r--src/test/ui/parser/issues/issue-73568-lifetime-after-mut.stderr23
-rw-r--r--src/test/ui/parser/issues/issue-84148-1.stderr4
-rw-r--r--src/test/ui/parser/issues/issue-84148-2.stderr4
-rw-r--r--src/test/ui/parser/issues/issue-87086-colon-path-sep.rs31
-rw-r--r--src/test/ui/parser/issues/issue-87086-colon-path-sep.stderr60
-rw-r--r--src/test/ui/parser/issues/issue-87217-keyword-order/const-async-const.rs8
-rw-r--r--src/test/ui/parser/issues/issue-87217-keyword-order/const-async-const.stderr16
-rw-r--r--src/test/ui/parser/issues/issue-87635.rs4
-rw-r--r--src/test/ui/parser/issues/issue-87635.stderr12
-rw-r--r--src/test/ui/parser/issues/issue-91461.rs6
-rw-r--r--src/test/ui/parser/issues/issue-91461.stderr31
-rw-r--r--src/test/ui/parser/macro/trait-object-macro-matcher.rs2
-rw-r--r--src/test/ui/parser/macro/trait-object-macro-matcher.stderr12
-rw-r--r--src/test/ui/parser/missing_right_paren.stderr4
-rw-r--r--src/test/ui/parser/misspelled-macro-rules.fixed13
-rw-r--r--src/test/ui/parser/misspelled-macro-rules.rs13
-rw-r--r--src/test/ui/parser/misspelled-macro-rules.stderr10
-rw-r--r--src/test/ui/parser/trait-object-trait-parens.stderr51
-rw-r--r--src/test/ui/pattern/issue-74702.stderr4
-rw-r--r--src/test/ui/pattern/non-structural-match-types.rs2
-rw-r--r--src/test/ui/pattern/non-structural-match-types.stderr2
-rw-r--r--src/test/ui/pattern/pat-tuple-overfield.stderr5
-rw-r--r--src/test/ui/pattern/usefulness/issue-88747.rs14
-rw-r--r--src/test/ui/privacy/reachable-unnameable-items.rs1
-rw-r--r--src/test/ui/proc-macro/allowed-attr-stmt-expr.stdout8
-rw-r--r--src/test/ui/proc-macro/attr-complex-fn.stdout2
-rw-r--r--src/test/ui/proc-macro/attr-stmt-expr.stdout8
-rw-r--r--src/test/ui/proc-macro/attribute-after-derive.stdout4
-rw-r--r--src/test/ui/proc-macro/auxiliary/attr-args.rs2
-rw-r--r--src/test/ui/proc-macro/auxiliary/attr-on-trait.rs2
-rw-r--r--src/test/ui/proc-macro/auxiliary/custom-quote.rs3
-rw-r--r--src/test/ui/proc-macro/cfg-eval-inner.stdout2
-rw-r--r--src/test/ui/proc-macro/crate-attrs-multiple.rs14
-rw-r--r--src/test/ui/proc-macro/derive-expand-order.stdout10
-rw-r--r--src/test/ui/proc-macro/expand-with-a-macro.rs1
-rw-r--r--src/test/ui/proc-macro/expr-stmt-nonterminal-tokens.stdout2
-rw-r--r--src/test/ui/proc-macro/inner-attrs.stdout6
-rw-r--r--src/test/ui/proc-macro/input-interpolated.stdout2
-rw-r--r--src/test/ui/proc-macro/issue-59191-replace-root-with-fn.rs9
-rw-r--r--src/test/ui/proc-macro/issue-59191-replace-root-with-fn.stderr8
-rw-r--r--src/test/ui/proc-macro/issue-75734-pp-paren.stdout2
-rw-r--r--src/test/ui/proc-macro/issue-75930-derive-cfg.stdout6
-rw-r--r--src/test/ui/proc-macro/issue-81007-item-attrs.stdout4
-rw-r--r--src/test/ui/proc-macro/macro-brackets.stderr5
-rw-r--r--src/test/ui/proc-macro/nested-macro-rules.stdout4
-rw-r--r--src/test/ui/proc-macro/nonterminal-token-hygiene.stdout2
-rw-r--r--src/test/ui/proc-macro/trailing-plus.stdout2
-rw-r--r--src/test/ui/proc-macro/weird-braces.stdout2
-rw-r--r--src/test/ui/regions/region-object-lifetime-in-coercion.stderr21
-rw-r--r--src/test/ui/regions/regions-addr-of-self.stderr2
-rw-r--r--src/test/ui/regions/regions-assoc-type-in-supertrait-outlives-container.migrate.nll.stderr15
-rw-r--r--src/test/ui/regions/regions-assoc-type-in-supertrait-outlives-container.migrate.stderr6
-rw-r--r--src/test/ui/regions/regions-assoc-type-in-supertrait-outlives-container.nll.stderr2
-rw-r--r--src/test/ui/regions/regions-assoc-type-in-supertrait-outlives-container.rs5
-rw-r--r--src/test/ui/regions/regions-assoc-type-region-bound-in-trait-not-met.stderr8
-rw-r--r--src/test/ui/regions/regions-assoc-type-static-bound-in-trait-not-met.stderr4
-rw-r--r--src/test/ui/regions/regions-close-object-into-object-2.stderr9
-rw-r--r--src/test/ui/regions/regions-close-object-into-object-4.stderr9
-rw-r--r--src/test/ui/regions/regions-free-region-ordering-caller.migrate.nll.stderr39
-rw-r--r--src/test/ui/regions/regions-free-region-ordering-caller.migrate.stderr18
-rw-r--r--src/test/ui/regions/regions-free-region-ordering-caller.nll.stderr6
-rw-r--r--src/test/ui/regions/regions-free-region-ordering-caller.rs5
-rw-r--r--src/test/ui/regions/regions-outlives-projection-container-hrtb.migrate.nll.stderr28
-rw-r--r--src/test/ui/regions/regions-outlives-projection-container-hrtb.migrate.stderr12
-rw-r--r--src/test/ui/regions/regions-outlives-projection-container-hrtb.nll.stderr4
-rw-r--r--src/test/ui/regions/regions-outlives-projection-container-hrtb.rs5
-rw-r--r--src/test/ui/regions/regions-outlives-projection-container-wc.migrate.nll.stderr15
-rw-r--r--src/test/ui/regions/regions-outlives-projection-container-wc.migrate.stderr6
-rw-r--r--src/test/ui/regions/regions-outlives-projection-container-wc.nll.stderr2
-rw-r--r--src/test/ui/regions/regions-outlives-projection-container-wc.rs5
-rw-r--r--src/test/ui/regions/regions-proc-bound-capture.stderr10
-rw-r--r--src/test/ui/regions/regions-static-bound.stderr4
-rw-r--r--src/test/ui/repr/issue-83921-pretty.pretty.stdout5
-rw-r--r--src/test/ui/resolve/issue-70736-async-fn-no-body-def-collector.stderr8
-rw-r--r--src/test/ui/return/return-type.stderr14
-rw-r--r--src/test/ui/rfc-1937-termination-trait/termination-trait-in-test.rs1
-rw-r--r--src/test/ui/rfc-2008-non-exhaustive/auxiliary/enums.rs12
-rw-r--r--src/test/ui/rfc-2008-non-exhaustive/enum-as-cast.rs17
-rw-r--r--src/test/ui/rfc-2091-track-caller/error-with-naked.rs4
-rw-r--r--src/test/ui/rfc-2091-track-caller/error-with-naked.stderr4
-rw-r--r--src/test/ui/rfc-2091-track-caller/std-panic-locations.rs1
-rw-r--r--src/test/ui/rfc-2497-if-let-chains/ast-pretty-check.stdout2
-rw-r--r--src/test/ui/rfc-2497-if-let-chains/disallowed-positions.stderr8
-rw-r--r--src/test/ui/rfc-2565-param-attrs/auxiliary/param-attrs.rs18
-rw-r--r--src/test/ui/rfc-2632-const-trait-impl/assoc-type.rs1
-rw-r--r--src/test/ui/rfc-2632-const-trait-impl/assoc-type.stderr6
-rw-r--r--src/test/ui/rfc-2632-const-trait-impl/auxiliary/cross-crate.rs3
-rw-r--r--src/test/ui/rfc-2632-const-trait-impl/const-drop-bound.rs20
-rw-r--r--src/test/ui/rfc-2632-const-trait-impl/cross-crate-default-method-body-is-const.rs18
-rw-r--r--src/test/ui/rfc-2632-const-trait-impl/default-method-body-is-const-body-checking.rs17
-rw-r--r--src/test/ui/rfc-2632-const-trait-impl/default-method-body-is-const-body-checking.stderr19
-rw-r--r--src/test/ui/rfc-2632-const-trait-impl/non-const-op-in-closure-in-const.rs18
-rw-r--r--src/test/ui/rfc-2632-const-trait-impl/trait-default-body-stability.rs51
-rw-r--r--src/test/ui/rfc1623.nll.stderr34
-rw-r--r--src/test/ui/rfc1623.rs4
-rw-r--r--src/test/ui/rfc1623.stderr2
-rw-r--r--src/test/ui/rfcs/rfc1857-drop-order.rs1
-rw-r--r--src/test/ui/runtime/rt-explody-panic-payloads.rs1
-rw-r--r--src/test/ui/rust-2018/uniform-paths/deadlock.rs3
-rw-r--r--src/test/ui/rust-2018/uniform-paths/deadlock.stderr21
-rw-r--r--src/test/ui/rustdoc/doc_keyword.rs2
-rw-r--r--src/test/ui/rustdoc/renamed-features-rustdoc_internals.rs5
-rw-r--r--src/test/ui/rustdoc/renamed-features-rustdoc_internals.stderr19
-rw-r--r--src/test/ui/self/arbitrary_self_types_pin_lifetime_impl_trait-async.stderr2
-rw-r--r--src/test/ui/self/arbitrary_self_types_pin_lifetime_impl_trait.stderr2
-rw-r--r--src/test/ui/sepcomp/sepcomp-unwind.rs1
-rw-r--r--src/test/ui/simd/intrinsic/generic-elements-pass.rs1
-rw-r--r--src/test/ui/simple_global_asm.rs3
-rw-r--r--src/test/ui/slightly-nice-generic-literal-messages.stderr2
-rw-r--r--src/test/ui/span/issue-43927-non-ADT-derive.rs1
-rw-r--r--src/test/ui/span/issue-43927-non-ADT-derive.stderr13
-rw-r--r--src/test/ui/specialization/deafult-associated-type-bound-1.stderr4
-rw-r--r--src/test/ui/specialization/deafult-associated-type-bound-2.stderr4
-rw-r--r--src/test/ui/specialization/deafult-generic-associated-type-bound.stderr4
-rw-r--r--src/test/ui/specialization/issue-33017.stderr4
-rw-r--r--src/test/ui/specialization/issue-38091.stderr4
-rw-r--r--src/test/ui/specialization/issue-44861.stderr4
-rw-r--r--src/test/ui/specialization/issue-59435.stderr4
-rw-r--r--src/test/ui/specialization/min_specialization/repeated_projection_type.stderr2
-rw-r--r--src/test/ui/stability-attribute/suggest-vec-allocator-api.rs9
-rw-r--r--src/test/ui/stability-attribute/suggest-vec-allocator-api.stderr49
-rw-r--r--src/test/ui/stack-protector/warn-stack-protector-unsupported.all.stderr4
-rw-r--r--src/test/ui/stack-protector/warn-stack-protector-unsupported.basic.stderr4
-rw-r--r--src/test/ui/stack-protector/warn-stack-protector-unsupported.rs19
-rw-r--r--src/test/ui/stack-protector/warn-stack-protector-unsupported.strong.stderr4
-rw-r--r--src/test/ui/static/static-mut-bad-types.stderr3
-rw-r--r--src/test/ui/structs-enums/unit-like-struct-drop-run.rs1
-rw-r--r--src/test/ui/structs/structure-constructor-type-mismatch.stderr6
-rw-r--r--src/test/ui/suggestions/as-ref-2.stderr4
-rw-r--r--src/test/ui/suggestions/async-fn-ctor-passed-as-arg-where-it-should-have-been-called.stderr2
-rw-r--r--src/test/ui/suggestions/count2len.rs8
-rw-r--r--src/test/ui/suggestions/count2len.stderr36
-rw-r--r--src/test/ui/suggestions/derive-macro-missing-bounds.rs89
-rw-r--r--src/test/ui/suggestions/derive-macro-missing-bounds.stderr107
-rw-r--r--src/test/ui/suggestions/expected-boxed-future-isnt-pinned.stderr2
-rw-r--r--src/test/ui/suggestions/fn-ctor-passed-as-arg-where-it-should-have-been-called.stderr4
-rw-r--r--src/test/ui/suggestions/fn-or-tuple-struct-with-underscore-args.rs6
-rw-r--r--src/test/ui/suggestions/fn-or-tuple-struct-with-underscore-args.stderr65
-rw-r--r--src/test/ui/suggestions/if-let-typo.rs5
-rw-r--r--src/test/ui/suggestions/if-let-typo.stderr52
-rw-r--r--src/test/ui/suggestions/impl-on-dyn-trait-with-implicit-static-bound-needing-more-suggestions.stderr2
-rw-r--r--src/test/ui/suggestions/impl-on-dyn-trait-with-implicit-static-bound.stderr12
-rw-r--r--src/test/ui/suggestions/issue-61963.rs10
-rw-r--r--src/test/ui/suggestions/issue-61963.stderr88
-rw-r--r--src/test/ui/suggestions/issue-71394-no-from-impl.stderr3
-rw-r--r--src/test/ui/suggestions/issue-85945-check-where-clause-before-suggesting-unsized.rs2
-rw-r--r--src/test/ui/suggestions/lifetimes/trait-object-nested-in-impl-trait.stderr8
-rw-r--r--src/test/ui/suggestions/mut-ref-reassignment.stderr8
-rw-r--r--src/test/ui/suggestions/suggest-add-self.rs15
-rw-r--r--src/test/ui/suggestions/suggest-add-self.stderr29
-rw-r--r--src/test/ui/suggestions/suggest-move-lifetimes.stderr8
-rw-r--r--src/test/ui/suggestions/suggest-semicolon-for-fn-in-extern-block.fixed9
-rw-r--r--src/test/ui/suggestions/suggest-semicolon-for-fn-in-extern-block.rs9
-rw-r--r--src/test/ui/suggestions/suggest-semicolon-for-fn-in-extern-block.stderr10
-rw-r--r--src/test/ui/svh/changing-crates.rs2
-rw-r--r--src/test/ui/svh/changing-crates.stderr2
-rw-r--r--src/test/ui/svh/svh-change-lit.rs2
-rw-r--r--src/test/ui/svh/svh-change-lit.stderr2
-rw-r--r--src/test/ui/svh/svh-change-significant-cfg.rs2
-rw-r--r--src/test/ui/svh/svh-change-significant-cfg.stderr2
-rw-r--r--src/test/ui/svh/svh-change-trait-bound.rs2
-rw-r--r--src/test/ui/svh/svh-change-trait-bound.stderr2
-rw-r--r--src/test/ui/svh/svh-change-type-arg.rs2
-rw-r--r--src/test/ui/svh/svh-change-type-arg.stderr2
-rw-r--r--src/test/ui/svh/svh-change-type-ret.rs2
-rw-r--r--src/test/ui/svh/svh-change-type-ret.stderr2
-rw-r--r--src/test/ui/svh/svh-change-type-static.rs2
-rw-r--r--src/test/ui/svh/svh-change-type-static.stderr2
-rw-r--r--src/test/ui/svh/svh-use-trait.rs2
-rw-r--r--src/test/ui/svh/svh-use-trait.stderr2
-rw-r--r--src/test/ui/symbol-names/basic.legacy.stderr4
-rw-r--r--src/test/ui/symbol-names/basic.rs4
-rw-r--r--src/test/ui/symbol-names/basic.v0.stderr4
-rw-r--r--src/test/ui/symbol-names/const-generics-demangling.rs17
-rw-r--r--src/test/ui/symbol-names/const-generics-demangling.stderr40
-rw-r--r--src/test/ui/symbol-names/const-generics-str-demangling.rs25
-rw-r--r--src/test/ui/symbol-names/const-generics-str-demangling.stderr60
-rw-r--r--src/test/ui/symbol-names/const-generics-structural-demangling.rs36
-rw-r--r--src/test/ui/symbol-names/const-generics-structural-demangling.stderr32
-rw-r--r--src/test/ui/symbol-names/impl1.legacy.stderr12
-rw-r--r--src/test/ui/symbol-names/impl1.rs12
-rw-r--r--src/test/ui/symbol-names/impl1.v0.stderr12
-rw-r--r--src/test/ui/symbol-names/issue-60925.legacy.stderr4
-rw-r--r--src/test/ui/symbol-names/issue-60925.rs4
-rw-r--r--src/test/ui/symbol-names/issue-60925.v0.stderr4
-rw-r--r--src/test/ui/symbol-names/issue-75326.legacy.stderr4
-rw-r--r--src/test/ui/symbol-names/issue-75326.rs4
-rw-r--r--src/test/ui/symbol-names/issue-75326.v0.stderr4
-rw-r--r--src/test/ui/symbol-names/trait-objects.rs1
-rw-r--r--src/test/ui/symbol-names/trait-objects.v0.stderr30
-rw-r--r--src/test/ui/test-attrs/test-should-fail-good-message.rs1
-rw-r--r--src/test/ui/thir-tree.stdout4
-rw-r--r--src/test/ui/threads-sendsync/task-stderr.rs1
-rw-r--r--src/test/ui/threads-sendsync/unwind-resource.rs1
-rw-r--r--src/test/ui/traits/associated_type_bound/check-trait-object-bounds-5.stderr7
-rw-r--r--src/test/ui/traits/associated_type_bound/check-trait-object-bounds-6.stderr7
-rw-r--r--src/test/ui/traits/bound/not-on-bare-trait.stderr7
-rw-r--r--src/test/ui/traits/impl-method-mismatch.stderr8
-rw-r--r--src/test/ui/traits/inductive-overflow/lifetime.rs1
-rw-r--r--src/test/ui/traits/inductive-overflow/lifetime.stderr2
-rw-r--r--src/test/ui/traits/inductive-overflow/two-traits.stderr4
-rw-r--r--src/test/ui/traits/issue-65673.stderr4
-rw-r--r--src/test/ui/traits/issue-85360-eval-obligation-ice.rs143
-rw-r--r--src/test/ui/traits/issue-85360-eval-obligation-ice.stderr38
-rw-r--r--src/test/ui/traits/project-modulo-regions.rs55
-rw-r--r--src/test/ui/traits/project-modulo-regions.with_clause.stderr11
-rw-r--r--src/test/ui/traits/project-modulo-regions.without_clause.stderr11
-rw-r--r--src/test/ui/traits/trait-upcasting/type-checking-test-4.rs18
-rw-r--r--src/test/ui/traits/trait-upcasting/type-checking-test-4.stderr82
-rw-r--r--src/test/ui/traits/vtable/issue-91807.rs17
-rw-r--r--src/test/ui/try-block/try-block-maybe-bad-lifetime.stderr2
-rw-r--r--src/test/ui/type-alias-impl-trait/argument-types.stderr2
-rw-r--r--src/test/ui/type-alias-impl-trait/issue-63355.stderr7
-rw-r--r--src/test/ui/type-alias-impl-trait/issue-89686.rs2
-rw-r--r--src/test/ui/type-alias-impl-trait/issue-89686.stderr6
-rw-r--r--src/test/ui/type-alias-impl-trait/static-const-types.rs9
-rw-r--r--src/test/ui/type-alias-impl-trait/static-const-types.stderr6
-rw-r--r--src/test/ui/type/issue-91268.rs9
-rw-r--r--src/test/ui/type/issue-91268.stderr50
-rw-r--r--src/test/ui/type/type-annotation-needed.rs1
-rw-r--r--src/test/ui/type/type-annotation-needed.stderr2
-rw-r--r--src/test/ui/type/type-check/assignment-expected-bool.stderr4
-rw-r--r--src/test/ui/type/type-check/assignment-in-if.stderr4
-rw-r--r--src/test/ui/typeck/issue-57673-ice-on-deref-of-boxed-trait.stderr2
-rw-r--r--src/test/ui/typeck/issue-81293.stderr3
-rw-r--r--src/test/ui/typeck/issue-87771-ice-assign-assign-to-bool.stderr2
-rw-r--r--src/test/ui/typeck/issue-91210-ptr-method.fixed15
-rw-r--r--src/test/ui/typeck/issue-91210-ptr-method.rs15
-rw-r--r--src/test/ui/typeck/issue-91210-ptr-method.stderr11
-rw-r--r--src/test/ui/typeck/issue-91267.rs6
-rw-r--r--src/test/ui/typeck/issue-91267.stderr27
-rw-r--r--src/test/ui/typeck/issue-91334.rs10
-rw-r--r--src/test/ui/typeck/issue-91334.stderr50
-rw-r--r--src/test/ui/typeck/issue-91450-inner-ty-error.rs7
-rw-r--r--src/test/ui/typeck/issue-91450-inner-ty-error.stderr21
-rw-r--r--src/test/ui/typeck/return_type_containing_closure.rs10
-rw-r--r--src/test/ui/typeck/return_type_containing_closure.stderr17
-rw-r--r--src/test/ui/underscore-lifetime/dyn-trait-underscore.stderr12
-rw-r--r--src/test/ui/union/issue-81199.rs21
-rw-r--r--src/test/ui/union/issue-81199.stderr29
-rw-r--r--src/test/ui/unsafe/inline_asm.mir.stderr4
-rw-r--r--src/test/ui/unsafe/inline_asm.rs3
-rw-r--r--src/test/ui/unsafe/inline_asm.thir.stderr4
-rw-r--r--src/test/ui/unsafe/unsafe-trait-impl.stderr8
-rw-r--r--src/test/ui/unspecified-self-in-trait-ref.rs10
-rw-r--r--src/test/ui/unspecified-self-in-trait-ref.stderr76
-rw-r--r--src/test/ui/unwind-unique.rs1
-rw-r--r--src/test/ui/use/use-after-move-based-on-type.stderr2
-rw-r--r--src/test/ui/walk-struct-literal-with.stderr1
-rw-r--r--src/test/ui/weird-exprs.rs1
-rw-r--r--src/test/ui/wf/hir-wf-check-erase-regions.stderr12
m---------src/tools/cargo0
-rw-r--r--src/tools/clippy/.github/ISSUE_TEMPLATE/blank_issue.md18
-rw-r--r--src/tools/clippy/.github/ISSUE_TEMPLATE/blank_issue.yml44
-rw-r--r--src/tools/clippy/.github/ISSUE_TEMPLATE/bug_report.md43
-rw-r--r--src/tools/clippy/.github/ISSUE_TEMPLATE/bug_report.yml57
-rw-r--r--src/tools/clippy/.github/ISSUE_TEMPLATE/false_negative.md35
-rw-r--r--src/tools/clippy/.github/ISSUE_TEMPLATE/false_negative.yml50
-rw-r--r--src/tools/clippy/.github/ISSUE_TEMPLATE/false_positive.md44
-rw-r--r--src/tools/clippy/.github/ISSUE_TEMPLATE/false_positive.yml68
-rw-r--r--src/tools/clippy/.github/ISSUE_TEMPLATE/ice.md52
-rw-r--r--src/tools/clippy/.github/ISSUE_TEMPLATE/ice.yml48
-rw-r--r--src/tools/clippy/.github/ISSUE_TEMPLATE/new_lint.md36
-rw-r--r--src/tools/clippy/.github/ISSUE_TEMPLATE/new_lint.yml71
-rw-r--r--src/tools/clippy/.github/workflows/clippy_dev.yml12
-rw-r--r--src/tools/clippy/.gitignore4
-rw-r--r--src/tools/clippy/CHANGELOG.md22
-rw-r--r--src/tools/clippy/Cargo.toml3
-rw-r--r--src/tools/clippy/README.md3
-rw-r--r--src/tools/clippy/clippy_dev/Cargo.toml1
-rw-r--r--src/tools/clippy/clippy_dev/src/fmt.rs44
-rw-r--r--src/tools/clippy/clippy_dev/src/lib.rs1
-rw-r--r--src/tools/clippy/clippy_dev/src/lint.rs20
-rw-r--r--src/tools/clippy/clippy_dev/src/main.rs15
-rw-r--r--src/tools/clippy/clippy_dev/src/new_lint.rs21
-rw-r--r--src/tools/clippy/clippy_dev/src/update_lints.rs5
-rw-r--r--src/tools/clippy/clippy_lints/Cargo.toml2
-rw-r--r--src/tools/clippy/clippy_lints/src/absurd_extreme_comparisons.rs1
-rw-r--r--src/tools/clippy/clippy_lints/src/approx_const.rs1
-rw-r--r--src/tools/clippy/clippy_lints/src/arithmetic.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/as_conversions.rs1
-rw-r--r--src/tools/clippy/clippy_lints/src/asm_syntax.rs6
-rw-r--r--src/tools/clippy/clippy_lints/src/assertions_on_constants.rs13
-rw-r--r--src/tools/clippy/clippy_lints/src/assign_ops.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/async_yields_async.rs1
-rw-r--r--src/tools/clippy/clippy_lints/src/attrs.rs26
-rw-r--r--src/tools/clippy/clippy_lints/src/await_holding_invalid.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/bit_mask.rs3
-rw-r--r--src/tools/clippy/clippy_lints/src/blacklisted_name.rs1
-rw-r--r--src/tools/clippy/clippy_lints/src/blocks_in_if_conditions.rs9
-rw-r--r--src/tools/clippy/clippy_lints/src/bool_assert_comparison.rs3
-rw-r--r--src/tools/clippy/clippy_lints/src/booleans.rs30
-rw-r--r--src/tools/clippy/clippy_lints/src/bytecount.rs11
-rw-r--r--src/tools/clippy/clippy_lints/src/cargo_common_metadata.rs1
-rw-r--r--src/tools/clippy/clippy_lints/src/case_sensitive_file_extension_comparisons.rs1
-rw-r--r--src/tools/clippy/clippy_lints/src/casts/cast_lossless.rs41
-rw-r--r--src/tools/clippy/clippy_lints/src/casts/mod.rs29
-rw-r--r--src/tools/clippy/clippy_lints/src/checked_conversions.rs1
-rw-r--r--src/tools/clippy/clippy_lints/src/cognitive_complexity.rs1
-rw-r--r--src/tools/clippy/clippy_lints/src/collapsible_if.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/collapsible_match.rs21
-rw-r--r--src/tools/clippy/clippy_lints/src/comparison_chain.rs1
-rw-r--r--src/tools/clippy/clippy_lints/src/copies.rs10
-rw-r--r--src/tools/clippy/clippy_lints/src/copy_iterator.rs1
-rw-r--r--src/tools/clippy/clippy_lints/src/create_dir.rs1
-rw-r--r--src/tools/clippy/clippy_lints/src/dbg_macro.rs9
-rw-r--r--src/tools/clippy/clippy_lints/src/default.rs8
-rw-r--r--src/tools/clippy/clippy_lints/src/default_numeric_fallback.rs1
-rw-r--r--src/tools/clippy/clippy_lints/src/deprecated_lints.rs16
-rw-r--r--src/tools/clippy/clippy_lints/src/dereference.rs338
-rw-r--r--src/tools/clippy/clippy_lints/src/derivable_impls.rs7
-rw-r--r--src/tools/clippy/clippy_lints/src/derive.rs12
-rw-r--r--src/tools/clippy/clippy_lints/src/disallowed_methods.rs (renamed from src/tools/clippy/clippy_lints/src/disallowed_method.rs)13
-rw-r--r--src/tools/clippy/clippy_lints/src/disallowed_script_idents.rs1
-rw-r--r--src/tools/clippy/clippy_lints/src/disallowed_types.rs (renamed from src/tools/clippy/clippy_lints/src/disallowed_type.rs)15
-rw-r--r--src/tools/clippy/clippy_lints/src/doc.rs30
-rw-r--r--src/tools/clippy/clippy_lints/src/double_comparison.rs1
-rw-r--r--src/tools/clippy/clippy_lints/src/double_parens.rs1
-rw-r--r--src/tools/clippy/clippy_lints/src/drop_forget_ref.rs4
-rw-r--r--src/tools/clippy/clippy_lints/src/duration_subsec.rs1
-rw-r--r--src/tools/clippy/clippy_lints/src/else_if_without_else.rs1
-rw-r--r--src/tools/clippy/clippy_lints/src/empty_enum.rs1
-rw-r--r--src/tools/clippy/clippy_lints/src/entry.rs1
-rw-r--r--src/tools/clippy/clippy_lints/src/enum_clike.rs1
-rw-r--r--src/tools/clippy/clippy_lints/src/enum_variants.rs3
-rw-r--r--src/tools/clippy/clippy_lints/src/eq_op.rs8
-rw-r--r--src/tools/clippy/clippy_lints/src/equatable_if_let.rs17
-rw-r--r--src/tools/clippy/clippy_lints/src/erasing_op.rs1
-rw-r--r--src/tools/clippy/clippy_lints/src/escape.rs1
-rw-r--r--src/tools/clippy/clippy_lints/src/eta_reduction.rs8
-rw-r--r--src/tools/clippy/clippy_lints/src/eval_order_dependence.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/excessive_bools.rs5
-rw-r--r--src/tools/clippy/clippy_lints/src/exhaustive_items.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/exit.rs1
-rw-r--r--src/tools/clippy/clippy_lints/src/explicit_write.rs1
-rw-r--r--src/tools/clippy/clippy_lints/src/fallible_impl_from.rs1
-rw-r--r--src/tools/clippy/clippy_lints/src/feature_name.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/float_equality_without_abs.rs1
-rw-r--r--src/tools/clippy/clippy_lints/src/float_literal.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/floating_point_arithmetic.rs19
-rw-r--r--src/tools/clippy/clippy_lints/src/format.rs1
-rw-r--r--src/tools/clippy/clippy_lints/src/format_args.rs13
-rw-r--r--src/tools/clippy/clippy_lints/src/formatting.rs4
-rw-r--r--src/tools/clippy/clippy_lints/src/from_over_into.rs1
-rw-r--r--src/tools/clippy/clippy_lints/src/from_str_radix_10.rs1
-rw-r--r--src/tools/clippy/clippy_lints/src/functions/mod.rs7
-rw-r--r--src/tools/clippy/clippy_lints/src/functions/too_many_lines.rs4
-rw-r--r--src/tools/clippy/clippy_lints/src/future_not_send.rs5
-rw-r--r--src/tools/clippy/clippy_lints/src/get_last_with_len.rs1
-rw-r--r--src/tools/clippy/clippy_lints/src/identity_op.rs1
-rw-r--r--src/tools/clippy/clippy_lints/src/if_let_mutex.rs1
-rw-r--r--src/tools/clippy/clippy_lints/src/if_not_else.rs1
-rw-r--r--src/tools/clippy/clippy_lints/src/if_then_some_else_none.rs19
-rw-r--r--src/tools/clippy/clippy_lints/src/implicit_hasher.rs1
-rw-r--r--src/tools/clippy/clippy_lints/src/implicit_return.rs31
-rw-r--r--src/tools/clippy/clippy_lints/src/implicit_saturating_sub.rs19
-rw-r--r--src/tools/clippy/clippy_lints/src/inconsistent_struct_constructor.rs4
-rw-r--r--src/tools/clippy/clippy_lints/src/index_refutable_slice.rs276
-rw-r--r--src/tools/clippy/clippy_lints/src/indexing_slicing.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/infinite_iter.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/inherent_impl.rs9
-rw-r--r--src/tools/clippy/clippy_lints/src/inherent_to_string.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/inline_fn_without_body.rs1
-rw-r--r--src/tools/clippy/clippy_lints/src/int_plus_one.rs1
-rw-r--r--src/tools/clippy/clippy_lints/src/integer_division.rs1
-rw-r--r--src/tools/clippy/clippy_lints/src/invalid_upcast_comparisons.rs1
-rw-r--r--src/tools/clippy/clippy_lints/src/items_after_statements.rs1
-rw-r--r--src/tools/clippy/clippy_lints/src/iter_not_returning_iterator.rs1
-rw-r--r--src/tools/clippy/clippy_lints/src/large_const_arrays.rs1
-rw-r--r--src/tools/clippy/clippy_lints/src/large_enum_variant.rs1
-rw-r--r--src/tools/clippy/clippy_lints/src/large_stack_arrays.rs1
-rw-r--r--src/tools/clippy/clippy_lints/src/len_zero.rs3
-rw-r--r--src/tools/clippy/clippy_lints/src/let_if_seq.rs1
-rw-r--r--src/tools/clippy/clippy_lints/src/let_underscore.rs10
-rw-r--r--src/tools/clippy/clippy_lints/src/lib.register_all.rs9
-rw-r--r--src/tools/clippy/clippy_lints/src/lib.register_complexity.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/lib.register_internal.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/lib.register_lints.rs18
-rw-r--r--src/tools/clippy/clippy_lints/src/lib.register_nursery.rs6
-rw-r--r--src/tools/clippy/clippy_lints/src/lib.register_pedantic.rs3
-rw-r--r--src/tools/clippy/clippy_lints/src/lib.register_perf.rs1
-rw-r--r--src/tools/clippy/clippy_lints/src/lib.register_style.rs3
-rw-r--r--src/tools/clippy/clippy_lints/src/lib.register_suspicious.rs3
-rw-r--r--src/tools/clippy/clippy_lints/src/lib.rs139
-rw-r--r--src/tools/clippy/clippy_lints/src/lifetimes.rs8
-rw-r--r--src/tools/clippy/clippy_lints/src/literal_representation.rs13
-rw-r--r--src/tools/clippy/clippy_lints/src/loops/explicit_counter_loop.rs58
-rw-r--r--src/tools/clippy/clippy_lints/src/loops/manual_flatten.rs112
-rw-r--r--src/tools/clippy/clippy_lints/src/loops/manual_memcpy.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/loops/mod.rs18
-rw-r--r--src/tools/clippy/clippy_lints/src/loops/needless_collect.rs178
-rw-r--r--src/tools/clippy/clippy_lints/src/loops/never_loop.rs6
-rw-r--r--src/tools/clippy/clippy_lints/src/loops/utils.rs74
-rw-r--r--src/tools/clippy/clippy_lints/src/macro_use.rs7
-rw-r--r--src/tools/clippy/clippy_lints/src/main_recursion.rs1
-rw-r--r--src/tools/clippy/clippy_lints/src/manual_assert.rs3
-rw-r--r--src/tools/clippy/clippy_lints/src/manual_async_fn.rs1
-rw-r--r--src/tools/clippy/clippy_lints/src/manual_map.rs96
-rw-r--r--src/tools/clippy/clippy_lints/src/manual_non_exhaustive.rs1
-rw-r--r--src/tools/clippy/clippy_lints/src/manual_ok_or.rs1
-rw-r--r--src/tools/clippy/clippy_lints/src/manual_strip.rs1
-rw-r--r--src/tools/clippy/clippy_lints/src/manual_unwrap_or.rs1
-rw-r--r--src/tools/clippy/clippy_lints/src/map_clone.rs6
-rw-r--r--src/tools/clippy/clippy_lints/src/map_err_ignore.rs1
-rw-r--r--src/tools/clippy/clippy_lints/src/map_unit_fn.rs4
-rw-r--r--src/tools/clippy/clippy_lints/src/match_on_vec_items.rs1
-rw-r--r--src/tools/clippy/clippy_lints/src/match_result_ok.rs1
-rw-r--r--src/tools/clippy/clippy_lints/src/match_str_case_mismatch.rs1
-rw-r--r--src/tools/clippy/clippy_lints/src/matches.rs202
-rw-r--r--src/tools/clippy/clippy_lints/src/mem_forget.rs1
-rw-r--r--src/tools/clippy/clippy_lints/src/mem_replace.rs7
-rw-r--r--src/tools/clippy/clippy_lints/src/methods/bind_instead_of_map.rs6
-rw-r--r--src/tools/clippy/clippy_lints/src/methods/filter_map.rs4
-rw-r--r--src/tools/clippy/clippy_lints/src/methods/from_iter_instead_of_collect.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/methods/implicit_clone.rs29
-rw-r--r--src/tools/clippy/clippy_lints/src/methods/iter_cloned_collect.rs6
-rw-r--r--src/tools/clippy/clippy_lints/src/methods/mod.rs139
-rw-r--r--src/tools/clippy/clippy_lints/src/methods/option_as_ref_deref.rs4
-rw-r--r--src/tools/clippy/clippy_lints/src/methods/option_map_or_none.rs139
-rw-r--r--src/tools/clippy/clippy_lints/src/methods/or_fun_call.rs59
-rw-r--r--src/tools/clippy/clippy_lints/src/methods/search_is_some.rs18
-rw-r--r--src/tools/clippy/clippy_lints/src/methods/single_char_pattern.rs7
-rw-r--r--src/tools/clippy/clippy_lints/src/methods/str_splitn.rs (renamed from src/tools/clippy/clippy_lints/src/methods/manual_split_once.rs)152
-rw-r--r--src/tools/clippy/clippy_lints/src/methods/unnecessary_fold.rs4
-rw-r--r--src/tools/clippy/clippy_lints/src/methods/unnecessary_iter_cloned.rs177
-rw-r--r--src/tools/clippy/clippy_lints/src/methods/unnecessary_lazy_eval.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/methods/unnecessary_to_owned.rs397
-rw-r--r--src/tools/clippy/clippy_lints/src/methods/utils.rs8
-rw-r--r--src/tools/clippy/clippy_lints/src/minmax.rs1
-rw-r--r--src/tools/clippy/clippy_lints/src/misc.rs9
-rw-r--r--src/tools/clippy/clippy_lints/src/misc_early/mod.rs10
-rw-r--r--src/tools/clippy/clippy_lints/src/missing_const_for_fn.rs1
-rw-r--r--src/tools/clippy/clippy_lints/src/missing_doc.rs1
-rw-r--r--src/tools/clippy/clippy_lints/src/missing_enforced_import_rename.rs1
-rw-r--r--src/tools/clippy/clippy_lints/src/missing_inline.rs1
-rw-r--r--src/tools/clippy/clippy_lints/src/module_style.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/modulo_arithmetic.rs1
-rw-r--r--src/tools/clippy/clippy_lints/src/multiple_crate_versions.rs1
-rw-r--r--src/tools/clippy/clippy_lints/src/mut_key.rs1
-rw-r--r--src/tools/clippy/clippy_lints/src/mut_mut.rs1
-rw-r--r--src/tools/clippy/clippy_lints/src/mut_mutex_lock.rs1
-rw-r--r--src/tools/clippy/clippy_lints/src/mut_reference.rs1
-rw-r--r--src/tools/clippy/clippy_lints/src/mutable_debug_assertion.rs1
-rw-r--r--src/tools/clippy/clippy_lints/src/mutex_atomic.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/needless_arbitrary_self_type.rs8
-rw-r--r--src/tools/clippy/clippy_lints/src/needless_bitwise_bool.rs4
-rw-r--r--src/tools/clippy/clippy_lints/src/needless_bool.rs99
-rw-r--r--src/tools/clippy/clippy_lints/src/needless_borrow.rs282
-rw-r--r--src/tools/clippy/clippy_lints/src/needless_borrowed_ref.rs1
-rw-r--r--src/tools/clippy/clippy_lints/src/needless_continue.rs1
-rw-r--r--src/tools/clippy/clippy_lints/src/needless_for_each.rs1
-rw-r--r--src/tools/clippy/clippy_lints/src/needless_late_init.rs355
-rw-r--r--src/tools/clippy/clippy_lints/src/needless_option_as_deref.rs4
-rw-r--r--src/tools/clippy/clippy_lints/src/needless_pass_by_value.rs1
-rw-r--r--src/tools/clippy/clippy_lints/src/needless_question_mark.rs36
-rw-r--r--src/tools/clippy/clippy_lints/src/needless_update.rs1
-rw-r--r--src/tools/clippy/clippy_lints/src/neg_cmp_op_on_partial_ord.rs1
-rw-r--r--src/tools/clippy/clippy_lints/src/neg_multiply.rs1
-rw-r--r--src/tools/clippy/clippy_lints/src/new_without_default.rs1
-rw-r--r--src/tools/clippy/clippy_lints/src/no_effect.rs29
-rw-r--r--src/tools/clippy/clippy_lints/src/non_copy_const.rs6
-rw-r--r--src/tools/clippy/clippy_lints/src/non_expressive_names.rs17
-rw-r--r--src/tools/clippy/clippy_lints/src/non_octal_unix_permissions.rs1
-rw-r--r--src/tools/clippy/clippy_lints/src/non_send_fields_in_send_ty.rs61
-rw-r--r--src/tools/clippy/clippy_lints/src/nonstandard_macro_braces.rs33
-rw-r--r--src/tools/clippy/clippy_lints/src/octal_escapes.rs150
-rw-r--r--src/tools/clippy/clippy_lints/src/open_options.rs1
-rw-r--r--src/tools/clippy/clippy_lints/src/option_env_unwrap.rs1
-rw-r--r--src/tools/clippy/clippy_lints/src/option_if_let_else.rs50
-rw-r--r--src/tools/clippy/clippy_lints/src/overflow_check_conditional.rs1
-rw-r--r--src/tools/clippy/clippy_lints/src/panic_in_result_fn.rs1
-rw-r--r--src/tools/clippy/clippy_lints/src/panic_unimplemented.rs4
-rw-r--r--src/tools/clippy/clippy_lints/src/partialeq_ne_impl.rs1
-rw-r--r--src/tools/clippy/clippy_lints/src/pass_by_ref_or_value.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/path_buf_push_overwrite.rs1
-rw-r--r--src/tools/clippy/clippy_lints/src/pattern_type_mismatch.rs7
-rw-r--r--src/tools/clippy/clippy_lints/src/precedence.rs1
-rw-r--r--src/tools/clippy/clippy_lints/src/ptr.rs4
-rw-r--r--src/tools/clippy/clippy_lints/src/ptr_eq.rs4
-rw-r--r--src/tools/clippy/clippy_lints/src/ptr_offset_with_cast.rs1
-rw-r--r--src/tools/clippy/clippy_lints/src/question_mark.rs66
-rw-r--r--src/tools/clippy/clippy_lints/src/ranges.rs5
-rw-r--r--src/tools/clippy/clippy_lints/src/redundant_clone.rs9
-rw-r--r--src/tools/clippy/clippy_lints/src/redundant_closure_call.rs1
-rw-r--r--src/tools/clippy/clippy_lints/src/redundant_else.rs1
-rw-r--r--src/tools/clippy/clippy_lints/src/redundant_field_names.rs1
-rw-r--r--src/tools/clippy/clippy_lints/src/redundant_pub_crate.rs1
-rw-r--r--src/tools/clippy/clippy_lints/src/redundant_slicing.rs5
-rw-r--r--src/tools/clippy/clippy_lints/src/redundant_static_lifetimes.rs1
-rw-r--r--src/tools/clippy/clippy_lints/src/ref_option_ref.rs1
-rw-r--r--src/tools/clippy/clippy_lints/src/reference.rs5
-rw-r--r--src/tools/clippy/clippy_lints/src/regex.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/repeat_once.rs4
-rw-r--r--src/tools/clippy/clippy_lints/src/return_self_not_must_use.rs105
-rw-r--r--src/tools/clippy/clippy_lints/src/returns.rs7
-rw-r--r--src/tools/clippy/clippy_lints/src/same_name_method.rs7
-rw-r--r--src/tools/clippy/clippy_lints/src/self_assignment.rs1
-rw-r--r--src/tools/clippy/clippy_lints/src/self_named_constructors.rs5
-rw-r--r--src/tools/clippy/clippy_lints/src/semicolon_if_nothing_returned.rs3
-rw-r--r--src/tools/clippy/clippy_lints/src/serde_api.rs1
-rw-r--r--src/tools/clippy/clippy_lints/src/shadow.rs10
-rw-r--r--src/tools/clippy/clippy_lints/src/single_component_path_imports.rs4
-rw-r--r--src/tools/clippy/clippy_lints/src/size_of_in_element_count.rs1
-rw-r--r--src/tools/clippy/clippy_lints/src/slow_vector_initialization.rs1
-rw-r--r--src/tools/clippy/clippy_lints/src/stable_sort_primitive.rs1
-rw-r--r--src/tools/clippy/clippy_lints/src/strings.rs16
-rw-r--r--src/tools/clippy/clippy_lints/src/strlen_on_c_strings.rs67
-rw-r--r--src/tools/clippy/clippy_lints/src/suspicious_operation_groupings.rs1
-rw-r--r--src/tools/clippy/clippy_lints/src/suspicious_trait_impl.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/swap.rs50
-rw-r--r--src/tools/clippy/clippy_lints/src/tabs_in_doc_comments.rs1
-rw-r--r--src/tools/clippy/clippy_lints/src/temporary_assignment.rs1
-rw-r--r--src/tools/clippy/clippy_lints/src/to_digit_is_some.rs1
-rw-r--r--src/tools/clippy/clippy_lints/src/to_string_in_display.rs1
-rw-r--r--src/tools/clippy/clippy_lints/src/trailing_empty_array.rs1
-rw-r--r--src/tools/clippy/clippy_lints/src/trait_bounds.rs12
-rw-r--r--src/tools/clippy/clippy_lints/src/transmute/mod.rs13
-rw-r--r--src/tools/clippy/clippy_lints/src/transmuting_null.rs1
-rw-r--r--src/tools/clippy/clippy_lints/src/try_err.rs23
-rw-r--r--src/tools/clippy/clippy_lints/src/types/mod.rs55
-rw-r--r--src/tools/clippy/clippy_lints/src/undocumented_unsafe_blocks.rs13
-rw-r--r--src/tools/clippy/clippy_lints/src/undropped_manually_drops.rs1
-rw-r--r--src/tools/clippy/clippy_lints/src/unicode.rs13
-rw-r--r--src/tools/clippy/clippy_lints/src/uninit_vec.rs1
-rw-r--r--src/tools/clippy/clippy_lints/src/unit_hash.rs1
-rw-r--r--src/tools/clippy/clippy_lints/src/unit_return_expecting_ord.rs3
-rw-r--r--src/tools/clippy/clippy_lints/src/unit_types/mod.rs3
-rw-r--r--src/tools/clippy/clippy_lints/src/unnamed_address.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/unnecessary_self_imports.rs1
-rw-r--r--src/tools/clippy/clippy_lints/src/unnecessary_sort_by.rs1
-rw-r--r--src/tools/clippy/clippy_lints/src/unnecessary_wraps.rs5
-rw-r--r--src/tools/clippy/clippy_lints/src/unnested_or_patterns.rs1
-rw-r--r--src/tools/clippy/clippy_lints/src/unsafe_removed_from_name.rs1
-rw-r--r--src/tools/clippy/clippy_lints/src/unused_async.rs1
-rw-r--r--src/tools/clippy/clippy_lints/src/unused_io_amount.rs3
-rw-r--r--src/tools/clippy/clippy_lints/src/unused_self.rs3
-rw-r--r--src/tools/clippy/clippy_lints/src/unused_unit.rs1
-rw-r--r--src/tools/clippy/clippy_lints/src/unwrap.rs6
-rw-r--r--src/tools/clippy/clippy_lints/src/unwrap_in_result.rs1
-rw-r--r--src/tools/clippy/clippy_lints/src/upper_case_acronyms.rs1
-rw-r--r--src/tools/clippy/clippy_lints/src/use_self.rs11
-rw-r--r--src/tools/clippy/clippy_lints/src/useless_conversion.rs1
-rw-r--r--src/tools/clippy/clippy_lints/src/utils/author.rs1168
-rw-r--r--src/tools/clippy/clippy_lints/src/utils/conf.rs16
-rw-r--r--src/tools/clippy/clippy_lints/src/utils/inspector.rs7
-rw-r--r--src/tools/clippy/clippy_lints/src/utils/internal_lints.rs90
-rw-r--r--src/tools/clippy/clippy_lints/src/utils/internal_lints/metadata_collector.rs38
-rw-r--r--src/tools/clippy/clippy_lints/src/vec.rs1
-rw-r--r--src/tools/clippy/clippy_lints/src/vec_init_then_push.rs1
-rw-r--r--src/tools/clippy/clippy_lints/src/vec_resize_to_zero.rs1
-rw-r--r--src/tools/clippy/clippy_lints/src/verbose_file_reads.rs1
-rw-r--r--src/tools/clippy/clippy_lints/src/wildcard_dependencies.rs1
-rw-r--r--src/tools/clippy/clippy_lints/src/wildcard_imports.rs6
-rw-r--r--src/tools/clippy/clippy_lints/src/write.rs29
-rw-r--r--src/tools/clippy/clippy_lints/src/zero_div_zero.rs1
-rw-r--r--src/tools/clippy/clippy_lints/src/zero_sized_map_values.rs1
-rw-r--r--src/tools/clippy/clippy_utils/Cargo.toml2
-rw-r--r--src/tools/clippy/clippy_utils/src/ast_utils.rs115
-rw-r--r--src/tools/clippy/clippy_utils/src/attrs.rs15
-rw-r--r--src/tools/clippy/clippy_utils/src/eager_or_lazy.rs307
-rw-r--r--src/tools/clippy/clippy_utils/src/higher.rs26
-rw-r--r--src/tools/clippy/clippy_utils/src/hir_utils.rs17
-rw-r--r--src/tools/clippy/clippy_utils/src/lib.rs218
-rw-r--r--src/tools/clippy/clippy_utils/src/msrvs.rs5
-rw-r--r--src/tools/clippy/clippy_utils/src/paths.rs5
-rw-r--r--src/tools/clippy/clippy_utils/src/ptr.rs58
-rw-r--r--src/tools/clippy/clippy_utils/src/source.rs16
-rw-r--r--src/tools/clippy/clippy_utils/src/sugg.rs278
-rw-r--r--src/tools/clippy/clippy_utils/src/ty.rs61
-rw-r--r--src/tools/clippy/clippy_utils/src/usage.rs113
-rw-r--r--src/tools/clippy/clippy_utils/src/visitors.rs289
-rw-r--r--src/tools/clippy/doc/adding_lints.md15
-rw-r--r--src/tools/clippy/doc/changelog_update.md2
-rw-r--r--src/tools/clippy/doc/common_tools_writing_lints.md155
-rw-r--r--src/tools/clippy/lintcheck-logs/lintcheck_crates_logs.txt3862
-rw-r--r--src/tools/clippy/lintcheck/src/main.rs178
-rw-r--r--src/tools/clippy/rust-toolchain4
-rw-r--r--src/tools/clippy/src/driver.rs2
-rw-r--r--src/tools/clippy/tests/compile-test.rs3
-rw-r--r--src/tools/clippy/tests/fmt.rs5
-rw-r--r--src/tools/clippy/tests/ui-internal/check_clippy_version_attribute.rs87
-rw-r--r--src/tools/clippy/tests/ui-internal/check_clippy_version_attribute.stderr73
-rw-r--r--src/tools/clippy/tests/ui-internal/collapsible_span_lint_calls.fixed1
-rw-r--r--src/tools/clippy/tests/ui-internal/collapsible_span_lint_calls.rs1
-rw-r--r--src/tools/clippy/tests/ui-internal/collapsible_span_lint_calls.stderr10
-rw-r--r--src/tools/clippy/tests/ui-internal/custom_ice_message.rs1
-rw-r--r--src/tools/clippy/tests/ui-internal/default_lint.rs1
-rw-r--r--src/tools/clippy/tests/ui-internal/default_lint.stderr2
-rw-r--r--src/tools/clippy/tests/ui-internal/if_chain_style.rs2
-rw-r--r--src/tools/clippy/tests/ui-internal/interning_defined_symbol.fixed1
-rw-r--r--src/tools/clippy/tests/ui-internal/interning_defined_symbol.rs1
-rw-r--r--src/tools/clippy/tests/ui-internal/interning_defined_symbol.stderr8
-rw-r--r--src/tools/clippy/tests/ui-internal/invalid_paths.rs1
-rw-r--r--src/tools/clippy/tests/ui-internal/invalid_paths.stderr4
-rw-r--r--src/tools/clippy/tests/ui-internal/lint_without_lint_pass.rs1
-rw-r--r--src/tools/clippy/tests/ui-internal/lint_without_lint_pass.stderr2
-rw-r--r--src/tools/clippy/tests/ui-internal/match_type_on_diag_item.rs1
-rw-r--r--src/tools/clippy/tests/ui-internal/match_type_on_diag_item.stderr6
-rw-r--r--src/tools/clippy/tests/ui-internal/outer_expn_data.fixed1
-rw-r--r--src/tools/clippy/tests/ui-internal/outer_expn_data.rs1
-rw-r--r--src/tools/clippy/tests/ui-internal/outer_expn_data.stderr2
-rw-r--r--src/tools/clippy/tests/ui-internal/unnecessary_symbol_str.fixed6
-rw-r--r--src/tools/clippy/tests/ui-internal/unnecessary_symbol_str.rs6
-rw-r--r--src/tools/clippy/tests/ui-internal/unnecessary_symbol_str.stderr10
-rw-r--r--src/tools/clippy/tests/ui-toml/max_suggested_slice_pattern_length/clippy.toml1
-rw-r--r--src/tools/clippy/tests/ui-toml/max_suggested_slice_pattern_length/index_refutable_slice.rs23
-rw-r--r--src/tools/clippy/tests/ui-toml/max_suggested_slice_pattern_length/index_refutable_slice.stderr22
-rw-r--r--src/tools/clippy/tests/ui-toml/min_rust_version/min_rust_version.rs10
-rw-r--r--src/tools/clippy/tests/ui-toml/strict_non_send_fields_in_send_ty/test.stderr28
-rw-r--r--src/tools/clippy/tests/ui-toml/toml_disallowed_methods/clippy.toml (renamed from src/tools/clippy/tests/ui-toml/toml_disallowed_method/clippy.toml)0
-rw-r--r--src/tools/clippy/tests/ui-toml/toml_disallowed_methods/conf_disallowed_methods.rs (renamed from src/tools/clippy/tests/ui-toml/toml_disallowed_method/conf_disallowed_method.rs)2
-rw-r--r--src/tools/clippy/tests/ui-toml/toml_disallowed_methods/conf_disallowed_methods.stderr (renamed from src/tools/clippy/tests/ui-toml/toml_disallowed_method/conf_disallowed_method.stderr)8
-rw-r--r--src/tools/clippy/tests/ui-toml/toml_disallowed_types/clippy.toml (renamed from src/tools/clippy/tests/ui-toml/toml_disallowed_type/clippy.toml)0
-rw-r--r--src/tools/clippy/tests/ui-toml/toml_disallowed_types/conf_disallowed_types.rs (renamed from src/tools/clippy/tests/ui-toml/toml_disallowed_type/conf_disallowed_type.rs)2
-rw-r--r--src/tools/clippy/tests/ui-toml/toml_disallowed_types/conf_disallowed_types.stderr (renamed from src/tools/clippy/tests/ui-toml/toml_disallowed_type/conf_disallowed_type.stderr)44
-rw-r--r--src/tools/clippy/tests/ui-toml/toml_unknown_key/conf_unknown_key.stderr2
-rw-r--r--src/tools/clippy/tests/ui/asm_syntax.rs4
-rw-r--r--src/tools/clippy/tests/ui/asm_syntax.stderr6
-rw-r--r--src/tools/clippy/tests/ui/author.stdout12
-rw-r--r--src/tools/clippy/tests/ui/author/blocks.rs9
-rw-r--r--src/tools/clippy/tests/ui/author/blocks.stdout68
-rw-r--r--src/tools/clippy/tests/ui/author/call.stdout14
-rw-r--r--src/tools/clippy/tests/ui/author/for_loop.rs8
-rw-r--r--src/tools/clippy/tests/ui/author/for_loop.stdout49
-rw-r--r--src/tools/clippy/tests/ui/author/if.rs7
-rw-r--r--src/tools/clippy/tests/ui/author/if.stdout54
-rw-r--r--src/tools/clippy/tests/ui/author/issue_3849.stdout14
-rw-r--r--src/tools/clippy/tests/ui/author/loop.rs36
-rw-r--r--src/tools/clippy/tests/ui/author/loop.stdout113
-rw-r--r--src/tools/clippy/tests/ui/author/matches.stdout49
-rw-r--r--src/tools/clippy/tests/ui/author/repeat.rs5
-rw-r--r--src/tools/clippy/tests/ui/author/repeat.stdout11
-rw-r--r--src/tools/clippy/tests/ui/author/struct.rs40
-rw-r--r--src/tools/clippy/tests/ui/author/struct.stdout64
-rw-r--r--src/tools/clippy/tests/ui/auxiliary/option_helpers.rs2
-rw-r--r--src/tools/clippy/tests/ui/blocks_in_if_conditions_closure.rs8
-rw-r--r--src/tools/clippy/tests/ui/cast_lossless_bool.fixed42
-rw-r--r--src/tools/clippy/tests/ui/cast_lossless_bool.rs42
-rw-r--r--src/tools/clippy/tests/ui/cast_lossless_bool.stderr82
-rw-r--r--src/tools/clippy/tests/ui/crashes/auxiliary/ice-7934-aux.rs4
-rw-r--r--src/tools/clippy/tests/ui/crashes/ice-6250.stderr18
-rw-r--r--src/tools/clippy/tests/ui/crashes/ice-7934.rs7
-rw-r--r--src/tools/clippy/tests/ui/crate_level_checks/no_std_swap.rs14
-rw-r--r--src/tools/clippy/tests/ui/crate_level_checks/no_std_swap.stderr12
-rw-r--r--src/tools/clippy/tests/ui/deref_addrof.fixed1
-rw-r--r--src/tools/clippy/tests/ui/deref_addrof.rs1
-rw-r--r--src/tools/clippy/tests/ui/deref_addrof.stderr20
-rw-r--r--src/tools/clippy/tests/ui/doc/doc-fixable.stderr209
-rw-r--r--src/tools/clippy/tests/ui/doc/unbalanced_ticks.stderr21
-rw-r--r--src/tools/clippy/tests/ui/entry.fixed2
-rw-r--r--src/tools/clippy/tests/ui/entry.rs2
-rw-r--r--src/tools/clippy/tests/ui/explicit_counter_loop.rs30
-rw-r--r--src/tools/clippy/tests/ui/explicit_counter_loop.stderr16
-rw-r--r--src/tools/clippy/tests/ui/floating_point_abs.fixed6
-rw-r--r--src/tools/clippy/tests/ui/floating_point_abs.rs6
-rw-r--r--src/tools/clippy/tests/ui/floating_point_abs.stderr16
-rw-r--r--src/tools/clippy/tests/ui/floating_point_mul_add.fixed11
-rw-r--r--src/tools/clippy/tests/ui/floating_point_mul_add.rs11
-rw-r--r--src/tools/clippy/tests/ui/floating_point_mul_add.stderr20
-rw-r--r--src/tools/clippy/tests/ui/floating_point_rad.fixed7
-rw-r--r--src/tools/clippy/tests/ui/floating_point_rad.rs7
-rw-r--r--src/tools/clippy/tests/ui/floating_point_rad.stderr4
-rw-r--r--src/tools/clippy/tests/ui/future_not_send.stderr24
-rw-r--r--src/tools/clippy/tests/ui/if_then_some_else_none.rs11
-rw-r--r--src/tools/clippy/tests/ui/index_refutable_slice/if_let_slice_binding.rs166
-rw-r--r--src/tools/clippy/tests/ui/index_refutable_slice/if_let_slice_binding.stderr158
-rw-r--r--src/tools/clippy/tests/ui/index_refutable_slice/slice_indexing_in_macro.rs28
-rw-r--r--src/tools/clippy/tests/ui/index_refutable_slice/slice_indexing_in_macro.stderr22
-rw-r--r--src/tools/clippy/tests/ui/iter_cloned_collect.fixed3
-rw-r--r--src/tools/clippy/tests/ui/iter_cloned_collect.rs3
-rw-r--r--src/tools/clippy/tests/ui/iter_cloned_collect.stderr8
-rw-r--r--src/tools/clippy/tests/ui/let_if_seq.rs3
-rw-r--r--src/tools/clippy/tests/ui/let_if_seq.stderr8
-rw-r--r--src/tools/clippy/tests/ui/let_underscore_lock.rs14
-rw-r--r--src/tools/clippy/tests/ui/let_underscore_lock.stderr46
-rw-r--r--src/tools/clippy/tests/ui/manual_assert.edition2018.fixed2
-rw-r--r--src/tools/clippy/tests/ui/manual_assert.edition2018.stderr14
-rw-r--r--src/tools/clippy/tests/ui/manual_assert.edition2021.fixed2
-rw-r--r--src/tools/clippy/tests/ui/manual_assert.edition2021.stderr14
-rw-r--r--src/tools/clippy/tests/ui/manual_assert.fixed2
-rw-r--r--src/tools/clippy/tests/ui/manual_assert.rs2
-rw-r--r--src/tools/clippy/tests/ui/manual_map_option_2.fixed10
-rw-r--r--src/tools/clippy/tests/ui/manual_map_option_2.rs19
-rw-r--r--src/tools/clippy/tests/ui/manual_map_option_2.stderr32
-rw-r--r--src/tools/clippy/tests/ui/manual_split_once.fixed6
-rw-r--r--src/tools/clippy/tests/ui/manual_split_once.rs2
-rw-r--r--src/tools/clippy/tests/ui/manual_split_once.stderr10
-rw-r--r--src/tools/clippy/tests/ui/match_overlapping_arm.rs18
-rw-r--r--src/tools/clippy/tests/ui/match_overlapping_arm.stderr26
-rw-r--r--src/tools/clippy/tests/ui/min_max.rs7
-rw-r--r--src/tools/clippy/tests/ui/min_max.stderr26
-rw-r--r--src/tools/clippy/tests/ui/min_rust_version_attr.rs19
-rw-r--r--src/tools/clippy/tests/ui/min_rust_version_attr.stderr8
-rw-r--r--src/tools/clippy/tests/ui/missing-doc.rs3
-rw-r--r--src/tools/clippy/tests/ui/missing-doc.stderr48
-rw-r--r--src/tools/clippy/tests/ui/needless_bool/fixable.fixed17
-rw-r--r--src/tools/clippy/tests/ui/needless_bool/fixable.rs21
-rw-r--r--src/tools/clippy/tests/ui/needless_bool/fixable.stderr42
-rw-r--r--src/tools/clippy/tests/ui/needless_borrow.fixed23
-rw-r--r--src/tools/clippy/tests/ui/needless_borrow.rs23
-rw-r--r--src/tools/clippy/tests/ui/needless_borrow.stderr50
-rw-r--r--src/tools/clippy/tests/ui/needless_collect_indirect.rs31
-rw-r--r--src/tools/clippy/tests/ui/needless_late_init.rs180
-rw-r--r--src/tools/clippy/tests/ui/needless_late_init.stderr186
-rw-r--r--src/tools/clippy/tests/ui/needless_late_init_fixable.fixed25
-rw-r--r--src/tools/clippy/tests/ui/needless_late_init_fixable.rs25
-rw-r--r--src/tools/clippy/tests/ui/needless_late_init_fixable.stderr69
-rw-r--r--src/tools/clippy/tests/ui/needless_question_mark.stderr24
-rw-r--r--src/tools/clippy/tests/ui/needless_return.fixed1
-rw-r--r--src/tools/clippy/tests/ui/needless_return.rs1
-rw-r--r--src/tools/clippy/tests/ui/needless_return.stderr36
-rw-r--r--src/tools/clippy/tests/ui/needless_splitn.fixed27
-rw-r--r--src/tools/clippy/tests/ui/needless_splitn.rs27
-rw-r--r--src/tools/clippy/tests/ui/needless_splitn.stderr40
-rw-r--r--src/tools/clippy/tests/ui/no_effect.rs35
-rw-r--r--src/tools/clippy/tests/ui/no_effect.stderr60
-rw-r--r--src/tools/clippy/tests/ui/non_send_fields_in_send_ty.rs5
-rw-r--r--src/tools/clippy/tests/ui/non_send_fields_in_send_ty.stderr72
-rw-r--r--src/tools/clippy/tests/ui/octal_escapes.rs20
-rw-r--r--src/tools/clippy/tests/ui/octal_escapes.stderr131
-rw-r--r--src/tools/clippy/tests/ui/option_env_unwrap.rs1
-rw-r--r--src/tools/clippy/tests/ui/option_env_unwrap.stderr12
-rw-r--r--src/tools/clippy/tests/ui/option_filter_map.fixed10
-rw-r--r--src/tools/clippy/tests/ui/option_filter_map.rs10
-rw-r--r--src/tools/clippy/tests/ui/option_filter_map.stderr16
-rw-r--r--src/tools/clippy/tests/ui/option_if_let_else.fixed29
-rw-r--r--src/tools/clippy/tests/ui/option_if_let_else.rs31
-rw-r--r--src/tools/clippy/tests/ui/option_if_let_else.stderr24
-rw-r--r--src/tools/clippy/tests/ui/option_map_or_none.fixed18
-rw-r--r--src/tools/clippy/tests/ui/option_map_or_none.rs16
-rw-r--r--src/tools/clippy/tests/ui/option_map_or_none.stderr53
-rw-r--r--src/tools/clippy/tests/ui/or_fun_call.fixed30
-rw-r--r--src/tools/clippy/tests/ui/or_fun_call.rs18
-rw-r--r--src/tools/clippy/tests/ui/or_fun_call.stderr60
-rw-r--r--src/tools/clippy/tests/ui/pattern_type_mismatch/mutability.rs9
-rw-r--r--src/tools/clippy/tests/ui/question_mark.fixed19
-rw-r--r--src/tools/clippy/tests/ui/question_mark.rs19
-rw-r--r--src/tools/clippy/tests/ui/redundant_closure_call_late.rs1
-rw-r--r--src/tools/clippy/tests/ui/redundant_closure_call_late.stderr6
-rw-r--r--src/tools/clippy/tests/ui/redundant_else.rs2
-rw-r--r--src/tools/clippy/tests/ui/redundant_pattern_matching_option.fixed6
-rw-r--r--src/tools/clippy/tests/ui/redundant_pattern_matching_option.rs6
-rw-r--r--src/tools/clippy/tests/ui/redundant_pattern_matching_option.stderr14
-rw-r--r--src/tools/clippy/tests/ui/redundant_pattern_matching_result.fixed4
-rw-r--r--src/tools/clippy/tests/ui/redundant_pattern_matching_result.stderr4
-rw-r--r--src/tools/clippy/tests/ui/rename.fixed5
-rw-r--r--src/tools/clippy/tests/ui/rename.rs5
-rw-r--r--src/tools/clippy/tests/ui/rename.stderr74
-rw-r--r--src/tools/clippy/tests/ui/return_self_not_must_use.rs42
-rw-r--r--src/tools/clippy/tests/ui/return_self_not_must_use.stderr26
-rw-r--r--src/tools/clippy/tests/ui/same_name_method.stderr10
-rw-r--r--src/tools/clippy/tests/ui/search_is_some.rs6
-rw-r--r--src/tools/clippy/tests/ui/search_is_some.stderr20
-rw-r--r--src/tools/clippy/tests/ui/search_is_some_fixable.fixed68
-rw-r--r--src/tools/clippy/tests/ui/search_is_some_fixable.rs68
-rw-r--r--src/tools/clippy/tests/ui/search_is_some_fixable.stderr184
-rw-r--r--src/tools/clippy/tests/ui/search_is_some_fixable_none.fixed216
-rw-r--r--src/tools/clippy/tests/ui/search_is_some_fixable_none.rs222
-rw-r--r--src/tools/clippy/tests/ui/search_is_some_fixable_none.stderr293
-rw-r--r--src/tools/clippy/tests/ui/search_is_some_fixable_some.fixed218
-rw-r--r--src/tools/clippy/tests/ui/search_is_some_fixable_some.rs221
-rw-r--r--src/tools/clippy/tests/ui/search_is_some_fixable_some.stderr276
-rw-r--r--src/tools/clippy/tests/ui/semicolon_if_nothing_returned.rs10
-rw-r--r--src/tools/clippy/tests/ui/semicolon_if_nothing_returned.stderr10
-rw-r--r--src/tools/clippy/tests/ui/shadow.rs6
-rw-r--r--src/tools/clippy/tests/ui/shadow.stderr14
-rw-r--r--src/tools/clippy/tests/ui/should_impl_trait/corner_cases.rs3
-rw-r--r--src/tools/clippy/tests/ui/should_impl_trait/method_list_1.rs3
-rw-r--r--src/tools/clippy/tests/ui/should_impl_trait/method_list_1.stderr28
-rw-r--r--src/tools/clippy/tests/ui/should_impl_trait/method_list_2.rs3
-rw-r--r--src/tools/clippy/tests/ui/should_impl_trait/method_list_2.stderr30
-rw-r--r--src/tools/clippy/tests/ui/single_char_pattern.fixed10
-rw-r--r--src/tools/clippy/tests/ui/single_char_pattern.rs10
-rw-r--r--src/tools/clippy/tests/ui/single_char_pattern.stderr102
-rw-r--r--src/tools/clippy/tests/ui/strlen_on_c_strings.fixed34
-rw-r--r--src/tools/clippy/tests/ui/strlen_on_c_strings.rs22
-rw-r--r--src/tools/clippy/tests/ui/strlen_on_c_strings.stderr47
-rw-r--r--src/tools/clippy/tests/ui/suspicious_splitn.rs1
-rw-r--r--src/tools/clippy/tests/ui/suspicious_splitn.stderr18
-rw-r--r--src/tools/clippy/tests/ui/trailing_empty_array.rs1
-rw-r--r--src/tools/clippy/tests/ui/trailing_empty_array.stderr22
-rw-r--r--src/tools/clippy/tests/ui/type_complexity.rs9
-rw-r--r--src/tools/clippy/tests/ui/type_complexity.stderr6
-rw-r--r--src/tools/clippy/tests/ui/undocumented_unsafe_blocks.rs4
-rw-r--r--src/tools/clippy/tests/ui/undocumented_unsafe_blocks.stderr14
-rw-r--r--src/tools/clippy/tests/ui/unicode.rs8
-rw-r--r--src/tools/clippy/tests/ui/unicode.stderr14
-rw-r--r--src/tools/clippy/tests/ui/unnecessary_iter_cloned.fixed142
-rw-r--r--src/tools/clippy/tests/ui/unnecessary_iter_cloned.rs142
-rw-r--r--src/tools/clippy/tests/ui/unnecessary_iter_cloned.stderr35
-rw-r--r--src/tools/clippy/tests/ui/unnecessary_to_owned.fixed214
-rw-r--r--src/tools/clippy/tests/ui/unnecessary_to_owned.rs214
-rw-r--r--src/tools/clippy/tests/ui/unnecessary_to_owned.stderr495
-rw-r--r--src/tools/clippy/triagebot.toml5
-rw-r--r--src/tools/clippy/util/gh-pages/index.html16
-rw-r--r--src/tools/compiletest/src/runtest.rs83
m---------src/tools/miri16
m---------src/tools/rust-analyzer38
-rw-r--r--src/tools/rustbook/Cargo.toml2
-rw-r--r--src/tools/rustdoc-gui/tester.js25
-rw-r--r--src/tools/rustfmt/.github/workflows/linux.yml5
-rw-r--r--src/tools/rustfmt/.github/workflows/mac.yml5
-rw-r--r--src/tools/rustfmt/.github/workflows/windows.yml5
-rw-r--r--src/tools/rustfmt/Configurations.md102
-rw-r--r--src/tools/rustfmt/README.md11
-rw-r--r--src/tools/rustfmt/config_proc_macro/src/lib.rs42
-rw-r--r--src/tools/rustfmt/src/comment.rs62
-rw-r--r--src/tools/rustfmt/src/config/mod.rs86
-rw-r--r--src/tools/rustfmt/src/expr.rs57
-rw-r--r--src/tools/rustfmt/src/ignore_path.rs24
-rw-r--r--src/tools/rustfmt/src/items.rs538
-rw-r--r--src/tools/rustfmt/src/lists.rs13
-rw-r--r--src/tools/rustfmt/src/macros.rs5
-rw-r--r--src/tools/rustfmt/src/syntux/session.rs15
-rw-r--r--src/tools/rustfmt/src/test/mod.rs13
-rw-r--r--src/tools/rustfmt/src/types.rs13
-rw-r--r--src/tools/rustfmt/src/visitor.rs4
-rw-r--r--src/tools/rustfmt/tests/source/comments-in-lists/wrap-comments-not-normalized.rs129
-rw-r--r--src/tools/rustfmt/tests/source/comments-in-lists/wrap-comments-true.rs130
-rw-r--r--src/tools/rustfmt/tests/source/issue-5088/deeply_nested_long_comment_wrap_comments_true.rs33
-rw-r--r--src/tools/rustfmt/tests/source/issue-5088/start_with_empty_comment_very_long_itemized_block_wrap_comments_true.rs19
-rw-r--r--src/tools/rustfmt/tests/source/issue-5088/very_long_comment_wrap_comments_true.rs13
-rw-r--r--src/tools/rustfmt/tests/source/issue_4823.rs5
-rw-r--r--src/tools/rustfmt/tests/source/issue_5027.rs7
-rw-r--r--src/tools/rustfmt/tests/source/issue_5086.rs2
-rw-r--r--src/tools/rustfmt/tests/target/comments-in-lists/format-doc-comments.rs96
-rw-r--r--src/tools/rustfmt/tests/target/comments-in-lists/wrap-comments-false.rs85
-rw-r--r--src/tools/rustfmt/tests/target/comments-in-lists/wrap-comments-not-normalized.rs142
-rw-r--r--src/tools/rustfmt/tests/target/comments-in-lists/wrap-comments-true.rs143
-rw-r--r--src/tools/rustfmt/tests/target/issue-5088/deeply_nested_long_comment_wrap_comments_false.rs33
-rw-r--r--src/tools/rustfmt/tests/target/issue-5088/deeply_nested_long_comment_wrap_comments_true.rs49
-rw-r--r--src/tools/rustfmt/tests/target/issue-5088/multi_line_itemized_block_wrap_comments_false.rs17
-rw-r--r--src/tools/rustfmt/tests/target/issue-5088/multi_line_itemized_block_wrap_comments_true.rs17
-rw-r--r--src/tools/rustfmt/tests/target/issue-5088/multi_line_text_with_itemized_block_wrap_comments_false.rs37
-rw-r--r--src/tools/rustfmt/tests/target/issue-5088/multi_line_text_with_itemized_block_wrap_comments_true.rs37
-rw-r--r--src/tools/rustfmt/tests/target/issue-5088/single_line_itemized_block_wrap_comments_false.rs9
-rw-r--r--src/tools/rustfmt/tests/target/issue-5088/single_line_itemized_block_wrap_comments_true.rs9
-rw-r--r--src/tools/rustfmt/tests/target/issue-5088/start_with_empty_comment_very_long_itemized_block_wrap_comments_false.rs19
-rw-r--r--src/tools/rustfmt/tests/target/issue-5088/start_with_empty_comment_very_long_itemized_block_wrap_comments_true.rs27
-rw-r--r--src/tools/rustfmt/tests/target/issue-5088/start_with_empty_comment_wrap_comments_false.rs17
-rw-r--r--src/tools/rustfmt/tests/target/issue-5088/start_with_empty_comment_wrap_comments_true.rs17
-rw-r--r--src/tools/rustfmt/tests/target/issue-5088/very_long_comment_wrap_comments_false.rs13
-rw-r--r--src/tools/rustfmt/tests/target/issue-5088/very_long_comment_wrap_comments_true.rs21
-rw-r--r--src/tools/rustfmt/tests/target/issue-5095.rs27
-rw-r--r--src/tools/rustfmt/tests/target/issue_4823.rs5
-rw-r--r--src/tools/rustfmt/tests/target/issue_5027.rs17
-rw-r--r--src/tools/rustfmt/tests/target/issue_5086.rs2
-rw-r--r--src/tools/tidy/src/deps.rs14
-rw-r--r--src/tools/tidy/src/edition.rs6
-rw-r--r--src/tools/tidy/src/ui_tests.rs6
-rw-r--r--src/version2
-rw-r--r--triagebot.toml32
2773 files changed, 47458 insertions, 23875 deletions
diff --git a/.mailmap b/.mailmap
index a160f2f4fbf..3d4d4711939 100644
--- a/.mailmap
+++ b/.mailmap
@@ -246,6 +246,7 @@ Philipp Brüschweiler <blei42@gmail.com> <bruphili@student.ethz.ch>
Philipp Krones <hello@philkrones.com> flip1995 <hello@philkrones.com>
Philipp Krones <hello@philkrones.com> <philipp.krones@embecosm.com>
Philipp Matthias Schäfer <philipp.matthias.schaefer@posteo.de>
+pierwill <pierwill@users.noreply.github.com> <19642016+pierwill@users.noreply.github.com>
Przemysław Wesołek <jest@go.art.pl> Przemek Wesołek <jest@go.art.pl>
Rafael Ávila de Espíndola <respindola@mozilla.com> Rafael Avila de Espindola <espindola@dream.(none)>
Ralph Giles <giles@thaumas.net> Ralph Giles <giles@mozilla.com>
diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md
index 2827a46ae6f..223fd0065bf 100644
--- a/CONTRIBUTING.md
+++ b/CONTRIBUTING.md
@@ -3,13 +3,14 @@
Thank you for your interest in contributing to Rust! There are many ways to contribute
and we appreciate all of them.
+The best way to get started is by asking for help in the [#new
+members](https://rust-lang.zulipchat.com/#narrow/stream/122652-new-members)
+Zulip stream. We have lots of docs below of how to get started on your own, but
+the Zulip stream is the best place to *ask* for help.
+
Documentation for contributing to Rust is located in the [Guide to Rustc Development](https://rustc-dev-guide.rust-lang.org/),
commonly known as the [rustc-dev-guide]. Despite the name, this guide documents
-not just how to develop rustc (the Rust compiler), but also how to contribute to any part
-of the Rust project.
-
-To get started with contributing, please read the [Contributing to Rust] chapter of the guide.
-That chapter explains how to get your development environment set up and how to get help.
+not just how to develop rustc (the Rust compiler), but also how to contribute to the standard library and rustdoc.
## About the [rustc-dev-guide]
diff --git a/Cargo.lock b/Cargo.lock
index 28b922cf913..961a3ba9f19 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -276,7 +276,7 @@ dependencies = [
[[package]]
name = "cargo"
-version = "0.59.0"
+version = "0.60.0"
dependencies = [
"anyhow",
"atty",
@@ -419,7 +419,7 @@ dependencies = [
[[package]]
name = "cargo-util"
-version = "0.1.1"
+version = "0.1.2"
dependencies = [
"anyhow",
"core-foundation",
@@ -558,11 +558,11 @@ dependencies = [
[[package]]
name = "clap"
-version = "2.33.3"
+version = "2.34.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "37e58ac78573c40708d45522f0d80fa2f01cc4f9b4e2bf749807255454312002"
+checksum = "a0610544180c38b88101fecf2dd634b174a62eef6946f84dfc6a7127512b381c"
dependencies = [
- "ansi_term 0.11.0",
+ "ansi_term 0.12.1",
"atty",
"bitflags",
"strsim",
@@ -574,7 +574,7 @@ dependencies = [
[[package]]
name = "clippy"
-version = "0.1.58"
+version = "0.1.59"
dependencies = [
"cargo_metadata 0.14.0",
"clippy_lints",
@@ -584,6 +584,7 @@ dependencies = [
"filetime",
"if_chain",
"itertools 0.10.1",
+ "parking_lot",
"quote",
"regex",
"rustc-workspace-hack",
@@ -600,6 +601,7 @@ name = "clippy_dev"
version = "0.0.1"
dependencies = [
"bytecount",
+ "cargo_metadata 0.14.0",
"clap",
"indoc",
"itertools 0.10.1",
@@ -611,13 +613,13 @@ dependencies = [
[[package]]
name = "clippy_lints"
-version = "0.1.58"
+version = "0.1.59"
dependencies = [
"cargo_metadata 0.14.0",
"clippy_utils",
"if_chain",
"itertools 0.10.1",
- "pulldown-cmark 0.8.0",
+ "pulldown-cmark",
"quine-mc_cluskey",
"regex-syntax",
"rustc-semver",
@@ -632,7 +634,7 @@ dependencies = [
[[package]]
name = "clippy_utils"
-version = "0.1.58"
+version = "0.1.59"
dependencies = [
"if_chain",
"rustc-semver",
@@ -678,9 +680,9 @@ dependencies = [
[[package]]
name = "compiler_builtins"
-version = "0.1.52"
+version = "0.1.66"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "b6591c2442ee984e2b264638a8b5e7ae44fd47b32d28e3a08e2e9c3cdb0c2fb0"
+checksum = "191424db7756bbed2c4996959a0fbda94388abcf4f5a2728a8af17481ad9c4f7"
dependencies = [
"cc",
"rustc-std-workspace-core",
@@ -766,7 +768,7 @@ checksum = "8aebca1129a03dc6dc2b127edd729435bbc4a37e1d5f4d7513165089ceb02634"
[[package]]
name = "crates-io"
-version = "0.33.0"
+version = "0.33.1"
dependencies = [
"anyhow",
"curl",
@@ -888,9 +890,9 @@ dependencies = [
[[package]]
name = "curl"
-version = "0.4.40"
+version = "0.4.41"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "877cc2f9b8367e32b6dabb9d581557e651cb3aa693a37f8679091bbf42687d5d"
+checksum = "1bc6d233563261f8db6ffb83bbaad5a73837a6e6b28868e926337ebbdece0be3"
dependencies = [
"curl-sys",
"libc",
@@ -903,9 +905,9 @@ dependencies = [
[[package]]
name = "curl-sys"
-version = "0.4.50+curl-7.79.1"
+version = "0.4.51+curl-7.80.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "4856b76919dd599f31236bb18db5f5bd36e2ce131e64f857ca5c259665b76171"
+checksum = "d130987e6a6a34fe0889e1083022fa48cd90e6709a84be3fb8dd95801de5af20"
dependencies = [
"cc",
"libc",
@@ -1713,9 +1715,12 @@ dependencies = [
[[package]]
name = "instant"
-version = "0.1.6"
+version = "0.1.12"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "5b141fdc7836c525d4d594027d318c84161ca17aaf8113ab1f81ab93ae897485"
+checksum = "7a5bbe824c507c5da5956355e86a746d82e0e1464f65d862cc5e71da70e94b2c"
+dependencies = [
+ "cfg-if 1.0.0",
+]
[[package]]
name = "itertools"
@@ -1900,9 +1905,9 @@ checksum = "830d08ce1d1d941e6b30645f1a0eb5643013d835ce3779a5fc208261dbe10f55"
[[package]]
name = "libc"
-version = "0.2.106"
+version = "0.2.108"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "a60553f9a9e039a333b4e9b20573b9e9b9c0bb3a11e201ccc48ef4283456d673"
+checksum = "8521a1b57e76b1ec69af7599e75e38e7b7fad6610f037db8c79b127201b5d119"
dependencies = [
"rustc-std-workspace-core",
]
@@ -1922,6 +1927,16 @@ dependencies = [
]
[[package]]
+name = "libloading"
+version = "0.7.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "c0cf036d15402bea3c5d4de17b3fce76b3e4a56ebc1f577be0e7a72f7c607cf0"
+dependencies = [
+ "cfg-if 1.0.0",
+ "winapi",
+]
+
+[[package]]
name = "libm"
version = "0.1.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -1992,9 +2007,9 @@ version = "0.1.0"
[[package]]
name = "lock_api"
-version = "0.4.1"
+version = "0.4.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "28247cc5a5be2f05fbcd76dd0cf2c7d3b5400cb978a28042abcd4fa0b3f8261c"
+checksum = "712a4d093c9976e24e7dbca41db895dabcbac38eb5f4045393d17a95bdfb1109"
dependencies = [
"scopeguard",
]
@@ -2124,9 +2139,9 @@ dependencies = [
[[package]]
name = "mdbook"
-version = "0.4.12"
+version = "0.4.14"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "0651782b4cc514c3f98c0acf9b5af1101a735bbe1ac6852bb1a90cb91bdf0ed4"
+checksum = "f6e77253c46a90eb7e96b2807201dab941a4db5ea05eca5aaaf7027395f352b3"
dependencies = [
"ammonia",
"anyhow",
@@ -2138,8 +2153,8 @@ dependencies = [
"lazy_static",
"log",
"memchr",
- "open",
- "pulldown-cmark 0.7.2",
+ "opener",
+ "pulldown-cmark",
"regex",
"serde",
"serde_derive",
@@ -2147,6 +2162,7 @@ dependencies = [
"shlex",
"tempfile",
"toml",
+ "topological-sort",
]
[[package]]
@@ -2375,15 +2391,6 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "624a8340c38c1b80fd549087862da4ba43e08858af025b236e509b6649fc13d5"
[[package]]
-name = "open"
-version = "1.4.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "7c283bf0114efea9e42f1a60edea9859e8c47528eae09d01df4b29c1e489cc48"
-dependencies = [
- "winapi",
-]
-
-[[package]]
name = "opener"
version = "0.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -2511,9 +2518,9 @@ dependencies = [
[[package]]
name = "parking_lot"
-version = "0.11.1"
+version = "0.11.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "6d7744ac029df22dca6284efe4e898991d28e3085c706c972bcd7da4a27a15eb"
+checksum = "7d17b78036a60663b797adeaee46f5c9dfebb86948d1255007a1d6be0271ff99"
dependencies = [
"instant",
"lock_api",
@@ -2522,9 +2529,9 @@ dependencies = [
[[package]]
name = "parking_lot_core"
-version = "0.8.3"
+version = "0.8.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "fa7a782938e745763fe6907fc6ba86946d72f49fe7e21de074e08128a99fb018"
+checksum = "d76e8e1493bcac0d2766c42737f34458f1c8c50c0d23bcb24ea953affb273216"
dependencies = [
"cfg-if 1.0.0",
"instant",
@@ -2796,23 +2803,12 @@ dependencies = [
[[package]]
name = "pulldown-cmark"
-version = "0.7.2"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "ca36dea94d187597e104a5c8e4b07576a8a45aa5db48a65e12940d3eb7461f55"
-dependencies = [
- "bitflags",
- "getopts",
- "memchr",
- "unicase",
-]
-
-[[package]]
-name = "pulldown-cmark"
version = "0.8.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ffade02495f22453cd593159ea2f59827aae7f53fa8323f756799b670881dcf8"
dependencies = [
"bitflags",
+ "getopts",
"memchr",
"unicase",
]
@@ -3692,6 +3688,7 @@ dependencies = [
"rustc_expand",
"rustc_feature",
"rustc_lexer",
+ "rustc_lint_defs",
"rustc_parse",
"rustc_parse_format",
"rustc_session",
@@ -3708,6 +3705,7 @@ dependencies = [
"bitflags",
"cstr",
"libc",
+ "libloading",
"measureme 10.0.0",
"rustc-demangle",
"rustc_arena",
@@ -3728,7 +3726,6 @@ dependencies = [
"rustc_span",
"rustc_target",
"smallvec",
- "snap",
"tracing",
]
@@ -3763,6 +3760,7 @@ dependencies = [
"rustc_symbol_mangling",
"rustc_target",
"smallvec",
+ "snap",
"tempfile",
"tracing",
]
@@ -3992,6 +3990,7 @@ name = "rustc_interface"
version = "0.0.0"
dependencies = [
"libc",
+ "libloading",
"rustc-rayon",
"rustc-rayon-core",
"rustc_ast",
@@ -4040,6 +4039,7 @@ name = "rustc_lexer"
version = "0.1.0"
dependencies = [
"expect-test",
+ "unic-emoji-char",
"unicode-xid",
]
@@ -4103,7 +4103,7 @@ dependencies = [
name = "rustc_metadata"
version = "0.0.0"
dependencies = [
- "libc",
+ "libloading",
"odht",
"rustc_ast",
"rustc_attr",
@@ -4123,7 +4123,6 @@ dependencies = [
"smallvec",
"snap",
"tracing",
- "winapi",
]
[[package]]
@@ -4296,6 +4295,7 @@ dependencies = [
name = "rustc_plugin_impl"
version = "0.0.0"
dependencies = [
+ "libloading",
"rustc_ast",
"rustc_errors",
"rustc_hir",
@@ -4615,7 +4615,7 @@ dependencies = [
"expect-test",
"itertools 0.9.0",
"minifier",
- "pulldown-cmark 0.8.0",
+ "pulldown-cmark",
"rayon",
"regex",
"rustdoc-json-types",
@@ -5393,6 +5393,12 @@ dependencies = [
]
[[package]]
+name = "topological-sort"
+version = "0.1.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "aa7c7f42dea4b1b99439786f5633aeb9c14c1b53f75e282803c2ec2ad545873c"
+
+[[package]]
name = "tower-service"
version = "0.3.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -5511,6 +5517,47 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "56dee185309b50d1f11bfedef0fe6d036842e3fb77413abef29f8f8d1c5d4c1c"
[[package]]
+name = "unic-char-property"
+version = "0.9.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "a8c57a407d9b6fa02b4795eb81c5b6652060a15a7903ea981f3d723e6c0be221"
+dependencies = [
+ "unic-char-range",
+]
+
+[[package]]
+name = "unic-char-range"
+version = "0.9.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "0398022d5f700414f6b899e10b8348231abf9173fa93144cbc1a43b9793c1fbc"
+
+[[package]]
+name = "unic-common"
+version = "0.9.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "80d7ff825a6a654ee85a63e80f92f054f904f21e7d12da4e22f9834a4aaa35bc"
+
+[[package]]
+name = "unic-emoji-char"
+version = "0.9.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "0b07221e68897210270a38bde4babb655869637af0f69407f96053a34f76494d"
+dependencies = [
+ "unic-char-property",
+ "unic-char-range",
+ "unic-ucd-version",
+]
+
+[[package]]
+name = "unic-ucd-version"
+version = "0.9.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "96bd2f2237fe450fcd0a1d2f5f4e91711124f7857ba2e964247776ebeeb7b0c4"
+dependencies = [
+ "unic-common",
+]
+
+[[package]]
name = "unicase"
version = "2.6.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
diff --git a/README.md b/README.md
index 32fab9fc25d..78edac9d12c 100644
--- a/README.md
+++ b/README.md
@@ -7,7 +7,10 @@ standard library, and documentation.
**Note: this README is for _users_ rather than _contributors_.
If you wish to _contribute_ to the compiler, you should read the
-[Getting Started][gettingstarted] section of the rustc-dev-guide instead.**
+[Getting Started][gettingstarted] section of the rustc-dev-guide instead.
+You can ask for help in the [#new members Zulip stream][new-members].**
+
+[new-members]: https://rust-lang.zulipchat.com/#narrow/stream/122652-new-members
## Quick Start
diff --git a/RELEASES.md b/RELEASES.md
index a38ab7cabf4..4b9b20f4cba 100644
--- a/RELEASES.md
+++ b/RELEASES.md
@@ -1,3 +1,117 @@
+Version 1.57.0 (2021-12-02)
+==========================
+
+Language
+--------
+
+- [Macro attributes may follow `#[derive]` and will see the original (pre-`cfg`) input.][87220]
+- [Accept curly-brace macros in expressions, like `m!{ .. }.method()` and `m!{ .. }?`.][88690]
+- [Allow panicking in constant evaluation.][89508]
+
+Compiler
+--------
+
+- [Create more accurate debuginfo for vtables.][89597]
+- [Add `armv6k-nintendo-3ds` at Tier 3\*.][88529]
+- [Add `armv7-unknown-linux-uclibceabihf` at Tier 3\*.][88952]
+- [Add `m68k-unknown-linux-gnu` at Tier 3\*.][88321]
+- [Add SOLID targets at Tier 3\*:][86191] `aarch64-kmc-solid_asp3`, `armv7a-kmc-solid_asp3-eabi`, `armv7a-kmc-solid_asp3-eabihf`
+
+\* Refer to Rust's [platform support page][platform-support-doc] for more
+ information on Rust's tiered platform support.
+
+Libraries
+---------
+
+- [Avoid allocations and copying in `Vec::leak`][89337]
+- [Add `#[repr(i8)]` to `Ordering`][89507]
+- [Optimize `File::read_to_end` and `read_to_string`][89582]
+- [Update to Unicode 14.0][89614]
+- [Many more functions are marked `#[must_use]`][89692], producing a warning
+ when ignoring their return value. This helps catch mistakes such as expecting
+ a function to mutate a value in place rather than return a new value.
+
+Stabilised APIs
+---------------
+
+- [`[T; N]::as_mut_slice`][`array::as_mut_slice`]
+- [`[T; N]::as_slice`][`array::as_slice`]
+- [`collections::TryReserveError`]
+- [`HashMap::try_reserve`]
+- [`HashSet::try_reserve`]
+- [`String::try_reserve`]
+- [`String::try_reserve_exact`]
+- [`Vec::try_reserve`]
+- [`Vec::try_reserve_exact`]
+- [`VecDeque::try_reserve`]
+- [`VecDeque::try_reserve_exact`]
+- [`Iterator::map_while`]
+- [`iter::MapWhile`]
+- [`proc_macro::is_available`]
+- [`Command::get_program`]
+- [`Command::get_args`]
+- [`Command::get_envs`]
+- [`Command::get_current_dir`]
+- [`CommandArgs`]
+- [`CommandEnvs`]
+
+These APIs are now usable in const contexts:
+
+- [`hint::unreachable_unchecked`]
+
+Cargo
+-----
+
+- [Stabilize custom profiles][cargo/9943]
+
+Compatibility notes
+-------------------
+
+Internal changes
+----------------
+These changes provide no direct user facing benefits, but represent significant
+improvements to the internals and overall performance of rustc
+and related tools.
+
+- [Added an experimental backend for codegen with `libgccjit`.][87260]
+
+[86191]: https://github.com/rust-lang/rust/pull/86191/
+[87220]: https://github.com/rust-lang/rust/pull/87220/
+[87260]: https://github.com/rust-lang/rust/pull/87260/
+[88243]: https://github.com/rust-lang/rust/pull/88243/
+[88321]: https://github.com/rust-lang/rust/pull/88321/
+[88529]: https://github.com/rust-lang/rust/pull/88529/
+[88690]: https://github.com/rust-lang/rust/pull/88690/
+[88952]: https://github.com/rust-lang/rust/pull/88952/
+[89337]: https://github.com/rust-lang/rust/pull/89337/
+[89507]: https://github.com/rust-lang/rust/pull/89507/
+[89508]: https://github.com/rust-lang/rust/pull/89508/
+[89582]: https://github.com/rust-lang/rust/pull/89582/
+[89597]: https://github.com/rust-lang/rust/pull/89597/
+[89614]: https://github.com/rust-lang/rust/pull/89614/
+[89692]: https://github.com/rust-lang/rust/issues/89692/
+[cargo/9943]: https://github.com/rust-lang/cargo/pull/9943/
+[`array::as_mut_slice`]: https://doc.rust-lang.org/std/primitive.array.html#method.as_mut_slice
+[`array::as_slice`]: https://doc.rust-lang.org/std/primitive.array.html#method.as_slice
+[`collections::TryReserveError`]: https://doc.rust-lang.org/std/collections/struct.TryReserveError.html
+[`HashMap::try_reserve`]: https://doc.rust-lang.org/std/collections/hash_map/struct.HashMap.html#method.try_reserve
+[`HashSet::try_reserve`]: https://doc.rust-lang.org/std/collections/hash_set/struct.HashSet.html#method.try_reserve
+[`String::try_reserve`]: https://doc.rust-lang.org/alloc/string/struct.String.html#method.try_reserve
+[`String::try_reserve_exact`]: https://doc.rust-lang.org/alloc/string/struct.String.html#method.try_reserve_exact
+[`Vec::try_reserve`]: https://doc.rust-lang.org/std/vec/struct.Vec.html#method.try_reserve
+[`Vec::try_reserve_exact`]: https://doc.rust-lang.org/std/vec/struct.Vec.html#method.try_reserve_exact
+[`VecDeque::try_reserve`]: https://doc.rust-lang.org/std/collections/struct.VecDeque.html#method.try_reserve
+[`VecDeque::try_reserve_exact`]: https://doc.rust-lang.org/std/collections/struct.VecDeque.html#method.try_reserve_exact
+[`Iterator::map_while`]: https://doc.rust-lang.org/std/iter/trait.Iterator.html#method.map_while
+[`iter::MapWhile`]: https://doc.rust-lang.org/std/iter/struct.MapWhile.html
+[`proc_macro::is_available`]: https://doc.rust-lang.org/proc_macro/fn.is_available.html
+[`Command::get_program`]: https://doc.rust-lang.org/std/process/struct.Command.html#method.get_program
+[`Command::get_args`]: https://doc.rust-lang.org/std/process/struct.Command.html#method.get_args
+[`Command::get_envs`]: https://doc.rust-lang.org/std/process/struct.Command.html#method.get_envs
+[`Command::get_current_dir`]: https://doc.rust-lang.org/std/process/struct.Command.html#method.get_current_dir
+[`CommandArgs`]: https://doc.rust-lang.org/std/process/struct.CommandArgs.html
+[`CommandEnvs`]: https://doc.rust-lang.org/std/process/struct.CommandEnvs.html
+
Version 1.56.1 (2021-11-01)
===========================
diff --git a/compiler/rustc_apfloat/src/lib.rs b/compiler/rustc_apfloat/src/lib.rs
index 7eeec4aa86b..143c6f7610c 100644
--- a/compiler/rustc_apfloat/src/lib.rs
+++ b/compiler/rustc_apfloat/src/lib.rs
@@ -33,7 +33,6 @@
#![doc(html_root_url = "https://doc.rust-lang.org/nightly/nightly-rustc/")]
#![no_std]
#![forbid(unsafe_code)]
-#![feature(iter_zip)]
#![feature(nll)]
#[macro_use]
diff --git a/compiler/rustc_ast/src/ast.rs b/compiler/rustc_ast/src/ast.rs
index abfe8360987..4f55f37e2e9 100644
--- a/compiler/rustc_ast/src/ast.rs
+++ b/compiler/rustc_ast/src/ast.rs
@@ -332,10 +332,7 @@ pub type GenericBounds = Vec<GenericBound>;
pub enum ParamKindOrd {
Lifetime,
Type,
- // `unordered` is only `true` if `sess.unordered_const_ty_params()`
- // returns true. Specifically, if it's only `min_const_generics`, it will still require
- // ordering consts after types.
- Const { unordered: bool },
+ Const,
// `Infer` is not actually constructed directly from the AST, but is implicitly constructed
// during HIR lowering, and `ParamKindOrd` will implicitly order inferred variables last.
Infer,
@@ -346,11 +343,7 @@ impl Ord for ParamKindOrd {
use ParamKindOrd::*;
let to_int = |v| match v {
Lifetime => 0,
- Infer | Type | Const { unordered: true } => 1,
- // technically both consts should be ordered equally,
- // but only one is ever encountered at a time, so this is
- // fine.
- Const { unordered: false } => 2,
+ Infer | Type | Const => 1,
};
to_int(*self).cmp(&to_int(*other))
@@ -405,6 +398,21 @@ pub struct GenericParam {
pub kind: GenericParamKind,
}
+impl GenericParam {
+ pub fn span(&self) -> Span {
+ match &self.kind {
+ GenericParamKind::Lifetime | GenericParamKind::Type { default: None } => {
+ self.ident.span
+ }
+ GenericParamKind::Type { default: Some(ty) } => self.ident.span.to(ty.span),
+ GenericParamKind::Const { kw_span, default: Some(default), .. } => {
+ kw_span.to(default.value.span)
+ }
+ GenericParamKind::Const { kw_span, default: None, ty } => kw_span.to(ty.span),
+ }
+ }
+}
+
/// Represents lifetime, type and const parameters attached to a declaration of
/// a function, enum, trait, etc.
#[derive(Clone, Encodable, Decodable, Debug)]
@@ -502,6 +510,8 @@ pub struct Crate {
pub attrs: Vec<Attribute>,
pub items: Vec<P<Item>>,
pub span: Span,
+ // Placeholder ID if the crate node is a macro placeholder.
+ pub is_placeholder: Option<NodeId>,
}
/// Possible values inside of compile-time attribute lists.
@@ -1964,7 +1974,7 @@ pub enum InlineAsmRegOrRegClass {
bitflags::bitflags! {
#[derive(Encodable, Decodable, HashStable_Generic)]
- pub struct InlineAsmOptions: u8 {
+ pub struct InlineAsmOptions: u16 {
const PURE = 1 << 0;
const NOMEM = 1 << 1;
const READONLY = 1 << 2;
@@ -1973,6 +1983,7 @@ bitflags::bitflags! {
const NOSTACK = 1 << 5;
const ATT_SYNTAX = 1 << 6;
const RAW = 1 << 7;
+ const MAY_UNWIND = 1 << 8;
}
}
diff --git a/compiler/rustc_ast/src/ast_like.rs b/compiler/rustc_ast/src/ast_like.rs
index d586426d70e..b9c397974a1 100644
--- a/compiler/rustc_ast/src/ast_like.rs
+++ b/compiler/rustc_ast/src/ast_like.rs
@@ -1,7 +1,7 @@
use super::ptr::P;
use super::token::Nonterminal;
use super::tokenstream::LazyTokenStream;
-use super::{Arm, ExprField, FieldDef, GenericParam, Param, PatField, Variant};
+use super::{Arm, Crate, ExprField, FieldDef, GenericParam, Param, PatField, Variant};
use super::{AssocItem, Expr, ForeignItem, Item, Local, MacCallStmt};
use super::{AttrItem, AttrKind, Block, Pat, Path, Ty, Visibility};
use super::{AttrVec, Attribute, Stmt, StmtKind};
@@ -276,7 +276,7 @@ derive_has_tokens_and_attrs! {
// These ast nodes only support inert attributes, so they don't
// store tokens (since nothing can observe them)
derive_has_attrs_no_tokens! {
- FieldDef, Arm, ExprField, PatField, Variant, Param, GenericParam
+ FieldDef, Arm, ExprField, PatField, Variant, Param, GenericParam, Crate
}
// These AST nodes don't support attributes, but can
diff --git a/compiler/rustc_ast/src/lib.rs b/compiler/rustc_ast/src/lib.rs
index b9db2a7e089..ff3b501a0bd 100644
--- a/compiler/rustc_ast/src/lib.rs
+++ b/compiler/rustc_ast/src/lib.rs
@@ -11,7 +11,6 @@
#![feature(box_patterns)]
#![feature(crate_visibility_modifier)]
#![feature(if_let_guard)]
-#![feature(iter_zip)]
#![feature(label_break_value)]
#![feature(nll)]
#![feature(min_specialization)]
diff --git a/compiler/rustc_ast/src/mut_visit.rs b/compiler/rustc_ast/src/mut_visit.rs
index fc5cc963992..6bf23af81bf 100644
--- a/compiler/rustc_ast/src/mut_visit.rs
+++ b/compiler/rustc_ast/src/mut_visit.rs
@@ -1,5 +1,5 @@
//! A `MutVisitor` represents an AST modification; it accepts an AST piece and
-//! and mutates it in place. So, for instance, macro expansion is a `MutVisitor`
+//! mutates it in place. So, for instance, macro expansion is a `MutVisitor`
//! that walks over an AST and modifies it.
//!
//! Note: using a `MutVisitor` (other than the `MacroExpander` `MutVisitor`) on
@@ -284,6 +284,10 @@ pub trait MutVisitor: Sized {
/// Use a map-style function (`FnOnce(T) -> T`) to overwrite a `&mut T`. Useful
/// when using a `flat_map_*` or `filter_map_*` method within a `visit_`
/// method. Abort the program if the closure panics.
+///
+/// FIXME: Abort on panic means that any fatal error inside `visit_clobber` will abort the compiler.
+/// Instead of aborting on catching a panic we need to reset the visited node to some valid but
+/// possibly meaningless value and rethrow the panic.
//
// No `noop_` prefix because there isn't a corresponding method in `MutVisitor`.
pub fn visit_clobber<T, F>(t: &mut T, f: F)
@@ -1105,36 +1109,11 @@ pub fn noop_visit_fn_header<T: MutVisitor>(header: &mut FnHeader, vis: &mut T) {
visit_unsafety(unsafety, vis);
}
-// FIXME: Avoid visiting the crate as a `Mod` item, flat map only the inner items if possible,
-// or make crate visiting first class if necessary.
pub fn noop_visit_crate<T: MutVisitor>(krate: &mut Crate, vis: &mut T) {
- visit_clobber(krate, |Crate { attrs, items, span }| {
- let item_vis =
- Visibility { kind: VisibilityKind::Public, span: span.shrink_to_lo(), tokens: None };
- let item = P(Item {
- ident: Ident::empty(),
- attrs,
- id: DUMMY_NODE_ID,
- vis: item_vis,
- span,
- kind: ItemKind::Mod(Unsafe::No, ModKind::Loaded(items, Inline::Yes, span)),
- tokens: None,
- });
- let items = vis.flat_map_item(item);
-
- let len = items.len();
- if len == 0 {
- Crate { attrs: vec![], items: vec![], span }
- } else if len == 1 {
- let Item { attrs, span, kind, .. } = items.into_iter().next().unwrap().into_inner();
- match kind {
- ItemKind::Mod(_, ModKind::Loaded(items, ..)) => Crate { attrs, items, span },
- _ => panic!("visitor converted a module to not a module"),
- }
- } else {
- panic!("a crate cannot expand to more than one item");
- }
- });
+ let Crate { attrs, items, span, is_placeholder: _ } = krate;
+ visit_attrs(attrs, vis);
+ items.flat_map_in_place(|item| vis.flat_map_item(item));
+ vis.visit_span(span);
}
// Mutates one item into possibly many items.
diff --git a/compiler/rustc_ast/src/util/literal.rs b/compiler/rustc_ast/src/util/literal.rs
index 9c6ad47427d..8a41aec0819 100644
--- a/compiler/rustc_ast/src/util/literal.rs
+++ b/compiler/rustc_ast/src/util/literal.rs
@@ -57,7 +57,7 @@ impl LitKind {
// string in the token.
let s = symbol.as_str();
let symbol =
- if s.contains(&['\\', '\r'][..]) {
+ if s.contains(&['\\', '\r']) {
let mut buf = String::with_capacity(s.len());
let mut error = Ok(());
unescape_literal(&s, Mode::Str, &mut |_, unescaped_char| {
diff --git a/compiler/rustc_ast/src/visit.rs b/compiler/rustc_ast/src/visit.rs
index be794ed221a..6840f092da6 100644
--- a/compiler/rustc_ast/src/visit.rs
+++ b/compiler/rustc_ast/src/visit.rs
@@ -211,6 +211,9 @@ pub trait Visitor<'ast>: Sized {
fn visit_pat_field(&mut self, fp: &'ast PatField) {
walk_pat_field(self, fp)
}
+ fn visit_crate(&mut self, krate: &'ast Crate) {
+ walk_crate(self, krate)
+ }
}
#[macro_export]
diff --git a/compiler/rustc_ast_lowering/src/asm.rs b/compiler/rustc_ast_lowering/src/asm.rs
index cfa97ff84ec..9c28f3c7f58 100644
--- a/compiler/rustc_ast_lowering/src/asm.rs
+++ b/compiler/rustc_ast_lowering/src/asm.rs
@@ -49,11 +49,27 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
.struct_span_err(sp, "the `att_syntax` option is only supported on x86")
.emit();
}
+ if asm.options.contains(InlineAsmOptions::MAY_UNWIND)
+ && !self.sess.features_untracked().asm_unwind
+ {
+ feature_err(
+ &self.sess.parse_sess,
+ sym::asm_unwind,
+ sp,
+ "the `may_unwind` option is unstable",
+ )
+ .emit();
+ }
let mut clobber_abis = FxHashMap::default();
if let Some(asm_arch) = asm_arch {
for (abi_name, abi_span) in &asm.clobber_abis {
- match asm::InlineAsmClobberAbi::parse(asm_arch, &self.sess.target, *abi_name) {
+ match asm::InlineAsmClobberAbi::parse(
+ asm_arch,
+ |feature| self.sess.target_features.contains(&Symbol::intern(feature)),
+ &self.sess.target,
+ *abi_name,
+ ) {
Ok(abi) => {
// If the abi was already in the list, emit an error
match clobber_abis.get(&abi) {
diff --git a/compiler/rustc_ast_lowering/src/block.rs b/compiler/rustc_ast_lowering/src/block.rs
index 14a894d61f4..082c5bb7833 100644
--- a/compiler/rustc_ast_lowering/src/block.rs
+++ b/compiler/rustc_ast_lowering/src/block.rs
@@ -2,7 +2,6 @@ use crate::{ImplTraitContext, ImplTraitPosition, LoweringContext};
use rustc_ast::{AttrVec, Block, BlockCheckMode, Expr, Local, LocalKind, Stmt, StmtKind};
use rustc_hir as hir;
use rustc_session::parse::feature_err;
-use rustc_span::symbol::Ident;
use rustc_span::{sym, DesugaringKind};
use smallvec::SmallVec;
@@ -39,8 +38,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
let hir_id = self.lower_node_id(s.id);
match &local.kind {
LocalKind::InitElse(init, els) => {
- let (s, e) = self.lower_let_else(hir_id, local, init, els, tail);
- stmts.push(s);
+ let e = self.lower_let_else(hir_id, local, init, els, tail);
expr = Some(e);
// remaining statements are in let-else expression
break;
@@ -125,36 +123,25 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
init: &Expr,
els: &Block,
tail: &[Stmt],
- ) -> (hir::Stmt<'hir>, &'hir hir::Expr<'hir>) {
+ ) -> &'hir hir::Expr<'hir> {
let ty = local
.ty
.as_ref()
.map(|t| self.lower_ty(t, ImplTraitContext::Disallowed(ImplTraitPosition::Binding)));
let span = self.lower_span(local.span);
let span = self.mark_span_with_reason(DesugaringKind::LetElse, span, None);
- let init = Some(self.lower_expr(init));
- let val = Ident::with_dummy_span(sym::val);
- let (pat, val_id) =
- self.pat_ident_binding_mode(span, val, hir::BindingAnnotation::Unannotated);
+ let init = self.lower_expr(init);
let local_hir_id = self.lower_node_id(local.id);
self.lower_attrs(local_hir_id, &local.attrs);
- // first statement which basically exists for the type annotation
- let stmt = {
- let local = self.arena.alloc(hir::Local {
+ let let_expr = {
+ let lex = self.arena.alloc(hir::Let {
hir_id: local_hir_id,
+ pat: self.lower_pat(&local.pat),
ty,
- pat,
init,
span,
- source: hir::LocalSource::Normal,
});
- let kind = hir::StmtKind::Local(local);
- hir::Stmt { hir_id: stmt_hir_id, kind, span }
- };
- let let_expr = {
- let scrutinee = self.expr_ident(span, val, val_id);
- let let_kind = hir::ExprKind::Let(self.lower_pat(&local.pat), scrutinee, span);
- self.arena.alloc(self.expr(span, let_kind, AttrVec::new()))
+ self.arena.alloc(self.expr(span, hir::ExprKind::Let(lex), AttrVec::new()))
};
let then_expr = {
let (stmts, expr) = self.lower_stmts(tail);
@@ -165,9 +152,10 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
let block = self.lower_block(els, false);
self.arena.alloc(self.expr_block(block, AttrVec::new()))
};
+ self.alias_attrs(let_expr.hir_id, local_hir_id);
self.alias_attrs(else_expr.hir_id, local_hir_id);
let if_expr = self.arena.alloc(hir::Expr {
- hir_id: self.next_id(),
+ hir_id: stmt_hir_id,
span,
kind: hir::ExprKind::If(let_expr, then_expr, Some(else_expr)),
});
@@ -180,6 +168,6 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
)
.emit();
}
- (stmt, if_expr)
+ if_expr
}
}
diff --git a/compiler/rustc_ast_lowering/src/expr.rs b/compiler/rustc_ast_lowering/src/expr.rs
index a0a63620c08..6ee1dbe4ae3 100644
--- a/compiler/rustc_ast_lowering/src/expr.rs
+++ b/compiler/rustc_ast_lowering/src/expr.rs
@@ -9,7 +9,6 @@ use rustc_errors::struct_span_err;
use rustc_hir as hir;
use rustc_hir::def::Res;
use rustc_hir::definitions::DefPathData;
-use rustc_session::parse::feature_err;
use rustc_span::hygiene::ExpnId;
use rustc_span::source_map::{respan, DesugaringKind, Span, Spanned};
use rustc_span::symbol::{sym, Ident, Symbol};
@@ -92,11 +91,15 @@ impl<'hir> LoweringContext<'_, 'hir> {
let ohs = self.lower_expr(ohs);
hir::ExprKind::AddrOf(k, m, ohs)
}
- ExprKind::Let(ref pat, ref scrutinee, span) => hir::ExprKind::Let(
- self.lower_pat(pat),
- self.lower_expr(scrutinee),
- self.lower_span(span),
- ),
+ ExprKind::Let(ref pat, ref scrutinee, span) => {
+ hir::ExprKind::Let(self.arena.alloc(hir::Let {
+ hir_id: self.next_id(),
+ span: self.lower_span(span),
+ pat: self.lower_pat(pat),
+ ty: None,
+ init: self.lower_expr(scrutinee),
+ }))
+ }
ExprKind::If(ref cond, ref then, ref else_opt) => {
self.lower_expr_if(cond, then, else_opt.as_deref())
}
@@ -130,7 +133,15 @@ impl<'hir> LoweringContext<'_, 'hir> {
hir::AsyncGeneratorKind::Block,
|this| this.with_new_scopes(|this| this.lower_block_expr(block)),
),
- ExprKind::Await(ref expr) => self.lower_expr_await(e.span, expr),
+ ExprKind::Await(ref expr) => {
+ let span = if expr.span.hi() < e.span.hi() {
+ expr.span.shrink_to_hi().with_hi(e.span.hi())
+ } else {
+ // this is a recovered `await expr`
+ e.span
+ };
+ self.lower_expr_await(span, expr)
+ }
ExprKind::Closure(
capture_clause,
asyncness,
@@ -479,8 +490,12 @@ impl<'hir> LoweringContext<'_, 'hir> {
expr: &'hir hir::Expr<'hir>,
overall_span: Span,
) -> &'hir hir::Expr<'hir> {
- let constructor =
- self.arena.alloc(self.expr_lang_item_path(method_span, lang_item, ThinVec::new()));
+ let constructor = self.arena.alloc(self.expr_lang_item_path(
+ method_span,
+ lang_item,
+ ThinVec::new(),
+ None,
+ ));
self.expr_call(overall_span, constructor, std::slice::from_ref(expr))
}
@@ -584,8 +599,12 @@ impl<'hir> LoweringContext<'_, 'hir> {
// `future::from_generator`:
let unstable_span =
self.mark_span_with_reason(DesugaringKind::Async, span, self.allow_gen_future.clone());
- let gen_future =
- self.expr_lang_item_path(unstable_span, hir::LangItem::FromGenerator, ThinVec::new());
+ let gen_future = self.expr_lang_item_path(
+ unstable_span,
+ hir::LangItem::FromGenerator,
+ ThinVec::new(),
+ None,
+ );
// `future::from_generator(generator)`:
hir::ExprKind::Call(self.arena.alloc(gen_future), arena_vec![self; generator])
@@ -593,7 +612,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
/// Desugar `<expr>.await` into:
/// ```rust
- /// match <expr> {
+ /// match ::std::future::IntoFuture::into_future(<expr>) {
/// mut pinned => loop {
/// match unsafe { ::std::future::Future::poll(
/// <::std::pin::Pin>::new_unchecked(&mut pinned),
@@ -607,6 +626,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
/// }
/// ```
fn lower_expr_await(&mut self, await_span: Span, expr: &Expr) -> hir::ExprKind<'hir> {
+ let dot_await_span = expr.span.shrink_to_hi().to(await_span);
match self.generator_kind {
Some(hir::GeneratorKind::Async(_)) => {}
Some(hir::GeneratorKind::Gen) | None => {
@@ -623,13 +643,14 @@ impl<'hir> LoweringContext<'_, 'hir> {
err.emit();
}
}
- let span = self.mark_span_with_reason(DesugaringKind::Await, await_span, None);
+ let span = self.mark_span_with_reason(DesugaringKind::Await, dot_await_span, None);
let gen_future_span = self.mark_span_with_reason(
DesugaringKind::Await,
await_span,
self.allow_gen_future.clone(),
);
- let expr = self.lower_expr(expr);
+ let expr = self.lower_expr_mut(expr);
+ let expr_hir_id = expr.hir_id;
let pinned_ident = Ident::with_dummy_span(sym::pinned);
let (pinned_pat, pinned_pat_hid) =
@@ -656,16 +677,19 @@ impl<'hir> LoweringContext<'_, 'hir> {
span,
hir::LangItem::PinNewUnchecked,
arena_vec![self; ref_mut_pinned],
+ Some(expr_hir_id),
);
let get_context = self.expr_call_lang_item_fn_mut(
gen_future_span,
hir::LangItem::GetContext,
arena_vec![self; task_context],
+ Some(expr_hir_id),
);
let call = self.expr_call_lang_item_fn(
span,
hir::LangItem::FuturePoll,
arena_vec![self; new_unchecked, get_context],
+ Some(expr_hir_id),
);
self.arena.alloc(self.expr_unsafe(call))
};
@@ -678,18 +702,28 @@ impl<'hir> LoweringContext<'_, 'hir> {
let (x_pat, x_pat_hid) = self.pat_ident(span, x_ident);
let x_expr = self.expr_ident(span, x_ident, x_pat_hid);
let ready_field = self.single_pat_field(span, x_pat);
- let ready_pat = self.pat_lang_item_variant(span, hir::LangItem::PollReady, ready_field);
+ let ready_pat = self.pat_lang_item_variant(
+ span,
+ hir::LangItem::PollReady,
+ ready_field,
+ Some(expr_hir_id),
+ );
let break_x = self.with_loop_scope(loop_node_id, move |this| {
let expr_break =
hir::ExprKind::Break(this.lower_loop_destination(None), Some(x_expr));
- this.arena.alloc(this.expr(await_span, expr_break, ThinVec::new()))
+ this.arena.alloc(this.expr(span, expr_break, ThinVec::new()))
});
self.arm(ready_pat, break_x)
};
// `::std::task::Poll::Pending => {}`
let pending_arm = {
- let pending_pat = self.pat_lang_item_variant(span, hir::LangItem::PollPending, &[]);
+ let pending_pat = self.pat_lang_item_variant(
+ span,
+ hir::LangItem::PollPending,
+ &[],
+ Some(expr_hir_id),
+ );
let empty_block = self.expr_block_empty(span);
self.arm(pending_pat, empty_block)
};
@@ -709,7 +743,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
let unit = self.expr_unit(span);
let yield_expr = self.expr(
span,
- hir::ExprKind::Yield(unit, hir::YieldSource::Await { expr: Some(expr.hir_id) }),
+ hir::ExprKind::Yield(unit, hir::YieldSource::Await { expr: Some(expr_hir_id) }),
ThinVec::new(),
);
let yield_expr = self.arena.alloc(yield_expr);
@@ -746,10 +780,27 @@ impl<'hir> LoweringContext<'_, 'hir> {
// mut pinned => loop { ... }
let pinned_arm = self.arm(pinned_pat, loop_expr);
- // match <expr> {
+ // `match ::std::future::IntoFuture::into_future(<expr>) { ... }`
+ let into_future_span = self.mark_span_with_reason(
+ DesugaringKind::Await,
+ await_span,
+ self.allow_into_future.clone(),
+ );
+ let into_future_expr = self.expr_call_lang_item_fn(
+ into_future_span,
+ hir::LangItem::IntoFutureIntoFuture,
+ arena_vec![self; expr],
+ Some(expr_hir_id),
+ );
+
+ // match <into_future_expr> {
// mut pinned => loop { .. }
// }
- hir::ExprKind::Match(expr, arena_vec![self; pinned_arm], hir::MatchSource::AwaitDesugar)
+ hir::ExprKind::Match(
+ into_future_expr,
+ arena_vec![self; pinned_arm],
+ hir::MatchSource::AwaitDesugar,
+ )
}
fn lower_expr_closure(
@@ -914,16 +965,6 @@ impl<'hir> LoweringContext<'_, 'hir> {
self.lower_span(eq_sign_span),
);
}
- if !self.sess.features_untracked().destructuring_assignment {
- feature_err(
- &self.sess.parse_sess,
- sym::destructuring_assignment,
- eq_sign_span,
- "destructuring assignments are unstable",
- )
- .span_label(lhs.span, "cannot assign to this expression")
- .emit();
- }
let mut assignments = vec![];
@@ -1136,7 +1177,8 @@ impl<'hir> LoweringContext<'_, 'hir> {
fn lower_expr_range_closed(&mut self, span: Span, e1: &Expr, e2: &Expr) -> hir::ExprKind<'hir> {
let e1 = self.lower_expr_mut(e1);
let e2 = self.lower_expr_mut(e2);
- let fn_path = hir::QPath::LangItem(hir::LangItem::RangeInclusiveNew, self.lower_span(span));
+ let fn_path =
+ hir::QPath::LangItem(hir::LangItem::RangeInclusiveNew, self.lower_span(span), None);
let fn_expr =
self.arena.alloc(self.expr(span, hir::ExprKind::Path(fn_path), ThinVec::new()));
hir::ExprKind::Call(fn_expr, arena_vec![self; e1, e2])
@@ -1170,7 +1212,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
);
hir::ExprKind::Struct(
- self.arena.alloc(hir::QPath::LangItem(lang_item, self.lower_span(span))),
+ self.arena.alloc(hir::QPath::LangItem(lang_item, self.lower_span(span), None)),
fields,
None,
)
@@ -1365,6 +1407,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
head_span,
hir::LangItem::IteratorNext,
arena_vec![self; ref_mut_iter],
+ None,
);
let arms = arena_vec![self; none_arm, some_arm];
@@ -1393,6 +1436,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
head_span,
hir::LangItem::IntoIterIntoIter,
arena_vec![self; head],
+ None,
)
};
@@ -1448,6 +1492,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
unstable_span,
hir::LangItem::TryTraitBranch,
arena_vec![self; sub_expr],
+ None,
)
};
@@ -1604,8 +1649,10 @@ impl<'hir> LoweringContext<'_, 'hir> {
span: Span,
lang_item: hir::LangItem,
args: &'hir [hir::Expr<'hir>],
+ hir_id: Option<hir::HirId>,
) -> hir::Expr<'hir> {
- let path = self.arena.alloc(self.expr_lang_item_path(span, lang_item, ThinVec::new()));
+ let path =
+ self.arena.alloc(self.expr_lang_item_path(span, lang_item, ThinVec::new(), hir_id));
self.expr_call_mut(span, path, args)
}
@@ -1614,8 +1661,9 @@ impl<'hir> LoweringContext<'_, 'hir> {
span: Span,
lang_item: hir::LangItem,
args: &'hir [hir::Expr<'hir>],
+ hir_id: Option<hir::HirId>,
) -> &'hir hir::Expr<'hir> {
- self.arena.alloc(self.expr_call_lang_item_fn_mut(span, lang_item, args))
+ self.arena.alloc(self.expr_call_lang_item_fn_mut(span, lang_item, args, hir_id))
}
fn expr_lang_item_path(
@@ -1623,10 +1671,11 @@ impl<'hir> LoweringContext<'_, 'hir> {
span: Span,
lang_item: hir::LangItem,
attrs: AttrVec,
+ hir_id: Option<hir::HirId>,
) -> hir::Expr<'hir> {
self.expr(
span,
- hir::ExprKind::Path(hir::QPath::LangItem(lang_item, self.lower_span(span))),
+ hir::ExprKind::Path(hir::QPath::LangItem(lang_item, self.lower_span(span), hir_id)),
attrs,
)
}
diff --git a/compiler/rustc_ast_lowering/src/item.rs b/compiler/rustc_ast_lowering/src/item.rs
index 6a4571cf6d2..ca7a64e254e 100644
--- a/compiler/rustc_ast_lowering/src/item.rs
+++ b/compiler/rustc_ast_lowering/src/item.rs
@@ -40,6 +40,11 @@ impl ItemLowerer<'_, '_, '_> {
}
impl<'a> Visitor<'a> for ItemLowerer<'a, '_, '_> {
+ fn visit_attribute(&mut self, _: &'a Attribute) {
+ // We do not want to lower expressions that appear in attributes,
+ // as they are not accessible to the rest of the HIR.
+ }
+
fn visit_item(&mut self, item: &'a Item) {
let hir_id = self.lctx.with_hir_id_owner(item.id, |lctx| {
let node = lctx.without_in_scope_lifetime_defs(|lctx| lctx.lower_item(item));
@@ -242,12 +247,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
AnonymousLifetimeMode::PassThrough,
|this, idty| {
let ret_id = asyncness.opt_return_id();
- this.lower_fn_decl(
- &decl,
- Some((fn_def_id.to_def_id(), idty)),
- true,
- ret_id,
- )
+ this.lower_fn_decl(&decl, Some((fn_def_id, idty)), true, ret_id)
},
);
let sig = hir::FnSig {
@@ -1259,7 +1259,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
|this, idty| {
this.lower_fn_decl(
&sig.decl,
- Some((fn_def_id.to_def_id(), idty)),
+ Some((fn_def_id, idty)),
impl_trait_return_allow,
is_async,
)
diff --git a/compiler/rustc_ast_lowering/src/lib.rs b/compiler/rustc_ast_lowering/src/lib.rs
index 2b3a538772e..77738b2c5cc 100644
--- a/compiler/rustc_ast_lowering/src/lib.rs
+++ b/compiler/rustc_ast_lowering/src/lib.rs
@@ -32,7 +32,6 @@
#![feature(crate_visibility_modifier)]
#![feature(box_patterns)]
-#![feature(iter_zip)]
#![feature(never_type)]
#![recursion_limit = "256"]
@@ -47,20 +46,18 @@ use rustc_data_structures::fx::FxHashSet;
use rustc_data_structures::sorted_map::SortedMap;
use rustc_data_structures::stable_hasher::{HashStable, StableHasher};
use rustc_data_structures::sync::Lrc;
-use rustc_errors::{struct_span_err, Applicability};
+use rustc_errors::struct_span_err;
use rustc_hir as hir;
use rustc_hir::def::{DefKind, Namespace, PartialRes, PerNS, Res};
use rustc_hir::def_id::{DefId, DefPathHash, LocalDefId, CRATE_DEF_ID};
use rustc_hir::definitions::{DefKey, DefPathData, Definitions};
use rustc_hir::intravisit;
-use rustc_hir::{ConstArg, GenericArg, InferKind, ParamName};
+use rustc_hir::{ConstArg, GenericArg, ParamName};
use rustc_index::vec::{Idx, IndexVec};
use rustc_query_system::ich::StableHashingContext;
-use rustc_session::lint::builtin::BARE_TRAIT_OBJECTS;
-use rustc_session::lint::{BuiltinLintDiagnostics, LintBuffer};
+use rustc_session::lint::LintBuffer;
use rustc_session::utils::{FlattenNonterminals, NtToTokenstream};
use rustc_session::Session;
-use rustc_span::edition::Edition;
use rustc_span::hygiene::ExpnId;
use rustc_span::source_map::{respan, DesugaringKind};
use rustc_span::symbol::{kw, sym, Ident, Symbol};
@@ -70,10 +67,9 @@ use smallvec::SmallVec;
use tracing::{debug, trace};
macro_rules! arena_vec {
- ($this:expr; $($x:expr),*) => ({
- let a = [$($x),*];
- $this.arena.alloc_from_iter(std::array::IntoIter::new(a))
- });
+ ($this:expr; $($x:expr),*) => (
+ $this.arena.alloc_from_iter([$($x),*])
+ );
}
mod asm;
@@ -162,6 +158,7 @@ struct LoweringContext<'a, 'hir: 'a> {
allow_try_trait: Option<Lrc<[Symbol]>>,
allow_gen_future: Option<Lrc<[Symbol]>>,
+ allow_into_future: Option<Lrc<[Symbol]>>,
}
pub trait ResolverAstLowering {
@@ -228,7 +225,7 @@ enum ImplTraitContext<'b, 'a> {
ReturnPositionOpaqueTy {
/// `DefId` for the parent function, used to look up necessary
/// information later.
- fn_def_id: DefId,
+ fn_def_id: LocalDefId,
/// Origin: Either OpaqueTyOrigin::FnReturn or OpaqueTyOrigin::AsyncFn,
origin: hir::OpaqueTyOrigin,
},
@@ -320,6 +317,7 @@ pub fn lower_crate<'a, 'hir>(
in_scope_lifetimes: Vec::new(),
allow_try_trait: Some([sym::try_trait_v2][..].into()),
allow_gen_future: Some([sym::gen_future][..].into()),
+ allow_into_future: Some([sym::into_future][..].into()),
}
.lower_crate(krate)
}
@@ -645,31 +643,16 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
/// parameter while `f` is running (and restored afterwards).
fn collect_in_band_defs<T>(
&mut self,
- parent_def_id: LocalDefId,
- anonymous_lifetime_mode: AnonymousLifetimeMode,
- f: impl FnOnce(&mut Self) -> (Vec<hir::GenericParam<'hir>>, T),
- ) -> (Vec<hir::GenericParam<'hir>>, T) {
- assert!(!self.is_collecting_in_band_lifetimes);
- assert!(self.lifetimes_to_define.is_empty());
- let old_anonymous_lifetime_mode = self.anonymous_lifetime_mode;
-
- self.anonymous_lifetime_mode = anonymous_lifetime_mode;
- self.is_collecting_in_band_lifetimes = true;
-
- let (in_band_ty_params, res) = f(self);
-
- self.is_collecting_in_band_lifetimes = false;
- self.anonymous_lifetime_mode = old_anonymous_lifetime_mode;
-
- let lifetimes_to_define = self.lifetimes_to_define.split_off(0);
+ f: impl FnOnce(&mut Self) -> T,
+ ) -> (Vec<(Span, ParamName)>, T) {
+ let was_collecting = std::mem::replace(&mut self.is_collecting_in_band_lifetimes, true);
+ let len = self.lifetimes_to_define.len();
- let params = lifetimes_to_define
- .into_iter()
- .map(|(span, hir_name)| self.lifetime_to_generic_param(span, hir_name, parent_def_id))
- .chain(in_band_ty_params.into_iter())
- .collect();
+ let res = f(self);
- (params, res)
+ let lifetimes_to_define = self.lifetimes_to_define.split_off(len);
+ self.is_collecting_in_band_lifetimes = was_collecting;
+ (lifetimes_to_define, res)
}
/// Converts a lifetime into a new generic parameter.
@@ -784,27 +767,39 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
anonymous_lifetime_mode: AnonymousLifetimeMode,
f: impl FnOnce(&mut Self, &mut Vec<hir::GenericParam<'hir>>) -> T,
) -> (hir::Generics<'hir>, T) {
- let (in_band_defs, (mut lowered_generics, res)) =
- self.with_in_scope_lifetime_defs(&generics.params, |this| {
- this.collect_in_band_defs(parent_def_id, anonymous_lifetime_mode, |this| {
- let mut params = Vec::new();
- // Note: it is necessary to lower generics *before* calling `f`.
- // When lowering `async fn`, there's a final step when lowering
- // the return type that assumes that all in-scope lifetimes have
- // already been added to either `in_scope_lifetimes` or
- // `lifetimes_to_define`. If we swapped the order of these two,
- // in-band-lifetimes introduced by generics or where-clauses
- // wouldn't have been added yet.
- let generics = this.lower_generics_mut(
- generics,
- ImplTraitContext::Universal(&mut params, this.current_hir_id_owner),
- );
- let res = f(this, &mut params);
- (params, (generics, res))
+ let (lifetimes_to_define, (mut lowered_generics, impl_trait_defs, res)) = self
+ .collect_in_band_defs(|this| {
+ this.with_anonymous_lifetime_mode(anonymous_lifetime_mode, |this| {
+ this.with_in_scope_lifetime_defs(&generics.params, |this| {
+ let mut impl_trait_defs = Vec::new();
+ // Note: it is necessary to lower generics *before* calling `f`.
+ // When lowering `async fn`, there's a final step when lowering
+ // the return type that assumes that all in-scope lifetimes have
+ // already been added to either `in_scope_lifetimes` or
+ // `lifetimes_to_define`. If we swapped the order of these two,
+ // in-band-lifetimes introduced by generics or where-clauses
+ // wouldn't have been added yet.
+ let generics = this.lower_generics_mut(
+ generics,
+ ImplTraitContext::Universal(
+ &mut impl_trait_defs,
+ this.current_hir_id_owner,
+ ),
+ );
+ let res = f(this, &mut impl_trait_defs);
+ (generics, impl_trait_defs, res)
+ })
})
});
- lowered_generics.params.extend(in_band_defs);
+ lowered_generics.params.extend(
+ lifetimes_to_define
+ .into_iter()
+ .map(|(span, hir_name)| {
+ self.lifetime_to_generic_param(span, hir_name, parent_def_id)
+ })
+ .chain(impl_trait_defs),
+ );
let lowered_generics = lowered_generics.into_generics(self.arena);
(lowered_generics, res)
@@ -1116,7 +1111,6 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
return GenericArg::Infer(hir::InferArg {
hir_id: self.lower_node_id(ty.id),
span: self.lower_span(ty.span),
- kind: InferKind::Type,
});
}
// We parse const arguments as path types as we cannot distinguish them during
@@ -1188,11 +1182,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
) -> hir::Ty<'hir> {
let id = self.lower_node_id(t.id);
let qpath = self.lower_qpath(t.id, qself, path, param_mode, itctx);
- let ty = self.ty_path(id, t.span, qpath);
- if let hir::TyKind::TraitObject(..) = ty.kind {
- self.maybe_lint_bare_trait(t.span, t.id, qself.is_none() && path.is_global());
- }
- ty
+ self.ty_path(id, t.span, qpath)
}
fn ty(&mut self, span: Span, kind: hir::TyKind<'hir>) -> hir::Ty<'hir> {
@@ -1289,9 +1279,6 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
lifetime_bound.unwrap_or_else(|| this.elided_dyn_bound(t.span));
(bounds, lifetime_bound)
});
- if kind != TraitObjectSyntax::Dyn {
- self.maybe_lint_bare_trait(t.span, t.id, false);
- }
hir::TyKind::TraitObject(bounds, lifetime_bound, kind)
}
TyKind::ImplTrait(def_node_id, ref bounds) => {
@@ -1379,7 +1366,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
fn lower_opaque_impl_trait(
&mut self,
span: Span,
- fn_def_id: Option<DefId>,
+ fn_def_id: Option<LocalDefId>,
origin: hir::OpaqueTyOrigin,
opaque_ty_node_id: NodeId,
capturable_lifetimes: Option<&FxHashSet<hir::LifetimeName>>,
@@ -1451,7 +1438,6 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
span: lctx.lower_span(span),
},
bounds: hir_bounds,
- impl_trait_fn: fn_def_id,
origin,
};
@@ -1521,7 +1507,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
fn lower_fn_decl(
&mut self,
decl: &FnDecl,
- mut in_band_ty_params: Option<(DefId, &mut Vec<hir::GenericParam<'hir>>)>,
+ mut in_band_ty_params: Option<(LocalDefId, &mut Vec<hir::GenericParam<'hir>>)>,
impl_trait_return_allow: bool,
make_ret_async: Option<NodeId>,
) -> &'hir hir::FnDecl<'hir> {
@@ -1579,7 +1565,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
Some((def_id, _)) if impl_trait_return_allow => {
ImplTraitContext::ReturnPositionOpaqueTy {
fn_def_id: def_id,
- origin: hir::OpaqueTyOrigin::FnReturn,
+ origin: hir::OpaqueTyOrigin::FnReturn(def_id),
}
}
_ => ImplTraitContext::disallowed(),
@@ -1634,7 +1620,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
fn lower_async_fn_ret_ty(
&mut self,
output: &FnRetTy,
- fn_def_id: DefId,
+ fn_def_id: LocalDefId,
opaque_ty_node_id: NodeId,
) -> hir::FnRetTy<'hir> {
debug!(
@@ -1688,18 +1674,29 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
// this is because the elided lifetimes from the return type
// should be figured out using the ordinary elision rules, and
// this desugaring achieves that.
+
+ debug!("lower_async_fn_ret_ty: in_scope_lifetimes={:#?}", self.in_scope_lifetimes);
+ debug!("lower_async_fn_ret_ty: lifetimes_to_define={:#?}", self.lifetimes_to_define);
+
+ // Calculate all the lifetimes that should be captured
+ // by the opaque type. This should include all in-scope
+ // lifetime parameters, including those defined in-band.
//
- // The variable `input_lifetimes_count` tracks the number of
- // lifetime parameters to the opaque type *not counting* those
- // lifetimes elided in the return type. This includes those
- // that are explicitly declared (`in_scope_lifetimes`) and
- // those elided lifetimes we found in the arguments (current
- // content of `lifetimes_to_define`). Next, we will process
- // the return type, which will cause `lifetimes_to_define` to
- // grow.
- let input_lifetimes_count = self.in_scope_lifetimes.len() + self.lifetimes_to_define.len();
-
- let mut lifetime_params = Vec::new();
+ // `lifetime_params` is a vector of tuple (span, parameter name, lifetime name).
+
+ // Input lifetime like `'a` or `'1`:
+ let mut lifetime_params: Vec<_> = self
+ .in_scope_lifetimes
+ .iter()
+ .cloned()
+ .map(|name| (name.ident().span, name, hir::LifetimeName::Param(name)))
+ .chain(
+ self.lifetimes_to_define
+ .iter()
+ .map(|&(span, name)| (span, name, hir::LifetimeName::Param(name))),
+ )
+ .collect();
+
self.with_hir_id_owner(opaque_ty_node_id, |this| {
// We have to be careful to get elision right here. The
// idea is that we create a lifetime parameter for each
@@ -1709,34 +1706,26 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
//
// Then, we will create `fn foo(..) -> Foo<'_, '_>`, and
// hence the elision takes place at the fn site.
- let future_bound = this
- .with_anonymous_lifetime_mode(AnonymousLifetimeMode::CreateParameter, |this| {
- this.lower_async_fn_output_type_to_future_bound(output, fn_def_id, span)
+ let (lifetimes_to_define, future_bound) =
+ this.with_anonymous_lifetime_mode(AnonymousLifetimeMode::CreateParameter, |this| {
+ this.collect_in_band_defs(|this| {
+ this.lower_async_fn_output_type_to_future_bound(output, fn_def_id, span)
+ })
});
-
debug!("lower_async_fn_ret_ty: future_bound={:#?}", future_bound);
+ debug!("lower_async_fn_ret_ty: lifetimes_to_define={:#?}", lifetimes_to_define);
- // Calculate all the lifetimes that should be captured
- // by the opaque type. This should include all in-scope
- // lifetime parameters, including those defined in-band.
- //
- // Note: this must be done after lowering the output type,
- // as the output type may introduce new in-band lifetimes.
- lifetime_params = this
- .in_scope_lifetimes
- .iter()
- .cloned()
- .map(|name| (name.ident().span, name))
- .chain(this.lifetimes_to_define.iter().cloned())
- .collect();
-
- debug!("lower_async_fn_ret_ty: in_scope_lifetimes={:#?}", this.in_scope_lifetimes);
- debug!("lower_async_fn_ret_ty: lifetimes_to_define={:#?}", this.lifetimes_to_define);
+ lifetime_params.extend(
+ // Output lifetime like `'_`:
+ lifetimes_to_define
+ .into_iter()
+ .map(|(span, name)| (span, name, hir::LifetimeName::Implicit(false))),
+ );
debug!("lower_async_fn_ret_ty: lifetime_params={:#?}", lifetime_params);
let generic_params =
- this.arena.alloc_from_iter(lifetime_params.iter().map(|(span, hir_name)| {
- this.lifetime_to_generic_param(*span, *hir_name, opaque_ty_def_id)
+ this.arena.alloc_from_iter(lifetime_params.iter().map(|&(span, hir_name, _)| {
+ this.lifetime_to_generic_param(span, hir_name, opaque_ty_def_id)
}));
let opaque_ty_item = hir::OpaqueTy {
@@ -1746,8 +1735,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
span: this.lower_span(span),
},
bounds: arena_vec![this; future_bound],
- impl_trait_fn: Some(fn_def_id),
- origin: hir::OpaqueTyOrigin::AsyncFn,
+ origin: hir::OpaqueTyOrigin::AsyncFn(fn_def_id),
};
trace!("exist ty from async fn def id: {:#?}", opaque_ty_def_id);
@@ -1770,25 +1758,14 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
//
// For the "output" lifetime parameters, we just want to
// generate `'_`.
- let mut generic_args = Vec::with_capacity(lifetime_params.len());
- generic_args.extend(lifetime_params[..input_lifetimes_count].iter().map(
- |&(span, hir_name)| {
- // Input lifetime like `'a` or `'1`:
+ let generic_args =
+ self.arena.alloc_from_iter(lifetime_params.into_iter().map(|(span, _, name)| {
GenericArg::Lifetime(hir::Lifetime {
hir_id: self.next_id(),
span: self.lower_span(span),
- name: hir::LifetimeName::Param(hir_name),
+ name,
})
- },
- ));
- generic_args.extend(lifetime_params[input_lifetimes_count..].iter().map(|&(span, _)|
- // Output lifetime like `'_`.
- GenericArg::Lifetime(hir::Lifetime {
- hir_id: self.next_id(),
- span: self.lower_span(span),
- name: hir::LifetimeName::Implicit,
- })));
- let generic_args = self.arena.alloc_from_iter(generic_args);
+ }));
// Create the `Foo<...>` reference itself. Note that the `type
// Foo = impl Trait` is, internally, created as a child of the
@@ -1804,7 +1781,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
fn lower_async_fn_output_type_to_future_bound(
&mut self,
output: &FnRetTy,
- fn_def_id: DefId,
+ fn_def_id: LocalDefId,
span: Span,
) -> hir::GenericBound<'hir> {
// Compute the `T` in `Future<Output = T>` from the return type.
@@ -1815,7 +1792,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
// generates.
let context = ImplTraitContext::ReturnPositionOpaqueTy {
fn_def_id,
- origin: hir::OpaqueTyOrigin::FnReturn,
+ origin: hir::OpaqueTyOrigin::FnReturn(fn_def_id),
};
self.lower_ty(ty, context)
}
@@ -1927,7 +1904,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
});
let param_name = match lt.name {
hir::LifetimeName::Param(param_name) => param_name,
- hir::LifetimeName::Implicit
+ hir::LifetimeName::Implicit(_)
| hir::LifetimeName::Underscore
| hir::LifetimeName::Static => hir::ParamName::Plain(lt.name.ident()),
hir::LifetimeName::ImplicitObjectLifetimeDefault => {
@@ -2139,21 +2116,21 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
fn pat_cf_continue(&mut self, span: Span, pat: &'hir hir::Pat<'hir>) -> &'hir hir::Pat<'hir> {
let field = self.single_pat_field(span, pat);
- self.pat_lang_item_variant(span, hir::LangItem::ControlFlowContinue, field)
+ self.pat_lang_item_variant(span, hir::LangItem::ControlFlowContinue, field, None)
}
fn pat_cf_break(&mut self, span: Span, pat: &'hir hir::Pat<'hir>) -> &'hir hir::Pat<'hir> {
let field = self.single_pat_field(span, pat);
- self.pat_lang_item_variant(span, hir::LangItem::ControlFlowBreak, field)
+ self.pat_lang_item_variant(span, hir::LangItem::ControlFlowBreak, field, None)
}
fn pat_some(&mut self, span: Span, pat: &'hir hir::Pat<'hir>) -> &'hir hir::Pat<'hir> {
let field = self.single_pat_field(span, pat);
- self.pat_lang_item_variant(span, hir::LangItem::OptionSome, field)
+ self.pat_lang_item_variant(span, hir::LangItem::OptionSome, field, None)
}
fn pat_none(&mut self, span: Span) -> &'hir hir::Pat<'hir> {
- self.pat_lang_item_variant(span, hir::LangItem::OptionNone, &[])
+ self.pat_lang_item_variant(span, hir::LangItem::OptionNone, &[], None)
}
fn single_pat_field(
@@ -2176,8 +2153,9 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
span: Span,
lang_item: hir::LangItem,
fields: &'hir [hir::PatField<'hir>],
+ hir_id: Option<hir::HirId>,
) -> &'hir hir::Pat<'hir> {
- let qpath = hir::QPath::LangItem(lang_item, self.lower_span(span));
+ let qpath = hir::QPath::LangItem(lang_item, self.lower_span(span), hir_id);
self.pat(span, hir::PatKind::Struct(qpath, fields, false))
}
@@ -2290,7 +2268,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
AnonymousLifetimeMode::ReportError => self.new_error_lifetime(None, span),
- AnonymousLifetimeMode::PassThrough => self.new_implicit_lifetime(span),
+ AnonymousLifetimeMode::PassThrough => self.new_implicit_lifetime(span, false),
}
}
@@ -2322,11 +2300,12 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
&'s mut self,
span: Span,
count: usize,
+ param_mode: ParamMode,
) -> impl Iterator<Item = hir::Lifetime> + Captures<'a> + Captures<'s> + Captures<'hir> {
- (0..count).map(move |_| self.elided_path_lifetime(span))
+ (0..count).map(move |_| self.elided_path_lifetime(span, param_mode))
}
- fn elided_path_lifetime(&mut self, span: Span) -> hir::Lifetime {
+ fn elided_path_lifetime(&mut self, span: Span, param_mode: ParamMode) -> hir::Lifetime {
match self.anonymous_lifetime_mode {
AnonymousLifetimeMode::CreateParameter => {
// We should have emitted E0726 when processing this path above
@@ -2342,7 +2321,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
// lifetime. Instead, we simply create an implicit lifetime, which will be checked
// later, at which point a suitable error will be emitted.
AnonymousLifetimeMode::PassThrough | AnonymousLifetimeMode::ReportError => {
- self.new_implicit_lifetime(span)
+ self.new_implicit_lifetime(span, param_mode == ParamMode::Explicit)
}
}
}
@@ -2385,44 +2364,11 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
r
}
- fn new_implicit_lifetime(&mut self, span: Span) -> hir::Lifetime {
+ fn new_implicit_lifetime(&mut self, span: Span, missing: bool) -> hir::Lifetime {
hir::Lifetime {
hir_id: self.next_id(),
span: self.lower_span(span),
- name: hir::LifetimeName::Implicit,
- }
- }
-
- fn maybe_lint_bare_trait(&mut self, span: Span, id: NodeId, is_global: bool) {
- // FIXME(davidtwco): This is a hack to detect macros which produce spans of the
- // call site which do not have a macro backtrace. See #61963.
- let is_macro_callsite = self
- .sess
- .source_map()
- .span_to_snippet(span)
- .map(|snippet| snippet.starts_with("#["))
- .unwrap_or(true);
- if !is_macro_callsite {
- if span.edition() < Edition::Edition2021 {
- self.resolver.lint_buffer().buffer_lint_with_diagnostic(
- BARE_TRAIT_OBJECTS,
- id,
- span,
- "trait objects without an explicit `dyn` are deprecated",
- BuiltinLintDiagnostics::BareTraitObject(span, is_global),
- )
- } else {
- let msg = "trait objects must include the `dyn` keyword";
- let label = "add `dyn` keyword before this trait";
- let mut err = struct_span_err!(self.sess, span, E0782, "{}", msg,);
- err.span_suggestion_verbose(
- span.shrink_to_lo(),
- label,
- String::from("dyn "),
- Applicability::MachineApplicable,
- );
- err.emit();
- }
+ name: hir::LifetimeName::Implicit(missing),
}
}
}
@@ -2451,17 +2397,12 @@ impl<'hir> GenericArgsCtor<'hir> {
}
}
+#[tracing::instrument(level = "debug")]
fn lifetimes_from_impl_trait_bounds(
opaque_ty_id: NodeId,
bounds: hir::GenericBounds<'_>,
lifetimes_to_include: Option<&FxHashSet<hir::LifetimeName>>,
) -> Vec<(hir::LifetimeName, Span)> {
- debug!(
- "lifetimes_from_impl_trait_bounds(opaque_ty_id={:?}, \
- bounds={:#?})",
- opaque_ty_id, bounds,
- );
-
// This visitor walks over `impl Trait` bounds and creates defs for all lifetimes that
// appear in the bounds, excluding lifetimes that are created within the bounds.
// E.g., `'a`, `'b`, but not `'c` in `impl for<'c> SomeTrait<'a, 'b, 'c>`.
@@ -2536,7 +2477,7 @@ fn lifetimes_from_impl_trait_bounds(
fn visit_lifetime(&mut self, lifetime: &'v hir::Lifetime) {
let name = match lifetime.name {
- hir::LifetimeName::Implicit | hir::LifetimeName::Underscore => {
+ hir::LifetimeName::Implicit(_) | hir::LifetimeName::Underscore => {
if self.collect_elided_lifetimes {
// Use `'_` for both implicit and underscore lifetimes in
// `type Foo<'_> = impl SomeTrait<'_>;`.
diff --git a/compiler/rustc_ast_lowering/src/path.rs b/compiler/rustc_ast_lowering/src/path.rs
index 929f427484d..78afc339748 100644
--- a/compiler/rustc_ast_lowering/src/path.rs
+++ b/compiler/rustc_ast_lowering/src/path.rs
@@ -7,8 +7,6 @@ use rustc_hir as hir;
use rustc_hir::def::{DefKind, PartialRes, Res};
use rustc_hir::def_id::DefId;
use rustc_hir::GenericArg;
-use rustc_session::lint::builtin::ELIDED_LIFETIMES_IN_PATHS;
-use rustc_session::lint::BuiltinLintDiagnostics;
use rustc_span::symbol::Ident;
use rustc_span::{BytePos, Span, DUMMY_SP};
@@ -231,15 +229,19 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
if let Ok(snippet) = self.sess.source_map().span_to_snippet(data.span) {
// Do not suggest going from `Trait()` to `Trait<>`
if !data.inputs.is_empty() {
- if let Some(split) = snippet.find('(') {
- let trait_name = &snippet[0..split];
- let args = &snippet[split + 1..snippet.len() - 1];
- err.span_suggestion(
- data.span,
- "use angle brackets instead",
- format!("{}<{}>", trait_name, args),
- Applicability::MaybeIncorrect,
- );
+ // Suggest replacing `(` and `)` with `<` and `>`
+ // The snippet may be missing the closing `)`, skip that case
+ if snippet.ends_with(')') {
+ if let Some(split) = snippet.find('(') {
+ let trait_name = &snippet[0..split];
+ let args = &snippet[split + 1..snippet.len() - 1];
+ err.span_suggestion(
+ data.span,
+ "use angle brackets instead",
+ format!("{}<{}>", trait_name, args),
+ Applicability::MaybeIncorrect,
+ );
+ }
}
}
};
@@ -270,12 +272,12 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
let has_lifetimes =
generic_args.args.iter().any(|arg| matches!(arg, GenericArg::Lifetime(_)));
- if !generic_args.parenthesized && !has_lifetimes {
+ if !generic_args.parenthesized && !has_lifetimes && expected_lifetimes > 0 {
// Note: these spans are used for diagnostics when they can't be inferred.
// See rustc_resolve::late::lifetimes::LifetimeContext::add_missing_lifetime_specifiers_label
let elided_lifetime_span = if generic_args.span.is_empty() {
// If there are no brackets, use the identifier span.
- segment.ident.span
+ path_span
} else if generic_args.is_empty() {
// If there are brackets, but not generic arguments, then use the opening bracket
generic_args.span.with_hi(generic_args.span.lo() + BytePos(1))
@@ -284,67 +286,47 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
generic_args.span.with_lo(generic_args.span.lo() + BytePos(1)).shrink_to_lo()
};
generic_args.args = self
- .elided_path_lifetimes(elided_lifetime_span, expected_lifetimes)
+ .elided_path_lifetimes(elided_lifetime_span, expected_lifetimes, param_mode)
.map(GenericArg::Lifetime)
.chain(generic_args.args.into_iter())
.collect();
- if expected_lifetimes > 0 && param_mode == ParamMode::Explicit {
+ // In create-parameter mode we error here because we don't want to support
+ // deprecated impl elision in new features like impl elision and `async fn`,
+ // both of which work using the `CreateParameter` mode:
+ //
+ // impl Foo for std::cell::Ref<u32> // note lack of '_
+ // async fn foo(_: std::cell::Ref<u32>) { ... }
+ if let (ParamMode::Explicit, AnonymousLifetimeMode::CreateParameter) =
+ (param_mode, self.anonymous_lifetime_mode)
+ {
let anon_lt_suggestion = vec!["'_"; expected_lifetimes].join(", ");
let no_non_lt_args = generic_args.args.len() == expected_lifetimes;
let no_bindings = generic_args.bindings.is_empty();
- let (incl_angl_brckt, insertion_sp, suggestion) = if no_non_lt_args && no_bindings {
+ let (incl_angl_brckt, suggestion) = if no_non_lt_args && no_bindings {
// If there are no generic args, our suggestion can include the angle brackets.
- (true, path_span.shrink_to_hi(), format!("<{}>", anon_lt_suggestion))
+ (true, format!("<{}>", anon_lt_suggestion))
} else {
// Otherwise we'll insert a `'_, ` right after the opening bracket.
- let span = generic_args
- .span
- .with_lo(generic_args.span.lo() + BytePos(1))
- .shrink_to_lo();
- (false, span, format!("{}, ", anon_lt_suggestion))
+ (false, format!("{}, ", anon_lt_suggestion))
};
- match self.anonymous_lifetime_mode {
- // In create-parameter mode we error here because we don't want to support
- // deprecated impl elision in new features like impl elision and `async fn`,
- // both of which work using the `CreateParameter` mode:
- //
- // impl Foo for std::cell::Ref<u32> // note lack of '_
- // async fn foo(_: std::cell::Ref<u32>) { ... }
- AnonymousLifetimeMode::CreateParameter => {
- let mut err = struct_span_err!(
- self.sess,
- path_span,
- E0726,
- "implicit elided lifetime not allowed here"
- );
- rustc_errors::add_elided_lifetime_in_path_suggestion(
- &self.sess.source_map(),
- &mut err,
- expected_lifetimes,
- path_span,
- incl_angl_brckt,
- insertion_sp,
- suggestion,
- );
- err.note("assuming a `'static` lifetime...");
- err.emit();
- }
- AnonymousLifetimeMode::PassThrough | AnonymousLifetimeMode::ReportError => {
- self.resolver.lint_buffer().buffer_lint_with_diagnostic(
- ELIDED_LIFETIMES_IN_PATHS,
- CRATE_NODE_ID,
- path_span,
- "hidden lifetime parameters in types are deprecated",
- BuiltinLintDiagnostics::ElidedLifetimesInPaths(
- expected_lifetimes,
- path_span,
- incl_angl_brckt,
- insertion_sp,
- suggestion,
- ),
- );
- }
- }
+ let insertion_sp = elided_lifetime_span.shrink_to_hi();
+ let mut err = struct_span_err!(
+ self.sess,
+ path_span,
+ E0726,
+ "implicit elided lifetime not allowed here"
+ );
+ rustc_errors::add_elided_lifetime_in_path_suggestion(
+ &self.sess.source_map(),
+ &mut err,
+ expected_lifetimes,
+ path_span,
+ incl_angl_brckt,
+ insertion_sp,
+ suggestion,
+ );
+ err.note("assuming a `'static` lifetime...");
+ err.emit();
}
}
diff --git a/compiler/rustc_ast_passes/src/ast_validation.rs b/compiler/rustc_ast_passes/src/ast_validation.rs
index 1822ba6ec99..ae8c4330a1c 100644
--- a/compiler/rustc_ast_passes/src/ast_validation.rs
+++ b/compiler/rustc_ast_passes/src/ast_validation.rs
@@ -23,7 +23,7 @@ use rustc_span::symbol::{kw, sym, Ident};
use rustc_span::Span;
use rustc_target::spec::abi;
use std::mem;
-use std::ops::DerefMut;
+use std::ops::{Deref, DerefMut};
const MORE_EXTERN: &str =
"for more information, visit https://doc.rust-lang.org/std/keyword.extern.html";
@@ -894,7 +894,6 @@ impl<'a> AstValidator<'a> {
/// Checks that generic parameters are in the correct order,
/// which is lifetimes, then types and then consts. (`<'a, T, const N: usize>`)
fn validate_generic_param_order(
- sess: &Session,
handler: &rustc_errors::Handler,
generics: &[GenericParam],
span: Span,
@@ -911,8 +910,7 @@ fn validate_generic_param_order(
GenericParamKind::Type { default: _ } => (ParamKindOrd::Type, ident.to_string()),
GenericParamKind::Const { ref ty, kw_span: _, default: _ } => {
let ty = pprust::ty_to_string(ty);
- let unordered = sess.features_untracked().unordered_const_ty_params();
- (ParamKindOrd::Const { unordered }, format!("const {}: {}", ident, ty))
+ (ParamKindOrd::Const, format!("const {}: {}", ident, ty))
}
};
param_idents.push((kind, ord_kind, bounds, idx, ident));
@@ -968,14 +966,7 @@ fn validate_generic_param_order(
);
err.span_suggestion(
span,
- &format!(
- "reorder the parameters: lifetimes, {}",
- if sess.features_untracked().unordered_const_ty_params() {
- "then consts and types"
- } else {
- "then types, then consts"
- }
- ),
+ "reorder the parameters: lifetimes, then consts and types",
ordered_params.clone(),
Applicability::MachineApplicable,
);
@@ -1342,8 +1333,6 @@ impl<'a> Visitor<'a> for AstValidator<'a> {
}
fn visit_generics(&mut self, generics: &'a Generics) {
- let cg_defaults = self.session.features_untracked().unordered_const_ty_params();
-
let mut prev_param_default = None;
for param in &generics.params {
match param.kind {
@@ -1358,12 +1347,6 @@ impl<'a> Visitor<'a> for AstValidator<'a> {
span,
"generic parameters with a default must be trailing",
);
- if matches!(param.kind, GenericParamKind::Const { .. }) && !cg_defaults {
- err.note(
- "using type defaults and const parameters \
- in the same parameter list is currently not permitted",
- );
- }
err.emit();
break;
}
@@ -1371,12 +1354,7 @@ impl<'a> Visitor<'a> for AstValidator<'a> {
}
}
- validate_generic_param_order(
- self.session,
- self.err_handler(),
- &generics.params,
- generics.span,
- );
+ validate_generic_param_order(self.err_handler(), &generics.params, generics.span);
for predicate in &generics.where_clause.predicates {
if let WherePredicate::EqPredicate(ref predicate) = *predicate {
@@ -1714,6 +1692,53 @@ fn deny_equality_constraints(
}
}
}
+ // Given `A: Foo, A::Bar = RhsTy`, suggest `A: Foo<Bar = RhsTy>`.
+ if let TyKind::Path(None, full_path) = &predicate.lhs_ty.kind {
+ if let [potential_param, potential_assoc] = &full_path.segments[..] {
+ for param in &generics.params {
+ if param.ident == potential_param.ident {
+ for bound in &param.bounds {
+ if let ast::GenericBound::Trait(trait_ref, TraitBoundModifier::None) = bound
+ {
+ if let [trait_segment] = &trait_ref.trait_ref.path.segments[..] {
+ let assoc = pprust::path_to_string(&ast::Path::from_ident(
+ potential_assoc.ident,
+ ));
+ let ty = pprust::ty_to_string(&predicate.rhs_ty);
+ let (args, span) = match &trait_segment.args {
+ Some(args) => match args.deref() {
+ ast::GenericArgs::AngleBracketed(args) => {
+ let Some(arg) = args.args.last() else {
+ continue;
+ };
+ (
+ format!(", {} = {}", assoc, ty),
+ arg.span().shrink_to_hi(),
+ )
+ }
+ _ => continue,
+ },
+ None => (
+ format!("<{} = {}>", assoc, ty),
+ trait_segment.span().shrink_to_hi(),
+ ),
+ };
+ err.multipart_suggestion(
+ &format!(
+ "if `{}::{}` is an associated type you're trying to set, \
+ use the associated type binding syntax",
+ trait_segment.ident, potential_assoc.ident,
+ ),
+ vec![(span, args), (predicate.span, String::new())],
+ Applicability::MaybeIncorrect,
+ );
+ }
+ }
+ }
+ }
+ }
+ }
+ }
err.note(
"see issue #20041 <https://github.com/rust-lang/rust/issues/20041> for more information",
);
diff --git a/compiler/rustc_ast_passes/src/feature_gate.rs b/compiler/rustc_ast_passes/src/feature_gate.rs
index b011a2e8117..975874b6b2c 100644
--- a/compiler/rustc_ast_passes/src/feature_gate.rs
+++ b/compiler/rustc_ast_passes/src/feature_gate.rs
@@ -325,8 +325,12 @@ impl<'a> Visitor<'a> for PostExpansionVisitor<'a> {
cfg_hide => doc_cfg_hide
masked => doc_masked
notable_trait => doc_notable_trait
- keyword => doc_keyword
);
+
+ if nested_meta.has_name(sym::keyword) {
+ let msg = "`#[doc(keyword)]` is meant for internal use only";
+ gate_feature_post!(self, rustdoc_internals, attr.span, msg);
+ }
}
}
@@ -343,7 +347,7 @@ impl<'a> Visitor<'a> for PostExpansionVisitor<'a> {
if let Some(modifiers) = nested_meta.value_str() {
for modifier in modifiers.as_str().split(',') {
- if let Some(modifier) = modifier.strip_prefix(&['+', '-'][..]) {
+ if let Some(modifier) = modifier.strip_prefix(&['+', '-']) {
macro_rules! gate_modifier { ($($name:literal => $feature:ident)*) => {
$(if modifier == $name {
let msg = concat!("`#[link(modifiers=\"", $name, "\")]` is unstable");
@@ -379,7 +383,7 @@ impl<'a> Visitor<'a> for PostExpansionVisitor<'a> {
}
ast::ItemKind::Fn(..) => {
- if self.sess.contains_name(&i.attrs[..], sym::start) {
+ if self.sess.contains_name(&i.attrs, sym::start) {
gate_feature_post!(
&self,
start,
@@ -392,7 +396,7 @@ impl<'a> Visitor<'a> for PostExpansionVisitor<'a> {
}
ast::ItemKind::Struct(..) => {
- for attr in self.sess.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!(
@@ -719,15 +723,7 @@ pub fn check_crate(krate: &ast::Crate, sess: &Session) {
gate_all!(const_trait_impl, "const trait impls are experimental");
gate_all!(half_open_range_patterns, "half-open range patterns are unstable");
gate_all!(inline_const, "inline-const is experimental");
- gate_all!(
- const_generics_defaults,
- "default values for const generic parameters are experimental"
- );
- if sess.parse_sess.span_diagnostic.err_count() == 0 {
- // Errors for `destructuring_assignment` can get quite noisy, especially where `_` is
- // involved, so we only emit errors where there are no other parsing errors.
- gate_all!(destructuring_assignment, "destructuring assignments are unstable");
- }
+ gate_all!(inline_const_pat, "inline-const in pattern position is experimental");
// All uses of `gate_all!` below this point were added in #65742,
// and subsequently disabled (with the non-early gating readded).
diff --git a/compiler/rustc_ast_passes/src/lib.rs b/compiler/rustc_ast_passes/src/lib.rs
index 47666670b2b..adc4d117b80 100644
--- a/compiler/rustc_ast_passes/src/lib.rs
+++ b/compiler/rustc_ast_passes/src/lib.rs
@@ -6,6 +6,7 @@
#![feature(iter_is_partitioned)]
#![feature(box_patterns)]
+#![feature(let_else)]
#![recursion_limit = "256"]
pub mod ast_validation;
diff --git a/compiler/rustc_ast_pretty/src/helpers.rs b/compiler/rustc_ast_pretty/src/helpers.rs
index dce856df9c6..5ec71cddf7d 100644
--- a/compiler/rustc_ast_pretty/src/helpers.rs
+++ b/compiler/rustc_ast_pretty/src/helpers.rs
@@ -35,4 +35,14 @@ impl Printer {
self.word(w);
self.nbsp()
}
+
+ // Synthesizes a comment that was not textually present in the original
+ // source file.
+ pub fn synth_comment(&mut self, text: impl Into<Cow<'static, str>>) {
+ self.word("/*");
+ self.space();
+ self.word(text);
+ self.space();
+ self.word("*/")
+ }
}
diff --git a/compiler/rustc_ast_pretty/src/pprust/mod.rs b/compiler/rustc_ast_pretty/src/pprust/mod.rs
index e74f38dd89c..4b5703a429e 100644
--- a/compiler/rustc_ast_pretty/src/pprust/mod.rs
+++ b/compiler/rustc_ast_pretty/src/pprust/mod.rs
@@ -75,3 +75,12 @@ pub fn attribute_to_string(attr: &ast::Attribute) -> String {
pub fn to_string(f: impl FnOnce(&mut State<'_>)) -> String {
State::new().to_string(f)
}
+
+pub fn crate_to_string_for_macros(krate: &ast::Crate) -> String {
+ State::new().to_string(|s| {
+ s.print_inner_attributes(&krate.attrs);
+ for item in &krate.items {
+ s.print_item(item);
+ }
+ })
+}
diff --git a/compiler/rustc_ast_pretty/src/pprust/state.rs b/compiler/rustc_ast_pretty/src/pprust/state.rs
index f1f2387866d..2e511447693 100644
--- a/compiler/rustc_ast_pretty/src/pprust/state.rs
+++ b/compiler/rustc_ast_pretty/src/pprust/state.rs
@@ -263,14 +263,17 @@ pub trait PrintState<'a>: std::ops::Deref<Target = pp::Printer> + std::ops::Dere
self.strsep(",", false, b, elts, op)
}
- fn maybe_print_comment(&mut self, pos: BytePos) {
+ fn maybe_print_comment(&mut self, pos: BytePos) -> bool {
+ let mut has_comment = false;
while let Some(ref cmnt) = self.next_comment() {
if cmnt.pos < pos {
+ has_comment = true;
self.print_comment(cmnt);
} else {
break;
}
}
+ has_comment
}
fn print_comment(&mut self, cmnt: &Comment) {
@@ -346,6 +349,25 @@ pub trait PrintState<'a>: std::ops::Deref<Target = pp::Printer> + std::ops::Dere
self.comments().as_mut().and_then(|c| c.next())
}
+ fn maybe_print_trailing_comment(&mut self, span: rustc_span::Span, next_pos: Option<BytePos>) {
+ if let Some(cmnts) = self.comments() {
+ if let Some(cmnt) = cmnts.trailing_comment(span, next_pos) {
+ self.print_comment(&cmnt);
+ }
+ }
+ }
+
+ fn print_remaining_comments(&mut self) {
+ // If there aren't any remaining comments, then we need to manually
+ // make sure there is a line break at the end.
+ if self.next_comment().is_none() {
+ self.hardbreak();
+ }
+ while let Some(ref cmnt) = self.next_comment() {
+ self.print_comment(cmnt)
+ }
+ }
+
fn print_literal(&mut self, lit: &ast::Lit) {
self.maybe_print_comment(lit.span.lo());
self.word(lit.token.to_string())
@@ -477,7 +499,7 @@ pub trait PrintState<'a>: std::ops::Deref<Target = pp::Printer> + std::ops::Dere
ast::MetaItemKind::List(ref items) => {
self.print_path(&item.path, false, 0);
self.popen();
- self.commasep(Consistent, &items[..], |s, i| s.print_meta_list_item(i));
+ self.commasep(Consistent, &items, |s, i| s.print_meta_list_item(i));
self.pclose();
}
}
@@ -570,7 +592,10 @@ pub trait PrintState<'a>: std::ops::Deref<Target = pp::Printer> + std::ops::Dere
self.print_tts(tts, convert_dollar_crate);
self.end();
match delim {
- DelimToken::Brace => self.bclose(span),
+ DelimToken::Brace => {
+ let empty = tts.is_empty();
+ self.bclose(span, empty);
+ }
_ => {
let token_str = self.token_kind_to_string(&token::CloseDelim(delim));
self.word(token_str)
@@ -642,17 +667,20 @@ pub trait PrintState<'a>: std::ops::Deref<Target = pp::Printer> + std::ops::Dere
self.end(); // Close the head-box.
}
- fn bclose_maybe_open(&mut self, span: rustc_span::Span, close_box: bool) {
- self.maybe_print_comment(span.hi());
- self.break_offset_if_not_bol(1, -(INDENT_UNIT as isize));
+ fn bclose_maybe_open(&mut self, span: rustc_span::Span, empty: bool, close_box: bool) {
+ let has_comment = self.maybe_print_comment(span.hi());
+ if !empty || has_comment {
+ self.break_offset_if_not_bol(1, -(INDENT_UNIT as isize));
+ }
self.word("}");
if close_box {
self.end(); // Close the outer-box.
}
}
- fn bclose(&mut self, span: rustc_span::Span) {
- self.bclose_maybe_open(span, true)
+ fn bclose(&mut self, span: rustc_span::Span, empty: bool) {
+ let close_box = true;
+ self.bclose_maybe_open(span, empty, close_box)
}
fn break_offset_if_not_bol(&mut self, n: usize, off: isize) {
@@ -850,29 +878,29 @@ impl<'a> PrintState<'a> for State<'a> {
}
fn print_ident(&mut self, ident: Ident) {
- self.s.word(IdentPrinter::for_ast_ident(ident, ident.is_raw_guess()).to_string());
+ self.word(IdentPrinter::for_ast_ident(ident, ident.is_raw_guess()).to_string());
self.ann.post(self, AnnNode::Ident(&ident))
}
fn print_generic_args(&mut self, args: &ast::GenericArgs, colons_before_params: bool) {
if colons_before_params {
- self.s.word("::")
+ self.word("::")
}
match *args {
ast::GenericArgs::AngleBracketed(ref data) => {
- self.s.word("<");
+ self.word("<");
self.commasep(Inconsistent, &data.args, |s, arg| match arg {
ast::AngleBracketedArg::Arg(a) => s.print_generic_arg(a),
ast::AngleBracketedArg::Constraint(c) => s.print_assoc_constraint(c),
});
- self.s.word(">")
+ self.word(">")
}
ast::GenericArgs::Parenthesized(ref data) => {
- self.s.word("(");
+ self.word("(");
self.commasep(Inconsistent, &data.inputs, |s, ty| s.print_type(ty));
- self.s.word(")");
+ self.word(")");
self.print_fn_ret_ty(&data.output);
}
}
@@ -884,16 +912,6 @@ impl<'a> State<'a> {
State { s: pp::mk_printer(), comments: None, ann: &NoAnn }
}
- // Synthesizes a comment that was not textually present in the original source
- // file.
- pub fn synth_comment(&mut self, text: String) {
- self.s.word("/*");
- self.s.space();
- self.s.word(text);
- self.s.space();
- self.s.word("*/")
- }
-
crate fn commasep_cmnt<T, F, G>(&mut self, b: Breaks, elts: &[T], mut op: F, mut get_span: G)
where
F: FnMut(&mut State<'_>, &T),
@@ -907,7 +925,7 @@ impl<'a> State<'a> {
op(self, elt);
i += 1;
if i < len {
- self.s.word(",");
+ self.word(",");
self.maybe_print_trailing_comment(get_span(elt), Some(get_span(&elts[i]).hi()));
self.space_if_not_bol();
}
@@ -936,7 +954,7 @@ impl<'a> State<'a> {
pub fn print_assoc_constraint(&mut self, constraint: &ast::AssocTyConstraint) {
self.print_ident(constraint.ident);
constraint.gen_args.as_ref().map(|args| self.print_generic_args(args, false));
- self.s.space();
+ self.space();
match &constraint.kind {
ast::AssocTyConstraintKind::Equality { ty } => {
self.word_space("=");
@@ -961,27 +979,27 @@ impl<'a> State<'a> {
self.ibox(0);
match ty.kind {
ast::TyKind::Slice(ref ty) => {
- self.s.word("[");
+ self.word("[");
self.print_type(ty);
- self.s.word("]");
+ self.word("]");
}
ast::TyKind::Ptr(ref mt) => {
- self.s.word("*");
+ self.word("*");
self.print_mt(mt, true);
}
ast::TyKind::Rptr(ref lifetime, ref mt) => {
- self.s.word("&");
+ self.word("&");
self.print_opt_lifetime(lifetime);
self.print_mt(mt, false);
}
ast::TyKind::Never => {
- self.s.word("!");
+ self.word("!");
}
ast::TyKind::Tup(ref elts) => {
self.popen();
- self.commasep(Inconsistent, &elts[..], |s, ty| s.print_type(ty));
+ self.commasep(Inconsistent, &elts, |s, ty| s.print_type(ty));
if elts.len() == 1 {
- self.s.word(",");
+ self.word(",");
}
self.pclose();
}
@@ -999,39 +1017,39 @@ impl<'a> State<'a> {
ast::TyKind::Path(Some(ref qself), ref path) => self.print_qpath(path, qself, false),
ast::TyKind::TraitObject(ref bounds, syntax) => {
let prefix = if syntax == ast::TraitObjectSyntax::Dyn { "dyn" } else { "" };
- self.print_type_bounds(prefix, &bounds[..]);
+ self.print_type_bounds(prefix, &bounds);
}
ast::TyKind::ImplTrait(_, ref bounds) => {
- self.print_type_bounds("impl", &bounds[..]);
+ self.print_type_bounds("impl", &bounds);
}
ast::TyKind::Array(ref ty, ref length) => {
- self.s.word("[");
+ self.word("[");
self.print_type(ty);
- self.s.word("; ");
+ self.word("; ");
self.print_expr(&length.value);
- self.s.word("]");
+ self.word("]");
}
ast::TyKind::Typeof(ref e) => {
- self.s.word("typeof(");
+ self.word("typeof(");
self.print_expr(&e.value);
- self.s.word(")");
+ self.word(")");
}
ast::TyKind::Infer => {
- self.s.word("_");
+ self.word("_");
}
ast::TyKind::Err => {
self.popen();
- self.s.word("/*ERROR*/");
+ self.word("/*ERROR*/");
self.pclose();
}
ast::TyKind::ImplicitSelf => {
- self.s.word("Self");
+ self.word("Self");
}
ast::TyKind::MacCall(ref m) => {
self.print_mac(m);
}
ast::TyKind::CVarArgs => {
- self.s.word("...");
+ self.word("...");
}
}
self.end();
@@ -1069,7 +1087,7 @@ impl<'a> State<'a> {
ast::ForeignItemKind::MacCall(m) => {
self.print_mac(m);
if m.args.need_semicolon() {
- self.s.word(";");
+ self.word(";");
}
}
}
@@ -1097,13 +1115,13 @@ impl<'a> State<'a> {
self.print_ident(ident);
self.word_space(":");
self.print_type(ty);
- self.s.space();
+ self.space();
self.end(); // end the head-ibox
if let Some(body) = body {
self.word_space("=");
self.print_expr(body);
}
- self.s.word(";");
+ self.word(";");
self.end(); // end the outer cbox
}
@@ -1125,11 +1143,11 @@ impl<'a> State<'a> {
self.print_type_bounds(":", bounds);
self.print_where_clause(&generics.where_clause);
if let Some(ty) = ty {
- self.s.space();
+ self.space();
self.word_space("=");
self.print_type(ty);
}
- self.s.word(";");
+ self.word(";");
self.end(); // end inner head-block
self.end(); // end outer head-block
}
@@ -1145,19 +1163,19 @@ impl<'a> State<'a> {
self.head(visibility_qualified(&item.vis, "extern crate"));
if let Some(orig_name) = orig_name {
self.print_name(orig_name);
- self.s.space();
- self.s.word("as");
- self.s.space();
+ self.space();
+ self.word("as");
+ self.space();
}
self.print_ident(item.ident);
- self.s.word(";");
+ self.word(";");
self.end(); // end inner head-block
self.end(); // end outer head-block
}
ast::ItemKind::Use(ref tree) => {
self.head(visibility_qualified(&item.vis, "use"));
self.print_use_tree(tree);
- self.s.word(";");
+ self.word(";");
self.end(); // end inner head-block
self.end(); // end outer head-block
}
@@ -1196,10 +1214,11 @@ impl<'a> State<'a> {
for item in items {
self.print_item(item);
}
- self.bclose(item.span);
+ let empty = item.attrs.is_empty() && items.is_empty();
+ self.bclose(item.span, empty);
}
ModKind::Unloaded => {
- self.s.word(";");
+ self.word(";");
self.end(); // end inner head-block
self.end(); // end outer head-block
}
@@ -1216,7 +1235,8 @@ impl<'a> State<'a> {
}
self.bopen();
self.print_foreign_mod(nmod, &item.attrs);
- self.bclose(item.span);
+ let empty = item.attrs.is_empty() && nmod.items.is_empty();
+ self.bclose(item.span, empty);
}
ast::ItemKind::GlobalAsm(ref asm) => {
self.head(visibility_qualified(&item.vis, "global_asm!"));
@@ -1269,29 +1289,30 @@ impl<'a> State<'a> {
if !generics.params.is_empty() {
self.print_generic_params(&generics.params);
- self.s.space();
+ self.space();
}
if let ast::ImplPolarity::Negative(_) = polarity {
- self.s.word("!");
+ self.word("!");
}
if let Some(ref t) = *of_trait {
self.print_trait_ref(t);
- self.s.space();
+ self.space();
self.word_space("for");
}
self.print_type(self_ty);
self.print_where_clause(&generics.where_clause);
- self.s.space();
+ self.space();
self.bopen();
self.print_inner_attributes(&item.attrs);
for impl_item in items {
self.print_assoc_item(impl_item);
}
- self.bclose(item.span);
+ let empty = item.attrs.is_empty() && items.is_empty();
+ self.bclose(item.span, empty);
}
ast::ItemKind::Trait(box ast::Trait {
is_auto,
@@ -1311,22 +1332,23 @@ impl<'a> State<'a> {
let mut real_bounds = Vec::with_capacity(bounds.len());
for b in bounds.iter() {
if let GenericBound::Trait(ref ptr, ast::TraitBoundModifier::Maybe) = *b {
- self.s.space();
+ self.space();
self.word_space("for ?");
self.print_trait_ref(&ptr.trait_ref);
} else {
real_bounds.push(b.clone());
}
}
- self.print_type_bounds(":", &real_bounds[..]);
+ self.print_type_bounds(":", &real_bounds);
self.print_where_clause(&generics.where_clause);
- self.s.word(" ");
+ self.word(" ");
self.bopen();
self.print_inner_attributes(&item.attrs);
for trait_item in items {
self.print_assoc_item(trait_item);
}
- self.bclose(item.span);
+ let empty = item.attrs.is_empty() && items.is_empty();
+ self.bclose(item.span, empty);
}
ast::ItemKind::TraitAlias(ref generics, ref bounds) => {
self.head("");
@@ -1338,7 +1360,7 @@ impl<'a> State<'a> {
// FIXME(durka) this seems to be some quite outdated syntax
for b in bounds.iter() {
if let GenericBound::Trait(ref ptr, ast::TraitBoundModifier::Maybe) = *b {
- self.s.space();
+ self.space();
self.word_space("for ?");
self.print_trait_ref(&ptr.trait_ref);
} else {
@@ -1346,14 +1368,14 @@ impl<'a> State<'a> {
}
}
self.nbsp();
- self.print_type_bounds("=", &real_bounds[..]);
+ self.print_type_bounds("=", &real_bounds);
self.print_where_clause(&generics.where_clause);
- self.s.word(";");
+ self.word(";");
}
ast::ItemKind::MacCall(ref mac) => {
self.print_mac(mac);
if mac.args.need_semicolon() {
- self.s.word(";");
+ self.word(";");
}
}
ast::ItemKind::MacroDef(ref macro_def) => {
@@ -1371,7 +1393,7 @@ impl<'a> State<'a> {
fn print_formal_generic_params(&mut self, generic_params: &[ast::GenericParam]) {
if !generic_params.is_empty() {
- self.s.word("for");
+ self.word("for");
self.print_generic_params(generic_params);
self.nbsp();
}
@@ -1394,7 +1416,7 @@ impl<'a> State<'a> {
self.print_ident(ident);
self.print_generic_params(&generics.params);
self.print_where_clause(&generics.where_clause);
- self.s.space();
+ self.space();
self.print_variants(&enum_definition.variants, span)
}
@@ -1406,11 +1428,12 @@ impl<'a> State<'a> {
self.print_outer_attributes(&v.attrs);
self.ibox(INDENT_UNIT);
self.print_variant(v);
- self.s.word(",");
+ self.word(",");
self.end();
self.maybe_print_trailing_comment(v.span, None);
}
- self.bclose(span)
+ let empty = variants.is_empty();
+ self.bclose(span, empty)
}
crate fn print_visibility(&mut self, vis: &ast::Visibility) {
@@ -1441,20 +1464,24 @@ impl<'a> State<'a> {
crate fn print_record_struct_body(&mut self, fields: &[ast::FieldDef], span: rustc_span::Span) {
self.nbsp();
self.bopen();
- self.hardbreak_if_not_bol();
- for field in fields {
+ let empty = fields.is_empty();
+ if !empty {
self.hardbreak_if_not_bol();
- self.maybe_print_comment(field.span.lo());
- self.print_outer_attributes(&field.attrs);
- self.print_visibility(&field.vis);
- self.print_ident(field.ident.unwrap());
- self.word_nbsp(":");
- self.print_type(&field.ty);
- self.s.word(",");
+
+ for field in fields {
+ self.hardbreak_if_not_bol();
+ self.maybe_print_comment(field.span.lo());
+ self.print_outer_attributes(&field.attrs);
+ self.print_visibility(&field.vis);
+ self.print_ident(field.ident.unwrap());
+ self.word_nbsp(":");
+ self.print_type(&field.ty);
+ self.word(",");
+ }
}
- self.bclose(span)
+ self.bclose(span, empty);
}
crate fn print_struct(
@@ -1481,7 +1508,7 @@ impl<'a> State<'a> {
}
self.print_where_clause(&generics.where_clause);
if print_finalizer {
- self.s.word(";");
+ self.word(";");
}
self.end();
self.end(); // Close the outer-box.
@@ -1499,7 +1526,7 @@ impl<'a> State<'a> {
let generics = ast::Generics::default();
self.print_struct(&v.data, &generics, v.ident, v.span, false);
if let Some(ref d) = v.disr_expr {
- self.s.space();
+ self.space();
self.word_space("=");
self.print_expr(&d.value)
}
@@ -1531,7 +1558,7 @@ impl<'a> State<'a> {
ast::AssocItemKind::MacCall(m) => {
self.print_mac(m);
if m.args.need_semicolon() {
- self.s.word(";");
+ self.word(";");
}
}
}
@@ -1557,11 +1584,11 @@ impl<'a> State<'a> {
if let Some(els) = els {
self.cbox(INDENT_UNIT);
self.ibox(INDENT_UNIT);
- self.s.word(" else ");
+ self.word(" else ");
self.print_block(els);
}
}
- self.s.word(";");
+ self.word(";");
self.end(); // `let` ibox
}
ast::StmtKind::Item(ref item) => self.print_item(item),
@@ -1569,24 +1596,24 @@ impl<'a> State<'a> {
self.space_if_not_bol();
self.print_expr_outer_attr_style(expr, false);
if classify::expr_requires_semi_to_be_stmt(expr) {
- self.s.word(";");
+ self.word(";");
}
}
ast::StmtKind::Semi(ref expr) => {
self.space_if_not_bol();
self.print_expr_outer_attr_style(expr, false);
- self.s.word(";");
+ self.word(";");
}
ast::StmtKind::Empty => {
self.space_if_not_bol();
- self.s.word(";");
+ self.word(";");
}
ast::StmtKind::MacCall(ref mac) => {
self.space_if_not_bol();
self.print_outer_attributes(&mac.attrs);
self.print_mac(&mac.mac);
if mac.style == ast::MacStmtStyle::Semicolon {
- self.s.word(";");
+ self.word(";");
}
}
}
@@ -1633,15 +1660,16 @@ impl<'a> State<'a> {
}
}
- self.bclose_maybe_open(blk.span, close_box);
+ let empty = attrs.is_empty() && blk.stmts.is_empty();
+ self.bclose_maybe_open(blk.span, empty, close_box);
self.ann.post(self, AnnNode::Block(blk))
}
/// Print a `let pat = expr` expression.
crate fn print_let(&mut self, pat: &ast::Pat, expr: &ast::Expr) {
- self.s.word("let ");
+ self.word("let ");
self.print_pat(pat);
- self.s.space();
+ self.space();
self.word_space("=");
let npals = || parser::needs_par_as_let_scrutinee(expr.precedence().order());
self.print_expr_cond_paren(expr, Self::cond_needs_par(expr) || npals())
@@ -1654,9 +1682,9 @@ impl<'a> State<'a> {
ast::ExprKind::If(ref i, ref then, ref e) => {
self.cbox(INDENT_UNIT - 1);
self.ibox(0);
- self.s.word(" else if ");
+ self.word(" else if ");
self.print_expr_as_cond(i);
- self.s.space();
+ self.space();
self.print_block(then);
self.print_else(e.as_deref())
}
@@ -1664,7 +1692,7 @@ impl<'a> State<'a> {
ast::ExprKind::Block(ref b, _) => {
self.cbox(INDENT_UNIT - 1);
self.ibox(0);
- self.s.word(" else ");
+ self.word(" else ");
self.print_block(b)
}
// Constraints would be great here!
@@ -1678,7 +1706,7 @@ impl<'a> State<'a> {
crate fn print_if(&mut self, test: &ast::Expr, blk: &ast::Block, elseopt: Option<&ast::Expr>) {
self.head("if");
self.print_expr_as_cond(test);
- self.s.space();
+ self.space();
self.print_block(blk);
self.print_else(elseopt)
}
@@ -1735,26 +1763,26 @@ impl<'a> State<'a> {
fn print_expr_vec(&mut self, exprs: &[P<ast::Expr>]) {
self.ibox(INDENT_UNIT);
- self.s.word("[");
+ self.word("[");
self.commasep_exprs(Inconsistent, exprs);
- self.s.word("]");
+ self.word("]");
self.end();
}
fn print_expr_anon_const(&mut self, expr: &ast::AnonConst) {
self.ibox(INDENT_UNIT);
- self.s.word("const");
+ self.word("const");
self.print_expr(&expr.value);
self.end();
}
fn print_expr_repeat(&mut self, element: &ast::Expr, count: &ast::AnonConst) {
self.ibox(INDENT_UNIT);
- self.s.word("[");
+ self.word("[");
self.print_expr(element);
self.word_space(";");
self.print_expr(&count.value);
- self.s.word("]");
+ self.word("]");
self.end();
}
@@ -1770,7 +1798,7 @@ impl<'a> State<'a> {
} else {
self.print_path(path, true, 0);
}
- self.s.word("{");
+ self.word("{");
self.commasep_cmnt(
Consistent,
fields,
@@ -1790,26 +1818,26 @@ impl<'a> State<'a> {
ast::StructRest::Base(_) | ast::StructRest::Rest(_) => {
self.ibox(INDENT_UNIT);
if !fields.is_empty() {
- self.s.word(",");
- self.s.space();
+ self.word(",");
+ self.space();
}
- self.s.word("..");
+ self.word("..");
if let ast::StructRest::Base(ref expr) = *rest {
self.print_expr(expr);
}
self.end();
}
- ast::StructRest::None if !fields.is_empty() => self.s.word(","),
+ ast::StructRest::None if !fields.is_empty() => self.word(","),
_ => {}
}
- self.s.word("}");
+ self.word("}");
}
fn print_expr_tup(&mut self, exprs: &[P<ast::Expr>]) {
self.popen();
self.commasep_exprs(Inconsistent, exprs);
if exprs.len() == 1 {
- self.s.word(",");
+ self.word(",");
}
self.pclose()
}
@@ -1827,7 +1855,7 @@ impl<'a> State<'a> {
fn print_expr_method_call(&mut self, segment: &ast::PathSegment, args: &[P<ast::Expr>]) {
let base_args = &args[1..];
self.print_expr_maybe_paren(&args[0], parser::PREC_POSTFIX);
- self.s.word(".");
+ self.word(".");
self.print_ident(segment.ident);
if let Some(ref args) = segment.args {
self.print_generic_args(args, true);
@@ -1868,13 +1896,13 @@ impl<'a> State<'a> {
};
self.print_expr_maybe_paren(lhs, left_prec);
- self.s.space();
+ self.space();
self.word_space(op.node.to_string());
self.print_expr_maybe_paren(rhs, right_prec)
}
fn print_expr_unary(&mut self, op: ast::UnOp, expr: &ast::Expr) {
- self.s.word(ast::UnOp::to_string(op));
+ self.word(ast::UnOp::to_string(op));
self.print_expr_maybe_paren(expr, parser::PREC_PREFIX)
}
@@ -1884,7 +1912,7 @@ impl<'a> State<'a> {
mutability: ast::Mutability,
expr: &ast::Expr,
) {
- self.s.word("&");
+ self.word("&");
match kind {
ast::BorrowKind::Ref => self.print_mutability(mutability, false),
ast::BorrowKind::Raw => {
@@ -1932,10 +1960,10 @@ impl<'a> State<'a> {
self.print_expr_tup(exprs);
}
ast::ExprKind::Call(ref func, ref args) => {
- self.print_expr_call(func, &args[..]);
+ self.print_expr_call(func, &args);
}
ast::ExprKind::MethodCall(ref segment, ref args, _) => {
- self.print_expr_method_call(segment, &args[..]);
+ self.print_expr_method_call(segment, &args);
}
ast::ExprKind::Binary(op, ref lhs, ref rhs) => {
self.print_expr_binary(op, lhs, rhs);
@@ -1952,7 +1980,7 @@ impl<'a> State<'a> {
ast::ExprKind::Cast(ref expr, ref ty) => {
let prec = AssocOp::As.precedence() as i8;
self.print_expr_maybe_paren(expr, prec);
- self.s.space();
+ self.space();
self.word_space("as");
self.print_type(ty);
}
@@ -1975,7 +2003,7 @@ impl<'a> State<'a> {
}
self.head("while");
self.print_expr_as_cond(test);
- self.s.space();
+ self.space();
self.print_block_with_attrs(blk, attrs);
}
ast::ExprKind::ForLoop(ref pat, ref iter, ref blk, opt_label) => {
@@ -1985,10 +2013,10 @@ impl<'a> State<'a> {
}
self.head("for");
self.print_pat(pat);
- self.s.space();
+ self.space();
self.word_space("in");
self.print_expr_as_cond(iter);
- self.s.space();
+ self.space();
self.print_block_with_attrs(blk, attrs);
}
ast::ExprKind::Loop(ref blk, opt_label) => {
@@ -2004,13 +2032,14 @@ impl<'a> State<'a> {
self.ibox(INDENT_UNIT);
self.word_nbsp("match");
self.print_expr_as_cond(expr);
- self.s.space();
+ self.space();
self.bopen();
self.print_inner_attributes_no_trailing_hardbreak(attrs);
for arm in arms {
self.print_arm(arm);
}
- self.bclose(expr.span);
+ let empty = attrs.is_empty() && arms.is_empty();
+ self.bclose(expr.span, empty);
}
ast::ExprKind::Closure(
capture_clause,
@@ -2025,7 +2054,7 @@ impl<'a> State<'a> {
self.print_capture_clause(capture_clause);
self.print_fn_params_and_ret(decl, true);
- self.s.space();
+ self.space();
self.print_expr(body);
self.end(); // need to close a box
@@ -2048,7 +2077,6 @@ impl<'a> State<'a> {
ast::ExprKind::Async(capture_clause, _, ref blk) => {
self.word_nbsp("async");
self.print_capture_clause(capture_clause);
- self.s.space();
// cbox/ibox in analogy to the `ExprKind::Block` arm above
self.cbox(INDENT_UNIT);
self.ibox(0);
@@ -2056,33 +2084,33 @@ impl<'a> State<'a> {
}
ast::ExprKind::Await(ref expr) => {
self.print_expr_maybe_paren(expr, parser::PREC_POSTFIX);
- self.s.word(".await");
+ self.word(".await");
}
ast::ExprKind::Assign(ref lhs, ref rhs, _) => {
let prec = AssocOp::Assign.precedence() as i8;
self.print_expr_maybe_paren(lhs, prec + 1);
- self.s.space();
+ self.space();
self.word_space("=");
self.print_expr_maybe_paren(rhs, prec);
}
ast::ExprKind::AssignOp(op, ref lhs, ref rhs) => {
let prec = AssocOp::Assign.precedence() as i8;
self.print_expr_maybe_paren(lhs, prec + 1);
- self.s.space();
- self.s.word(op.node.to_string());
+ self.space();
+ self.word(op.node.to_string());
self.word_space("=");
self.print_expr_maybe_paren(rhs, prec);
}
ast::ExprKind::Field(ref expr, ident) => {
self.print_expr_maybe_paren(expr, parser::PREC_POSTFIX);
- self.s.word(".");
+ self.word(".");
self.print_ident(ident);
}
ast::ExprKind::Index(ref expr, ref index) => {
self.print_expr_maybe_paren(expr, parser::PREC_POSTFIX);
- self.s.word("[");
+ self.word("[");
self.print_expr(index);
- self.s.word("]");
+ self.word("]");
}
ast::ExprKind::Range(ref start, ref end, limits) => {
// Special case for `Range`. `AssocOp` claims that `Range` has higher precedence
@@ -2094,41 +2122,39 @@ impl<'a> State<'a> {
self.print_expr_maybe_paren(e, fake_prec);
}
if limits == ast::RangeLimits::HalfOpen {
- self.s.word("..");
+ self.word("..");
} else {
- self.s.word("..=");
+ self.word("..=");
}
if let Some(ref e) = *end {
self.print_expr_maybe_paren(e, fake_prec);
}
}
- ast::ExprKind::Underscore => self.s.word("_"),
+ ast::ExprKind::Underscore => self.word("_"),
ast::ExprKind::Path(None, ref path) => self.print_path(path, true, 0),
ast::ExprKind::Path(Some(ref qself), ref path) => self.print_qpath(path, qself, true),
ast::ExprKind::Break(opt_label, ref opt_expr) => {
- self.s.word("break");
- self.s.space();
+ self.word("break");
if let Some(label) = opt_label {
+ self.space();
self.print_ident(label.ident);
- self.s.space();
}
if let Some(ref expr) = *opt_expr {
+ self.space();
self.print_expr_maybe_paren(expr, parser::PREC_JUMP);
- self.s.space();
}
}
ast::ExprKind::Continue(opt_label) => {
- self.s.word("continue");
- self.s.space();
+ self.word("continue");
if let Some(label) = opt_label {
+ self.space();
self.print_ident(label.ident);
- self.s.space()
}
}
ast::ExprKind::Ret(ref result) => {
- self.s.word("return");
+ self.word("return");
if let Some(ref expr) = *result {
- self.s.word(" ");
+ self.word(" ");
self.print_expr_maybe_paren(expr, parser::PREC_JUMP);
}
}
@@ -2137,7 +2163,7 @@ impl<'a> State<'a> {
self.print_inline_asm(a);
}
ast::ExprKind::LlvmInlineAsm(ref a) => {
- self.s.word("llvm_asm!");
+ self.word("llvm_asm!");
self.popen();
self.print_symbol(a.asm, a.asm_str_style);
self.word_space(":");
@@ -2155,7 +2181,7 @@ impl<'a> State<'a> {
s.print_expr(&out.expr);
s.pclose();
});
- self.s.space();
+ self.space();
self.word_space(":");
self.commasep(Inconsistent, &a.inputs, |s, &(co, ref o)| {
@@ -2164,7 +2190,7 @@ impl<'a> State<'a> {
s.print_expr(o);
s.pclose();
});
- self.s.space();
+ self.space();
self.word_space(":");
self.commasep(Inconsistent, &a.clobbers, |s, &co| {
@@ -2183,7 +2209,7 @@ impl<'a> State<'a> {
}
if !options.is_empty() {
- self.s.space();
+ self.space();
self.word_space(":");
self.commasep(Inconsistent, &options, |s, &co| {
s.print_string(co, ast::StrStyle::Cooked);
@@ -2199,25 +2225,25 @@ impl<'a> State<'a> {
self.pclose();
}
ast::ExprKind::Yield(ref e) => {
- self.s.word("yield");
+ self.word("yield");
if let Some(ref expr) = *e {
- self.s.space();
+ self.space();
self.print_expr_maybe_paren(expr, parser::PREC_JUMP);
}
}
ast::ExprKind::Try(ref e) => {
self.print_expr_maybe_paren(e, parser::PREC_POSTFIX);
- self.s.word("?")
+ self.word("?")
}
ast::ExprKind::TryBlock(ref blk) => {
self.head("try");
- self.s.space();
+ self.space();
self.print_block_with_attrs(blk, attrs)
}
ast::ExprKind::Err => {
self.popen();
- self.s.word("/*ERROR*/");
+ self.word("/*ERROR*/");
self.pclose()
}
}
@@ -2338,6 +2364,9 @@ impl<'a> State<'a> {
if opts.contains(InlineAsmOptions::RAW) {
options.push("raw");
}
+ if opts.contains(InlineAsmOptions::MAY_UNWIND) {
+ options.push("may_unwind");
+ }
s.commasep(Inconsistent, &options, |s, &opt| {
s.word(opt);
});
@@ -2356,22 +2385,22 @@ impl<'a> State<'a> {
}
crate fn print_name(&mut self, name: Symbol) {
- self.s.word(name.to_string());
+ self.word(name.to_string());
self.ann.post(self, AnnNode::Name(&name))
}
fn print_qpath(&mut self, path: &ast::Path, qself: &ast::QSelf, colons_before_params: bool) {
- self.s.word("<");
+ self.word("<");
self.print_type(&qself.ty);
if qself.position > 0 {
- self.s.space();
+ self.space();
self.word_space("as");
let depth = path.segments.len() - qself.position;
self.print_path(path, false, depth);
}
- self.s.word(">");
+ self.word(">");
for item_segment in &path.segments[qself.position..] {
- self.s.word("::");
+ self.word("::");
self.print_ident(item_segment.ident);
if let Some(ref args) = item_segment.args {
self.print_generic_args(args, colons_before_params)
@@ -2385,7 +2414,7 @@ impl<'a> State<'a> {
/* Pat isn't normalized, but the beauty of it
is that it doesn't matter */
match pat.kind {
- PatKind::Wild => self.s.word("_"),
+ PatKind::Wild => self.word("_"),
PatKind::Ident(binding_mode, ident, ref sub) => {
match binding_mode {
ast::BindingMode::ByRef(mutbl) => {
@@ -2399,8 +2428,8 @@ impl<'a> State<'a> {
}
self.print_ident(ident);
if let Some(ref p) = *sub {
- self.s.space();
- self.s.word_space("@");
+ self.space();
+ self.word_space("@");
self.print_pat(p);
}
}
@@ -2411,11 +2440,11 @@ impl<'a> State<'a> {
self.print_path(path, true, 0);
}
self.popen();
- self.commasep(Inconsistent, &elts[..], |s, p| s.print_pat(p));
+ self.commasep(Inconsistent, &elts, |s, p| s.print_pat(p));
self.pclose();
}
PatKind::Or(ref pats) => {
- self.strsep("|", true, Inconsistent, &pats[..], |s, p| s.print_pat(p));
+ self.strsep("|", true, Inconsistent, &pats, |s, p| s.print_pat(p));
}
PatKind::Path(None, ref path) => {
self.print_path(path, true, 0);
@@ -2433,7 +2462,7 @@ impl<'a> State<'a> {
self.word_space("{");
self.commasep_cmnt(
Consistent,
- &fields[..],
+ &fields,
|s, f| {
s.cbox(INDENT_UNIT);
if !f.is_shorthand {
@@ -2449,27 +2478,27 @@ impl<'a> State<'a> {
if !fields.is_empty() {
self.word_space(",");
}
- self.s.word("..");
+ self.word("..");
}
- self.s.space();
- self.s.word("}");
+ self.space();
+ self.word("}");
}
PatKind::Tuple(ref elts) => {
self.popen();
- self.commasep(Inconsistent, &elts[..], |s, p| s.print_pat(p));
+ self.commasep(Inconsistent, &elts, |s, p| s.print_pat(p));
if elts.len() == 1 {
- self.s.word(",");
+ self.word(",");
}
self.pclose();
}
PatKind::Box(ref inner) => {
- self.s.word("box ");
+ self.word("box ");
self.print_pat(inner);
}
PatKind::Ref(ref inner, mutbl) => {
- self.s.word("&");
+ self.word("&");
if mutbl == ast::Mutability::Mut {
- self.s.word("mut ");
+ self.word("mut ");
}
if let PatKind::Ident(ast::BindingMode::ByValue(ast::Mutability::Mut), ..) =
inner.kind
@@ -2485,23 +2514,23 @@ impl<'a> State<'a> {
PatKind::Range(ref begin, ref end, Spanned { node: ref end_kind, .. }) => {
if let Some(e) = begin {
self.print_expr(e);
- self.s.space();
+ self.space();
}
match *end_kind {
- RangeEnd::Included(RangeSyntax::DotDotDot) => self.s.word("..."),
- RangeEnd::Included(RangeSyntax::DotDotEq) => self.s.word("..="),
- RangeEnd::Excluded => self.s.word(".."),
+ RangeEnd::Included(RangeSyntax::DotDotDot) => self.word("..."),
+ RangeEnd::Included(RangeSyntax::DotDotEq) => self.word("..="),
+ RangeEnd::Excluded => self.word(".."),
}
if let Some(e) = end {
self.print_expr(e);
}
}
PatKind::Slice(ref elts) => {
- self.s.word("[");
- self.commasep(Inconsistent, &elts[..], |s, p| s.print_pat(p));
- self.s.word("]");
+ self.word("[");
+ self.commasep(Inconsistent, &elts, |s, p| s.print_pat(p));
+ self.word("]");
}
- PatKind::Rest => self.s.word(".."),
+ PatKind::Rest => self.word(".."),
PatKind::Paren(ref inner) => {
self.popen();
self.print_pat(inner);
@@ -2515,18 +2544,18 @@ impl<'a> State<'a> {
fn print_arm(&mut self, arm: &ast::Arm) {
// Note, I have no idea why this check is necessary, but here it is.
if arm.attrs.is_empty() {
- self.s.space();
+ self.space();
}
self.cbox(INDENT_UNIT);
self.ibox(0);
self.maybe_print_comment(arm.pat.span.lo());
self.print_outer_attributes(&arm.attrs);
self.print_pat(&arm.pat);
- self.s.space();
+ self.space();
if let Some(ref e) = arm.guard {
self.word_space("if");
self.print_expr(e);
- self.s.space();
+ self.space();
}
self.word_space("=>");
@@ -2542,13 +2571,13 @@ impl<'a> State<'a> {
// If it is a user-provided unsafe block, print a comma after it.
if let BlockCheckMode::Unsafe(ast::UserProvided) = blk.rules {
- self.s.word(",");
+ self.word(",");
}
}
_ => {
self.end(); // Close the ibox for the pattern.
self.print_expr(&arm.body);
- self.s.word(",");
+ self.word(",");
}
}
self.end(); // Close enclosing cbox.
@@ -2558,17 +2587,17 @@ impl<'a> State<'a> {
match explicit_self.node {
SelfKind::Value(m) => {
self.print_mutability(m, false);
- self.s.word("self")
+ self.word("self")
}
SelfKind::Region(ref lt, m) => {
- self.s.word("&");
+ self.word("&");
self.print_opt_lifetime(lt);
self.print_mutability(m, false);
- self.s.word("self")
+ self.word("self")
}
SelfKind::Explicit(ref typ, m) => {
self.print_mutability(m, false);
- self.s.word("self");
+ self.word("self");
self.word_space(":");
self.print_type(typ)
}
@@ -2595,7 +2624,7 @@ impl<'a> State<'a> {
self.nbsp();
self.print_block_with_attrs(body, attrs);
} else {
- self.s.word(";");
+ self.word(";");
}
}
@@ -2646,7 +2675,7 @@ impl<'a> State<'a> {
pub fn print_type_bounds(&mut self, prefix: &'static str, bounds: &[ast::GenericBound]) {
if !bounds.is_empty() {
- self.s.word(prefix);
+ self.word(prefix);
let mut first = true;
for bound in bounds {
if !(first && prefix.is_empty()) {
@@ -2661,7 +2690,7 @@ impl<'a> State<'a> {
match bound {
GenericBound::Trait(tref, modifier) => {
if modifier == &TraitBoundModifier::Maybe {
- self.s.word("?");
+ self.word("?");
}
self.print_poly_trait_ref(tref);
}
@@ -2682,10 +2711,10 @@ impl<'a> State<'a> {
) {
self.print_lifetime(lifetime);
if !bounds.is_empty() {
- self.s.word(": ");
+ self.word(": ");
for (i, bound) in bounds.iter().enumerate() {
if i != 0 {
- self.s.word(" + ");
+ self.word(" + ");
}
match bound {
ast::GenericBound::Outlives(lt) => self.print_lifetime(*lt),
@@ -2700,7 +2729,7 @@ impl<'a> State<'a> {
return;
}
- self.s.word("<");
+ self.word("<");
self.commasep(Inconsistent, &generic_params, |s, param| {
s.print_outer_attributes_inline(&param.attrs);
@@ -2714,7 +2743,7 @@ impl<'a> State<'a> {
s.print_ident(param.ident);
s.print_type_bounds(":", &param.bounds);
if let Some(ref default) = default {
- s.s.space();
+ s.space();
s.word_space("=");
s.print_type(default)
}
@@ -2722,12 +2751,12 @@ impl<'a> State<'a> {
ast::GenericParamKind::Const { ref ty, kw_span: _, ref default } => {
s.word_space("const");
s.print_ident(param.ident);
- s.s.space();
+ s.space();
s.word_space(":");
s.print_type(ty);
s.print_type_bounds(":", &param.bounds);
if let Some(ref default) = default {
- s.s.space();
+ s.space();
s.word_space("=");
s.print_expr(&default.value);
}
@@ -2735,7 +2764,7 @@ impl<'a> State<'a> {
}
});
- self.s.word(">");
+ self.word(">");
}
crate fn print_where_clause(&mut self, where_clause: &ast::WhereClause) {
@@ -2743,7 +2772,7 @@ impl<'a> State<'a> {
return;
}
- self.s.space();
+ self.space();
self.word_space("where");
for (i, predicate) in where_clause.predicates.iter().enumerate() {
@@ -2775,7 +2804,7 @@ impl<'a> State<'a> {
..
}) => {
self.print_type(lhs_ty);
- self.s.space();
+ self.space();
self.word_space("=");
self.print_type(rhs_ty);
}
@@ -2788,7 +2817,7 @@ impl<'a> State<'a> {
ast::UseTreeKind::Simple(rename, ..) => {
self.print_path(&tree.prefix, false, 0);
if let Some(rename) = rename {
- self.s.space();
+ self.space();
self.word_space("as");
self.print_ident(rename);
}
@@ -2796,21 +2825,21 @@ impl<'a> State<'a> {
ast::UseTreeKind::Glob => {
if !tree.prefix.segments.is_empty() {
self.print_path(&tree.prefix, false, 0);
- self.s.word("::");
+ self.word("::");
}
- self.s.word("*");
+ self.word("*");
}
ast::UseTreeKind::Nested(ref items) => {
if tree.prefix.segments.is_empty() {
- self.s.word("{");
+ self.word("{");
} else {
self.print_path(&tree.prefix, false, 0);
- self.s.word("::{");
+ self.word("::{");
}
- self.commasep(Inconsistent, &items[..], |this, &(ref tree, _)| {
+ self.commasep(Inconsistent, &items, |this, &(ref tree, _)| {
this.print_use_tree(tree)
});
- self.s.word("}");
+ self.word("}");
}
}
}
@@ -2849,8 +2878,8 @@ impl<'a> State<'a> {
};
if !invalid {
self.print_pat(&input.pat);
- self.s.word(":");
- self.s.space();
+ self.word(":");
+ self.space();
}
self.print_type(&input.ty);
}
@@ -2880,7 +2909,7 @@ impl<'a> State<'a> {
) {
self.ibox(INDENT_UNIT);
if !generic_params.is_empty() {
- self.s.word("for");
+ self.word("for");
self.print_generic_params(generic_params);
}
let generics = ast::Generics {
@@ -2897,29 +2926,6 @@ impl<'a> State<'a> {
self.end();
}
- crate fn maybe_print_trailing_comment(
- &mut self,
- span: rustc_span::Span,
- next_pos: Option<BytePos>,
- ) {
- if let Some(cmnts) = self.comments() {
- if let Some(cmnt) = cmnts.trailing_comment(span, next_pos) {
- self.print_comment(&cmnt);
- }
- }
- }
-
- crate fn print_remaining_comments(&mut self) {
- // If there aren't any remaining comments, then we need to manually
- // make sure there is a line break at the end.
- if self.next_comment().is_none() {
- self.s.hardbreak();
- }
- while let Some(ref cmnt) = self.next_comment() {
- self.print_comment(cmnt);
- }
- }
-
crate fn print_fn_header_info(&mut self, header: ast::FnHeader) {
self.print_constness(header.constness);
self.print_asyncness(header.asyncness);
@@ -2937,7 +2943,7 @@ impl<'a> State<'a> {
}
}
- self.s.word("fn")
+ self.word("fn")
}
crate fn print_unsafety(&mut self, s: ast::Unsafe) {
diff --git a/compiler/rustc_attr/src/builtin.rs b/compiler/rustc_attr/src/builtin.rs
index 719caaabbbf..f441c105f70 100644
--- a/compiler/rustc_attr/src/builtin.rs
+++ b/compiler/rustc_attr/src/builtin.rs
@@ -519,8 +519,10 @@ pub fn eval_condition(
[NestedMetaItem::Literal(Lit { kind: LitKind::Str(sym, ..), span, .. })] => {
(sym, span)
}
- [NestedMetaItem::Literal(Lit { span, .. })
- | NestedMetaItem::MetaItem(MetaItem { span, .. })] => {
+ [
+ NestedMetaItem::Literal(Lit { span, .. })
+ | NestedMetaItem::MetaItem(MetaItem { span, .. }),
+ ] => {
sess.span_diagnostic
.struct_span_err(*span, "expected a version literal")
.emit();
diff --git a/compiler/rustc_borrowck/src/borrow_set.rs b/compiler/rustc_borrowck/src/borrow_set.rs
index 952e18c1e57..4a9904891ec 100644
--- a/compiler/rustc_borrowck/src/borrow_set.rs
+++ b/compiler/rustc_borrowck/src/borrow_set.rs
@@ -84,7 +84,7 @@ pub enum LocalsStateAtExit {
}
impl LocalsStateAtExit {
- fn build(
+ fn build<'tcx>(
locals_are_invalidated_at_exit: bool,
body: &Body<'tcx>,
move_data: &MoveData<'tcx>,
diff --git a/compiler/rustc_borrowck/src/dataflow.rs b/compiler/rustc_borrowck/src/dataflow.rs
index 7db8d4520d4..15372ec1534 100644
--- a/compiler/rustc_borrowck/src/dataflow.rs
+++ b/compiler/rustc_borrowck/src/dataflow.rs
@@ -5,7 +5,7 @@ use rustc_middle::ty::RegionVid;
use rustc_middle::ty::TyCtxt;
use rustc_mir_dataflow::impls::{EverInitializedPlaces, MaybeUninitializedPlaces};
use rustc_mir_dataflow::ResultsVisitable;
-use rustc_mir_dataflow::{self, fmt::DebugWithContext, GenKill};
+use rustc_mir_dataflow::{self, fmt::DebugWithContext, CallReturnPlaces, GenKill};
use rustc_mir_dataflow::{Analysis, Direction, Results};
use std::fmt;
use std::iter;
@@ -434,9 +434,7 @@ impl<'tcx> rustc_mir_dataflow::GenKillAnalysis<'tcx> for Borrows<'_, 'tcx> {
&self,
_trans: &mut impl GenKill<Self::Idx>,
_block: mir::BasicBlock,
- _func: &mir::Operand<'tcx>,
- _args: &[mir::Operand<'tcx>],
- _dest_place: mir::Place<'tcx>,
+ _return_places: CallReturnPlaces<'_, 'tcx>,
) {
}
}
diff --git a/compiler/rustc_borrowck/src/def_use.rs b/compiler/rustc_borrowck/src/def_use.rs
index 689ec249a2f..70acbc9ee2d 100644
--- a/compiler/rustc_borrowck/src/def_use.rs
+++ b/compiler/rustc_borrowck/src/def_use.rs
@@ -17,7 +17,7 @@ pub fn categorize(context: PlaceContext) -> Option<DefUse> {
PlaceContext::MutatingUse(MutatingUseContext::Store) |
// This is potentially both a def and a use...
- PlaceContext::MutatingUse(MutatingUseContext::AsmOutput) |
+ PlaceContext::MutatingUse(MutatingUseContext::LlvmAsmOutput) |
// We let Call define the result in both the success and
// unwind cases. This is not really correct, however it
@@ -26,6 +26,7 @@ pub fn categorize(context: PlaceContext) -> Option<DefUse> {
// the def in call only to the input from the success
// path and not the unwind path. -nmatsakis
PlaceContext::MutatingUse(MutatingUseContext::Call) |
+ PlaceContext::MutatingUse(MutatingUseContext::AsmOutput) |
PlaceContext::MutatingUse(MutatingUseContext::Yield) |
// Storage live and storage dead aren't proper defines, but we can ignore
diff --git a/compiler/rustc_borrowck/src/diagnostics/bound_region_errors.rs b/compiler/rustc_borrowck/src/diagnostics/bound_region_errors.rs
index 1bc9f8cf3cc..96326ef2d5a 100644
--- a/compiler/rustc_borrowck/src/diagnostics/bound_region_errors.rs
+++ b/compiler/rustc_borrowck/src/diagnostics/bound_region_errors.rs
@@ -31,7 +31,7 @@ enum UniverseInfoInner<'tcx> {
Other,
}
-impl UniverseInfo<'tcx> {
+impl<'tcx> UniverseInfo<'tcx> {
crate fn other() -> UniverseInfo<'tcx> {
UniverseInfo(UniverseInfoInner::Other)
}
@@ -191,7 +191,7 @@ struct PredicateQuery<'tcx> {
base_universe: ty::UniverseIndex,
}
-impl TypeOpInfo<'tcx> for PredicateQuery<'tcx> {
+impl<'tcx> TypeOpInfo<'tcx> for PredicateQuery<'tcx> {
fn fallback_error(&self, tcx: TyCtxt<'tcx>, span: Span) -> DiagnosticBuilder<'tcx> {
let mut err = tcx.sess.struct_span_err(span, "higher-ranked lifetime error");
err.note(&format!("could not prove {}", self.canonical_query.value.value.predicate));
@@ -231,7 +231,7 @@ struct NormalizeQuery<'tcx, T> {
base_universe: ty::UniverseIndex,
}
-impl<T> TypeOpInfo<'tcx> for NormalizeQuery<'tcx, T>
+impl<'tcx, T> TypeOpInfo<'tcx> for NormalizeQuery<'tcx, T>
where
T: Copy + fmt::Display + TypeFoldable<'tcx> + 'tcx,
{
@@ -291,7 +291,7 @@ struct AscribeUserTypeQuery<'tcx> {
base_universe: ty::UniverseIndex,
}
-impl TypeOpInfo<'tcx> for AscribeUserTypeQuery<'tcx> {
+impl<'tcx> TypeOpInfo<'tcx> for AscribeUserTypeQuery<'tcx> {
fn fallback_error(&self, tcx: TyCtxt<'tcx>, span: Span) -> DiagnosticBuilder<'tcx> {
// FIXME: This error message isn't great, but it doesn't show up in the existing UI tests,
// and is only the fallback when the nice error fails. Consider improving this some more.
@@ -368,6 +368,7 @@ fn try_extract_error_from_fulfill_cx<'tcx>(
error_region,
cause.clone(),
placeholder_region,
+ vec![],
),
),
(Some(error_region), _) => NiceRegionError::new(
diff --git a/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs b/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs
index 46a3c0fa101..ab9ecec9715 100644
--- a/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs
+++ b/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs
@@ -15,16 +15,18 @@ use rustc_span::symbol::sym;
use rustc_span::{BytePos, MultiSpan, Span, DUMMY_SP};
use rustc_trait_selection::infer::InferCtxtExt;
+use crate::borrow_set::TwoPhaseActivation;
use crate::borrowck_errors;
+use crate::diagnostics::find_all_local_uses;
use crate::{
borrow_set::BorrowData, diagnostics::Instance, prefixes::IsPrefixOf,
InitializationRequiringAction, MirBorrowckCtxt, PrefixSet, WriteKind,
};
use super::{
- explain_borrow::BorrowExplanation, FnSelfUseKind, IncludingDowncast, RegionName,
- RegionNameSource, UseSpans,
+ explain_borrow::{BorrowExplanation, LaterUseKind},
+ FnSelfUseKind, IncludingDowncast, RegionName, RegionNameSource, UseSpans,
};
#[derive(Debug)]
@@ -768,9 +770,92 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
Some((issued_span, span)),
);
+ self.suggest_using_local_if_applicable(
+ &mut err,
+ location,
+ (place, span),
+ gen_borrow_kind,
+ issued_borrow,
+ explanation,
+ );
+
err
}
+ #[instrument(level = "debug", skip(self, err))]
+ fn suggest_using_local_if_applicable(
+ &self,
+ err: &mut DiagnosticBuilder<'_>,
+ location: Location,
+ (place, span): (Place<'tcx>, Span),
+ gen_borrow_kind: BorrowKind,
+ issued_borrow: &BorrowData<'tcx>,
+ explanation: BorrowExplanation,
+ ) {
+ let used_in_call =
+ matches!(explanation, BorrowExplanation::UsedLater(LaterUseKind::Call, _call_span, _));
+ if !used_in_call {
+ debug!("not later used in call");
+ return;
+ }
+
+ let outer_call_loc =
+ if let TwoPhaseActivation::ActivatedAt(loc) = issued_borrow.activation_location {
+ loc
+ } else {
+ issued_borrow.reserve_location
+ };
+ let outer_call_stmt = self.body.stmt_at(outer_call_loc);
+
+ let inner_param_location = location;
+ let Some(inner_param_stmt) = self.body.stmt_at(inner_param_location).left() else {
+ debug!("`inner_param_location` {:?} is not for a statement", inner_param_location);
+ return;
+ };
+ let Some(&inner_param) = inner_param_stmt.kind.as_assign().map(|(p, _)| p) else {
+ debug!(
+ "`inner_param_location` {:?} is not for an assignment: {:?}",
+ inner_param_location, inner_param_stmt
+ );
+ return;
+ };
+ let inner_param_uses = find_all_local_uses::find(self.body, inner_param.local);
+ let Some((inner_call_loc,inner_call_term)) = inner_param_uses.into_iter().find_map(|loc| {
+ let Either::Right(term) = self.body.stmt_at(loc) else {
+ debug!("{:?} is a statement, so it can't be a call", loc);
+ return None;
+ };
+ let TerminatorKind::Call { args, .. } = &term.kind else {
+ debug!("not a call: {:?}", term);
+ return None;
+ };
+ debug!("checking call args for uses of inner_param: {:?}", args);
+ if args.contains(&Operand::Move(inner_param)) {
+ Some((loc,term))
+ } else {
+ None
+ }
+ }) else {
+ debug!("no uses of inner_param found as a by-move call arg");
+ return;
+ };
+ debug!("===> outer_call_loc = {:?}, inner_call_loc = {:?}", outer_call_loc, inner_call_loc);
+
+ let inner_call_span = inner_call_term.source_info.span;
+ let outer_call_span = outer_call_stmt.either(|s| s.source_info, |t| t.source_info).span;
+ if outer_call_span == inner_call_span || !outer_call_span.contains(inner_call_span) {
+ // FIXME: This stops the suggestion in some cases where it should be emitted.
+ // Fix the spans for those cases so it's emitted correctly.
+ debug!(
+ "outer span {:?} does not strictly contain inner span {:?}",
+ outer_call_span, inner_call_span
+ );
+ return;
+ }
+ err.span_help(inner_call_span, "try adding a local storing this argument...");
+ err.span_help(outer_call_span, "...and then using that local as the argument to this call");
+ }
+
fn suggest_split_at_mut_if_applicable(
&self,
err: &mut DiagnosticBuilder<'_>,
@@ -977,9 +1062,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
Some(ref name),
BorrowExplanation::MustBeValidFor {
category:
- category
- @
- (ConstraintCategory::Return(_)
+ category @ (ConstraintCategory::Return(_)
| ConstraintCategory::CallArgument
| ConstraintCategory::OpaqueType),
from_closure: false,
@@ -1515,8 +1598,8 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
location: Location,
mpi: MovePathIndex,
) -> (Vec<MoveSite>, Vec<Location>) {
- fn predecessor_locations(
- body: &'a mir::Body<'tcx>,
+ fn predecessor_locations<'a>(
+ body: &'a mir::Body<'_>,
location: Location,
) -> impl Iterator<Item = Location> + 'a {
if location.statement_index == 0 {
diff --git a/compiler/rustc_borrowck/src/diagnostics/find_all_local_uses.rs b/compiler/rustc_borrowck/src/diagnostics/find_all_local_uses.rs
new file mode 100644
index 00000000000..49d9caae711
--- /dev/null
+++ b/compiler/rustc_borrowck/src/diagnostics/find_all_local_uses.rs
@@ -0,0 +1,26 @@
+use std::collections::BTreeSet;
+
+use rustc_middle::mir::visit::{PlaceContext, Visitor};
+use rustc_middle::mir::{Body, Local, Location};
+
+/// Find all uses of (including assignments to) a [`Local`].
+///
+/// Uses `BTreeSet` so output is deterministic.
+pub(super) fn find<'tcx>(body: &Body<'tcx>, local: Local) -> BTreeSet<Location> {
+ let mut visitor = AllLocalUsesVisitor { for_local: local, uses: BTreeSet::default() };
+ visitor.visit_body(body);
+ visitor.uses
+}
+
+struct AllLocalUsesVisitor {
+ for_local: Local,
+ uses: BTreeSet<Location>,
+}
+
+impl<'tcx> Visitor<'tcx> for AllLocalUsesVisitor {
+ fn visit_local(&mut self, local: &Local, _context: PlaceContext, location: Location) {
+ if *local == self.for_local {
+ self.uses.insert(location);
+ }
+ }
+}
diff --git a/compiler/rustc_borrowck/src/diagnostics/mod.rs b/compiler/rustc_borrowck/src/diagnostics/mod.rs
index 79623e26eb7..46c85dd6d35 100644
--- a/compiler/rustc_borrowck/src/diagnostics/mod.rs
+++ b/compiler/rustc_borrowck/src/diagnostics/mod.rs
@@ -19,6 +19,7 @@ use rustc_target::abi::VariantIdx;
use super::borrow_set::BorrowData;
use super::MirBorrowckCtxt;
+mod find_all_local_uses;
mod find_use;
mod outlives_suggestion;
mod region_name;
@@ -408,7 +409,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
/// Add a note that a type does not implement `Copy`
pub(super) fn note_type_does_not_implement_copy(
&self,
- err: &mut DiagnosticBuilder<'a>,
+ err: &mut DiagnosticBuilder<'_>,
place_desc: &str,
ty: Ty<'tcx>,
span: Option<Span>,
@@ -732,21 +733,19 @@ pub(super) enum BorrowedContentSource<'tcx> {
OverloadedIndex(Ty<'tcx>),
}
-impl BorrowedContentSource<'tcx> {
+impl<'tcx> BorrowedContentSource<'tcx> {
pub(super) fn describe_for_unnamed_place(&self, tcx: TyCtxt<'_>) -> String {
match *self {
BorrowedContentSource::DerefRawPointer => "a raw pointer".to_string(),
BorrowedContentSource::DerefSharedRef => "a shared reference".to_string(),
BorrowedContentSource::DerefMutableRef => "a mutable reference".to_string(),
- BorrowedContentSource::OverloadedDeref(ty) => match ty.kind() {
- ty::Adt(def, _) if tcx.is_diagnostic_item(sym::Rc, def.did) => {
- "an `Rc`".to_string()
- }
- ty::Adt(def, _) if tcx.is_diagnostic_item(sym::Arc, def.did) => {
- "an `Arc`".to_string()
- }
- _ => format!("dereference of `{}`", ty),
- },
+ BorrowedContentSource::OverloadedDeref(ty) => ty
+ .ty_adt_def()
+ .and_then(|adt| match tcx.get_diagnostic_name(adt.did)? {
+ name @ (sym::Rc | sym::Arc) => Some(format!("an `{}`", name)),
+ _ => None,
+ })
+ .unwrap_or_else(|| format!("dereference of `{}`", ty)),
BorrowedContentSource::OverloadedIndex(ty) => format!("index of `{}`", ty),
}
}
@@ -770,15 +769,13 @@ impl BorrowedContentSource<'tcx> {
BorrowedContentSource::DerefMutableRef => {
bug!("describe_for_immutable_place: DerefMutableRef isn't immutable")
}
- BorrowedContentSource::OverloadedDeref(ty) => match ty.kind() {
- ty::Adt(def, _) if tcx.is_diagnostic_item(sym::Rc, def.did) => {
- "an `Rc`".to_string()
- }
- ty::Adt(def, _) if tcx.is_diagnostic_item(sym::Arc, def.did) => {
- "an `Arc`".to_string()
- }
- _ => format!("a dereference of `{}`", ty),
- },
+ BorrowedContentSource::OverloadedDeref(ty) => ty
+ .ty_adt_def()
+ .and_then(|adt| match tcx.get_diagnostic_name(adt.did)? {
+ name @ (sym::Rc | sym::Arc) => Some(format!("an `{}`", name)),
+ _ => None,
+ })
+ .unwrap_or_else(|| format!("dereference of `{}`", ty)),
BorrowedContentSource::OverloadedIndex(ty) => format!("an index of `{}`", ty),
}
}
@@ -960,8 +957,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
_ => None,
});
let is_option_or_result = parent_self_ty.map_or(false, |def_id| {
- tcx.is_diagnostic_item(sym::Option, def_id)
- || tcx.is_diagnostic_item(sym::Result, def_id)
+ matches!(tcx.get_diagnostic_name(def_id), Some(sym::Option | sym::Result))
});
FnSelfUseKind::Normal { self_arg, implicit_into_iter, is_option_or_result }
});
diff --git a/compiler/rustc_borrowck/src/diagnostics/mutability_errors.rs b/compiler/rustc_borrowck/src/diagnostics/mutability_errors.rs
index 46e2a99a0d0..b5dad5ccdea 100644
--- a/compiler/rustc_borrowck/src/diagnostics/mutability_errors.rs
+++ b/compiler/rustc_borrowck/src/diagnostics/mutability_errors.rs
@@ -165,10 +165,13 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
PlaceRef {
local: _,
projection:
- [.., ProjectionElem::Index(_)
- | ProjectionElem::ConstantIndex { .. }
- | ProjectionElem::Subslice { .. }
- | ProjectionElem::Downcast(..)],
+ [
+ ..,
+ ProjectionElem::Index(_)
+ | ProjectionElem::ConstantIndex { .. }
+ | ProjectionElem::Subslice { .. }
+ | ProjectionElem::Downcast(..),
+ ],
} => bug!("Unexpected immutable place."),
}
@@ -217,19 +220,24 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
PlaceRef {
local,
projection:
- [proj_base @ .., ProjectionElem::Deref, ProjectionElem::Field(field, _), ProjectionElem::Deref],
+ [
+ proj_base @ ..,
+ ProjectionElem::Deref,
+ ProjectionElem::Field(field, _),
+ ProjectionElem::Deref,
+ ],
} => {
err.span_label(span, format!("cannot {ACT}", ACT = act));
- if let Some((span, message)) = annotate_struct_field(
+ if let Some(span) = get_mut_span_in_struct_field(
self.infcx.tcx,
Place::ty_from(local, proj_base, self.body, self.infcx.tcx).ty,
field,
) {
- err.span_suggestion(
+ err.span_suggestion_verbose(
span,
"consider changing this to be mutable",
- message,
+ " mut ".into(),
Applicability::MaybeIncorrect,
);
}
@@ -447,16 +455,20 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
// check if the RHS is from desugaring
let opt_assignment_rhs_span =
self.body.find_assignments(local).first().map(|&location| {
- let stmt = &self.body[location.block].statements
- [location.statement_index];
- match stmt.kind {
- mir::StatementKind::Assign(box (
- _,
- mir::Rvalue::Use(mir::Operand::Copy(place)),
- )) => {
- self.body.local_decls[place.local].source_info.span
- }
- _ => self.body.source_info(location).span,
+ if let Some(mir::Statement {
+ source_info: _,
+ kind:
+ mir::StatementKind::Assign(box (
+ _,
+ mir::Rvalue::Use(mir::Operand::Copy(place)),
+ )),
+ }) = self.body[location.block]
+ .statements
+ .get(location.statement_index)
+ {
+ self.body.local_decls[place.local].source_info.span
+ } else {
+ self.body.source_info(location).span
}
});
match opt_assignment_rhs_span.and_then(|s| s.desugaring_kind()) {
@@ -735,7 +747,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
HirId, ImplItem, ImplItemKind, Item, ItemKind,
};
- fn maybe_body_id_of_fn(hir_map: &Map<'tcx>, id: HirId) -> Option<BodyId> {
+ fn maybe_body_id_of_fn(hir_map: &Map<'_>, id: HirId) -> Option<BodyId> {
match hir_map.find(id) {
Some(Node::Item(Item { kind: ItemKind::Fn(_, _, body_id), .. }))
| Some(Node::ImplItem(ImplItem { kind: ImplItemKind::Fn(_, body_id), .. })) => {
@@ -759,11 +771,14 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
kind:
Call(
_,
- [Expr {
- kind: MethodCall(path_segment, ..),
- hir_id,
- ..
- }, ..],
+ [
+ Expr {
+ kind: MethodCall(path_segment, ..),
+ hir_id,
+ ..
+ },
+ ..,
+ ],
),
..
},
@@ -1044,18 +1059,18 @@ fn is_closure_or_generator(ty: Ty<'_>) -> bool {
ty.is_closure() || ty.is_generator()
}
-/// Adds a suggestion to a struct definition given a field access to a local.
-/// This function expects the local to be a reference to a struct in order to produce a suggestion.
+/// Given a field that needs to be mutable, returns a span where the " mut " could go.
+/// This function expects the local to be a reference to a struct in order to produce a span.
///
/// ```text
-/// LL | s: &'a String
-/// | ---------- use `&'a mut String` here to make mutable
+/// LL | s: &'a String
+/// | ^^^ returns a span taking up the space here
/// ```
-fn annotate_struct_field(
+fn get_mut_span_in_struct_field<'tcx>(
tcx: TyCtxt<'tcx>,
ty: Ty<'tcx>,
field: &mir::Field,
-) -> Option<(Span, String)> {
+) -> Option<Span> {
// Expect our local to be a reference to a struct of some kind.
if let ty::Ref(_, ty, _) = ty.kind() {
if let ty::Adt(def, _) = ty.kind() {
@@ -1066,25 +1081,10 @@ fn annotate_struct_field(
// Now we're dealing with the actual struct that we're going to suggest a change to,
// we can expect a field that is an immutable reference to a type.
if let hir::Node::Field(field) = node {
- if let hir::TyKind::Rptr(
- lifetime,
- hir::MutTy { mutbl: hir::Mutability::Not, ref ty },
- ) = field.ty.kind
+ if let hir::TyKind::Rptr(lifetime, hir::MutTy { mutbl: hir::Mutability::Not, ty }) =
+ field.ty.kind
{
- // Get the snippets in two parts - the named lifetime (if there is one) and
- // type being referenced, that way we can reconstruct the snippet without loss
- // of detail.
- let type_snippet = tcx.sess.source_map().span_to_snippet(ty.span).ok()?;
- let lifetime_snippet = if !lifetime.is_elided() {
- format!("{} ", tcx.sess.source_map().span_to_snippet(lifetime.span).ok()?)
- } else {
- String::new()
- };
-
- return Some((
- field.ty.span,
- format!("&{}mut {}", lifetime_snippet, &*type_snippet,),
- ));
+ return Some(lifetime.span.between(ty.span));
}
}
}
diff --git a/compiler/rustc_borrowck/src/diagnostics/region_name.rs b/compiler/rustc_borrowck/src/diagnostics/region_name.rs
index 5edb52b0b65..80f5f77a025 100644
--- a/compiler/rustc_borrowck/src/diagnostics/region_name.rs
+++ b/compiler/rustc_borrowck/src/diagnostics/region_name.rs
@@ -584,7 +584,7 @@ impl<'tcx> MirBorrowckCtxt<'_, 'tcx> {
Some(RegionNameHighlight::MatchedAdtAndSegment(lifetime_span))
}
- hir::LifetimeName::ImplicitObjectLifetimeDefault | hir::LifetimeName::Implicit => {
+ hir::LifetimeName::ImplicitObjectLifetimeDefault | hir::LifetimeName::Implicit(_) => {
// In this case, the user left off the lifetime; so
// they wrote something like:
//
@@ -769,20 +769,24 @@ impl<'tcx> MirBorrowckCtxt<'_, 'tcx> {
let opaque_ty = hir.item(id);
if let hir::ItemKind::OpaqueTy(hir::OpaqueTy {
bounds:
- [hir::GenericBound::LangItemTrait(
- hir::LangItem::Future,
- _,
- _,
- hir::GenericArgs {
- bindings:
- [hir::TypeBinding {
- ident: Ident { name: sym::Output, .. },
- kind: hir::TypeBindingKind::Equality { ty },
- ..
- }],
- ..
- },
- )],
+ [
+ hir::GenericBound::LangItemTrait(
+ hir::LangItem::Future,
+ _,
+ _,
+ hir::GenericArgs {
+ bindings:
+ [
+ hir::TypeBinding {
+ ident: Ident { name: sym::Output, .. },
+ kind: hir::TypeBindingKind::Equality { ty },
+ ..
+ },
+ ],
+ ..
+ },
+ ),
+ ],
..
}) = opaque_ty.kind
{
diff --git a/compiler/rustc_borrowck/src/invalidation.rs b/compiler/rustc_borrowck/src/invalidation.rs
index efd34f4e0a5..c03e4d8a448 100644
--- a/compiler/rustc_borrowck/src/invalidation.rs
+++ b/compiler/rustc_borrowck/src/invalidation.rs
@@ -199,6 +199,7 @@ impl<'cx, 'tcx> Visitor<'tcx> for InvalidationGenerator<'cx, 'tcx> {
options: _,
line_spans: _,
destination: _,
+ cleanup: _,
} => {
for op in operands {
match *op {
diff --git a/compiler/rustc_borrowck/src/lib.rs b/compiler/rustc_borrowck/src/lib.rs
index 76d3a83b48d..63ffcb3ec45 100644
--- a/compiler/rustc_borrowck/src/lib.rs
+++ b/compiler/rustc_borrowck/src/lib.rs
@@ -3,9 +3,6 @@
#![feature(bool_to_option)]
#![feature(box_patterns)]
#![feature(crate_visibility_modifier)]
-#![cfg_attr(bootstrap, feature(format_args_capture))]
-#![feature(in_band_lifetimes)]
-#![feature(iter_zip)]
#![feature(let_else)]
#![feature(min_specialization)]
#![feature(stmt_expr_attributes)]
@@ -792,6 +789,7 @@ impl<'cx, 'tcx> rustc_mir_dataflow::ResultsVisitor<'cx, 'tcx> for MirBorrowckCtx
options: _,
line_spans: _,
destination: _,
+ cleanup: _,
} => {
for op in operands {
match *op {
diff --git a/compiler/rustc_borrowck/src/member_constraints.rs b/compiler/rustc_borrowck/src/member_constraints.rs
index f22d355e613..0fe44328fd9 100644
--- a/compiler/rustc_borrowck/src/member_constraints.rs
+++ b/compiler/rustc_borrowck/src/member_constraints.rs
@@ -53,7 +53,7 @@ rustc_index::newtype_index! {
}
}
-impl Default for MemberConstraintSet<'tcx, ty::RegionVid> {
+impl Default for MemberConstraintSet<'_, ty::RegionVid> {
fn default() -> Self {
Self {
first_constraints: Default::default(),
@@ -97,7 +97,7 @@ impl<'tcx> MemberConstraintSet<'tcx, ty::RegionVid> {
}
}
-impl<R1> MemberConstraintSet<'tcx, R1>
+impl<'tcx, R1> MemberConstraintSet<'tcx, R1>
where
R1: Copy + Hash + Eq,
{
@@ -140,7 +140,7 @@ where
}
}
-impl<R> MemberConstraintSet<'tcx, R>
+impl<R> MemberConstraintSet<'_, R>
where
R: Copy + Hash + Eq,
{
diff --git a/compiler/rustc_borrowck/src/path_utils.rs b/compiler/rustc_borrowck/src/path_utils.rs
index d5d00b467ee..b2c8dfc82c2 100644
--- a/compiler/rustc_borrowck/src/path_utils.rs
+++ b/compiler/rustc_borrowck/src/path_utils.rs
@@ -141,7 +141,7 @@ pub(super) fn borrow_of_local_data(place: Place<'_>) -> bool {
/// then returns the index of the field being projected. Note that this closure will always
/// be `self` in the current MIR, because that is the only time we directly access the fields
/// of a closure type.
-pub(crate) fn is_upvar_field_projection(
+pub(crate) fn is_upvar_field_projection<'tcx>(
tcx: TyCtxt<'tcx>,
upvars: &[Upvar<'tcx>],
place_ref: PlaceRef<'tcx>,
diff --git a/compiler/rustc_borrowck/src/region_infer/opaque_types.rs b/compiler/rustc_borrowck/src/region_infer/opaque_types.rs
index 4eb7be542e7..76b3be7976c 100644
--- a/compiler/rustc_borrowck/src/region_infer/opaque_types.rs
+++ b/compiler/rustc_borrowck/src/region_infer/opaque_types.rs
@@ -173,7 +173,7 @@ fn check_opaque_type_parameter_valid(
// fn foo<l0..'ln>() -> foo::<'static..'static>::Foo<'l0..'lm>.
//
// which would error here on all of the `'static` args.
- OpaqueTyOrigin::FnReturn | OpaqueTyOrigin::AsyncFn => return true,
+ OpaqueTyOrigin::FnReturn(..) | OpaqueTyOrigin::AsyncFn(..) => return true,
// Check these
OpaqueTyOrigin::TyAlias => {}
}
diff --git a/compiler/rustc_borrowck/src/region_infer/values.rs b/compiler/rustc_borrowck/src/region_infer/values.rs
index 8819039c752..100ac578f92 100644
--- a/compiler/rustc_borrowck/src/region_infer/values.rs
+++ b/compiler/rustc_borrowck/src/region_infer/values.rs
@@ -60,6 +60,11 @@ impl RegionValueElements {
PointIndex::new(start_index)
}
+ /// Return the PointIndex for the block start of this index.
+ crate fn to_block_start(&self, index: PointIndex) -> PointIndex {
+ PointIndex::new(self.statements_before_block[self.basic_blocks[index]])
+ }
+
/// Converts a `PointIndex` back to a location. O(1).
crate fn to_location(&self, index: PointIndex) -> Location {
assert!(index.index() < self.num_points);
@@ -76,29 +81,6 @@ impl RegionValueElements {
crate fn point_in_range(&self, index: PointIndex) -> bool {
index.index() < self.num_points
}
-
- /// Pushes all predecessors of `index` onto `stack`.
- crate fn push_predecessors(
- &self,
- body: &Body<'_>,
- index: PointIndex,
- stack: &mut Vec<PointIndex>,
- ) {
- let Location { block, statement_index } = self.to_location(index);
- if statement_index == 0 {
- // If this is a basic block head, then the predecessors are
- // the terminators of other basic blocks
- stack.extend(
- body.predecessors()[block]
- .iter()
- .map(|&pred_bb| body.terminator_loc(pred_bb))
- .map(|pred_loc| self.point_from_location(pred_loc)),
- );
- } else {
- // Otherwise, the pred is just the previous statement
- stack.push(PointIndex::new(index.index() - 1));
- }
- }
}
rustc_index::newtype_index! {
diff --git a/compiler/rustc_borrowck/src/renumber.rs b/compiler/rustc_borrowck/src/renumber.rs
index 20567610f65..4b6cab24cdb 100644
--- a/compiler/rustc_borrowck/src/renumber.rs
+++ b/compiler/rustc_borrowck/src/renumber.rs
@@ -1,7 +1,7 @@
use rustc_index::vec::IndexVec;
use rustc_infer::infer::{InferCtxt, NllRegionVariableOrigin};
use rustc_middle::mir::visit::{MutVisitor, TyContext};
-use rustc_middle::mir::{Body, Location, PlaceElem, Promoted};
+use rustc_middle::mir::{Body, Location, Promoted};
use rustc_middle::ty::subst::SubstsRef;
use rustc_middle::ty::{self, Ty, TyCtxt, TypeFoldable};
@@ -62,22 +62,6 @@ impl<'a, 'tcx> MutVisitor<'tcx> for NllVisitor<'a, 'tcx> {
debug!(?ty);
}
- fn process_projection_elem(
- &mut self,
- elem: PlaceElem<'tcx>,
- _: Location,
- ) -> Option<PlaceElem<'tcx>> {
- if let PlaceElem::Field(field, ty) = elem {
- let new_ty = self.renumber_regions(ty);
-
- if new_ty != ty {
- return Some(PlaceElem::Field(field, new_ty));
- }
- }
-
- None
- }
-
#[instrument(skip(self), level = "debug")]
fn visit_substs(&mut self, substs: &mut SubstsRef<'tcx>, location: Location) {
*substs = self.renumber_regions(*substs);
diff --git a/compiler/rustc_borrowck/src/type_check/constraint_conversion.rs b/compiler/rustc_borrowck/src/type_check/constraint_conversion.rs
index ab1a7461b4b..a3b39591f8d 100644
--- a/compiler/rustc_borrowck/src/type_check/constraint_conversion.rs
+++ b/compiler/rustc_borrowck/src/type_check/constraint_conversion.rs
@@ -6,6 +6,7 @@ use rustc_infer::infer::region_constraints::{GenericKind, VerifyBound};
use rustc_infer::infer::{self, InferCtxt, SubregionOrigin};
use rustc_middle::mir::ConstraintCategory;
use rustc_middle::ty::subst::GenericArgKind;
+use rustc_middle::ty::TypeFoldable;
use rustc_middle::ty::{self, TyCtxt};
use rustc_span::DUMMY_SP;
@@ -95,11 +96,23 @@ impl<'a, 'tcx> ConstraintConversion<'a, 'tcx> {
self.add_outlives(r1_vid, r2_vid);
}
- GenericArgKind::Type(t1) => {
+ GenericArgKind::Type(mut t1) => {
// we don't actually use this for anything, but
// the `TypeOutlives` code needs an origin.
let origin = infer::RelateParamBound(DUMMY_SP, t1, None);
+ // Placeholder regions need to be converted now because it may
+ // create new region variables, which can't be done later when
+ // verifying these bounds.
+ if t1.has_placeholders() {
+ t1 = tcx.fold_regions(&t1, &mut false, |r, _| match *r {
+ ty::RegionKind::RePlaceholder(placeholder) => {
+ self.constraints.placeholder_region(self.infcx, placeholder)
+ }
+ _ => r,
+ });
+ }
+
TypeOutlives::new(
&mut *self,
tcx,
diff --git a/compiler/rustc_borrowck/src/type_check/free_region_relations.rs b/compiler/rustc_borrowck/src/type_check/free_region_relations.rs
index f71cf09ecf6..fec6bdf314b 100644
--- a/compiler/rustc_borrowck/src/type_check/free_region_relations.rs
+++ b/compiler/rustc_borrowck/src/type_check/free_region_relations.rs
@@ -58,7 +58,7 @@ crate struct CreateResult<'tcx> {
crate normalized_inputs_and_output: NormalizedInputsAndOutput<'tcx>,
}
-crate fn create(
+crate fn create<'tcx>(
infcx: &InferCtxt<'_, 'tcx>,
param_env: ty::ParamEnv<'tcx>,
implicit_region_bound: Option<ty::Region<'tcx>>,
@@ -81,7 +81,7 @@ crate fn create(
.create()
}
-impl UniversalRegionRelations<'tcx> {
+impl UniversalRegionRelations<'_> {
/// Records in the `outlives_relation` (and
/// `inverse_outlives_relation`) that `fr_a: fr_b`. Invoked by the
/// builder below.
@@ -110,7 +110,7 @@ impl UniversalRegionRelations<'tcx> {
/// outlives `fr` and (b) is not local.
///
/// (*) If there are multiple competing choices, we return all of them.
- crate fn non_local_upper_bounds(&'a self, fr: &'a RegionVid) -> Vec<&'a RegionVid> {
+ crate fn non_local_upper_bounds<'a>(&'a self, fr: &'a RegionVid) -> Vec<&'a RegionVid> {
debug!("non_local_upper_bound(fr={:?})", fr);
let res = self.non_local_bounds(&self.inverse_outlives, fr);
assert!(!res.is_empty(), "can't find an upper bound!?");
@@ -232,7 +232,7 @@ struct UniversalRegionRelationsBuilder<'this, 'tcx> {
region_bound_pairs: RegionBoundPairs<'tcx>,
}
-impl UniversalRegionRelationsBuilder<'cx, 'tcx> {
+impl<'tcx> UniversalRegionRelationsBuilder<'_, 'tcx> {
crate fn create(mut self) -> CreateResult<'tcx> {
let unnormalized_input_output_tys = self
.universal_regions
@@ -256,7 +256,6 @@ impl UniversalRegionRelationsBuilder<'cx, 'tcx> {
debug!("build: input_or_output={:?}", ty);
// We add implied bounds from both the unnormalized and normalized ty
// See issue #87748
- let constraints_implied_1 = self.add_implied_bounds(ty);
let TypeOpOutput { output: norm_ty, constraints: constraints1, .. } = self
.param_env
.and(type_op::normalize::Normalize::new(ty))
@@ -284,10 +283,9 @@ impl UniversalRegionRelationsBuilder<'cx, 'tcx> {
// }
// ```
// Both &Self::Bar and &() are WF
- let constraints_implied_2 =
- if ty != norm_ty { self.add_implied_bounds(norm_ty) } else { None };
+ let constraints_implied = self.add_implied_bounds(norm_ty);
normalized_inputs_and_output.push(norm_ty);
- constraints1.into_iter().chain(constraints_implied_1).chain(constraints_implied_2)
+ constraints1.into_iter().chain(constraints_implied)
})
.collect();
diff --git a/compiler/rustc_borrowck/src/type_check/input_output.rs b/compiler/rustc_borrowck/src/type_check/input_output.rs
index 92d2d04f23f..bc740de5150 100644
--- a/compiler/rustc_borrowck/src/type_check/input_output.rs
+++ b/compiler/rustc_borrowck/src/type_check/input_output.rs
@@ -117,9 +117,29 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
}
}
- assert!(body.yield_ty().is_some() == universal_regions.yield_ty.is_some());
- if let Some(mir_yield_ty) = body.yield_ty() {
- let ur_yield_ty = universal_regions.yield_ty.unwrap();
+ debug!(
+ "equate_inputs_and_outputs: body.yield_ty {:?}, universal_regions.yield_ty {:?}",
+ body.yield_ty(),
+ universal_regions.yield_ty
+ );
+
+ // We will not have a universal_regions.yield_ty if we yield (by accident)
+ // outside of a generator and return an `impl Trait`, so emit a delay_span_bug
+ // because we don't want to panic in an assert here if we've already got errors.
+ if body.yield_ty().is_some() != universal_regions.yield_ty.is_some() {
+ self.tcx().sess.delay_span_bug(
+ body.span,
+ &format!(
+ "Expected body to have yield_ty ({:?}) iff we have a UR yield_ty ({:?})",
+ body.yield_ty(),
+ universal_regions.yield_ty,
+ ),
+ );
+ }
+
+ if let (Some(mir_yield_ty), Some(ur_yield_ty)) =
+ (body.yield_ty(), universal_regions.yield_ty)
+ {
let yield_span = body.local_decls[RETURN_PLACE].source_info.span;
self.equate_normalized_input_or_output(ur_yield_ty, mir_yield_ty, yield_span);
}
diff --git a/compiler/rustc_borrowck/src/type_check/liveness/local_use_map.rs b/compiler/rustc_borrowck/src/type_check/liveness/local_use_map.rs
index 8b74abd94c0..dd23683fae8 100644
--- a/compiler/rustc_borrowck/src/type_check/liveness/local_use_map.rs
+++ b/compiler/rustc_borrowck/src/type_check/liveness/local_use_map.rs
@@ -152,7 +152,7 @@ impl LocalUseMapBuild<'_> {
}
}
-impl Visitor<'tcx> for LocalUseMapBuild<'_> {
+impl Visitor<'_> for LocalUseMapBuild<'_> {
fn visit_local(&mut self, &local: &Local, context: PlaceContext, location: Location) {
if self.locals_with_use_data[local] {
match def_use::categorize(context) {
diff --git a/compiler/rustc_borrowck/src/type_check/liveness/mod.rs b/compiler/rustc_borrowck/src/type_check/liveness/mod.rs
index 1e712354d6a..f18fe1f43d4 100644
--- a/compiler/rustc_borrowck/src/type_check/liveness/mod.rs
+++ b/compiler/rustc_borrowck/src/type_check/liveness/mod.rs
@@ -74,7 +74,7 @@ pub(super) fn generate<'mir, 'tcx>(
// to compute whether a variable `X` is live if that variable contains
// some region `R` in its type where `R` is not known to outlive a free
// region (i.e., where `R` may be valid for just a subset of the fn body).
-fn compute_live_locals(
+fn compute_live_locals<'tcx>(
tcx: TyCtxt<'tcx>,
free_regions: &FxHashSet<RegionVid>,
body: &Body<'tcx>,
@@ -104,7 +104,7 @@ fn compute_live_locals(
/// regions. For these regions, we do not need to compute
/// liveness, since the outlives constraints will ensure that they
/// are live over the whole fn body anyhow.
-fn regions_that_outlive_free_regions(
+fn regions_that_outlive_free_regions<'tcx>(
num_region_vars: usize,
universal_regions: &UniversalRegions<'tcx>,
constraint_set: &OutlivesConstraintSet<'tcx>,
diff --git a/compiler/rustc_borrowck/src/type_check/liveness/polonius.rs b/compiler/rustc_borrowck/src/type_check/liveness/polonius.rs
index 79ab8b713f9..ee067c4872f 100644
--- a/compiler/rustc_borrowck/src/type_check/liveness/polonius.rs
+++ b/compiler/rustc_borrowck/src/type_check/liveness/polonius.rs
@@ -53,7 +53,7 @@ impl UseFactsExtractor<'_> {
}
}
-impl Visitor<'tcx> for UseFactsExtractor<'_> {
+impl Visitor<'_> for UseFactsExtractor<'_> {
fn visit_local(&mut self, &local: &Local, context: PlaceContext, location: Location) {
match def_use::categorize(context) {
Some(DefUse::Def) => self.insert_def(local, location),
@@ -63,7 +63,7 @@ impl Visitor<'tcx> for UseFactsExtractor<'_> {
}
}
- fn visit_place(&mut self, place: &Place<'tcx>, context: PlaceContext, location: Location) {
+ fn visit_place(&mut self, place: &Place<'_>, context: PlaceContext, location: Location) {
self.super_place(place, context, location);
match context {
PlaceContext::NonMutatingUse(_) => {
@@ -82,7 +82,7 @@ impl Visitor<'tcx> for UseFactsExtractor<'_> {
}
}
-pub(super) fn populate_access_facts(
+pub(super) fn populate_access_facts<'tcx>(
typeck: &mut TypeChecker<'_, 'tcx>,
body: &Body<'tcx>,
location_table: &LocationTable,
@@ -123,7 +123,7 @@ pub(super) fn populate_access_facts(
// For every potentially drop()-touched region `region` in `local`'s type
// (`kind`), emit a Polonius `use_of_var_derefs_origin(local, origin)` fact.
-pub(super) fn add_drop_of_var_derefs_origin(
+pub(super) fn add_drop_of_var_derefs_origin<'tcx>(
typeck: &mut TypeChecker<'_, 'tcx>,
local: Local,
kind: &GenericArg<'tcx>,
diff --git a/compiler/rustc_borrowck/src/type_check/liveness/trace.rs b/compiler/rustc_borrowck/src/type_check/liveness/trace.rs
index 1671c7c627e..0969b9a508f 100644
--- a/compiler/rustc_borrowck/src/type_check/liveness/trace.rs
+++ b/compiler/rustc_borrowck/src/type_check/liveness/trace.rs
@@ -34,7 +34,7 @@ use crate::{
/// DROP-LIVE set are to the liveness sets for regions found in the
/// `dropck_outlives` result of the variable's type (in particular,
/// this respects `#[may_dangle]` annotations).
-pub(super) fn trace(
+pub(super) fn trace<'mir, 'tcx>(
typeck: &mut TypeChecker<'_, 'tcx>,
body: &Body<'tcx>,
elements: &Rc<RegionValueElements>,
@@ -119,7 +119,7 @@ struct LivenessResults<'me, 'typeck, 'flow, 'tcx> {
stack: Vec<PointIndex>,
}
-impl LivenessResults<'me, 'typeck, 'flow, 'tcx> {
+impl<'me, 'typeck, 'flow, 'tcx> LivenessResults<'me, 'typeck, 'flow, 'tcx> {
fn new(cx: LivenessContext<'me, 'typeck, 'flow, 'tcx>) -> Self {
let num_points = cx.elements.num_points();
LivenessResults {
@@ -205,12 +205,42 @@ impl LivenessResults<'me, 'typeck, 'flow, 'tcx> {
self.stack.extend(self.cx.local_use_map.uses(local));
while let Some(p) = self.stack.pop() {
- if self.defs.contains(p) {
+ // We are live in this block from the closest to us of:
+ //
+ // * Inclusively, the block start
+ // * Exclusively, the previous definition (if it's in this block)
+ // * Exclusively, the previous live_at setting (an optimization)
+ let block_start = self.cx.elements.to_block_start(p);
+ let previous_defs = self.defs.last_set_in(block_start..=p);
+ let previous_live_at = self.use_live_at.last_set_in(block_start..=p);
+
+ let exclusive_start = match (previous_defs, previous_live_at) {
+ (Some(a), Some(b)) => Some(std::cmp::max(a, b)),
+ (Some(a), None) | (None, Some(a)) => Some(a),
+ (None, None) => None,
+ };
+
+ if let Some(exclusive) = exclusive_start {
+ self.use_live_at.insert_range(exclusive + 1..=p);
+
+ // If we have a bound after the start of the block, we should
+ // not add the predecessors for this block.
continue;
- }
-
- if self.use_live_at.insert(p) {
- self.cx.elements.push_predecessors(self.cx.body, p, &mut self.stack)
+ } else {
+ // Add all the elements of this block.
+ self.use_live_at.insert_range(block_start..=p);
+
+ // Then add the predecessors for this block, which are the
+ // terminators of predecessor basic blocks. Push those onto the
+ // stack so that the next iteration(s) will process them.
+
+ let block = self.cx.elements.to_location(block_start).block;
+ self.stack.extend(
+ self.cx.body.predecessors()[block]
+ .iter()
+ .map(|&pred_bb| self.cx.body.terminator_loc(pred_bb))
+ .map(|pred_loc| self.cx.elements.point_from_location(pred_loc)),
+ );
}
}
}
@@ -388,7 +418,7 @@ impl LivenessResults<'me, 'typeck, 'flow, 'tcx> {
}
}
-impl LivenessContext<'_, '_, '_, 'tcx> {
+impl<'tcx> LivenessContext<'_, '_, '_, 'tcx> {
/// Returns `true` if the local variable (or some part of it) is initialized at the current
/// cursor position. Callers should call one of the `seek` methods immediately before to point
/// the cursor to the desired location.
diff --git a/compiler/rustc_borrowck/src/type_check/mod.rs b/compiler/rustc_borrowck/src/type_check/mod.rs
index da26d9c7b87..872a4321447 100644
--- a/compiler/rustc_borrowck/src/type_check/mod.rs
+++ b/compiler/rustc_borrowck/src/type_check/mod.rs
@@ -31,7 +31,7 @@ use rustc_middle::ty::fold::TypeFoldable;
use rustc_middle::ty::subst::{GenericArgKind, SubstsRef, UserSubsts};
use rustc_middle::ty::{
self, CanonicalUserTypeAnnotation, CanonicalUserTypeAnnotations, OpaqueTypeKey, RegionVid,
- ToPredicate, Ty, TyCtxt, UserType, UserTypeAnnotationIndex, WithConstness,
+ ToPredicate, Ty, TyCtxt, UserType, UserTypeAnnotationIndex,
};
use rustc_span::def_id::CRATE_DEF_ID;
use rustc_span::{Span, DUMMY_SP};
@@ -945,7 +945,7 @@ crate struct MirTypeckRegionConstraints<'tcx> {
crate type_tests: Vec<TypeTest<'tcx>>,
}
-impl MirTypeckRegionConstraints<'tcx> {
+impl<'tcx> MirTypeckRegionConstraints<'tcx> {
fn placeholder_region(
&mut self,
infcx: &InferCtxt<'_, 'tcx>,
@@ -1828,10 +1828,16 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
self.assert_iscleanup(body, block_data, unwind, true);
}
}
- TerminatorKind::InlineAsm { destination, .. } => {
+ TerminatorKind::InlineAsm { destination, cleanup, .. } => {
if let Some(target) = destination {
self.assert_iscleanup(body, block_data, target, is_cleanup);
}
+ if let Some(cleanup) = cleanup {
+ if is_cleanup {
+ span_mirbug!(self, block_data, "cleanup on cleanup block")
+ }
+ self.assert_iscleanup(body, block_data, cleanup, true);
+ }
}
}
}
diff --git a/compiler/rustc_borrowck/src/type_check/relate_tys.rs b/compiler/rustc_borrowck/src/type_check/relate_tys.rs
index 415d1abaa8b..cc3fe0a123c 100644
--- a/compiler/rustc_borrowck/src/type_check/relate_tys.rs
+++ b/compiler/rustc_borrowck/src/type_check/relate_tys.rs
@@ -51,7 +51,7 @@ struct NllTypeRelatingDelegate<'me, 'bccx, 'tcx> {
universe_info: UniverseInfo<'tcx>,
}
-impl NllTypeRelatingDelegate<'me, 'bccx, 'tcx> {
+impl<'me, 'bccx, 'tcx> NllTypeRelatingDelegate<'me, 'bccx, 'tcx> {
fn new(
type_checker: &'me mut TypeChecker<'bccx, 'tcx>,
locations: Locations,
@@ -62,7 +62,7 @@ impl NllTypeRelatingDelegate<'me, 'bccx, 'tcx> {
}
}
-impl TypeRelatingDelegate<'tcx> for NllTypeRelatingDelegate<'_, '_, 'tcx> {
+impl<'tcx> TypeRelatingDelegate<'tcx> for NllTypeRelatingDelegate<'_, '_, 'tcx> {
fn param_env(&self) -> ty::ParamEnv<'tcx> {
self.type_checker.param_env
}
diff --git a/compiler/rustc_builtin_macros/Cargo.toml b/compiler/rustc_builtin_macros/Cargo.toml
index fd34f947f72..9031c3b2ecf 100644
--- a/compiler/rustc_builtin_macros/Cargo.toml
+++ b/compiler/rustc_builtin_macros/Cargo.toml
@@ -15,6 +15,7 @@ rustc_data_structures = { path = "../rustc_data_structures" }
rustc_errors = { path = "../rustc_errors" }
rustc_feature = { path = "../rustc_feature" }
rustc_lexer = { path = "../rustc_lexer" }
+rustc_lint_defs = { path = "../rustc_lint_defs" }
rustc_parse = { path = "../rustc_parse" }
rustc_target = { path = "../rustc_target" }
rustc_session = { path = "../rustc_session" }
diff --git a/compiler/rustc_builtin_macros/src/asm.rs b/compiler/rustc_builtin_macros/src/asm.rs
index 41662f46f11..768cb99510f 100644
--- a/compiler/rustc_builtin_macros/src/asm.rs
+++ b/compiler/rustc_builtin_macros/src/asm.rs
@@ -8,13 +8,14 @@ use rustc_expand::base::{self, *};
use rustc_parse::parser::Parser;
use rustc_parse_format as parse;
use rustc_session::lint;
+use rustc_session::parse::ParseSess;
use rustc_span::symbol::Ident;
use rustc_span::symbol::{kw, sym, Symbol};
use rustc_span::{InnerSpan, Span};
use rustc_target::asm::InlineAsmArch;
use smallvec::smallvec;
-struct AsmArgs {
+pub struct AsmArgs {
templates: Vec<P<ast::Expr>>,
operands: Vec<(ast::InlineAsmOperand, Span)>,
named_args: FxHashMap<Symbol, usize>,
@@ -31,30 +32,30 @@ fn parse_args<'a>(
is_global_asm: bool,
) -> Result<AsmArgs, DiagnosticBuilder<'a>> {
let mut p = ecx.new_parser_from_tts(tts);
+ let sess = &ecx.sess.parse_sess;
+ parse_asm_args(&mut p, sess, sp, is_global_asm)
+}
+
+// Primarily public for rustfmt consumption.
+// Internal consumers should continue to leverage `expand_asm`/`expand__global_asm`
+pub fn parse_asm_args<'a>(
+ p: &mut Parser<'a>,
+ sess: &'a ParseSess,
+ sp: Span,
+ is_global_asm: bool,
+) -> Result<AsmArgs, DiagnosticBuilder<'a>> {
+ let diag = &sess.span_diagnostic;
if p.token == token::Eof {
- return Err(ecx.struct_span_err(sp, "requires at least a template string argument"));
+ return Err(diag.struct_span_err(sp, "requires at least a template string argument"));
}
// Detect use of the legacy llvm_asm! syntax (which used to be called asm!)
if !is_global_asm && p.look_ahead(1, |t| *t == token::Colon || *t == token::ModSep) {
let mut err =
- ecx.struct_span_err(sp, "the legacy LLVM-style asm! syntax is no longer supported");
+ diag.struct_span_err(sp, "the legacy LLVM-style asm! syntax is no longer supported");
err.note("consider migrating to the new asm! syntax specified in RFC 2873");
err.note("alternatively, switch to llvm_asm! to keep your code working as it is");
-
- // Find the span of the "asm!" so that we can offer an automatic suggestion
- let asm_span = sp.from_inner(InnerSpan::new(0, 4));
- if let Ok(s) = ecx.source_map().span_to_snippet(asm_span) {
- if s == "asm!" {
- err.span_suggestion(
- asm_span,
- "replace with",
- "llvm_asm!".into(),
- Applicability::MachineApplicable,
- );
- }
- }
return Err(err);
}
@@ -74,7 +75,7 @@ fn parse_args<'a>(
if !p.eat(&token::Comma) {
if allow_templates {
// After a template string, we always expect *only* a comma...
- let mut err = ecx.struct_span_err(p.token.span, "expected token: `,`");
+ let mut err = diag.struct_span_err(p.token.span, "expected token: `,`");
err.span_label(p.token.span, "expected `,`");
p.maybe_annotate_with_ascription(&mut err, false);
return Err(err);
@@ -89,14 +90,14 @@ fn parse_args<'a>(
// Parse clobber_abi
if p.eat_keyword(sym::clobber_abi) {
- parse_clobber_abi(&mut p, &mut args)?;
+ parse_clobber_abi(p, &mut args)?;
allow_templates = false;
continue;
}
// Parse options
if p.eat_keyword(sym::options) {
- parse_options(&mut p, &mut args, is_global_asm)?;
+ parse_options(p, &mut args, is_global_asm)?;
allow_templates = false;
continue;
}
@@ -116,25 +117,25 @@ fn parse_args<'a>(
let mut explicit_reg = false;
let op = if !is_global_asm && p.eat_keyword(kw::In) {
- let reg = parse_reg(&mut p, &mut explicit_reg)?;
+ let reg = parse_reg(p, &mut explicit_reg)?;
if p.eat_keyword(kw::Underscore) {
- let err = ecx.struct_span_err(p.token.span, "_ cannot be used for input operands");
+ let err = diag.struct_span_err(p.token.span, "_ cannot be used for input operands");
return Err(err);
}
let expr = p.parse_expr()?;
ast::InlineAsmOperand::In { reg, expr }
} else if !is_global_asm && p.eat_keyword(sym::out) {
- let reg = parse_reg(&mut p, &mut explicit_reg)?;
+ let reg = parse_reg(p, &mut explicit_reg)?;
let expr = if p.eat_keyword(kw::Underscore) { None } else { Some(p.parse_expr()?) };
ast::InlineAsmOperand::Out { reg, expr, late: false }
} else if !is_global_asm && p.eat_keyword(sym::lateout) {
- let reg = parse_reg(&mut p, &mut explicit_reg)?;
+ let reg = parse_reg(p, &mut explicit_reg)?;
let expr = if p.eat_keyword(kw::Underscore) { None } else { Some(p.parse_expr()?) };
ast::InlineAsmOperand::Out { reg, expr, late: true }
} else if !is_global_asm && p.eat_keyword(sym::inout) {
- let reg = parse_reg(&mut p, &mut explicit_reg)?;
+ let reg = parse_reg(p, &mut explicit_reg)?;
if p.eat_keyword(kw::Underscore) {
- let err = ecx.struct_span_err(p.token.span, "_ cannot be used for input operands");
+ let err = diag.struct_span_err(p.token.span, "_ cannot be used for input operands");
return Err(err);
}
let expr = p.parse_expr()?;
@@ -146,9 +147,9 @@ fn parse_args<'a>(
ast::InlineAsmOperand::InOut { reg, expr, late: false }
}
} else if !is_global_asm && p.eat_keyword(sym::inlateout) {
- let reg = parse_reg(&mut p, &mut explicit_reg)?;
+ let reg = parse_reg(p, &mut explicit_reg)?;
if p.eat_keyword(kw::Underscore) {
- let err = ecx.struct_span_err(p.token.span, "_ cannot be used for input operands");
+ let err = diag.struct_span_err(p.token.span, "_ cannot be used for input operands");
return Err(err);
}
let expr = p.parse_expr()?;
@@ -167,7 +168,7 @@ fn parse_args<'a>(
match expr.kind {
ast::ExprKind::Path(..) => {}
_ => {
- let err = ecx
+ let err = diag
.struct_span_err(expr.span, "argument to `sym` must be a path expression");
return Err(err);
}
@@ -186,7 +187,7 @@ fn parse_args<'a>(
} else {
"expected operand, clobber_abi, options, or additional template string"
};
- let mut err = ecx.struct_span_err(template.span, errstr);
+ let mut err = diag.struct_span_err(template.span, errstr);
err.span_label(template.span, errstr);
return Err(err);
}
@@ -206,31 +207,31 @@ fn parse_args<'a>(
// clobber_abi/options. We do this at the end once we have the full span
// of the argument available.
if !args.options_spans.is_empty() {
- ecx.struct_span_err(span, "arguments are not allowed after options")
+ diag.struct_span_err(span, "arguments are not allowed after options")
.span_labels(args.options_spans.clone(), "previous options")
.span_label(span, "argument")
.emit();
} else if let Some((_, abi_span)) = args.clobber_abis.last() {
- ecx.struct_span_err(span, "arguments are not allowed after clobber_abi")
+ diag.struct_span_err(span, "arguments are not allowed after clobber_abi")
.span_label(*abi_span, "clobber_abi")
.span_label(span, "argument")
.emit();
}
if explicit_reg {
if name.is_some() {
- ecx.struct_span_err(span, "explicit register arguments cannot have names").emit();
+ diag.struct_span_err(span, "explicit register arguments cannot have names").emit();
}
args.reg_args.insert(slot);
} else if let Some(name) = name {
if let Some(&prev) = args.named_args.get(&name) {
- ecx.struct_span_err(span, &format!("duplicate argument named `{}`", name))
+ diag.struct_span_err(span, &format!("duplicate argument named `{}`", name))
.span_label(args.operands[prev].1, "previously here")
.span_label(span, "duplicate argument")
.emit();
continue;
}
if !args.reg_args.is_empty() {
- let mut err = ecx.struct_span_err(
+ let mut err = diag.struct_span_err(
span,
"named arguments cannot follow explicit register arguments",
);
@@ -243,7 +244,7 @@ fn parse_args<'a>(
args.named_args.insert(name, slot);
} else {
if !args.named_args.is_empty() || !args.reg_args.is_empty() {
- let mut err = ecx.struct_span_err(
+ let mut err = diag.struct_span_err(
span,
"positional arguments cannot follow named arguments \
or explicit register arguments",
@@ -264,21 +265,21 @@ fn parse_args<'a>(
&& args.options.contains(ast::InlineAsmOptions::READONLY)
{
let spans = args.options_spans.clone();
- ecx.struct_span_err(spans, "the `nomem` and `readonly` options are mutually exclusive")
+ diag.struct_span_err(spans, "the `nomem` and `readonly` options are mutually exclusive")
.emit();
}
if args.options.contains(ast::InlineAsmOptions::PURE)
&& args.options.contains(ast::InlineAsmOptions::NORETURN)
{
let spans = args.options_spans.clone();
- ecx.struct_span_err(spans, "the `pure` and `noreturn` options are mutually exclusive")
+ diag.struct_span_err(spans, "the `pure` and `noreturn` options are mutually exclusive")
.emit();
}
if args.options.contains(ast::InlineAsmOptions::PURE)
&& !args.options.intersects(ast::InlineAsmOptions::NOMEM | ast::InlineAsmOptions::READONLY)
{
let spans = args.options_spans.clone();
- ecx.struct_span_err(
+ diag.struct_span_err(
spans,
"the `pure` option must be combined with either `nomem` or `readonly`",
)
@@ -309,14 +310,14 @@ fn parse_args<'a>(
}
}
if args.options.contains(ast::InlineAsmOptions::PURE) && !have_real_output {
- ecx.struct_span_err(
+ diag.struct_span_err(
args.options_spans.clone(),
"asm with the `pure` option must have at least one output",
)
.emit();
}
if args.options.contains(ast::InlineAsmOptions::NORETURN) && !outputs_sp.is_empty() {
- let err = ecx
+ let err = diag
.struct_span_err(outputs_sp, "asm outputs are not allowed with the `noreturn` option");
// Bail out now since this is likely to confuse MIR
@@ -325,7 +326,7 @@ fn parse_args<'a>(
if args.clobber_abis.len() > 0 {
if is_global_asm {
- let err = ecx.struct_span_err(
+ let err = diag.struct_span_err(
args.clobber_abis.iter().map(|(_, span)| *span).collect::<Vec<Span>>(),
"`clobber_abi` cannot be used with `global_asm!`",
);
@@ -334,7 +335,7 @@ fn parse_args<'a>(
return Err(err);
}
if !regclass_outputs.is_empty() {
- ecx.struct_span_err(
+ diag.struct_span_err(
regclass_outputs.clone(),
"asm with `clobber_abi` must specify explicit registers for outputs",
)
@@ -420,6 +421,8 @@ fn parse_options<'a>(
try_set_option(p, args, sym::att_syntax, ast::InlineAsmOptions::ATT_SYNTAX);
} else if p.eat_keyword(kw::Raw) {
try_set_option(p, args, kw::Raw, ast::InlineAsmOptions::RAW);
+ } else if p.eat_keyword(sym::may_unwind) {
+ try_set_option(p, args, kw::Raw, ast::InlineAsmOptions::MAY_UNWIND);
} else {
return p.unexpected();
}
@@ -710,7 +713,7 @@ fn expand_preparsed_asm(ecx: &mut ExtCtxt<'_>, args: AsmArgs) -> Option<ast::Inl
Some(&idx) => Some(idx),
None => {
let msg = format!("there is no argument named `{}`", name);
- ecx.struct_span_err(span, &msg[..]).emit();
+ ecx.struct_span_err(span, &msg).emit();
None
}
},
diff --git a/compiler/rustc_builtin_macros/src/cfg_eval.rs b/compiler/rustc_builtin_macros/src/cfg_eval.rs
index 307730f7f5f..31086a2acf8 100644
--- a/compiler/rustc_builtin_macros/src/cfg_eval.rs
+++ b/compiler/rustc_builtin_macros/src/cfg_eval.rs
@@ -1,4 +1,4 @@
-use crate::util::check_builtin_macro_attribute;
+use crate::util::{check_builtin_macro_attribute, warn_on_duplicate_attribute};
use rustc_ast as ast;
use rustc_ast::mut_visit::MutVisitor;
@@ -11,7 +11,7 @@ use rustc_expand::base::{Annotatable, ExtCtxt};
use rustc_expand::config::StripUnconfigured;
use rustc_expand::configure;
use rustc_feature::Features;
-use rustc_parse::parser::ForceCollect;
+use rustc_parse::parser::{ForceCollect, Parser};
use rustc_session::utils::FlattenNonterminals;
use rustc_session::Session;
use rustc_span::symbol::sym;
@@ -25,6 +25,7 @@ crate fn expand(
annotatable: Annotatable,
) -> Vec<Annotatable> {
check_builtin_macro_attribute(ecx, meta_item, sym::cfg_eval);
+ warn_on_duplicate_attribute(&ecx, &annotatable, sym::cfg_eval);
vec![cfg_eval(ecx.sess, ecx.ecfg.features, annotatable)]
}
@@ -77,6 +78,10 @@ fn flat_map_annotatable(
Annotatable::Param(param) => vis.flat_map_param(param).pop().map(Annotatable::Param),
Annotatable::FieldDef(sf) => vis.flat_map_field_def(sf).pop().map(Annotatable::FieldDef),
Annotatable::Variant(v) => vis.flat_map_variant(v).pop().map(Annotatable::Variant),
+ Annotatable::Crate(mut krate) => {
+ vis.visit_crate(&mut krate);
+ Some(Annotatable::Crate(krate))
+ }
}
}
@@ -101,6 +106,7 @@ impl CfgFinder {
Annotatable::Param(param) => finder.visit_param(&param),
Annotatable::FieldDef(field) => finder.visit_field_def(&field),
Annotatable::Variant(variant) => finder.visit_variant(&variant),
+ Annotatable::Crate(krate) => finder.visit_crate(krate),
};
finder.has_cfg_or_cfg_attr
}
@@ -138,8 +144,34 @@ impl CfgEval<'_, '_> {
// the location of `#[cfg]` and `#[cfg_attr]` in the token stream. The tokenization
// process is lossless, so this process is invisible to proc-macros.
- // FIXME - get rid of this clone
- let nt = annotatable.clone().into_nonterminal();
+ let parse_annotatable_with: fn(&mut Parser<'_>) -> _ = match annotatable {
+ Annotatable::Item(_) => {
+ |parser| Annotatable::Item(parser.parse_item(ForceCollect::Yes).unwrap().unwrap())
+ }
+ Annotatable::TraitItem(_) => |parser| {
+ Annotatable::TraitItem(
+ parser.parse_trait_item(ForceCollect::Yes).unwrap().unwrap().unwrap(),
+ )
+ },
+ Annotatable::ImplItem(_) => |parser| {
+ Annotatable::ImplItem(
+ parser.parse_impl_item(ForceCollect::Yes).unwrap().unwrap().unwrap(),
+ )
+ },
+ Annotatable::ForeignItem(_) => |parser| {
+ Annotatable::ForeignItem(
+ parser.parse_foreign_item(ForceCollect::Yes).unwrap().unwrap().unwrap(),
+ )
+ },
+ Annotatable::Stmt(_) => |parser| {
+ Annotatable::Stmt(P(parser.parse_stmt(ForceCollect::Yes).unwrap().unwrap()))
+ },
+ Annotatable::Expr(_) => {
+ |parser| Annotatable::Expr(parser.parse_expr_force_collect().unwrap())
+ }
+ _ => unreachable!(),
+ };
+ let nt = annotatable.into_nonterminal();
let mut orig_tokens = rustc_parse::nt_to_tokenstream(
&nt,
@@ -173,25 +205,7 @@ impl CfgEval<'_, '_> {
let mut parser =
rustc_parse::stream_to_parser(&self.cfg.sess.parse_sess, orig_tokens, None);
parser.capture_cfg = true;
- annotatable = match annotatable {
- Annotatable::Item(_) => {
- Annotatable::Item(parser.parse_item(ForceCollect::Yes).unwrap().unwrap())
- }
- Annotatable::TraitItem(_) => Annotatable::TraitItem(
- parser.parse_trait_item(ForceCollect::Yes).unwrap().unwrap().unwrap(),
- ),
- Annotatable::ImplItem(_) => Annotatable::ImplItem(
- parser.parse_impl_item(ForceCollect::Yes).unwrap().unwrap().unwrap(),
- ),
- Annotatable::ForeignItem(_) => Annotatable::ForeignItem(
- parser.parse_foreign_item(ForceCollect::Yes).unwrap().unwrap().unwrap(),
- ),
- Annotatable::Stmt(_) => {
- Annotatable::Stmt(P(parser.parse_stmt(ForceCollect::Yes).unwrap().unwrap()))
- }
- Annotatable::Expr(_) => Annotatable::Expr(parser.parse_expr_force_collect().unwrap()),
- _ => unreachable!(),
- };
+ annotatable = parse_annotatable_with(&mut parser);
// Now that we have our re-parsed `AttrAnnotatedTokenStream`, recursively configuring
// our attribute target will correctly the tokens as well.
diff --git a/compiler/rustc_builtin_macros/src/concat_bytes.rs b/compiler/rustc_builtin_macros/src/concat_bytes.rs
new file mode 100644
index 00000000000..a107f5993b5
--- /dev/null
+++ b/compiler/rustc_builtin_macros/src/concat_bytes.rs
@@ -0,0 +1,167 @@
+use rustc_ast as ast;
+use rustc_ast::{ptr::P, tokenstream::TokenStream};
+use rustc_data_structures::sync::Lrc;
+use rustc_errors::Applicability;
+use rustc_expand::base::{self, DummyResult};
+
+/// Emits errors for literal expressions that are invalid inside and outside of an array.
+fn invalid_type_err(cx: &mut base::ExtCtxt<'_>, expr: &P<rustc_ast::Expr>, is_nested: bool) {
+ let lit = if let ast::ExprKind::Lit(lit) = &expr.kind {
+ lit
+ } else {
+ unreachable!();
+ };
+ match lit.kind {
+ ast::LitKind::Char(_) => {
+ let mut err = cx.struct_span_err(expr.span, "cannot concatenate character literals");
+ if let Ok(snippet) = cx.sess.source_map().span_to_snippet(expr.span) {
+ err.span_suggestion(
+ expr.span,
+ "try using a byte character",
+ format!("b{}", snippet),
+ Applicability::MachineApplicable,
+ )
+ .emit();
+ }
+ }
+ ast::LitKind::Str(_, _) => {
+ let mut err = cx.struct_span_err(expr.span, "cannot concatenate string literals");
+ // suggestion would be invalid if we are nested
+ if !is_nested {
+ if let Ok(snippet) = cx.sess.source_map().span_to_snippet(expr.span) {
+ err.span_suggestion(
+ expr.span,
+ "try using a byte string",
+ format!("b{}", snippet),
+ Applicability::MachineApplicable,
+ );
+ }
+ }
+ err.emit();
+ }
+ ast::LitKind::Float(_, _) => {
+ cx.span_err(expr.span, "cannot concatenate float literals");
+ }
+ ast::LitKind::Bool(_) => {
+ cx.span_err(expr.span, "cannot concatenate boolean literals");
+ }
+ ast::LitKind::Err(_) => {}
+ ast::LitKind::Int(_, _) if !is_nested => {
+ let mut err = cx.struct_span_err(expr.span, "cannot concatenate numeric literals");
+ if let Ok(snippet) = cx.sess.source_map().span_to_snippet(expr.span) {
+ err.span_suggestion(
+ expr.span,
+ "try wrapping the number in an array",
+ format!("[{}]", snippet),
+ Applicability::MachineApplicable,
+ );
+ }
+ err.emit();
+ }
+ ast::LitKind::Int(
+ val,
+ ast::LitIntType::Unsuffixed | ast::LitIntType::Unsigned(ast::UintTy::U8),
+ ) => {
+ assert!(val > u8::MAX.into()); // must be an error
+ cx.span_err(expr.span, "numeric literal is out of bounds");
+ }
+ ast::LitKind::Int(_, _) => {
+ cx.span_err(expr.span, "numeric literal is not a `u8`");
+ }
+ _ => unreachable!(),
+ }
+}
+
+pub fn expand_concat_bytes(
+ cx: &mut base::ExtCtxt<'_>,
+ sp: rustc_span::Span,
+ tts: TokenStream,
+) -> Box<dyn base::MacResult + 'static> {
+ let es = match base::get_exprs_from_tts(cx, sp, tts) {
+ Some(e) => e,
+ None => return DummyResult::any(sp),
+ };
+ let mut accumulator = Vec::new();
+ let mut missing_literals = vec![];
+ let mut has_errors = false;
+ for e in es {
+ match e.kind {
+ ast::ExprKind::Array(ref exprs) => {
+ for expr in exprs {
+ match expr.kind {
+ ast::ExprKind::Array(_) => {
+ if !has_errors {
+ cx.span_err(expr.span, "cannot concatenate doubly nested array");
+ }
+ has_errors = true;
+ }
+ ast::ExprKind::Lit(ref lit) => match lit.kind {
+ ast::LitKind::Int(
+ val,
+ ast::LitIntType::Unsuffixed
+ | ast::LitIntType::Unsigned(ast::UintTy::U8),
+ ) if val <= u8::MAX.into() => {
+ accumulator.push(val as u8);
+ }
+
+ ast::LitKind::Byte(val) => {
+ accumulator.push(val);
+ }
+ ast::LitKind::ByteStr(_) => {
+ if !has_errors {
+ cx.struct_span_err(
+ expr.span,
+ "cannot concatenate doubly nested array",
+ )
+ .note("byte strings are treated as arrays of bytes")
+ .help("try flattening the array")
+ .emit();
+ }
+ has_errors = true;
+ }
+ _ => {
+ if !has_errors {
+ invalid_type_err(cx, expr, true);
+ }
+ has_errors = true;
+ }
+ },
+ _ => {
+ missing_literals.push(expr.span);
+ }
+ }
+ }
+ }
+ ast::ExprKind::Lit(ref lit) => match lit.kind {
+ ast::LitKind::Byte(val) => {
+ accumulator.push(val);
+ }
+ ast::LitKind::ByteStr(ref bytes) => {
+ accumulator.extend_from_slice(&bytes);
+ }
+ _ => {
+ if !has_errors {
+ invalid_type_err(cx, &e, false);
+ }
+ has_errors = true;
+ }
+ },
+ ast::ExprKind::Err => {
+ has_errors = true;
+ }
+ _ => {
+ missing_literals.push(e.span);
+ }
+ }
+ }
+ if !missing_literals.is_empty() {
+ let mut err = cx.struct_span_err(missing_literals.clone(), "expected a byte literal");
+ err.note("only byte literals (like `b\"foo\"`, `b's'`, and `[3, 4, 5]`) can be passed to `concat_bytes!()`");
+ err.emit();
+ return base::MacEager::expr(DummyResult::raw_expr(sp, true));
+ } else if has_errors {
+ return base::MacEager::expr(DummyResult::raw_expr(sp, true));
+ }
+ let sp = cx.with_def_site_ctxt(sp);
+ base::MacEager::expr(cx.expr_lit(sp, ast::LitKind::ByteStr(Lrc::from(accumulator))))
+}
diff --git a/compiler/rustc_builtin_macros/src/deriving/generic/mod.rs b/compiler/rustc_builtin_macros/src/deriving/generic/mod.rs
index 994a74a5a9b..985c45e2253 100644
--- a/compiler/rustc_builtin_macros/src/deriving/generic/mod.rs
+++ b/compiler/rustc_builtin_macros/src/deriving/generic/mod.rs
@@ -567,8 +567,11 @@ impl<'a> TraitDef<'a> {
})
});
- let Generics { mut params, mut where_clause, span } =
+ let Generics { mut params, mut where_clause, .. } =
self.generics.to_generics(cx, self.span, type_ident, generics);
+ where_clause.span = generics.where_clause.span;
+ let ctxt = self.span.ctxt();
+ let span = generics.span.with_ctxt(ctxt);
// Create the generic parameters
params.extend(generics.params.iter().map(|param| match &param.kind {
@@ -589,12 +592,12 @@ impl<'a> TraitDef<'a> {
param.bounds.iter().cloned()
).collect();
- cx.typaram(self.span, param.ident, vec![], bounds, None)
+ cx.typaram(param.ident.span.with_ctxt(ctxt), param.ident, vec![], bounds, None)
}
GenericParamKind::Const { ty, kw_span, .. } => {
let const_nodefault_kind = GenericParamKind::Const {
ty: ty.clone(),
- kw_span: *kw_span,
+ kw_span: kw_span.with_ctxt(ctxt),
// We can't have default values inside impl block
default: None,
@@ -607,28 +610,27 @@ impl<'a> TraitDef<'a> {
// and similarly for where clauses
where_clause.predicates.extend(generics.where_clause.predicates.iter().map(|clause| {
- match *clause {
- ast::WherePredicate::BoundPredicate(ref wb) => {
+ match clause {
+ ast::WherePredicate::BoundPredicate(wb) => {
+ let span = wb.span.with_ctxt(ctxt);
ast::WherePredicate::BoundPredicate(ast::WhereBoundPredicate {
- span: self.span,
- bound_generic_params: wb.bound_generic_params.clone(),
- bounded_ty: wb.bounded_ty.clone(),
- bounds: wb.bounds.to_vec(),
+ span,
+ ..wb.clone()
})
}
- ast::WherePredicate::RegionPredicate(ref rb) => {
+ ast::WherePredicate::RegionPredicate(wr) => {
+ let span = wr.span.with_ctxt(ctxt);
ast::WherePredicate::RegionPredicate(ast::WhereRegionPredicate {
- span: self.span,
- lifetime: rb.lifetime,
- bounds: rb.bounds.to_vec(),
+ span,
+ ..wr.clone()
})
}
- ast::WherePredicate::EqPredicate(ref we) => {
+ ast::WherePredicate::EqPredicate(we) => {
+ let span = we.span.with_ctxt(ctxt);
ast::WherePredicate::EqPredicate(ast::WhereEqPredicate {
id: ast::DUMMY_NODE_ID,
- span: self.span,
- lhs_ty: we.lhs_ty.clone(),
- rhs_ty: we.rhs_ty.clone(),
+ span,
+ ..we.clone()
})
}
}
@@ -691,13 +693,13 @@ impl<'a> TraitDef<'a> {
.iter()
.map(|param| match param.kind {
GenericParamKind::Lifetime { .. } => {
- GenericArg::Lifetime(cx.lifetime(self.span, param.ident))
+ GenericArg::Lifetime(cx.lifetime(param.ident.span.with_ctxt(ctxt), param.ident))
}
GenericParamKind::Type { .. } => {
- GenericArg::Type(cx.ty_ident(self.span, param.ident))
+ GenericArg::Type(cx.ty_ident(param.ident.span.with_ctxt(ctxt), param.ident))
}
GenericParamKind::Const { .. } => {
- GenericArg::Const(cx.const_ident(self.span, param.ident))
+ GenericArg::Const(cx.const_ident(param.ident.span.with_ctxt(ctxt), param.ident))
}
})
.collect();
@@ -764,8 +766,8 @@ impl<'a> TraitDef<'a> {
self,
struct_def,
type_ident,
- &self_args[..],
- &nonself_args[..],
+ &self_args,
+ &nonself_args,
)
} else {
method_def.expand_struct_method_body(
@@ -773,8 +775,8 @@ impl<'a> TraitDef<'a> {
self,
struct_def,
type_ident,
- &self_args[..],
- &nonself_args[..],
+ &self_args,
+ &nonself_args,
use_temporaries,
)
};
@@ -813,8 +815,8 @@ impl<'a> TraitDef<'a> {
self,
enum_def,
type_ident,
- &self_args[..],
- &nonself_args[..],
+ &self_args,
+ &nonself_args,
)
} else {
method_def.expand_enum_method_body(
@@ -823,7 +825,7 @@ impl<'a> TraitDef<'a> {
enum_def,
type_ident,
self_args,
- &nonself_args[..],
+ &nonself_args,
)
};
@@ -845,16 +847,17 @@ impl<'a> MethodDef<'a> {
nonself_args: &[P<Expr>],
fields: &SubstructureFields<'_>,
) -> P<Expr> {
+ let span = trait_.span;
let substructure = Substructure {
type_ident,
- method_ident: Ident::new(self.name, trait_.span),
+ method_ident: Ident::new(self.name, span),
self_args,
nonself_args,
fields,
};
let mut f = self.combine_substructure.borrow_mut();
let f: &mut CombineSubstructureFunc<'_> = &mut *f;
- f(cx, trait_.span, &substructure)
+ f(cx, span, &substructure)
}
fn get_ret_ty(
@@ -882,9 +885,10 @@ impl<'a> MethodDef<'a> {
let mut nonself_args = Vec::new();
let mut arg_tys = Vec::new();
let mut nonstatic = false;
+ let span = trait_.span;
let ast_explicit_self = self.explicit_self.as_ref().map(|self_ptr| {
- let (self_expr, explicit_self) = ty::get_explicit_self(cx, trait_.span, self_ptr);
+ let (self_expr, explicit_self) = ty::get_explicit_self(cx, span, self_ptr);
self_args.push(self_expr);
nonstatic = true;
@@ -893,11 +897,11 @@ impl<'a> MethodDef<'a> {
});
for (ty, name) in self.args.iter() {
- let ast_ty = ty.to_ty(cx, trait_.span, type_ident, generics);
- let ident = Ident::new(*name, trait_.span);
+ let ast_ty = ty.to_ty(cx, span, type_ident, generics);
+ let ident = Ident::new(*name, span);
arg_tys.push((ident, ast_ty));
- let arg_expr = cx.expr_ident(trait_.span, ident);
+ let arg_expr = cx.expr_ident(span, ident);
match *ty {
// for static methods, just treat any Self
@@ -906,7 +910,7 @@ impl<'a> MethodDef<'a> {
self_args.push(arg_expr);
}
Ptr(ref ty, _) if matches!(**ty, Self_) && nonstatic => {
- self_args.push(cx.expr_deref(trait_.span, arg_expr))
+ self_args.push(cx.expr_deref(span, arg_expr))
}
_ => {
nonself_args.push(arg_expr);
@@ -927,33 +931,33 @@ impl<'a> MethodDef<'a> {
arg_types: Vec<(Ident, P<ast::Ty>)>,
body: P<Expr>,
) -> P<ast::AssocItem> {
+ let span = trait_.span;
// Create the generics that aren't for `Self`.
- let fn_generics = self.generics.to_generics(cx, trait_.span, type_ident, generics);
+ let fn_generics = self.generics.to_generics(cx, span, type_ident, generics);
let args = {
let self_args = explicit_self.map(|explicit_self| {
- let ident = Ident::with_dummy_span(kw::SelfLower).with_span_pos(trait_.span);
+ let ident = Ident::with_dummy_span(kw::SelfLower).with_span_pos(span);
ast::Param::from_self(ast::AttrVec::default(), explicit_self, ident)
});
- let nonself_args =
- arg_types.into_iter().map(|(name, ty)| cx.param(trait_.span, name, ty));
+ let nonself_args = arg_types.into_iter().map(|(name, ty)| cx.param(span, name, ty));
self_args.into_iter().chain(nonself_args).collect()
};
let ret_type = self.get_ret_ty(cx, trait_, generics, type_ident);
- let method_ident = Ident::new(self.name, trait_.span);
+ let method_ident = Ident::new(self.name, span);
let fn_decl = cx.fn_decl(args, ast::FnRetTy::Ty(ret_type));
let body_block = cx.block_expr(body);
- let unsafety = if self.is_unsafe { ast::Unsafe::Yes(trait_.span) } else { ast::Unsafe::No };
+ let unsafety = if self.is_unsafe { ast::Unsafe::Yes(span) } else { ast::Unsafe::No };
- let trait_lo_sp = trait_.span.shrink_to_lo();
+ let trait_lo_sp = span.shrink_to_lo();
let sig = ast::FnSig {
header: ast::FnHeader { unsafety, ext: ast::Extern::None, ..ast::FnHeader::default() },
decl: fn_decl,
- span: trait_.span,
+ span,
};
let defaultness = ast::Defaultness::Final;
@@ -961,7 +965,7 @@ impl<'a> MethodDef<'a> {
P(ast::AssocItem {
id: ast::DUMMY_NODE_ID,
attrs: self.attributes.clone(),
- span: trait_.span,
+ span,
vis: ast::Visibility {
span: trait_lo_sp,
kind: ast::VisibilityKind::Inherited,
@@ -1024,11 +1028,11 @@ impl<'a> MethodDef<'a> {
nonself_args: &[P<Expr>],
use_temporaries: bool,
) -> P<Expr> {
- let mut raw_fields = Vec::new(); // Vec<[fields of self],
- // [fields of next Self arg], [etc]>
+ let mut raw_fields = Vec::new(); // Vec<[fields of self], [fields of next Self arg], [etc]>
+ let span = trait_.span;
let mut patterns = Vec::new();
for i in 0..self_args.len() {
- let struct_path = cx.path(trait_.span, vec![type_ident]);
+ let struct_path = cx.path(span, vec![type_ident]);
let (pat, ident_expr) = trait_.create_struct_pattern(
cx,
struct_path,
@@ -1048,7 +1052,7 @@ impl<'a> MethodDef<'a> {
let mut other_fields: Vec<vec::IntoIter<_>> = raw_fields.collect();
first_field
.map(|(span, opt_id, field, attrs)| FieldInfo {
- span,
+ span: span.with_ctxt(trait_.span.ctxt()),
name: opt_id,
self_: field,
other: other_fields
@@ -1062,7 +1066,7 @@ impl<'a> MethodDef<'a> {
})
.collect()
} else {
- cx.span_bug(trait_.span, "no `self` parameter for method in generic `derive`")
+ cx.span_bug(span, "no `self` parameter for method in generic `derive`")
};
// body of the inner most destructuring match
@@ -1079,11 +1083,7 @@ impl<'a> MethodDef<'a> {
// structs. This is actually right-to-left, but it shouldn't
// matter.
for (arg_expr, pat) in iter::zip(self_args, patterns) {
- body = cx.expr_match(
- trait_.span,
- arg_expr.clone(),
- vec![cx.arm(trait_.span, pat.clone(), body)],
- )
+ body = cx.expr_match(span, arg_expr.clone(), vec![cx.arm(span, pat.clone(), body)])
}
body
@@ -1193,7 +1193,7 @@ impl<'a> MethodDef<'a> {
mut self_args: Vec<P<Expr>>,
nonself_args: &[P<Expr>],
) -> P<Expr> {
- let sp = trait_.span;
+ let span = trait_.span;
let variants = &enum_def.variants;
let self_arg_names = iter::once("__self".to_string())
@@ -1208,7 +1208,7 @@ impl<'a> MethodDef<'a> {
let self_arg_idents = self_arg_names
.iter()
- .map(|name| Ident::from_str_and_span(name, sp))
+ .map(|name| Ident::from_str_and_span(name, span))
.collect::<Vec<Ident>>();
// The `vi_idents` will be bound, solely in the catch-all, to
@@ -1217,8 +1217,8 @@ impl<'a> MethodDef<'a> {
let vi_idents = self_arg_names
.iter()
.map(|name| {
- let vi_suffix = format!("{}_vi", &name[..]);
- Ident::from_str_and_span(&vi_suffix, trait_.span)
+ let vi_suffix = format!("{}_vi", name);
+ Ident::from_str_and_span(&vi_suffix, span)
})
.collect::<Vec<Ident>>();
@@ -1226,7 +1226,7 @@ impl<'a> MethodDef<'a> {
// delegated expression that handles the catch-all case,
// using `__variants_tuple` to drive logic if necessary.
let catch_all_substructure =
- EnumNonMatchingCollapsed(self_arg_idents, &variants[..], &vi_idents[..]);
+ EnumNonMatchingCollapsed(self_arg_idents, &variants, &vi_idents);
let first_fieldless = variants.iter().find(|v| v.data.fields().is_empty());
@@ -1248,7 +1248,7 @@ impl<'a> MethodDef<'a> {
self_arg_name,
ast::Mutability::Not,
);
- (cx.pat(sp, PatKind::Ref(p, ast::Mutability::Not)), idents)
+ (cx.pat(span, PatKind::Ref(p, ast::Mutability::Not)), idents)
};
// A single arm has form (&VariantK, &VariantK, ...) => BodyK
@@ -1261,13 +1261,13 @@ impl<'a> MethodDef<'a> {
idents
};
for self_arg_name in &self_arg_names[1..] {
- let (p, idents) = mk_self_pat(cx, &self_arg_name[..]);
+ let (p, idents) = mk_self_pat(cx, &self_arg_name);
subpats.push(p);
self_pats_idents.push(idents);
}
// Here is the pat = `(&VariantK, &VariantK, ...)`
- let single_pat = cx.pat_tuple(sp, subpats);
+ let single_pat = cx.pat_tuple(span, subpats);
// For the BodyK, we need to delegate to our caller,
// passing it an EnumMatching to indicate which case
@@ -1284,7 +1284,7 @@ impl<'a> MethodDef<'a> {
.into_iter()
.enumerate()
// For each arg field of self, pull out its getter expr ...
- .map(|(field_index, (sp, opt_ident, self_getter_expr, attrs))| {
+ .map(|(field_index, (span, opt_ident, self_getter_expr, attrs))| {
// ... but FieldInfo also wants getter expr
// for matching other arguments of Self type;
// so walk across the *other* self_pats_idents
@@ -1307,7 +1307,7 @@ impl<'a> MethodDef<'a> {
.collect::<Vec<P<Expr>>>();
FieldInfo {
- span: sp,
+ span,
name: opt_ident,
self_: self_getter_expr,
other: others,
@@ -1330,7 +1330,7 @@ impl<'a> MethodDef<'a> {
&substructure,
);
- cx.arm(sp, single_pat, arm_expr)
+ cx.arm(span, single_pat, arm_expr)
})
.collect();
@@ -1353,12 +1353,12 @@ impl<'a> MethodDef<'a> {
// Since we know that all the arguments will match if we reach
// the match expression we add the unreachable intrinsics as the
// result of the catch all which should help llvm in optimizing it
- Some(deriving::call_unreachable(cx, sp))
+ Some(deriving::call_unreachable(cx, span))
}
_ => None,
};
if let Some(arm) = default {
- match_arms.push(cx.arm(sp, cx.pat_wild(sp), arm));
+ match_arms.push(cx.arm(span, cx.pat_wild(span), arm));
}
// We will usually need the catch-all after matching the
@@ -1392,23 +1392,23 @@ impl<'a> MethodDef<'a> {
// We also build an expression which checks whether all discriminants are equal
// discriminant_test = __self0_vi == __self1_vi && __self0_vi == __self2_vi && ...
- let mut discriminant_test = cx.expr_bool(sp, true);
+ let mut discriminant_test = cx.expr_bool(span, true);
let mut first_ident = None;
for (&ident, self_arg) in iter::zip(&vi_idents, &self_args) {
- let self_addr = cx.expr_addr_of(sp, self_arg.clone());
+ let self_addr = cx.expr_addr_of(span, self_arg.clone());
let variant_value =
- deriving::call_intrinsic(cx, sp, sym::discriminant_value, vec![self_addr]);
- let let_stmt = cx.stmt_let(sp, false, ident, variant_value);
+ deriving::call_intrinsic(cx, span, sym::discriminant_value, vec![self_addr]);
+ let let_stmt = cx.stmt_let(span, false, ident, variant_value);
index_let_stmts.push(let_stmt);
match first_ident {
Some(first) => {
- let first_expr = cx.expr_ident(sp, first);
- let id = cx.expr_ident(sp, ident);
- let test = cx.expr_binary(sp, BinOpKind::Eq, first_expr, id);
+ let first_expr = cx.expr_ident(span, first);
+ let id = cx.expr_ident(span, ident);
+ let test = cx.expr_binary(span, BinOpKind::Eq, first_expr, id);
discriminant_test =
- cx.expr_binary(sp, BinOpKind::And, discriminant_test, test)
+ cx.expr_binary(span, BinOpKind::And, discriminant_test, test)
}
None => {
first_ident = Some(ident);
@@ -1430,8 +1430,8 @@ impl<'a> MethodDef<'a> {
// them when they are fed as r-values into a tuple
// expression; here add a layer of borrowing, turning
// `(*self, *__arg_0, ...)` into `(&*self, &*__arg_0, ...)`.
- self_args.map_in_place(|self_arg| cx.expr_addr_of(sp, self_arg));
- let match_arg = cx.expr(sp, ast::ExprKind::Tup(self_args));
+ self_args.map_in_place(|self_arg| cx.expr_addr_of(span, self_arg));
+ let match_arg = cx.expr(span, ast::ExprKind::Tup(self_args));
// Lastly we create an expression which branches on all discriminants being equal
// if discriminant_test {
@@ -1445,10 +1445,10 @@ impl<'a> MethodDef<'a> {
// else {
// <delegated expression referring to __self0_vi, et al.>
// }
- let all_match = cx.expr_match(sp, match_arg, match_arms);
- let arm_expr = cx.expr_if(sp, discriminant_test, all_match, Some(arm_expr));
+ let all_match = cx.expr_match(span, match_arg, match_arms);
+ let arm_expr = cx.expr_if(span, discriminant_test, all_match, Some(arm_expr));
index_let_stmts.push(cx.stmt_expr(arm_expr));
- cx.expr_block(cx.block(sp, index_let_stmts))
+ cx.expr_block(cx.block(span, index_let_stmts))
} else if variants.is_empty() {
// As an additional wrinkle, For a zero-variant enum A,
// currently the compiler
@@ -1499,16 +1499,16 @@ impl<'a> MethodDef<'a> {
// derive Debug on such a type could here generate code
// that needs the feature gate enabled.)
- deriving::call_unreachable(cx, sp)
+ deriving::call_unreachable(cx, span)
} else {
// Final wrinkle: the self_args are expressions that deref
// down to desired places, but we cannot actually deref
// them when they are fed as r-values into a tuple
// expression; here add a layer of borrowing, turning
// `(*self, *__arg_0, ...)` into `(&*self, &*__arg_0, ...)`.
- self_args.map_in_place(|self_arg| cx.expr_addr_of(sp, self_arg));
- let match_arg = cx.expr(sp, ast::ExprKind::Tup(self_args));
- cx.expr_match(sp, match_arg, match_arms)
+ self_args.map_in_place(|self_arg| cx.expr_addr_of(span, self_arg));
+ let match_arg = cx.expr(span, ast::ExprKind::Tup(self_args));
+ cx.expr_match(span, match_arg, match_arms)
}
}
@@ -1556,11 +1556,9 @@ impl<'a> TraitDef<'a> {
let is_tuple = matches!(struct_def, ast::VariantData::Tuple(..));
match (just_spans.is_empty(), named_idents.is_empty()) {
- (false, false) => cx.span_bug(
- self.span,
- "a struct with named and unnamed \
- fields in generic `derive`",
- ),
+ (false, false) => {
+ cx.span_bug(self.span, "a struct with named and unnamed fields in generic `derive`")
+ }
// named fields
(_, false) => Named(named_idents),
// unnamed fields
diff --git a/compiler/rustc_builtin_macros/src/deriving/generic/ty.rs b/compiler/rustc_builtin_macros/src/deriving/generic/ty.rs
index 00d75be4399..7a418003250 100644
--- a/compiler/rustc_builtin_macros/src/deriving/generic/ty.rs
+++ b/compiler/rustc_builtin_macros/src/deriving/generic/ty.rs
@@ -211,14 +211,6 @@ fn mk_ty_param(
cx.typaram(span, Ident::new(name, span), attrs.to_owned(), bounds, None)
}
-fn mk_generics(params: Vec<ast::GenericParam>, span: Span) -> Generics {
- Generics {
- params,
- where_clause: ast::WhereClause { has_where_token: false, predicates: Vec::new(), span },
- span,
- }
-}
-
/// Bounds on type parameters.
#[derive(Clone)]
pub struct Bounds {
@@ -236,7 +228,7 @@ impl Bounds {
self_ty: Ident,
self_generics: &Generics,
) -> Generics {
- let generic_params = self
+ let params = self
.bounds
.iter()
.map(|t| {
@@ -245,7 +237,11 @@ impl Bounds {
})
.collect();
- mk_generics(generic_params, span)
+ Generics {
+ params,
+ where_clause: ast::WhereClause { has_where_token: false, predicates: Vec::new(), span },
+ span,
+ }
}
}
diff --git a/compiler/rustc_builtin_macros/src/format.rs b/compiler/rustc_builtin_macros/src/format.rs
index 097eaddb874..cd16172fa31 100644
--- a/compiler/rustc_builtin_macros/src/format.rs
+++ b/compiler/rustc_builtin_macros/src/format.rs
@@ -88,8 +88,8 @@ struct Context<'a, 'b> {
/// * Implicit argument resolution: `"{1:.0$} {2:.foo$} {1:.3$} {4:.0$}"`
/// * Name resolution: `"{1:.0$} {2:.5$} {1:.3$} {4:.0$}"`
/// * `count_positions` (in JSON): `{0: 0, 5: 1, 3: 2}`
- /// * `count_args`: `vec![Exact(0), Exact(5), Exact(3)]`
- count_args: Vec<Position>,
+ /// * `count_args`: `vec![0, 5, 3]`
+ count_args: Vec<usize>,
/// Relative slot numbers for count arguments.
count_positions: FxHashMap<usize, usize>,
/// Number of count slots assigned.
@@ -513,7 +513,7 @@ impl<'a, 'b> Context<'a, 'b> {
if let Entry::Vacant(e) = self.count_positions.entry(arg) {
let i = self.count_positions_count;
e.insert(i);
- self.count_args.push(Exact(arg));
+ self.count_args.push(arg);
self.count_positions_count += 1;
}
}
@@ -549,7 +549,7 @@ impl<'a, 'b> Context<'a, 'b> {
} else {
self.fmtsp
};
- let mut err = self.ecx.struct_span_err(sp, &msg[..]);
+ let mut err = self.ecx.struct_span_err(sp, &msg);
err.note(&format!(
"did you intend to capture a variable `{}` from \
@@ -769,13 +769,12 @@ impl<'a, 'b> Context<'a, 'b> {
for arg_ty in self.arg_unique_types[i].iter() {
args.push(Context::format_arg(self.ecx, self.macsp, e.span, arg_ty, i));
}
- heads.push(self.ecx.expr_addr_of(e.span, e));
+ // use the arg span for `&arg` so that borrowck errors
+ // point to the specific expression passed to the macro
+ // (the span is otherwise unavailable in MIR)
+ heads.push(self.ecx.expr_addr_of(e.span.with_ctxt(self.macsp.ctxt()), e));
}
- for pos in self.count_args {
- let index = match pos {
- Exact(i) => i,
- _ => panic!("should never happen"),
- };
+ for index in self.count_args {
let span = spans_pos[index];
args.push(Context::format_arg(self.ecx, self.macsp, span, &Count, index));
}
@@ -996,8 +995,9 @@ pub fn expand_preparsed_format_args(
e.note(&note);
}
if let Some((label, span)) = err.secondary_label {
- let sp = fmt_span.from_inner(span);
- e.span_label(sp, label);
+ if efmt_kind_is_lit {
+ e.span_label(fmt_span.from_inner(span), label);
+ }
}
e.emit();
return DummyResult::raw_expr(sp, true);
diff --git a/compiler/rustc_builtin_macros/src/lib.rs b/compiler/rustc_builtin_macros/src/lib.rs
index d1d276930b9..3e8b43fea8a 100644
--- a/compiler/rustc_builtin_macros/src/lib.rs
+++ b/compiler/rustc_builtin_macros/src/lib.rs
@@ -6,7 +6,6 @@
#![feature(bool_to_option)]
#![feature(crate_visibility_modifier)]
#![feature(decl_macro)]
-#![feature(iter_zip)]
#![feature(nll)]
#![feature(proc_macro_internals)]
#![feature(proc_macro_quote)]
@@ -27,6 +26,7 @@ mod cfg_accessible;
mod cfg_eval;
mod compile_error;
mod concat;
+mod concat_bytes;
mod concat_idents;
mod derive;
mod deriving;
@@ -65,6 +65,7 @@ pub fn register_builtin_macros(resolver: &mut dyn ResolverExpand) {
cfg: cfg::expand_cfg,
column: source_util::expand_column,
compile_error: compile_error::expand_compile_error,
+ concat_bytes: concat_bytes::expand_concat_bytes,
concat_idents: concat_idents::expand_concat_idents,
concat: concat::expand_concat,
env: env::expand_env,
diff --git a/compiler/rustc_builtin_macros/src/test.rs b/compiler/rustc_builtin_macros/src/test.rs
index d2629926b51..c08b141b557 100644
--- a/compiler/rustc_builtin_macros/src/test.rs
+++ b/compiler/rustc_builtin_macros/src/test.rs
@@ -1,6 +1,6 @@
/// The expansion from a test function to the appropriate test struct for libtest
/// Ideally, this code would be in libtest but for efficiency and error messages it lives here.
-use crate::util::check_builtin_macro_attribute;
+use crate::util::{check_builtin_macro_attribute, warn_on_duplicate_attribute};
use rustc_ast as ast;
use rustc_ast::attr;
@@ -27,6 +27,7 @@ pub fn expand_test_case(
anno_item: Annotatable,
) -> Vec<Annotatable> {
check_builtin_macro_attribute(ecx, meta_item, sym::test_case);
+ warn_on_duplicate_attribute(&ecx, &anno_item, sym::test_case);
if !ecx.ecfg.should_test {
return vec![];
@@ -55,6 +56,7 @@ pub fn expand_test(
item: Annotatable,
) -> Vec<Annotatable> {
check_builtin_macro_attribute(cx, meta_item, sym::test);
+ warn_on_duplicate_attribute(&cx, &item, sym::test);
expand_test_or_bench(cx, attr_sp, item, false)
}
@@ -65,6 +67,7 @@ pub fn expand_bench(
item: Annotatable,
) -> Vec<Annotatable> {
check_builtin_macro_attribute(cx, meta_item, sym::bench);
+ warn_on_duplicate_attribute(&cx, &item, sym::bench);
expand_test_or_bench(cx, attr_sp, item, true)
}
diff --git a/compiler/rustc_builtin_macros/src/test_harness.rs b/compiler/rustc_builtin_macros/src/test_harness.rs
index 64ccd4331e5..418729e7843 100644
--- a/compiler/rustc_builtin_macros/src/test_harness.rs
+++ b/compiler/rustc_builtin_macros/src/test_harness.rs
@@ -84,9 +84,35 @@ struct TestHarnessGenerator<'a> {
tests: Vec<Test>,
}
+impl TestHarnessGenerator<'_> {
+ fn add_test_cases(&mut self, node_id: ast::NodeId, span: Span, prev_tests: Vec<Test>) {
+ let mut tests = mem::replace(&mut self.tests, prev_tests);
+
+ if !tests.is_empty() {
+ // Create an identifier that will hygienically resolve the test
+ // case name, even in another module.
+ let expn_id = self.cx.ext_cx.resolver.expansion_for_ast_pass(
+ span,
+ AstPass::TestHarness,
+ &[],
+ Some(node_id),
+ );
+ for test in &mut tests {
+ // See the comment on `mk_main` for why we're using
+ // `apply_mark` directly.
+ test.ident.span =
+ test.ident.span.apply_mark(expn_id.to_expn_id(), Transparency::Opaque);
+ }
+ self.cx.test_cases.extend(tests);
+ }
+ }
+}
+
impl<'a> MutVisitor for TestHarnessGenerator<'a> {
fn visit_crate(&mut self, c: &mut ast::Crate) {
+ let prev_tests = mem::take(&mut self.tests);
noop_visit_crate(c, self);
+ self.add_test_cases(ast::CRATE_NODE_ID, c.span, prev_tests);
// Create a main function to run our tests
c.items.push(mk_main(&mut self.cx));
@@ -103,34 +129,10 @@ impl<'a> MutVisitor for TestHarnessGenerator<'a> {
// We don't want to recurse into anything other than mods, since
// mods or tests inside of functions will break things
- if let ast::ItemKind::Mod(..) = item.kind {
- let tests = mem::take(&mut self.tests);
+ if let ast::ItemKind::Mod(_, ModKind::Loaded(.., span)) = item.kind {
+ let prev_tests = mem::take(&mut self.tests);
noop_visit_item_kind(&mut item.kind, self);
- let mut tests = mem::replace(&mut self.tests, tests);
-
- if !tests.is_empty() {
- let parent =
- if item.id == ast::DUMMY_NODE_ID { ast::CRATE_NODE_ID } else { item.id };
- // Create an identifier that will hygienically resolve the test
- // case name, even in another module.
- let inner_span = match item.kind {
- ast::ItemKind::Mod(_, ModKind::Loaded(.., span)) => span,
- _ => unreachable!(),
- };
- let expn_id = self.cx.ext_cx.resolver.expansion_for_ast_pass(
- inner_span,
- AstPass::TestHarness,
- &[],
- Some(parent),
- );
- for test in &mut tests {
- // See the comment on `mk_main` for why we're using
- // `apply_mark` directly.
- test.ident.span =
- test.ident.span.apply_mark(expn_id.to_expn_id(), Transparency::Opaque);
- }
- self.cx.test_cases.extend(tests);
- }
+ self.add_test_cases(item.id, span, prev_tests);
}
smallvec![P(item)]
}
@@ -146,7 +148,7 @@ fn entry_point_type(sess: &Session, item: &ast::Item, depth: usize) -> EntryPoin
} else if sess.contains_name(&item.attrs, sym::rustc_main) {
EntryPointType::MainAttr
} else if item.ident.name == sym::main {
- if depth == 1 {
+ if depth == 0 {
// This is a top-level function so can be 'main'
EntryPointType::MainNamed
} else {
diff --git a/compiler/rustc_builtin_macros/src/util.rs b/compiler/rustc_builtin_macros/src/util.rs
index 01ea80c4c8a..527fe50eff0 100644
--- a/compiler/rustc_builtin_macros/src/util.rs
+++ b/compiler/rustc_builtin_macros/src/util.rs
@@ -1,6 +1,7 @@
-use rustc_ast::MetaItem;
-use rustc_expand::base::ExtCtxt;
+use rustc_ast::{Attribute, MetaItem};
+use rustc_expand::base::{Annotatable, ExtCtxt};
use rustc_feature::AttributeTemplate;
+use rustc_lint_defs::builtin::DUPLICATE_MACRO_ATTRIBUTES;
use rustc_parse::validate_attr;
use rustc_span::Symbol;
@@ -10,3 +11,33 @@ pub fn check_builtin_macro_attribute(ecx: &ExtCtxt<'_>, meta_item: &MetaItem, na
let attr = ecx.attribute(meta_item.clone());
validate_attr::check_builtin_attribute(&ecx.sess.parse_sess, &attr, name, template);
}
+
+/// Emit a warning if the item is annotated with the given attribute. This is used to diagnose when
+/// an attribute may have been mistakenly duplicated.
+pub fn warn_on_duplicate_attribute(ecx: &ExtCtxt<'_>, item: &Annotatable, name: Symbol) {
+ let attrs: Option<&[Attribute]> = match item {
+ Annotatable::Item(item) => Some(&item.attrs),
+ Annotatable::TraitItem(item) => Some(&item.attrs),
+ Annotatable::ImplItem(item) => Some(&item.attrs),
+ Annotatable::ForeignItem(item) => Some(&item.attrs),
+ Annotatable::Expr(expr) => Some(&expr.attrs),
+ Annotatable::Arm(arm) => Some(&arm.attrs),
+ Annotatable::ExprField(field) => Some(&field.attrs),
+ Annotatable::PatField(field) => Some(&field.attrs),
+ Annotatable::GenericParam(param) => Some(&param.attrs),
+ Annotatable::Param(param) => Some(&param.attrs),
+ Annotatable::FieldDef(def) => Some(&def.attrs),
+ Annotatable::Variant(variant) => Some(&variant.attrs),
+ _ => None,
+ };
+ if let Some(attrs) = attrs {
+ if let Some(attr) = ecx.sess.find_by_name(attrs, name) {
+ ecx.parse_sess().buffer_lint(
+ DUPLICATE_MACRO_ATTRIBUTES,
+ attr.span,
+ ecx.current_expansion.lint_node_id,
+ "duplicated attribute",
+ );
+ }
+ }
+}
diff --git a/compiler/rustc_codegen_cranelift/scripts/cargo.rs b/compiler/rustc_codegen_cranelift/scripts/cargo.rs
index 89ec8da77d3..41d82b581cd 100644
--- a/compiler/rustc_codegen_cranelift/scripts/cargo.rs
+++ b/compiler/rustc_codegen_cranelift/scripts/cargo.rs
@@ -42,7 +42,7 @@ fn main() {
"RUSTFLAGS",
env::var("RUSTFLAGS").unwrap_or(String::new()) + " -Cprefer-dynamic",
);
- std::array::IntoIter::new(["rustc".to_string()])
+ IntoIterator::into_iter(["rustc".to_string()])
.chain(env::args().skip(2))
.chain([
"--".to_string(),
@@ -56,7 +56,7 @@ fn main() {
"RUSTFLAGS",
env::var("RUSTFLAGS").unwrap_or(String::new()) + " -Cprefer-dynamic",
);
- std::array::IntoIter::new(["rustc".to_string()])
+ IntoIterator::into_iter(["rustc".to_string()])
.chain(env::args().skip(2))
.chain([
"--".to_string(),
diff --git a/compiler/rustc_codegen_cranelift/src/abi/pass_mode.rs b/compiler/rustc_codegen_cranelift/src/abi/pass_mode.rs
index 2144e7ed67a..45d49062593 100644
--- a/compiler/rustc_codegen_cranelift/src/abi/pass_mode.rs
+++ b/compiler/rustc_codegen_cranelift/src/abi/pass_mode.rs
@@ -71,7 +71,7 @@ fn cast_target_to_abi_params(cast: CastTarget) -> SmallVec<[AbiParam; 2]> {
.prefix
.iter()
.flatten()
- .map(|&kind| reg_to_abi_param(Reg { kind, size: cast.prefix_chunk_size }))
+ .map(|&reg| reg_to_abi_param(reg))
.chain((0..rest_count).map(|_| reg_to_abi_param(cast.rest.unit)))
.collect::<SmallVec<_>>();
diff --git a/compiler/rustc_codegen_cranelift/src/base.rs b/compiler/rustc_codegen_cranelift/src/base.rs
index 1b30edd2938..371c71de62f 100644
--- a/compiler/rustc_codegen_cranelift/src/base.rs
+++ b/compiler/rustc_codegen_cranelift/src/base.rs
@@ -1,6 +1,7 @@
//! Codegen of a single function
use cranelift_codegen::binemit::{NullStackMapSink, NullTrapSink};
+use rustc_ast::InlineAsmOptions;
use rustc_index::vec::IndexVec;
use rustc_middle::ty::adjustment::PointerCast;
use rustc_middle::ty::layout::FnAbiOf;
@@ -239,7 +240,8 @@ fn codegen_fn_content(fx: &mut FunctionCx<'_, '_, '_>) {
fx.add_comment(inst, terminator_head);
}
- fx.set_debug_loc(bb_data.terminator().source_info);
+ let source_info = bb_data.terminator().source_info;
+ fx.set_debug_loc(source_info);
match &bb_data.terminator().kind {
TerminatorKind::Goto { target } => {
@@ -295,19 +297,19 @@ fn codegen_fn_content(fx: &mut FunctionCx<'_, '_, '_>) {
let len = codegen_operand(fx, len).load_scalar(fx);
let index = codegen_operand(fx, index).load_scalar(fx);
let location = fx
- .get_caller_location(bb_data.terminator().source_info.span)
+ .get_caller_location(source_info.span)
.load_scalar(fx);
codegen_panic_inner(
fx,
rustc_hir::LangItem::PanicBoundsCheck,
&[index, len, location],
- bb_data.terminator().source_info.span,
+ source_info.span,
);
}
_ => {
let msg_str = msg.description();
- codegen_panic(fx, msg_str, bb_data.terminator().source_info.span);
+ codegen_panic(fx, msg_str, source_info.span);
}
}
}
@@ -378,10 +380,18 @@ fn codegen_fn_content(fx: &mut FunctionCx<'_, '_, '_>) {
options,
destination,
line_spans: _,
+ cleanup: _,
} => {
+ if options.contains(InlineAsmOptions::MAY_UNWIND) {
+ fx.tcx.sess.span_fatal(
+ source_info.span,
+ "cranelift doesn't support unwinding from inline assembly.",
+ );
+ }
+
crate::inline_asm::codegen_inline_asm(
fx,
- bb_data.terminator().source_info.span,
+ source_info.span,
template,
operands,
*options,
@@ -415,7 +425,7 @@ fn codegen_fn_content(fx: &mut FunctionCx<'_, '_, '_>) {
}
TerminatorKind::Drop { place, target, unwind: _ } => {
let drop_place = codegen_place(fx, *place);
- crate::abi::codegen_drop(fx, bb_data.terminator().source_info.span, drop_place);
+ crate::abi::codegen_drop(fx, source_info.span, drop_place);
let target_block = fx.get_block(*target);
fx.bcx.ins().jump(target_block, &[]);
diff --git a/compiler/rustc_codegen_cranelift/src/inline_asm.rs b/compiler/rustc_codegen_cranelift/src/inline_asm.rs
index 09c5e6031c7..f5c9b0b5480 100644
--- a/compiler/rustc_codegen_cranelift/src/inline_asm.rs
+++ b/compiler/rustc_codegen_cranelift/src/inline_asm.rs
@@ -1,4 +1,4 @@
-//! Codegen of [`asm!`] invocations.
+//! Codegen of `asm!` invocations.
use crate::prelude::*;
diff --git a/compiler/rustc_codegen_cranelift/src/lib.rs b/compiler/rustc_codegen_cranelift/src/lib.rs
index beb97edf09e..fcdf6b50764 100644
--- a/compiler/rustc_codegen_cranelift/src/lib.rs
+++ b/compiler/rustc_codegen_cranelift/src/lib.rs
@@ -205,6 +205,7 @@ impl CodegenBackend for CraneliftCodegenBackend {
&self,
ongoing_codegen: Box<dyn Any>,
_sess: &Session,
+ _outputs: &OutputFilenames,
) -> Result<(CodegenResults, FxHashMap<WorkProductId, WorkProduct>), ErrorReported> {
Ok(*ongoing_codegen
.downcast::<(CodegenResults, FxHashMap<WorkProductId, WorkProduct>)>()
diff --git a/compiler/rustc_codegen_gcc/src/abi.rs b/compiler/rustc_codegen_gcc/src/abi.rs
index ce428c589a4..a8b1e70e2bb 100644
--- a/compiler/rustc_codegen_gcc/src/abi.rs
+++ b/compiler/rustc_codegen_gcc/src/abi.rs
@@ -14,7 +14,7 @@ impl<'a, 'gcc, 'tcx> AbiBuilderMethods<'tcx> for Builder<'a, 'gcc, 'tcx> {
// TODO(antoyo)
}
- fn get_param(&self, index: usize) -> Self::Value {
+ fn get_param(&mut self, index: usize) -> Self::Value {
self.cx.current_func.borrow().expect("current func")
.get_param(index as i32)
.to_rvalue()
@@ -48,8 +48,8 @@ impl GccType for CastTarget {
let mut args: Vec<_> = self
.prefix
.iter()
- .flat_map(|option_kind| {
- option_kind.map(|kind| Reg { kind, size: self.prefix_chunk_size }.gcc_type(cx))
+ .flat_map(|option_reg| {
+ option_reg.map(|reg| reg.gcc_type(cx))
})
.chain((0..rest_count).map(|_| rest_gcc_unit))
.collect();
diff --git a/compiler/rustc_codegen_gcc/src/asm.rs b/compiler/rustc_codegen_gcc/src/asm.rs
index 7c3ed3c5ee9..10edcf36955 100644
--- a/compiler/rustc_codegen_gcc/src/asm.rs
+++ b/compiler/rustc_codegen_gcc/src/asm.rs
@@ -118,7 +118,14 @@ impl<'a, 'gcc, 'tcx> AsmBuilderMethods<'tcx> for Builder<'a, 'gcc, 'tcx> {
true
}
- fn codegen_inline_asm(&mut self, template: &[InlineAsmTemplatePiece], rust_operands: &[InlineAsmOperandRef<'tcx, Self>], options: InlineAsmOptions, _span: &[Span], _instance: Instance<'_>) {
+ fn codegen_inline_asm(&mut self, template: &[InlineAsmTemplatePiece], rust_operands: &[InlineAsmOperandRef<'tcx, Self>], options: InlineAsmOptions, span: &[Span], _instance: Instance<'_>, _dest_catch_funclet: Option<(Self::BasicBlock, Self::BasicBlock, Option<&Self::Funclet>)>) {
+ if options.contains(InlineAsmOptions::MAY_UNWIND) {
+ self.sess()
+ .struct_span_err(span[0], "GCC backend does not support unwinding from inline asm")
+ .emit();
+ return;
+ }
+
let asm_arch = self.tcx.sess.asm_arch.unwrap();
let is_x86 = matches!(asm_arch, InlineAsmArch::X86 | InlineAsmArch::X86_64);
let att_dialect = is_x86 && options.contains(InlineAsmOptions::ATT_SYNTAX);
@@ -561,7 +568,6 @@ fn reg_to_gcc(reg: InlineAsmRegOrRegClass) -> ConstraintOrRegister {
InlineAsmRegClass::AArch64(AArch64InlineAsmRegClass::vreg) => unimplemented!(),
InlineAsmRegClass::AArch64(AArch64InlineAsmRegClass::vreg_low16) => unimplemented!(),
InlineAsmRegClass::Arm(ArmInlineAsmRegClass::reg) => unimplemented!(),
- InlineAsmRegClass::Arm(ArmInlineAsmRegClass::reg_thumb) => unimplemented!(),
InlineAsmRegClass::Arm(ArmInlineAsmRegClass::sreg)
| InlineAsmRegClass::Arm(ArmInlineAsmRegClass::dreg_low16)
| InlineAsmRegClass::Arm(ArmInlineAsmRegClass::qreg_low8) => unimplemented!(),
@@ -570,6 +576,7 @@ fn reg_to_gcc(reg: InlineAsmRegOrRegClass) -> ConstraintOrRegister {
| InlineAsmRegClass::Arm(ArmInlineAsmRegClass::qreg_low4) => unimplemented!(),
InlineAsmRegClass::Arm(ArmInlineAsmRegClass::dreg)
| InlineAsmRegClass::Arm(ArmInlineAsmRegClass::qreg) => unimplemented!(),
+ InlineAsmRegClass::Avr(_) => unimplemented!(),
InlineAsmRegClass::Bpf(_) => unimplemented!(),
InlineAsmRegClass::Hexagon(HexagonInlineAsmRegClass::reg) => unimplemented!(),
InlineAsmRegClass::Mips(MipsInlineAsmRegClass::reg) => unimplemented!(),
@@ -620,8 +627,7 @@ fn dummy_output_type<'gcc, 'tcx>(cx: &CodegenCx<'gcc, 'tcx>, reg: InlineAsmRegCl
| InlineAsmRegClass::AArch64(AArch64InlineAsmRegClass::vreg_low16) => {
unimplemented!()
}
- InlineAsmRegClass::Arm(ArmInlineAsmRegClass::reg)
- | InlineAsmRegClass::Arm(ArmInlineAsmRegClass::reg_thumb) => cx.type_i32(),
+ InlineAsmRegClass::Arm(ArmInlineAsmRegClass::reg)=> cx.type_i32(),
InlineAsmRegClass::Arm(ArmInlineAsmRegClass::sreg)
| InlineAsmRegClass::Arm(ArmInlineAsmRegClass::sreg_low16) => cx.type_f32(),
InlineAsmRegClass::Arm(ArmInlineAsmRegClass::dreg)
@@ -632,6 +638,7 @@ fn dummy_output_type<'gcc, 'tcx>(cx: &CodegenCx<'gcc, 'tcx>, reg: InlineAsmRegCl
| InlineAsmRegClass::Arm(ArmInlineAsmRegClass::qreg_low4) => {
unimplemented!()
}
+ InlineAsmRegClass::Avr(_) => unimplemented!(),
InlineAsmRegClass::Bpf(_) => unimplemented!(),
InlineAsmRegClass::Hexagon(HexagonInlineAsmRegClass::reg) => cx.type_i32(),
InlineAsmRegClass::Mips(MipsInlineAsmRegClass::reg) => cx.type_i32(),
@@ -728,8 +735,7 @@ fn modifier_to_gcc(arch: InlineAsmArch, reg: InlineAsmRegClass, modifier: Option
| InlineAsmRegClass::AArch64(AArch64InlineAsmRegClass::vreg_low16) => {
unimplemented!()
}
- InlineAsmRegClass::Arm(ArmInlineAsmRegClass::reg)
- | InlineAsmRegClass::Arm(ArmInlineAsmRegClass::reg_thumb) => unimplemented!(),
+ InlineAsmRegClass::Arm(ArmInlineAsmRegClass::reg) => unimplemented!(),
InlineAsmRegClass::Arm(ArmInlineAsmRegClass::sreg)
| InlineAsmRegClass::Arm(ArmInlineAsmRegClass::sreg_low16) => unimplemented!(),
InlineAsmRegClass::Arm(ArmInlineAsmRegClass::dreg)
@@ -740,6 +746,7 @@ fn modifier_to_gcc(arch: InlineAsmArch, reg: InlineAsmRegClass, modifier: Option
| InlineAsmRegClass::Arm(ArmInlineAsmRegClass::qreg_low4) => {
unimplemented!()
}
+ InlineAsmRegClass::Avr(_) => unimplemented!(),
InlineAsmRegClass::Bpf(_) => unimplemented!(),
InlineAsmRegClass::Hexagon(_) => unimplemented!(),
InlineAsmRegClass::Mips(_) => unimplemented!(),
diff --git a/compiler/rustc_codegen_gcc/src/back/write.rs b/compiler/rustc_codegen_gcc/src/back/write.rs
index c3e3847823d..4962d016152 100644
--- a/compiler/rustc_codegen_gcc/src/back/write.rs
+++ b/compiler/rustc_codegen_gcc/src/back/write.rs
@@ -32,7 +32,7 @@ pub(crate) unsafe fn codegen(cgcx: &CodegenContext<GccCodegenBackend>, _diag_han
if config.emit_asm {
let _timer = cgcx
.prof
- .generic_activity_with_arg("LLVM_module_codegen_emit_asm", &module.name[..]);
+ .generic_activity_with_arg("LLVM_module_codegen_emit_asm", &*module.name);
let path = cgcx.output_filenames.temp_path(OutputType::Assembly, module_name);
context.compile_to_file(OutputKind::Assembler, path.to_str().expect("path to str"));
}
@@ -41,7 +41,7 @@ pub(crate) unsafe fn codegen(cgcx: &CodegenContext<GccCodegenBackend>, _diag_han
EmitObj::ObjectCode(_) => {
let _timer = cgcx
.prof
- .generic_activity_with_arg("LLVM_module_codegen_emit_obj", &module.name[..]);
+ .generic_activity_with_arg("LLVM_module_codegen_emit_obj", &*module.name);
match &*module.name {
"std_example.7rcbfp3g-cgu.15" => {
println!("Dumping reproducer {}", module.name);
diff --git a/compiler/rustc_codegen_gcc/src/base.rs b/compiler/rustc_codegen_gcc/src/base.rs
index a3b8d328388..dee70bf7536 100644
--- a/compiler/rustc_codegen_gcc/src/base.rs
+++ b/compiler/rustc_codegen_gcc/src/base.rs
@@ -7,14 +7,12 @@ use gccjit::{
GlobalKind,
};
use rustc_middle::dep_graph;
-use rustc_middle::middle::exported_symbols;
use rustc_middle::ty::TyCtxt;
use rustc_middle::mir::mono::Linkage;
use rustc_codegen_ssa::{ModuleCodegen, ModuleKind};
use rustc_codegen_ssa::base::maybe_create_entry_wrapper;
use rustc_codegen_ssa::mono_item::MonoItemExt;
use rustc_codegen_ssa::traits::DebugInfoMethods;
-use rustc_metadata::EncodedMetadata;
use rustc_session::config::DebugInfo;
use rustc_span::Symbol;
@@ -132,40 +130,3 @@ pub fn compile_codegen_unit<'tcx>(tcx: TyCtxt<'tcx>, cgu_name: Symbol) -> (Modul
(module, cost)
}
-
-pub fn write_compressed_metadata<'tcx>(tcx: TyCtxt<'tcx>, metadata: &EncodedMetadata, gcc_module: &mut GccContext) {
- use snap::write::FrameEncoder;
- use std::io::Write;
-
- // Historical note:
- //
- // When using link.exe it was seen that the section name `.note.rustc`
- // was getting shortened to `.note.ru`, and according to the PE and COFF
- // specification:
- //
- // > Executable images do not use a string table and do not support
- // > section names longer than 8 characters
- //
- // https://docs.microsoft.com/en-us/windows/win32/debug/pe-format
- //
- // As a result, we choose a slightly shorter name! As to why
- // `.note.rustc` works on MinGW, see
- // https://github.com/llvm/llvm-project/blob/llvmorg-12.0.0/lld/COFF/Writer.cpp#L1190-L1197
- let section_name = if tcx.sess.target.is_like_osx { "__DATA,.rustc" } else { ".rustc" };
-
- let context = &gcc_module.context;
- let mut compressed = rustc_metadata::METADATA_HEADER.to_vec();
- FrameEncoder::new(&mut compressed).write_all(&metadata.raw_data()).unwrap();
-
- let name = exported_symbols::metadata_symbol_name(tcx);
- let typ = context.new_array_type(None, context.new_type::<u8>(), compressed.len() as i32);
- let global = context.new_global(None, GlobalKind::Exported, typ, name);
- global.global_set_initializer(&compressed);
- global.set_link_section(section_name);
-
- // Also generate a .section directive to force no
- // flags, at least for ELF outputs, so that the
- // metadata doesn't get loaded into memory.
- let directive = format!(".section {}", section_name);
- context.add_top_level_asm(None, &directive);
-}
diff --git a/compiler/rustc_codegen_gcc/src/lib.rs b/compiler/rustc_codegen_gcc/src/lib.rs
index 629003d7982..30a33b99e50 100644
--- a/compiler/rustc_codegen_gcc/src/lib.rs
+++ b/compiler/rustc_codegen_gcc/src/lib.rs
@@ -22,7 +22,6 @@ extern crate rustc_session;
extern crate rustc_span;
extern crate rustc_symbol_mangling;
extern crate rustc_target;
-extern crate snap;
// This prevents duplicating functions and statics that are already part of the host rustc process.
#[allow(unused_extern_crates)]
@@ -97,7 +96,7 @@ impl CodegenBackend for GccCodegenBackend {
Box::new(res)
}
- fn join_codegen(&self, ongoing_codegen: Box<dyn Any>, sess: &Session) -> Result<(CodegenResults, FxHashMap<WorkProductId, WorkProduct>), ErrorReported> {
+ fn join_codegen(&self, ongoing_codegen: Box<dyn Any>, sess: &Session, _outputs: &OutputFilenames) -> Result<(CodegenResults, FxHashMap<WorkProductId, WorkProduct>), ErrorReported> {
let (codegen_results, work_products) = ongoing_codegen
.downcast::<rustc_codegen_ssa::back::write::OngoingCodegen<GccCodegenBackend>>()
.expect("Expected GccCodegenBackend's OngoingCodegen, found Box<Any>")
@@ -128,10 +127,6 @@ impl ExtraBackendMethods for GccCodegenBackend {
}
}
- fn write_compressed_metadata<'tcx>(&self, tcx: TyCtxt<'tcx>, metadata: &EncodedMetadata, gcc_module: &mut Self::Module) {
- base::write_compressed_metadata(tcx, metadata, gcc_module)
- }
-
fn codegen_allocator<'tcx>(&self, tcx: TyCtxt<'tcx>, mods: &mut Self::Module, module_name: &str, kind: AllocatorKind, has_alloc_error_handler: bool) {
unsafe { allocator::codegen(tcx, mods, module_name, kind, has_alloc_error_handler) }
}
diff --git a/compiler/rustc_codegen_gcc/tests/run/asm.rs b/compiler/rustc_codegen_gcc/tests/run/asm.rs
index 9c0055b0b6b..48c0203d594 100644
--- a/compiler/rustc_codegen_gcc/tests/run/asm.rs
+++ b/compiler/rustc_codegen_gcc/tests/run/asm.rs
@@ -3,8 +3,6 @@
// Run-time:
// status: 0
-#![feature(asm, global_asm)]
-
global_asm!("
.global add_asm
add_asm:
diff --git a/compiler/rustc_codegen_llvm/Cargo.toml b/compiler/rustc_codegen_llvm/Cargo.toml
index 5f3f5334475..3b410c2cb4a 100644
--- a/compiler/rustc_codegen_llvm/Cargo.toml
+++ b/compiler/rustc_codegen_llvm/Cargo.toml
@@ -11,8 +11,8 @@ doctest = false
bitflags = "1.0"
cstr = "0.2"
libc = "0.2"
+libloading = "0.7.1"
measureme = "10.0.0"
-snap = "1"
tracing = "0.1"
rustc_middle = { path = "../rustc_middle" }
rustc-demangle = "0.1.21"
diff --git a/compiler/rustc_codegen_llvm/src/abi.rs b/compiler/rustc_codegen_llvm/src/abi.rs
index bedd3523d89..e9b66b54c58 100644
--- a/compiler/rustc_codegen_llvm/src/abi.rs
+++ b/compiler/rustc_codegen_llvm/src/abi.rs
@@ -136,11 +136,11 @@ impl ArgAttributesExt for ArgAttributes {
}
pub trait LlvmType {
- fn llvm_type(&self, cx: &CodegenCx<'ll, '_>) -> &'ll Type;
+ fn llvm_type<'ll>(&self, cx: &CodegenCx<'ll, '_>) -> &'ll Type;
}
impl LlvmType for Reg {
- fn llvm_type(&self, cx: &CodegenCx<'ll, '_>) -> &'ll Type {
+ fn llvm_type<'ll>(&self, cx: &CodegenCx<'ll, '_>) -> &'ll Type {
match self.kind {
RegKind::Integer => cx.type_ix(self.size.bits()),
RegKind::Float => match self.size.bits() {
@@ -154,7 +154,7 @@ impl LlvmType for Reg {
}
impl LlvmType for CastTarget {
- fn llvm_type(&self, cx: &CodegenCx<'ll, '_>) -> &'ll Type {
+ fn llvm_type<'ll>(&self, cx: &CodegenCx<'ll, '_>) -> &'ll Type {
let rest_ll_unit = self.rest.unit.llvm_type(cx);
let (rest_count, rem_bytes) = if self.rest.unit.size.bytes() == 0 {
(0, 0)
@@ -181,9 +181,7 @@ impl LlvmType for CastTarget {
let mut args: Vec<_> = self
.prefix
.iter()
- .flat_map(|option_kind| {
- option_kind.map(|kind| Reg { kind, size: self.prefix_chunk_size }.llvm_type(cx))
- })
+ .flat_map(|option_reg| option_reg.map(|reg| reg.llvm_type(cx)))
.chain((0..rest_count).map(|_| rest_ll_unit))
.collect();
@@ -214,7 +212,7 @@ pub trait ArgAbiExt<'ll, 'tcx> {
);
}
-impl ArgAbiExt<'ll, 'tcx> for ArgAbi<'tcx, Ty<'tcx>> {
+impl<'ll, 'tcx> ArgAbiExt<'ll, 'tcx> for ArgAbi<'tcx, Ty<'tcx>> {
/// Gets the LLVM type for a place of the original Rust type of
/// this argument/return, i.e., the result of `type_of::type_of`.
fn memory_ty(&self, cx: &CodegenCx<'ll, 'tcx>) -> &'ll Type {
@@ -289,7 +287,7 @@ impl ArgAbiExt<'ll, 'tcx> for ArgAbi<'tcx, Ty<'tcx>> {
fn store_fn_arg(
&self,
- bx: &mut Builder<'a, 'll, 'tcx>,
+ bx: &mut Builder<'_, 'll, 'tcx>,
idx: &mut usize,
dst: PlaceRef<'tcx, &'ll Value>,
) {
@@ -316,7 +314,7 @@ impl ArgAbiExt<'ll, 'tcx> for ArgAbi<'tcx, Ty<'tcx>> {
}
}
-impl ArgAbiMethods<'tcx> for Builder<'a, 'll, 'tcx> {
+impl<'ll, 'tcx> ArgAbiMethods<'tcx> for Builder<'_, 'll, 'tcx> {
fn store_fn_arg(
&mut self,
arg_abi: &ArgAbi<'tcx, Ty<'tcx>>,
@@ -338,15 +336,15 @@ impl ArgAbiMethods<'tcx> for Builder<'a, 'll, 'tcx> {
}
}
-pub trait FnAbiLlvmExt<'tcx> {
+pub trait FnAbiLlvmExt<'ll, 'tcx> {
fn llvm_type(&self, cx: &CodegenCx<'ll, 'tcx>) -> &'ll Type;
fn ptr_to_llvm_type(&self, cx: &CodegenCx<'ll, 'tcx>) -> &'ll Type;
fn llvm_cconv(&self) -> llvm::CallConv;
fn apply_attrs_llfn(&self, cx: &CodegenCx<'ll, 'tcx>, llfn: &'ll Value);
- fn apply_attrs_callsite(&self, bx: &mut Builder<'a, 'll, 'tcx>, callsite: &'ll Value);
+ fn apply_attrs_callsite(&self, bx: &mut Builder<'_, 'll, 'tcx>, callsite: &'ll Value);
}
-impl<'tcx> FnAbiLlvmExt<'tcx> for FnAbi<'tcx, Ty<'tcx>> {
+impl<'ll, 'tcx> FnAbiLlvmExt<'ll, 'tcx> for FnAbi<'tcx, Ty<'tcx>> {
fn llvm_type(&self, cx: &CodegenCx<'ll, 'tcx>) -> &'ll Type {
// Ignore "extra" args from the call site for C variadic functions.
// Only the "fixed" args are part of the LLVM function signature.
@@ -466,6 +464,9 @@ impl<'tcx> FnAbiLlvmExt<'tcx> for FnAbi<'tcx, Ty<'tcx>> {
);
}
}
+ PassMode::Cast(cast) => {
+ cast.attrs.apply_attrs_to_llfn(llvm::AttributePlace::ReturnValue, cx, llfn);
+ }
_ => {}
}
for arg in &self.args {
@@ -497,14 +498,14 @@ impl<'tcx> FnAbiLlvmExt<'tcx> for FnAbi<'tcx, Ty<'tcx>> {
apply(a);
apply(b);
}
- PassMode::Cast(_) => {
- apply(&ArgAttributes::new());
+ PassMode::Cast(cast) => {
+ apply(&cast.attrs);
}
}
}
}
- fn apply_attrs_callsite(&self, bx: &mut Builder<'a, 'll, 'tcx>, callsite: &'ll Value) {
+ fn apply_attrs_callsite(&self, bx: &mut Builder<'_, 'll, 'tcx>, callsite: &'ll Value) {
if self.ret.layout.abi.is_uninhabited() {
llvm::Attribute::NoReturn.apply_callsite(llvm::AttributePlace::Function, callsite);
}
@@ -533,6 +534,13 @@ impl<'tcx> FnAbiLlvmExt<'tcx> for FnAbi<'tcx, Ty<'tcx>> {
);
}
}
+ PassMode::Cast(cast) => {
+ cast.attrs.apply_attrs_to_callsite(
+ llvm::AttributePlace::ReturnValue,
+ &bx.cx,
+ callsite,
+ );
+ }
_ => {}
}
if let abi::Abi::Scalar(scalar) = self.ret.layout.abi {
@@ -577,8 +585,8 @@ impl<'tcx> FnAbiLlvmExt<'tcx> for FnAbi<'tcx, Ty<'tcx>> {
apply(bx.cx, a);
apply(bx.cx, b);
}
- PassMode::Cast(_) => {
- apply(bx.cx, &ArgAttributes::new());
+ PassMode::Cast(cast) => {
+ apply(bx.cx, &cast.attrs);
}
}
}
@@ -602,12 +610,12 @@ impl<'tcx> FnAbiLlvmExt<'tcx> for FnAbi<'tcx, Ty<'tcx>> {
}
}
-impl AbiBuilderMethods<'tcx> for Builder<'a, 'll, 'tcx> {
+impl<'tcx> AbiBuilderMethods<'tcx> for Builder<'_, '_, 'tcx> {
fn apply_attrs_callsite(&mut self, fn_abi: &FnAbi<'tcx, Ty<'tcx>>, callsite: Self::Value) {
fn_abi.apply_attrs_callsite(self, callsite)
}
- fn get_param(&self, index: usize) -> Self::Value {
+ fn get_param(&mut self, index: usize) -> Self::Value {
llvm::get_param(self.llfn(), index as c_uint)
}
}
diff --git a/compiler/rustc_codegen_llvm/src/asm.rs b/compiler/rustc_codegen_llvm/src/asm.rs
index 02096f4abfa..caf16c1939d 100644
--- a/compiler/rustc_codegen_llvm/src/asm.rs
+++ b/compiler/rustc_codegen_llvm/src/asm.rs
@@ -1,6 +1,8 @@
use crate::builder::Builder;
+use crate::common::Funclet;
use crate::context::CodegenCx;
use crate::llvm;
+use crate::llvm_util;
use crate::type_::Type;
use crate::type_of::LayoutLlvmExt;
use crate::value::Value;
@@ -21,7 +23,7 @@ use rustc_target::asm::*;
use libc::{c_char, c_uint};
use tracing::debug;
-impl AsmBuilderMethods<'tcx> for Builder<'a, 'll, 'tcx> {
+impl<'ll, 'tcx> AsmBuilderMethods<'tcx> for Builder<'_, 'll, 'tcx> {
fn codegen_llvm_inline_asm(
&mut self,
ia: &hir::LlvmInlineAsmInner,
@@ -98,6 +100,8 @@ impl AsmBuilderMethods<'tcx> for Builder<'a, 'll, 'tcx> {
ia.alignstack,
ia.dialect,
&[span],
+ false,
+ None,
);
if r.is_none() {
return false;
@@ -121,6 +125,7 @@ impl AsmBuilderMethods<'tcx> for Builder<'a, 'll, 'tcx> {
options: InlineAsmOptions,
line_spans: &[Span],
instance: Instance<'_>,
+ dest_catch_funclet: Option<(Self::BasicBlock, Self::BasicBlock, Option<&Self::Funclet>)>,
) {
let asm_arch = self.tcx.sess.asm_arch.unwrap();
@@ -314,6 +319,9 @@ impl AsmBuilderMethods<'tcx> for Builder<'a, 'll, 'tcx> {
"~{vxrm}".to_string(),
]);
}
+ InlineAsmArch::Avr => {
+ constraints.push("~{sreg}".to_string());
+ }
InlineAsmArch::Nvptx64 => {}
InlineAsmArch::PowerPC | InlineAsmArch::PowerPC64 => {}
InlineAsmArch::Hexagon => {}
@@ -355,6 +363,8 @@ impl AsmBuilderMethods<'tcx> for Builder<'a, 'll, 'tcx> {
alignstack,
dialect,
line_spans,
+ options.contains(InlineAsmOptions::MAY_UNWIND),
+ dest_catch_funclet,
)
.unwrap_or_else(|| span_bug!(line_spans[0], "LLVM asm constraint validation failed"));
@@ -389,7 +399,7 @@ impl AsmBuilderMethods<'tcx> for Builder<'a, 'll, 'tcx> {
}
}
-impl AsmMethods for CodegenCx<'ll, 'tcx> {
+impl AsmMethods for CodegenCx<'_, '_> {
fn codegen_global_asm(
&self,
template: &[InlineAsmTemplatePiece],
@@ -437,8 +447,8 @@ impl AsmMethods for CodegenCx<'ll, 'tcx> {
}
}
-pub(crate) fn inline_asm_call(
- bx: &mut Builder<'a, 'll, 'tcx>,
+pub(crate) fn inline_asm_call<'ll>(
+ bx: &mut Builder<'_, 'll, '_>,
asm: &str,
cons: &str,
inputs: &[&'ll Value],
@@ -447,9 +457,16 @@ pub(crate) fn inline_asm_call(
alignstack: bool,
dia: LlvmAsmDialect,
line_spans: &[Span],
+ unwind: bool,
+ dest_catch_funclet: Option<(
+ &'ll llvm::BasicBlock,
+ &'ll llvm::BasicBlock,
+ Option<&Funclet<'ll>>,
+ )>,
) -> Option<&'ll Value> {
let volatile = if volatile { llvm::True } else { llvm::False };
let alignstack = if alignstack { llvm::True } else { llvm::False };
+ let can_throw = if unwind { llvm::True } else { llvm::False };
let argtys = inputs
.iter()
@@ -460,12 +477,19 @@ pub(crate) fn inline_asm_call(
.collect::<Vec<_>>();
debug!("Asm Output Type: {:?}", output);
- let fty = bx.cx.type_func(&argtys[..], output);
+ let fty = bx.cx.type_func(&argtys, output);
unsafe {
// Ask LLVM to verify that the constraints are well-formed.
let constraints_ok = llvm::LLVMRustInlineAsmVerify(fty, cons.as_ptr().cast(), cons.len());
debug!("constraint verification result: {:?}", constraints_ok);
if constraints_ok {
+ if unwind && llvm_util::get_version() < (13, 0, 0) {
+ bx.cx.sess().span_fatal(
+ line_spans[0],
+ "unwinding from inline assembly is only supported on llvm >= 13.",
+ );
+ }
+
let v = llvm::LLVMRustInlineAsm(
fty,
asm.as_ptr().cast(),
@@ -475,8 +499,14 @@ pub(crate) fn inline_asm_call(
volatile,
alignstack,
llvm::AsmDialect::from_generic(dia),
+ can_throw,
);
- let call = bx.call(fty, v, inputs, None);
+
+ let call = if let Some((dest, catch, funclet)) = dest_catch_funclet {
+ bx.invoke(fty, v, inputs, dest, catch, funclet)
+ } else {
+ bx.call(fty, v, inputs, None)
+ };
// Store mark in a metadata node so we can map LLVM errors
// back to source locations. See #17552.
@@ -553,7 +583,7 @@ fn a64_vreg_index(reg: InlineAsmReg) -> Option<u32> {
}
/// Converts a register class to an LLVM constraint code.
-fn reg_to_llvm(reg: InlineAsmRegOrRegClass, layout: Option<&TyAndLayout<'tcx>>) -> String {
+fn reg_to_llvm(reg: InlineAsmRegOrRegClass, layout: Option<&TyAndLayout<'_>>) -> String {
match reg {
// For vector registers LLVM wants the register name to match the type size.
InlineAsmRegOrRegClass::Reg(reg) => {
@@ -602,7 +632,6 @@ fn reg_to_llvm(reg: InlineAsmRegOrRegClass, layout: Option<&TyAndLayout<'tcx>>)
unreachable!("clobber-only")
}
InlineAsmRegClass::Arm(ArmInlineAsmRegClass::reg) => "r",
- InlineAsmRegClass::Arm(ArmInlineAsmRegClass::reg_thumb) => "l",
InlineAsmRegClass::Arm(ArmInlineAsmRegClass::sreg)
| InlineAsmRegClass::Arm(ArmInlineAsmRegClass::dreg_low16)
| InlineAsmRegClass::Arm(ArmInlineAsmRegClass::qreg_low8) => "t",
@@ -642,6 +671,11 @@ fn reg_to_llvm(reg: InlineAsmRegOrRegClass, layout: Option<&TyAndLayout<'tcx>>)
InlineAsmRegClass::Wasm(WasmInlineAsmRegClass::local) => "r",
InlineAsmRegClass::Bpf(BpfInlineAsmRegClass::reg) => "r",
InlineAsmRegClass::Bpf(BpfInlineAsmRegClass::wreg) => "w",
+ InlineAsmRegClass::Avr(AvrInlineAsmRegClass::reg) => "r",
+ InlineAsmRegClass::Avr(AvrInlineAsmRegClass::reg_upper) => "d",
+ InlineAsmRegClass::Avr(AvrInlineAsmRegClass::reg_pair) => "r",
+ InlineAsmRegClass::Avr(AvrInlineAsmRegClass::reg_iw) => "w",
+ InlineAsmRegClass::Avr(AvrInlineAsmRegClass::reg_ptr) => "e",
InlineAsmRegClass::S390x(S390xInlineAsmRegClass::reg) => "r",
InlineAsmRegClass::S390x(S390xInlineAsmRegClass::freg) => "f",
InlineAsmRegClass::SpirV(SpirVInlineAsmRegClass::reg) => {
@@ -668,8 +702,7 @@ fn modifier_to_llvm(
InlineAsmRegClass::AArch64(AArch64InlineAsmRegClass::preg) => {
unreachable!("clobber-only")
}
- InlineAsmRegClass::Arm(ArmInlineAsmRegClass::reg)
- | InlineAsmRegClass::Arm(ArmInlineAsmRegClass::reg_thumb) => None,
+ InlineAsmRegClass::Arm(ArmInlineAsmRegClass::reg) => None,
InlineAsmRegClass::Arm(ArmInlineAsmRegClass::sreg)
| InlineAsmRegClass::Arm(ArmInlineAsmRegClass::sreg_low16) => None,
InlineAsmRegClass::Arm(ArmInlineAsmRegClass::dreg)
@@ -722,6 +755,14 @@ fn modifier_to_llvm(
}
InlineAsmRegClass::Wasm(WasmInlineAsmRegClass::local) => None,
InlineAsmRegClass::Bpf(_) => None,
+ InlineAsmRegClass::Avr(AvrInlineAsmRegClass::reg_pair)
+ | InlineAsmRegClass::Avr(AvrInlineAsmRegClass::reg_iw)
+ | InlineAsmRegClass::Avr(AvrInlineAsmRegClass::reg_ptr) => match modifier {
+ Some('h') => Some('B'),
+ Some('l') => Some('A'),
+ _ => None,
+ },
+ InlineAsmRegClass::Avr(_) => None,
InlineAsmRegClass::S390x(_) => None,
InlineAsmRegClass::SpirV(SpirVInlineAsmRegClass::reg) => {
bug!("LLVM backend does not support SPIR-V")
@@ -732,7 +773,7 @@ fn modifier_to_llvm(
/// Type to use for outputs that are discarded. It doesn't really matter what
/// the type is, as long as it is valid for the constraint code.
-fn dummy_output_type(cx: &CodegenCx<'ll, 'tcx>, reg: InlineAsmRegClass) -> &'ll Type {
+fn dummy_output_type<'ll>(cx: &CodegenCx<'ll, '_>, reg: InlineAsmRegClass) -> &'ll Type {
match reg {
InlineAsmRegClass::AArch64(AArch64InlineAsmRegClass::reg) => cx.type_i32(),
InlineAsmRegClass::AArch64(AArch64InlineAsmRegClass::vreg)
@@ -742,8 +783,7 @@ fn dummy_output_type(cx: &CodegenCx<'ll, 'tcx>, reg: InlineAsmRegClass) -> &'ll
InlineAsmRegClass::AArch64(AArch64InlineAsmRegClass::preg) => {
unreachable!("clobber-only")
}
- InlineAsmRegClass::Arm(ArmInlineAsmRegClass::reg)
- | InlineAsmRegClass::Arm(ArmInlineAsmRegClass::reg_thumb) => cx.type_i32(),
+ InlineAsmRegClass::Arm(ArmInlineAsmRegClass::reg) => cx.type_i32(),
InlineAsmRegClass::Arm(ArmInlineAsmRegClass::sreg)
| InlineAsmRegClass::Arm(ArmInlineAsmRegClass::sreg_low16) => cx.type_f32(),
InlineAsmRegClass::Arm(ArmInlineAsmRegClass::dreg)
@@ -785,6 +825,11 @@ fn dummy_output_type(cx: &CodegenCx<'ll, 'tcx>, reg: InlineAsmRegClass) -> &'ll
InlineAsmRegClass::Wasm(WasmInlineAsmRegClass::local) => cx.type_i32(),
InlineAsmRegClass::Bpf(BpfInlineAsmRegClass::reg) => cx.type_i64(),
InlineAsmRegClass::Bpf(BpfInlineAsmRegClass::wreg) => cx.type_i32(),
+ InlineAsmRegClass::Avr(AvrInlineAsmRegClass::reg) => cx.type_i8(),
+ InlineAsmRegClass::Avr(AvrInlineAsmRegClass::reg_upper) => cx.type_i8(),
+ InlineAsmRegClass::Avr(AvrInlineAsmRegClass::reg_pair) => cx.type_i16(),
+ InlineAsmRegClass::Avr(AvrInlineAsmRegClass::reg_iw) => cx.type_i16(),
+ InlineAsmRegClass::Avr(AvrInlineAsmRegClass::reg_ptr) => cx.type_i16(),
InlineAsmRegClass::S390x(S390xInlineAsmRegClass::reg) => cx.type_i32(),
InlineAsmRegClass::S390x(S390xInlineAsmRegClass::freg) => cx.type_f64(),
InlineAsmRegClass::SpirV(SpirVInlineAsmRegClass::reg) => {
@@ -796,7 +841,7 @@ fn dummy_output_type(cx: &CodegenCx<'ll, 'tcx>, reg: InlineAsmRegClass) -> &'ll
/// Helper function to get the LLVM type for a Scalar. Pointers are returned as
/// the equivalent integer type.
-fn llvm_asm_scalar_type(cx: &CodegenCx<'ll, 'tcx>, scalar: Scalar) -> &'ll Type {
+fn llvm_asm_scalar_type<'ll>(cx: &CodegenCx<'ll, '_>, scalar: Scalar) -> &'ll Type {
match scalar.value {
Primitive::Int(Integer::I8, _) => cx.type_i8(),
Primitive::Int(Integer::I16, _) => cx.type_i16(),
@@ -810,8 +855,8 @@ fn llvm_asm_scalar_type(cx: &CodegenCx<'ll, 'tcx>, scalar: Scalar) -> &'ll Type
}
/// Fix up an input value to work around LLVM bugs.
-fn llvm_fixup_input(
- bx: &mut Builder<'a, 'll, 'tcx>,
+fn llvm_fixup_input<'ll, 'tcx>(
+ bx: &mut Builder<'_, 'll, 'tcx>,
mut value: &'ll Value,
reg: InlineAsmRegClass,
layout: &TyAndLayout<'tcx>,
@@ -888,8 +933,8 @@ fn llvm_fixup_input(
}
/// Fix up an output value to work around LLVM bugs.
-fn llvm_fixup_output(
- bx: &mut Builder<'a, 'll, 'tcx>,
+fn llvm_fixup_output<'ll, 'tcx>(
+ bx: &mut Builder<'_, 'll, 'tcx>,
mut value: &'ll Value,
reg: InlineAsmRegClass,
layout: &TyAndLayout<'tcx>,
@@ -964,7 +1009,7 @@ fn llvm_fixup_output(
}
/// Output type to use for llvm_fixup_output.
-fn llvm_fixup_output_type(
+fn llvm_fixup_output_type<'ll, 'tcx>(
cx: &CodegenCx<'ll, 'tcx>,
reg: InlineAsmRegClass,
layout: &TyAndLayout<'tcx>,
diff --git a/compiler/rustc_codegen_llvm/src/attributes.rs b/compiler/rustc_codegen_llvm/src/attributes.rs
index 659cf9ea070..bd25087c08e 100644
--- a/compiler/rustc_codegen_llvm/src/attributes.rs
+++ b/compiler/rustc_codegen_llvm/src/attributes.rs
@@ -12,7 +12,7 @@ use rustc_middle::ty::{self, TyCtxt};
use rustc_session::config::OptLevel;
use rustc_session::Session;
use rustc_target::spec::abi::Abi;
-use rustc_target::spec::{FramePointer, SanitizerSet, StackProbeType};
+use rustc_target::spec::{FramePointer, SanitizerSet, StackProbeType, StackProtector};
use crate::attributes;
use crate::llvm::AttributePlace::Function;
@@ -25,7 +25,7 @@ use crate::value::Value;
/// Mark LLVM function to use provided inline heuristic.
#[inline]
-fn inline(cx: &CodegenCx<'ll, '_>, val: &'ll Value, inline: InlineAttr) {
+fn inline<'ll>(cx: &CodegenCx<'ll, '_>, val: &'ll Value, inline: InlineAttr) {
use self::InlineAttr::*;
match inline {
Hint => Attribute::InlineHint.apply_llfn(Function, val),
@@ -41,7 +41,7 @@ fn inline(cx: &CodegenCx<'ll, '_>, val: &'ll Value, inline: InlineAttr) {
/// Apply LLVM sanitize attributes.
#[inline]
-pub fn sanitize(cx: &CodegenCx<'ll, '_>, no_sanitize: SanitizerSet, llfn: &'ll Value) {
+pub fn sanitize<'ll>(cx: &CodegenCx<'ll, '_>, no_sanitize: SanitizerSet, llfn: &'ll Value) {
let enabled = cx.tcx.sess.opts.debugging_opts.sanitizer - no_sanitize;
if enabled.contains(SanitizerSet::ADDRESS) {
llvm::Attribute::SanitizeAddress.apply_llfn(Function, llfn);
@@ -59,17 +59,17 @@ pub fn sanitize(cx: &CodegenCx<'ll, '_>, no_sanitize: SanitizerSet, llfn: &'ll V
/// Tell LLVM to emit or not emit the information necessary to unwind the stack for the function.
#[inline]
-pub fn emit_uwtable(val: &'ll Value, emit: bool) {
+pub fn emit_uwtable(val: &Value, emit: bool) {
Attribute::UWTable.toggle_llfn(Function, val, emit);
}
/// Tell LLVM if this function should be 'naked', i.e., skip the epilogue and prologue.
#[inline]
-fn naked(val: &'ll Value, is_naked: bool) {
+fn naked(val: &Value, is_naked: bool) {
Attribute::Naked.toggle_llfn(Function, val, is_naked);
}
-pub fn set_frame_pointer_type(cx: &CodegenCx<'ll, '_>, llfn: &'ll Value) {
+pub fn set_frame_pointer_type<'ll>(cx: &CodegenCx<'ll, '_>, llfn: &'ll Value) {
let mut fp = cx.sess().target.frame_pointer;
// "mcount" function relies on stack pointer.
// See <https://sourceware.org/binutils/docs/gprof/Implementation.html>.
@@ -92,7 +92,7 @@ pub fn set_frame_pointer_type(cx: &CodegenCx<'ll, '_>, llfn: &'ll Value) {
/// Tell LLVM what instrument function to insert.
#[inline]
-fn set_instrument_function(cx: &CodegenCx<'ll, '_>, llfn: &'ll Value) {
+fn set_instrument_function<'ll>(cx: &CodegenCx<'ll, '_>, llfn: &'ll Value) {
if cx.sess().instrument_mcount() {
// Similar to `clang -pg` behavior. Handled by the
// `post-inline-ee-instrument` LLVM pass.
@@ -110,7 +110,7 @@ fn set_instrument_function(cx: &CodegenCx<'ll, '_>, llfn: &'ll Value) {
}
}
-fn set_probestack(cx: &CodegenCx<'ll, '_>, llfn: &'ll Value) {
+fn set_probestack<'ll>(cx: &CodegenCx<'ll, '_>, llfn: &'ll Value) {
// Currently stack probes seem somewhat incompatible with the address
// sanitizer and thread sanitizer. With asan we're already protected from
// stack overflow anyway so we don't really need stack probes regardless.
@@ -161,7 +161,18 @@ fn set_probestack(cx: &CodegenCx<'ll, '_>, llfn: &'ll Value) {
}
}
-pub fn apply_target_cpu_attr(cx: &CodegenCx<'ll, '_>, llfn: &'ll Value) {
+fn set_stackprotector<'ll>(cx: &CodegenCx<'ll, '_>, llfn: &'ll Value) {
+ let sspattr = match cx.sess().stack_protector() {
+ StackProtector::None => return,
+ StackProtector::All => Attribute::StackProtectReq,
+ StackProtector::Strong => Attribute::StackProtectStrong,
+ StackProtector::Basic => Attribute::StackProtect,
+ };
+
+ sspattr.apply_llfn(Function, llfn)
+}
+
+pub fn apply_target_cpu_attr<'ll>(cx: &CodegenCx<'ll, '_>, llfn: &'ll Value) {
let target_cpu = SmallCStr::new(llvm_util::target_cpu(cx.tcx.sess));
llvm::AddFunctionAttrStringValue(
llfn,
@@ -171,7 +182,7 @@ pub fn apply_target_cpu_attr(cx: &CodegenCx<'ll, '_>, llfn: &'ll Value) {
);
}
-pub fn apply_tune_cpu_attr(cx: &CodegenCx<'ll, '_>, llfn: &'ll Value) {
+pub fn apply_tune_cpu_attr<'ll>(cx: &CodegenCx<'ll, '_>, llfn: &'ll Value) {
if let Some(tune) = llvm_util::tune_cpu(cx.tcx.sess) {
let tune_cpu = SmallCStr::new(tune);
llvm::AddFunctionAttrStringValue(
@@ -185,14 +196,14 @@ pub fn apply_tune_cpu_attr(cx: &CodegenCx<'ll, '_>, llfn: &'ll Value) {
/// Sets the `NonLazyBind` LLVM attribute on a given function,
/// assuming the codegen options allow skipping the PLT.
-pub fn non_lazy_bind(sess: &Session, llfn: &'ll Value) {
+pub fn non_lazy_bind<'ll>(sess: &Session, llfn: &'ll Value) {
// Don't generate calls through PLT if it's not necessary
if !sess.needs_plt() {
Attribute::NonLazyBind.apply_llfn(Function, llfn);
}
}
-pub(crate) fn default_optimisation_attrs(sess: &Session, llfn: &'ll Value) {
+pub(crate) fn default_optimisation_attrs<'ll>(sess: &Session, llfn: &'ll Value) {
match sess.opts.optimize {
OptLevel::Size => {
llvm::Attribute::MinSize.unapply_llfn(Function, llfn);
@@ -215,7 +226,11 @@ pub(crate) fn default_optimisation_attrs(sess: &Session, llfn: &'ll Value) {
/// Composite function which sets LLVM attributes for function depending on its AST (`#[attribute]`)
/// attributes.
-pub fn from_fn_attrs(cx: &CodegenCx<'ll, 'tcx>, llfn: &'ll Value, instance: ty::Instance<'tcx>) {
+pub fn from_fn_attrs<'ll, 'tcx>(
+ cx: &CodegenCx<'ll, 'tcx>,
+ llfn: &'ll Value,
+ instance: ty::Instance<'tcx>,
+) {
let codegen_fn_attrs = cx.tcx.codegen_fn_attrs(instance.def_id());
match codegen_fn_attrs.optimize {
@@ -271,6 +286,7 @@ pub fn from_fn_attrs(cx: &CodegenCx<'ll, 'tcx>, llfn: &'ll Value, instance: ty::
set_frame_pointer_type(cx, llfn);
set_instrument_function(cx, llfn);
set_probestack(cx, llfn);
+ set_stackprotector(cx, llfn);
if codegen_fn_attrs.flags.contains(CodegenFnAttrFlags::COLD) {
Attribute::Cold.apply_llfn(Function, llfn);
diff --git a/compiler/rustc_codegen_llvm/src/back/lto.rs b/compiler/rustc_codegen_llvm/src/back/lto.rs
index 97780de9ba4..4bb1fed2d51 100644
--- a/compiler/rustc_codegen_llvm/src/back/lto.rs
+++ b/compiler/rustc_codegen_llvm/src/back/lto.rs
@@ -363,7 +363,7 @@ fn fat_lto(
crate struct Linker<'a>(&'a mut llvm::Linker<'a>);
-impl Linker<'a> {
+impl<'a> Linker<'a> {
crate fn new(llmod: &'a llvm::Module) -> Self {
unsafe { Linker(llvm::LLVMRustLinkerNew(llmod)) }
}
@@ -383,7 +383,7 @@ impl Linker<'a> {
}
}
-impl Drop for Linker<'a> {
+impl Drop for Linker<'_> {
fn drop(&mut self) {
unsafe {
llvm::LLVMRustLinkerFree(&mut *(self.0 as *mut _));
@@ -587,7 +587,7 @@ pub(crate) fn run_pass_manager(
config: &ModuleConfig,
thin: bool,
) -> Result<(), FatalError> {
- let _timer = cgcx.prof.extra_verbose_generic_activity("LLVM_lto_optimize", &module.name[..]);
+ let _timer = cgcx.prof.extra_verbose_generic_activity("LLVM_lto_optimize", &*module.name);
// Now we have one massive module inside of llmod. Time to run the
// LTO-specific optimization passes that LLVM provides.
diff --git a/compiler/rustc_codegen_llvm/src/back/write.rs b/compiler/rustc_codegen_llvm/src/back/write.rs
index 3d05fc15b38..fb194a98a0d 100644
--- a/compiler/rustc_codegen_llvm/src/back/write.rs
+++ b/compiler/rustc_codegen_llvm/src/back/write.rs
@@ -46,7 +46,7 @@ pub fn llvm_err(handler: &rustc_errors::Handler, msg: &str) -> FatalError {
}
}
-pub fn write_output_file(
+pub fn write_output_file<'ll>(
handler: &rustc_errors::Handler,
target: &'ll llvm::TargetMachine,
pm: &llvm::PassManager<'ll>,
@@ -205,8 +205,11 @@ pub fn target_machine_factory(
let use_init_array =
!sess.opts.debugging_opts.use_ctors_section.unwrap_or(sess.target.use_ctors_section);
+ let path_mapping = sess.source_map().path_mapping().clone();
+
Arc::new(move |config: TargetMachineFactoryConfig| {
- let split_dwarf_file = config.split_dwarf_file.unwrap_or_default();
+ let split_dwarf_file =
+ path_mapping.map_prefix(config.split_dwarf_file.unwrap_or_default()).0;
let split_dwarf_file = CString::new(split_dwarf_file.to_str().unwrap()).unwrap();
let tm = unsafe {
@@ -259,6 +262,7 @@ pub(crate) fn save_temp_bitcode(
pub struct DiagnosticHandlers<'a> {
data: *mut (&'a CodegenContext<LlvmCodegenBackend>, &'a Handler),
llcx: &'a llvm::Context,
+ old_handler: Option<&'a llvm::DiagnosticHandler>,
}
impl<'a> DiagnosticHandlers<'a> {
@@ -267,12 +271,35 @@ impl<'a> DiagnosticHandlers<'a> {
handler: &'a Handler,
llcx: &'a llvm::Context,
) -> Self {
+ let remark_passes_all: bool;
+ let remark_passes: Vec<CString>;
+ match &cgcx.remark {
+ Passes::All => {
+ remark_passes_all = true;
+ remark_passes = Vec::new();
+ }
+ Passes::Some(passes) => {
+ remark_passes_all = false;
+ remark_passes =
+ passes.iter().map(|name| CString::new(name.as_str()).unwrap()).collect();
+ }
+ };
+ let remark_passes: Vec<*const c_char> =
+ remark_passes.iter().map(|name: &CString| name.as_ptr()).collect();
let data = Box::into_raw(Box::new((cgcx, handler)));
unsafe {
+ let old_handler = llvm::LLVMRustContextGetDiagnosticHandler(llcx);
+ llvm::LLVMRustContextConfigureDiagnosticHandler(
+ llcx,
+ diagnostic_handler,
+ data.cast(),
+ remark_passes_all,
+ remark_passes.as_ptr(),
+ remark_passes.len(),
+ );
llvm::LLVMRustSetInlineAsmDiagnosticHandler(llcx, inline_asm_handler, data.cast());
- llvm::LLVMContextSetDiagnosticHandler(llcx, diagnostic_handler, data.cast());
+ DiagnosticHandlers { data, llcx, old_handler }
}
- DiagnosticHandlers { data, llcx }
}
}
@@ -281,7 +308,7 @@ impl<'a> Drop for DiagnosticHandlers<'a> {
use std::ptr::null_mut;
unsafe {
llvm::LLVMRustSetInlineAsmDiagnosticHandler(self.llcx, inline_asm_handler, null_mut());
- llvm::LLVMContextSetDiagnosticHandler(self.llcx, diagnostic_handler, null_mut());
+ llvm::LLVMRustContextSetDiagnosticHandler(self.llcx, self.old_handler);
drop(Box::from_raw(self.data));
}
}
@@ -337,13 +364,8 @@ unsafe extern "C" fn diagnostic_handler(info: &DiagnosticInfo, user: *mut c_void
if enabled {
diag_handler.note_without_error(&format!(
- "optimization {} for {} at {}:{}:{}: {}",
- opt.kind.describe(),
- opt.pass_name,
- opt.filename,
- opt.line,
- opt.column,
- opt.message
+ "{}:{}:{}: {}: {}",
+ opt.filename, opt.line, opt.column, opt.pass_name, opt.message,
));
}
}
@@ -491,7 +513,7 @@ pub(crate) unsafe fn optimize(
module: &ModuleCodegen<ModuleLlvm>,
config: &ModuleConfig,
) -> Result<(), FatalError> {
- let _timer = cgcx.prof.generic_activity_with_arg("LLVM_module_optimize", &module.name[..]);
+ let _timer = cgcx.prof.generic_activity_with_arg("LLVM_module_optimize", &*module.name);
let llmod = module.module_llvm.llmod();
let llcx = &*module.module_llvm.llcx;
@@ -644,14 +666,14 @@ pub(crate) unsafe fn optimize(
{
let _timer = cgcx.prof.extra_verbose_generic_activity(
"LLVM_module_optimize_function_passes",
- &module.name[..],
+ &*module.name,
);
llvm::LLVMRustRunFunctionPassManager(fpm, llmod);
}
{
let _timer = cgcx.prof.extra_verbose_generic_activity(
"LLVM_module_optimize_module_passes",
- &module.name[..],
+ &*module.name,
);
llvm::LLVMRunPassManager(mpm, llmod);
}
@@ -714,7 +736,7 @@ pub(crate) unsafe fn codegen(
module: ModuleCodegen<ModuleLlvm>,
config: &ModuleConfig,
) -> Result<CompiledModule, FatalError> {
- let _timer = cgcx.prof.generic_activity_with_arg("LLVM_module_codegen", &module.name[..]);
+ let _timer = cgcx.prof.generic_activity_with_arg("LLVM_module_codegen", &*module.name);
{
let llmod = module.module_llvm.llmod();
let llcx = &*module.module_llvm.llcx;
@@ -763,7 +785,7 @@ pub(crate) unsafe fn codegen(
if config.bitcode_needed() {
let _timer = cgcx
.prof
- .generic_activity_with_arg("LLVM_module_codegen_make_bitcode", &module.name[..]);
+ .generic_activity_with_arg("LLVM_module_codegen_make_bitcode", &*module.name);
let thin = ThinBuffer::new(llmod);
let data = thin.data();
@@ -776,10 +798,9 @@ pub(crate) unsafe fn codegen(
}
if config.emit_bc || config.emit_obj == EmitObj::Bitcode {
- let _timer = cgcx.prof.generic_activity_with_arg(
- "LLVM_module_codegen_emit_bitcode",
- &module.name[..],
- );
+ let _timer = cgcx
+ .prof
+ .generic_activity_with_arg("LLVM_module_codegen_emit_bitcode", &*module.name);
if let Err(e) = fs::write(&bc_out, data) {
let msg = format!("failed to write bytecode to {}: {}", bc_out.display(), e);
diag_handler.err(&msg);
@@ -787,18 +808,16 @@ pub(crate) unsafe fn codegen(
}
if config.emit_obj == EmitObj::ObjectCode(BitcodeSection::Full) {
- let _timer = cgcx.prof.generic_activity_with_arg(
- "LLVM_module_codegen_embed_bitcode",
- &module.name[..],
- );
+ let _timer = cgcx
+ .prof
+ .generic_activity_with_arg("LLVM_module_codegen_embed_bitcode", &*module.name);
embed_bitcode(cgcx, llcx, llmod, &config.bc_cmdline, data);
}
}
if config.emit_ir {
- let _timer = cgcx
- .prof
- .generic_activity_with_arg("LLVM_module_codegen_emit_ir", &module.name[..]);
+ let _timer =
+ cgcx.prof.generic_activity_with_arg("LLVM_module_codegen_emit_ir", &*module.name);
let out = cgcx.output_filenames.temp_path(OutputType::LlvmAssembly, module_name);
let out_c = path_to_c_string(&out);
@@ -847,9 +866,8 @@ pub(crate) unsafe fn codegen(
}
if config.emit_asm {
- let _timer = cgcx
- .prof
- .generic_activity_with_arg("LLVM_module_codegen_emit_asm", &module.name[..]);
+ let _timer =
+ cgcx.prof.generic_activity_with_arg("LLVM_module_codegen_emit_asm", &*module.name);
let path = cgcx.output_filenames.temp_path(OutputType::Assembly, module_name);
// We can't use the same module for asm and object code output,
@@ -879,7 +897,7 @@ pub(crate) unsafe fn codegen(
EmitObj::ObjectCode(_) => {
let _timer = cgcx
.prof
- .generic_activity_with_arg("LLVM_module_codegen_emit_obj", &module.name[..]);
+ .generic_activity_with_arg("LLVM_module_codegen_emit_obj", &*module.name);
let dwo_out = cgcx.output_filenames.temp_path_dwo(module_name);
let dwo_out = match cgcx.split_debuginfo {
@@ -935,6 +953,29 @@ pub(crate) unsafe fn codegen(
))
}
+fn create_section_with_flags_asm(section_name: &str, section_flags: &str, data: &[u8]) -> Vec<u8> {
+ let mut asm = format!(".section {},\"{}\"\n", section_name, section_flags).into_bytes();
+ asm.extend_from_slice(b".ascii \"");
+ asm.reserve(data.len());
+ for &byte in data {
+ if byte == b'\\' || byte == b'"' {
+ asm.push(b'\\');
+ asm.push(byte);
+ } else if byte < 0x20 || byte >= 0x80 {
+ // Avoid non UTF-8 inline assembly. Use octal escape sequence, because it is fixed
+ // width, while hex escapes will consume following characters.
+ asm.push(b'\\');
+ asm.push(b'0' + ((byte >> 6) & 0x7));
+ asm.push(b'0' + ((byte >> 3) & 0x7));
+ asm.push(b'0' + ((byte >> 0) & 0x7));
+ } else {
+ asm.push(byte);
+ }
+ }
+ asm.extend_from_slice(b"\"\n");
+ asm
+}
+
/// Embed the bitcode of an LLVM module in the LLVM module itself.
///
/// This is done primarily for iOS where it appears to be standard to compile C
@@ -960,34 +1001,6 @@ unsafe fn embed_bitcode(
cmdline: &str,
bitcode: &[u8],
) {
- let llconst = common::bytes_in_context(llcx, bitcode);
- let llglobal = llvm::LLVMAddGlobal(
- llmod,
- common::val_ty(llconst),
- "rustc.embedded.module\0".as_ptr().cast(),
- );
- llvm::LLVMSetInitializer(llglobal, llconst);
-
- let is_apple = cgcx.opts.target_triple.triple().contains("-ios")
- || cgcx.opts.target_triple.triple().contains("-darwin")
- || cgcx.opts.target_triple.triple().contains("-tvos");
-
- let section = if is_apple { "__LLVM,__bitcode\0" } else { ".llvmbc\0" };
- llvm::LLVMSetSection(llglobal, section.as_ptr().cast());
- llvm::LLVMRustSetLinkage(llglobal, llvm::Linkage::PrivateLinkage);
- llvm::LLVMSetGlobalConstant(llglobal, llvm::True);
-
- let llconst = common::bytes_in_context(llcx, cmdline.as_bytes());
- let llglobal = llvm::LLVMAddGlobal(
- llmod,
- common::val_ty(llconst),
- "rustc.embedded.cmdline\0".as_ptr().cast(),
- );
- llvm::LLVMSetInitializer(llglobal, llconst);
- let section = if is_apple { "__LLVM,__cmdline\0" } else { ".llvmcmd\0" };
- llvm::LLVMSetSection(llglobal, section.as_ptr().cast());
- llvm::LLVMRustSetLinkage(llglobal, llvm::Linkage::PrivateLinkage);
-
// We're adding custom sections to the output object file, but we definitely
// do not want these custom sections to make their way into the final linked
// executable. The purpose of these custom sections is for tooling
@@ -1009,31 +1022,54 @@ unsafe fn embed_bitcode(
// * COFF - if we don't do anything the linker will by default copy all
// these sections to the output artifact, not what we want! To subvert
// this we want to flag the sections we inserted here as
- // `IMAGE_SCN_LNK_REMOVE`. Unfortunately though LLVM has no native way to
- // do this. Thankfully though we can do this with some inline assembly,
- // which is easy enough to add via module-level global inline asm.
+ // `IMAGE_SCN_LNK_REMOVE`.
//
// * ELF - this is very similar to COFF above. One difference is that these
// sections are removed from the output linked artifact when
// `--gc-sections` is passed, which we pass by default. If that flag isn't
// passed though then these sections will show up in the final output.
// Additionally the flag that we need to set here is `SHF_EXCLUDE`.
+ //
+ // Unfortunately, LLVM provides no way to set custom section flags. For ELF
+ // and COFF we emit the sections using module level inline assembly for that
+ // reason (see issue #90326 for historical background).
+ let is_apple = cgcx.opts.target_triple.triple().contains("-ios")
+ || cgcx.opts.target_triple.triple().contains("-darwin")
+ || cgcx.opts.target_triple.triple().contains("-tvos");
if is_apple
|| cgcx.opts.target_triple.triple().starts_with("wasm")
|| cgcx.opts.target_triple.triple().starts_with("asmjs")
{
- // nothing to do here
- } else if cgcx.is_pe_coff {
- let asm = "
- .section .llvmbc,\"n\"
- .section .llvmcmd,\"n\"
- ";
- llvm::LLVMRustAppendModuleInlineAsm(llmod, asm.as_ptr().cast(), asm.len());
+ // We don't need custom section flags, create LLVM globals.
+ let llconst = common::bytes_in_context(llcx, bitcode);
+ let llglobal = llvm::LLVMAddGlobal(
+ llmod,
+ common::val_ty(llconst),
+ "rustc.embedded.module\0".as_ptr().cast(),
+ );
+ llvm::LLVMSetInitializer(llglobal, llconst);
+
+ let section = if is_apple { "__LLVM,__bitcode\0" } else { ".llvmbc\0" };
+ llvm::LLVMSetSection(llglobal, section.as_ptr().cast());
+ llvm::LLVMRustSetLinkage(llglobal, llvm::Linkage::PrivateLinkage);
+ llvm::LLVMSetGlobalConstant(llglobal, llvm::True);
+
+ let llconst = common::bytes_in_context(llcx, cmdline.as_bytes());
+ let llglobal = llvm::LLVMAddGlobal(
+ llmod,
+ common::val_ty(llconst),
+ "rustc.embedded.cmdline\0".as_ptr().cast(),
+ );
+ llvm::LLVMSetInitializer(llglobal, llconst);
+ let section = if is_apple { "__LLVM,__cmdline\0" } else { ".llvmcmd\0" };
+ llvm::LLVMSetSection(llglobal, section.as_ptr().cast());
+ llvm::LLVMRustSetLinkage(llglobal, llvm::Linkage::PrivateLinkage);
} else {
- let asm = "
- .section .llvmbc,\"e\"
- .section .llvmcmd,\"e\"
- ";
+ // We need custom section flags, so emit module-level inline assembly.
+ let section_flags = if cgcx.is_pe_coff { "n" } else { "e" };
+ let asm = create_section_with_flags_asm(".llvmbc", section_flags, bitcode);
+ llvm::LLVMRustAppendModuleInlineAsm(llmod, asm.as_ptr().cast(), asm.len());
+ let asm = create_section_with_flags_asm(".llvmcmd", section_flags, cmdline.as_bytes());
llvm::LLVMRustAppendModuleInlineAsm(llmod, asm.as_ptr().cast(), asm.len());
}
}
diff --git a/compiler/rustc_codegen_llvm/src/base.rs b/compiler/rustc_codegen_llvm/src/base.rs
index 8766caef6e3..483b81d23bc 100644
--- a/compiler/rustc_codegen_llvm/src/base.rs
+++ b/compiler/rustc_codegen_llvm/src/base.rs
@@ -9,13 +9,12 @@
//! int)` and `rec(x=int, y=int, z=int)` will have the same [`llvm::Type`].
//!
//! [`Ty`]: rustc_middle::ty::Ty
-//! [`val_ty`]: common::val_ty
+//! [`val_ty`]: crate::common::val_ty
use super::ModuleLlvm;
use crate::attributes;
use crate::builder::Builder;
-use crate::common;
use crate::context::CodegenCx;
use crate::llvm;
use crate::value::Value;
@@ -25,72 +24,22 @@ use rustc_codegen_ssa::mono_item::MonoItemExt;
use rustc_codegen_ssa::traits::*;
use rustc_codegen_ssa::{ModuleCodegen, ModuleKind};
use rustc_data_structures::small_c_str::SmallCStr;
-use rustc_metadata::EncodedMetadata;
use rustc_middle::dep_graph;
use rustc_middle::middle::codegen_fn_attrs::CodegenFnAttrs;
-use rustc_middle::middle::exported_symbols;
use rustc_middle::mir::mono::{Linkage, Visibility};
use rustc_middle::ty::TyCtxt;
use rustc_session::config::DebugInfo;
use rustc_span::symbol::Symbol;
use rustc_target::spec::SanitizerSet;
-use std::ffi::CString;
use std::time::Instant;
-pub fn write_compressed_metadata<'tcx>(
- tcx: TyCtxt<'tcx>,
- metadata: &EncodedMetadata,
- llvm_module: &mut ModuleLlvm,
-) {
- use snap::write::FrameEncoder;
- use std::io::Write;
-
- // Historical note:
- //
- // When using link.exe it was seen that the section name `.note.rustc`
- // was getting shortened to `.note.ru`, and according to the PE and COFF
- // specification:
- //
- // > Executable images do not use a string table and do not support
- // > section names longer than 8 characters
- //
- // https://docs.microsoft.com/en-us/windows/win32/debug/pe-format
- //
- // As a result, we choose a slightly shorter name! As to why
- // `.note.rustc` works on MinGW, see
- // https://github.com/llvm/llvm-project/blob/llvmorg-12.0.0/lld/COFF/Writer.cpp#L1190-L1197
- let section_name = if tcx.sess.target.is_like_osx { "__DATA,.rustc" } else { ".rustc" };
-
- let (metadata_llcx, metadata_llmod) = (&*llvm_module.llcx, llvm_module.llmod());
- let mut compressed = rustc_metadata::METADATA_HEADER.to_vec();
- FrameEncoder::new(&mut compressed).write_all(metadata.raw_data()).unwrap();
-
- let llmeta = common::bytes_in_context(metadata_llcx, &compressed);
- let llconst = common::struct_in_context(metadata_llcx, &[llmeta], false);
- let name = exported_symbols::metadata_symbol_name(tcx);
- let buf = CString::new(name).unwrap();
- let llglobal =
- unsafe { llvm::LLVMAddGlobal(metadata_llmod, common::val_ty(llconst), buf.as_ptr()) };
- unsafe {
- llvm::LLVMSetInitializer(llglobal, llconst);
- let name = SmallCStr::new(section_name);
- llvm::LLVMSetSection(llglobal, name.as_ptr());
-
- // Also generate a .section directive to force no
- // flags, at least for ELF outputs, so that the
- // metadata doesn't get loaded into memory.
- let directive = format!(".section {}", section_name);
- llvm::LLVMSetModuleInlineAsm2(metadata_llmod, directive.as_ptr().cast(), directive.len())
- }
-}
-
pub struct ValueIter<'ll> {
cur: Option<&'ll Value>,
step: unsafe extern "C" fn(&'ll Value) -> Option<&'ll Value>,
}
-impl Iterator for ValueIter<'ll> {
+impl<'ll> Iterator for ValueIter<'ll> {
type Item = &'ll Value;
fn next(&mut self) -> Option<&'ll Value> {
@@ -102,14 +51,11 @@ impl Iterator for ValueIter<'ll> {
}
}
-pub fn iter_globals(llmod: &'ll llvm::Module) -> ValueIter<'ll> {
+pub fn iter_globals(llmod: &llvm::Module) -> ValueIter<'_> {
unsafe { ValueIter { cur: llvm::LLVMGetFirstGlobal(llmod), step: llvm::LLVMGetNextGlobal } }
}
-pub fn compile_codegen_unit(
- tcx: TyCtxt<'tcx>,
- cgu_name: Symbol,
-) -> (ModuleCodegen<ModuleLlvm>, u64) {
+pub fn compile_codegen_unit(tcx: TyCtxt<'_>, cgu_name: Symbol) -> (ModuleCodegen<ModuleLlvm>, u64) {
let start_time = Instant::now();
let dep_node = tcx.codegen_unit(cgu_name).codegen_dep_node(tcx);
diff --git a/compiler/rustc_codegen_llvm/src/builder.rs b/compiler/rustc_codegen_llvm/src/builder.rs
index ff88302bf7a..8c3054b23ff 100644
--- a/compiler/rustc_codegen_llvm/src/builder.rs
+++ b/compiler/rustc_codegen_llvm/src/builder.rs
@@ -36,7 +36,7 @@ pub struct Builder<'a, 'll, 'tcx> {
pub cx: &'a CodegenCx<'ll, 'tcx>,
}
-impl Drop for Builder<'a, 'll, 'tcx> {
+impl Drop for Builder<'_, '_, '_> {
fn drop(&mut self) {
unsafe {
llvm::LLVMDisposeBuilder(&mut *(self.llbuilder as *mut _));
@@ -52,7 +52,7 @@ const EMPTY_C_STR: &CStr = unsafe { CStr::from_bytes_with_nul_unchecked(b"\0") }
// FIXME(eddyb) pass `&CStr` directly to FFI once it's a thin pointer.
const UNNAMED: *const c_char = EMPTY_C_STR.as_ptr();
-impl BackendTypes for Builder<'_, 'll, 'tcx> {
+impl<'ll, 'tcx> BackendTypes for Builder<'_, 'll, 'tcx> {
type Value = <CodegenCx<'ll, 'tcx> as BackendTypes>::Value;
type Function = <CodegenCx<'ll, 'tcx> as BackendTypes>::Function;
type BasicBlock = <CodegenCx<'ll, 'tcx> as BackendTypes>::BasicBlock;
@@ -70,27 +70,27 @@ impl abi::HasDataLayout for Builder<'_, '_, '_> {
}
}
-impl ty::layout::HasTyCtxt<'tcx> for Builder<'_, '_, 'tcx> {
+impl<'tcx> ty::layout::HasTyCtxt<'tcx> for Builder<'_, '_, 'tcx> {
#[inline]
fn tcx(&self) -> TyCtxt<'tcx> {
self.cx.tcx
}
}
-impl ty::layout::HasParamEnv<'tcx> for Builder<'_, '_, 'tcx> {
+impl<'tcx> ty::layout::HasParamEnv<'tcx> for Builder<'_, '_, 'tcx> {
fn param_env(&self) -> ty::ParamEnv<'tcx> {
self.cx.param_env()
}
}
-impl HasTargetSpec for Builder<'_, '_, 'tcx> {
+impl HasTargetSpec for Builder<'_, '_, '_> {
#[inline]
fn target_spec(&self) -> &Target {
self.cx.target_spec()
}
}
-impl LayoutOfHelpers<'tcx> for Builder<'_, '_, 'tcx> {
+impl<'tcx> LayoutOfHelpers<'tcx> for Builder<'_, '_, 'tcx> {
type LayoutOfResult = TyAndLayout<'tcx>;
#[inline]
@@ -99,7 +99,7 @@ impl LayoutOfHelpers<'tcx> for Builder<'_, '_, 'tcx> {
}
}
-impl FnAbiOfHelpers<'tcx> for Builder<'_, '_, 'tcx> {
+impl<'tcx> FnAbiOfHelpers<'tcx> for Builder<'_, '_, 'tcx> {
type FnAbiOfResult = &'tcx FnAbi<'tcx, Ty<'tcx>>;
#[inline]
@@ -113,7 +113,7 @@ impl FnAbiOfHelpers<'tcx> for Builder<'_, '_, 'tcx> {
}
}
-impl Deref for Builder<'_, 'll, 'tcx> {
+impl<'ll, 'tcx> Deref for Builder<'_, 'll, 'tcx> {
type Target = CodegenCx<'ll, 'tcx>;
#[inline]
@@ -122,7 +122,7 @@ impl Deref for Builder<'_, 'll, 'tcx> {
}
}
-impl HasCodegen<'tcx> for Builder<'_, 'll, 'tcx> {
+impl<'ll, 'tcx> HasCodegen<'tcx> for Builder<'_, 'll, 'tcx> {
type CodegenCx = CodegenCx<'ll, 'tcx>;
}
@@ -136,7 +136,7 @@ macro_rules! builder_methods_for_value_instructions {
}
}
-impl BuilderMethods<'a, 'tcx> for Builder<'a, 'll, 'tcx> {
+impl<'a, 'll, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'll, 'tcx> {
fn build(cx: &'a CodegenCx<'ll, 'tcx>, llbb: &'ll BasicBlock) -> Self {
let bx = Builder::with_cx(cx);
unsafe {
@@ -1206,14 +1206,14 @@ impl BuilderMethods<'a, 'tcx> for Builder<'a, 'll, 'tcx> {
}
}
-impl StaticBuilderMethods for Builder<'a, 'll, 'tcx> {
+impl<'ll> StaticBuilderMethods for Builder<'_, 'll, '_> {
fn get_static(&mut self, def_id: DefId) -> &'ll Value {
// Forward to the `get_static` method of `CodegenCx`
self.cx().get_static(def_id)
}
}
-impl Builder<'a, 'll, 'tcx> {
+impl<'a, 'll, 'tcx> Builder<'a, 'll, 'tcx> {
fn with_cx(cx: &'a CodegenCx<'ll, 'tcx>) -> Self {
// Create a fresh builder from the crate context.
let llbuilder = unsafe { llvm::LLVMCreateBuilderInContext(cx.llcx) };
diff --git a/compiler/rustc_codegen_llvm/src/callee.rs b/compiler/rustc_codegen_llvm/src/callee.rs
index 1bc924d3b90..ac423a22703 100644
--- a/compiler/rustc_codegen_llvm/src/callee.rs
+++ b/compiler/rustc_codegen_llvm/src/callee.rs
@@ -22,7 +22,7 @@ use rustc_middle::ty::{self, Instance, TypeFoldable};
///
/// - `cx`: the crate context
/// - `instance`: the instance to be instantiated
-pub fn get_fn(cx: &CodegenCx<'ll, 'tcx>, instance: Instance<'tcx>) -> &'ll Value {
+pub fn get_fn<'ll, 'tcx>(cx: &CodegenCx<'ll, 'tcx>, instance: Instance<'tcx>) -> &'ll Value {
let tcx = cx.tcx();
debug!("get_fn(instance={:?})", instance);
diff --git a/compiler/rustc_codegen_llvm/src/common.rs b/compiler/rustc_codegen_llvm/src/common.rs
index 73a8d464431..9d34734f4e5 100644
--- a/compiler/rustc_codegen_llvm/src/common.rs
+++ b/compiler/rustc_codegen_llvm/src/common.rs
@@ -65,7 +65,7 @@ pub struct Funclet<'ll> {
operand: OperandBundleDef<'ll>,
}
-impl Funclet<'ll> {
+impl<'ll> Funclet<'ll> {
pub fn new(cleanuppad: &'ll Value) -> Self {
Funclet { cleanuppad, operand: OperandBundleDef::new("funclet", &[cleanuppad]) }
}
@@ -79,7 +79,7 @@ impl Funclet<'ll> {
}
}
-impl BackendTypes for CodegenCx<'ll, 'tcx> {
+impl<'ll> BackendTypes for CodegenCx<'ll, '_> {
type Value = &'ll Value;
// FIXME(eddyb) replace this with a `Function` "subclass" of `Value`.
type Function = &'ll Value;
@@ -93,7 +93,7 @@ impl BackendTypes for CodegenCx<'ll, 'tcx> {
type DIVariable = &'ll llvm::debuginfo::DIVariable;
}
-impl CodegenCx<'ll, 'tcx> {
+impl<'ll> CodegenCx<'ll, '_> {
pub fn const_array(&self, ty: &'ll Type, elts: &[&'ll Value]) -> &'ll Value {
unsafe { llvm::LLVMConstArray(ty, elts.as_ptr(), elts.len() as c_uint) }
}
@@ -120,7 +120,7 @@ impl CodegenCx<'ll, 'tcx> {
!null_terminated as Bool,
);
let sym = self.generate_local_symbol_name("str");
- let g = self.define_global(&sym[..], self.val_ty(sc)).unwrap_or_else(|| {
+ let g = self.define_global(&sym, self.val_ty(sc)).unwrap_or_else(|| {
bug!("symbol `{}` is already defined", sym);
});
llvm::LLVMSetInitializer(g, sc);
@@ -145,7 +145,7 @@ impl CodegenCx<'ll, 'tcx> {
}
}
-impl ConstMethods<'tcx> for CodegenCx<'ll, 'tcx> {
+impl<'ll, 'tcx> ConstMethods<'tcx> for CodegenCx<'ll, 'tcx> {
fn const_null(&self, t: &'ll Type) -> &'ll Value {
unsafe { llvm::LLVMConstNull(t) }
}
@@ -327,14 +327,18 @@ pub fn val_ty(v: &Value) -> &Type {
unsafe { llvm::LLVMTypeOf(v) }
}
-pub fn bytes_in_context(llcx: &'ll llvm::Context, bytes: &[u8]) -> &'ll Value {
+pub fn bytes_in_context<'ll>(llcx: &'ll llvm::Context, bytes: &[u8]) -> &'ll Value {
unsafe {
let ptr = bytes.as_ptr() as *const c_char;
llvm::LLVMConstStringInContext(llcx, ptr, bytes.len() as c_uint, True)
}
}
-pub fn struct_in_context(llcx: &'a llvm::Context, elts: &[&'a Value], packed: bool) -> &'a Value {
+pub fn struct_in_context<'ll>(
+ llcx: &'ll llvm::Context,
+ elts: &[&'ll Value],
+ packed: bool,
+) -> &'ll Value {
unsafe {
llvm::LLVMConstStructInContext(llcx, elts.as_ptr(), elts.len() as c_uint, packed as Bool)
}
diff --git a/compiler/rustc_codegen_llvm/src/consts.rs b/compiler/rustc_codegen_llvm/src/consts.rs
index b154ced42f0..d43c7c60651 100644
--- a/compiler/rustc_codegen_llvm/src/consts.rs
+++ b/compiler/rustc_codegen_llvm/src/consts.rs
@@ -24,7 +24,7 @@ use rustc_target::abi::{
use std::ops::Range;
use tracing::debug;
-pub fn const_alloc_to_llvm(cx: &CodegenCx<'ll, '_>, alloc: &Allocation) -> &'ll Value {
+pub fn const_alloc_to_llvm<'ll>(cx: &CodegenCx<'ll, '_>, alloc: &Allocation) -> &'ll Value {
let mut llvals = Vec::with_capacity(alloc.relocations().len() + 1);
let dl = cx.data_layout();
let pointer_size = dl.pointer_size.bytes() as usize;
@@ -127,7 +127,7 @@ pub fn const_alloc_to_llvm(cx: &CodegenCx<'ll, '_>, alloc: &Allocation) -> &'ll
cx.const_struct(&llvals, true)
}
-pub fn codegen_static_initializer(
+pub fn codegen_static_initializer<'ll, 'tcx>(
cx: &CodegenCx<'ll, 'tcx>,
def_id: DefId,
) -> Result<(&'ll Value, &'tcx Allocation), ErrorHandled> {
@@ -135,7 +135,7 @@ pub fn codegen_static_initializer(
Ok((const_alloc_to_llvm(cx, alloc), alloc))
}
-fn set_global_alignment(cx: &CodegenCx<'ll, '_>, gv: &'ll Value, mut align: Align) {
+fn set_global_alignment<'ll>(cx: &CodegenCx<'ll, '_>, gv: &'ll Value, mut align: Align) {
// The target may require greater alignment for globals than the type does.
// Note: GCC and Clang also allow `__attribute__((aligned))` on variables,
// which can force it to be smaller. Rust doesn't support this yet.
@@ -152,7 +152,7 @@ fn set_global_alignment(cx: &CodegenCx<'ll, '_>, gv: &'ll Value, mut align: Alig
}
}
-fn check_and_apply_linkage(
+fn check_and_apply_linkage<'ll, 'tcx>(
cx: &CodegenCx<'ll, 'tcx>,
attrs: &CodegenFnAttrs,
ty: Ty<'tcx>,
@@ -206,11 +206,11 @@ fn check_and_apply_linkage(
}
}
-pub fn ptrcast(val: &'ll Value, ty: &'ll Type) -> &'ll Value {
+pub fn ptrcast<'ll>(val: &'ll Value, ty: &'ll Type) -> &'ll Value {
unsafe { llvm::LLVMConstPointerCast(val, ty) }
}
-impl CodegenCx<'ll, 'tcx> {
+impl<'ll> CodegenCx<'ll, '_> {
crate fn const_bitcast(&self, val: &'ll Value, ty: &'ll Type) -> &'ll Value {
unsafe { llvm::LLVMConstBitCast(val, ty) }
}
@@ -225,7 +225,7 @@ impl CodegenCx<'ll, 'tcx> {
let gv = match kind {
Some(kind) if !self.tcx.sess.fewer_names() => {
let name = self.generate_local_symbol_name(kind);
- let gv = self.define_global(&name[..], self.val_ty(cv)).unwrap_or_else(|| {
+ let gv = self.define_global(&name, self.val_ty(cv)).unwrap_or_else(|| {
bug!("symbol `{}` is already defined", name);
});
llvm::LLVMRustSetLinkage(gv, llvm::Linkage::PrivateLinkage);
@@ -344,7 +344,7 @@ impl CodegenCx<'ll, 'tcx> {
}
}
-impl StaticMethods for CodegenCx<'ll, 'tcx> {
+impl<'ll> StaticMethods for CodegenCx<'ll, '_> {
fn static_addr_of(&self, cv: &'ll Value, align: Align, kind: Option<&str>) -> &'ll Value {
if let Some(&gv) = self.const_globals.borrow().get(&cv) {
unsafe {
diff --git a/compiler/rustc_codegen_llvm/src/context.rs b/compiler/rustc_codegen_llvm/src/context.rs
index 613a8df891c..fe55bf8686e 100644
--- a/compiler/rustc_codegen_llvm/src/context.rs
+++ b/compiler/rustc_codegen_llvm/src/context.rs
@@ -124,7 +124,7 @@ fn to_llvm_tls_model(tls_model: TlsModel) -> llvm::ThreadLocalMode {
}
}
-pub unsafe fn create_module(
+pub unsafe fn create_module<'ll>(
tcx: TyCtxt<'_>,
llcx: &'ll llvm::Context,
mod_name: &str,
@@ -363,7 +363,7 @@ impl<'ll, 'tcx> CodegenCx<'ll, 'tcx> {
}
#[inline]
- pub fn coverage_context(&'a self) -> Option<&'a coverageinfo::CrateCoverageContext<'ll, 'tcx>> {
+ pub fn coverage_context(&self) -> Option<&coverageinfo::CrateCoverageContext<'ll, 'tcx>> {
self.coverage_cx.as_ref()
}
@@ -380,7 +380,7 @@ impl<'ll, 'tcx> CodegenCx<'ll, 'tcx> {
}
}
-impl MiscMethods<'tcx> for CodegenCx<'ll, 'tcx> {
+impl<'ll, 'tcx> MiscMethods<'tcx> for CodegenCx<'ll, 'tcx> {
fn vtables(
&self,
) -> &RefCell<FxHashMap<(Ty<'tcx>, Option<ty::PolyExistentialTraitRef<'tcx>>), &'ll Value>>
@@ -504,8 +504,8 @@ impl MiscMethods<'tcx> for CodegenCx<'ll, 'tcx> {
}
}
-impl CodegenCx<'b, 'tcx> {
- crate fn get_intrinsic(&self, key: &str) -> (&'b Type, &'b Value) {
+impl<'ll> CodegenCx<'ll, '_> {
+ crate fn get_intrinsic(&self, key: &str) -> (&'ll Type, &'ll Value) {
if let Some(v) = self.intrinsics.borrow().get(key).cloned() {
return v;
}
@@ -516,9 +516,9 @@ impl CodegenCx<'b, 'tcx> {
fn insert_intrinsic(
&self,
name: &'static str,
- args: Option<&[&'b llvm::Type]>,
- ret: &'b llvm::Type,
- ) -> (&'b llvm::Type, &'b llvm::Value) {
+ args: Option<&[&'ll llvm::Type]>,
+ ret: &'ll llvm::Type,
+ ) -> (&'ll llvm::Type, &'ll llvm::Value) {
let fn_ty = if let Some(args) = args {
self.type_func(args, ret)
} else {
@@ -529,7 +529,7 @@ impl CodegenCx<'b, 'tcx> {
(fn_ty, f)
}
- fn declare_intrinsic(&self, key: &str) -> Option<(&'b Type, &'b Value)> {
+ fn declare_intrinsic(&self, key: &str) -> Option<(&'ll Type, &'ll Value)> {
macro_rules! ifn {
($name:expr, fn() -> $ret:expr) => (
if key == $name {
@@ -793,7 +793,7 @@ impl CodegenCx<'b, 'tcx> {
None
}
- crate fn eh_catch_typeinfo(&self) -> &'b Value {
+ crate fn eh_catch_typeinfo(&self) -> &'ll Value {
if let Some(eh_catch_typeinfo) = self.eh_catch_typeinfo.get() {
return eh_catch_typeinfo;
}
@@ -813,7 +813,7 @@ impl CodegenCx<'b, 'tcx> {
}
}
-impl<'b, 'tcx> CodegenCx<'b, 'tcx> {
+impl CodegenCx<'_, '_> {
/// Generates a new symbol name with the given prefix. This symbol name must
/// only be used for definitions with `internal` or `private` linkage.
pub fn generate_local_symbol_name(&self, prefix: &str) -> String {
@@ -829,21 +829,21 @@ impl<'b, 'tcx> CodegenCx<'b, 'tcx> {
}
}
-impl HasDataLayout for CodegenCx<'ll, 'tcx> {
+impl HasDataLayout for CodegenCx<'_, '_> {
#[inline]
fn data_layout(&self) -> &TargetDataLayout {
&self.tcx.data_layout
}
}
-impl HasTargetSpec for CodegenCx<'ll, 'tcx> {
+impl HasTargetSpec for CodegenCx<'_, '_> {
#[inline]
fn target_spec(&self) -> &Target {
&self.tcx.sess.target
}
}
-impl ty::layout::HasTyCtxt<'tcx> for CodegenCx<'ll, 'tcx> {
+impl<'tcx> ty::layout::HasTyCtxt<'tcx> for CodegenCx<'_, 'tcx> {
#[inline]
fn tcx(&self) -> TyCtxt<'tcx> {
self.tcx
@@ -856,7 +856,7 @@ impl<'tcx, 'll> HasParamEnv<'tcx> for CodegenCx<'ll, 'tcx> {
}
}
-impl LayoutOfHelpers<'tcx> for CodegenCx<'ll, 'tcx> {
+impl<'tcx> LayoutOfHelpers<'tcx> for CodegenCx<'_, 'tcx> {
type LayoutOfResult = TyAndLayout<'tcx>;
#[inline]
@@ -869,7 +869,7 @@ impl LayoutOfHelpers<'tcx> for CodegenCx<'ll, 'tcx> {
}
}
-impl FnAbiOfHelpers<'tcx> for CodegenCx<'ll, 'tcx> {
+impl<'tcx> FnAbiOfHelpers<'tcx> for CodegenCx<'_, 'tcx> {
type FnAbiOfResult = &'tcx FnAbi<'tcx, Ty<'tcx>>;
#[inline]
diff --git a/compiler/rustc_codegen_llvm/src/coverageinfo/mapgen.rs b/compiler/rustc_codegen_llvm/src/coverageinfo/mapgen.rs
index 6830864ba04..e0af5653753 100644
--- a/compiler/rustc_codegen_llvm/src/coverageinfo/mapgen.rs
+++ b/compiler/rustc_codegen_llvm/src/coverageinfo/mapgen.rs
@@ -9,6 +9,7 @@ use rustc_data_structures::fx::{FxHashMap, FxHashSet, FxIndexSet};
use rustc_hir::def_id::{DefId, DefIdSet};
use rustc_llvm::RustString;
use rustc_middle::mir::coverage::CodeRegion;
+use rustc_middle::ty::TyCtxt;
use rustc_span::Symbol;
use std::ffi::CString;
@@ -17,10 +18,11 @@ use tracing::debug;
/// Generates and exports the Coverage Map.
///
-/// This Coverage Map complies with Coverage Mapping Format version 4 (zero-based encoded as 3),
-/// as defined at [LLVM Code Coverage Mapping Format](https://github.com/rust-lang/llvm-project/blob/rustc/11.0-2020-10-12/llvm/docs/CoverageMappingFormat.rst#llvm-code-coverage-mapping-format)
-/// and published in Rust's November 2020 fork of LLVM. This version is supported by the LLVM
-/// coverage tools (`llvm-profdata` and `llvm-cov`) bundled with Rust's fork of LLVM.
+/// Rust Coverage Map generation supports LLVM Coverage Mapping Format versions
+/// 5 (LLVM 12, only) and 6 (zero-based encoded as 4 and 5, respectively), as defined at
+/// [LLVM Code Coverage Mapping Format](https://github.com/rust-lang/llvm-project/blob/rustc/13.0-2021-09-30/llvm/docs/CoverageMappingFormat.rst#llvm-code-coverage-mapping-format).
+/// These versions are supported by the LLVM coverage tools (`llvm-profdata` and `llvm-cov`)
+/// bundled with Rust's fork of LLVM.
///
/// Consequently, Rust's bundled version of Clang also generates Coverage Maps compliant with
/// the same version. Clang's implementation of Coverage Map generation was referenced when
@@ -30,11 +32,12 @@ use tracing::debug;
pub fn finalize<'ll, 'tcx>(cx: &CodegenCx<'ll, 'tcx>) {
let tcx = cx.tcx;
- // Ensure LLVM supports Coverage Map Version 4 (encoded as a zero-based value: 3).
- // If not, the LLVM Version must be less than 11.
+ // Ensure the installed version of LLVM supports at least Coverage Map
+ // Version 5 (encoded as a zero-based value: 4), which was introduced with
+ // LLVM 12.
let version = coverageinfo::mapping_version();
- if version != 3 {
- tcx.sess.fatal("rustc option `-Z instrument-coverage` requires LLVM 11 or higher.");
+ if version < 4 {
+ tcx.sess.fatal("rustc option `-Z instrument-coverage` requires LLVM 12 or higher.");
}
debug!("Generating coverage map for CodegenUnit: `{}`", cx.codegen_unit.name());
@@ -57,7 +60,7 @@ pub fn finalize<'ll, 'tcx>(cx: &CodegenCx<'ll, 'tcx>) {
return;
}
- let mut mapgen = CoverageMapGenerator::new();
+ let mut mapgen = CoverageMapGenerator::new(tcx, version);
// Encode coverage mappings and generate function records
let mut function_data = Vec::new();
@@ -86,7 +89,7 @@ pub fn finalize<'ll, 'tcx>(cx: &CodegenCx<'ll, 'tcx>) {
});
let filenames_size = filenames_buffer.len();
- let filenames_val = cx.const_bytes(&filenames_buffer[..]);
+ let filenames_val = cx.const_bytes(&filenames_buffer);
let filenames_ref = coverageinfo::hash_bytes(filenames_buffer);
// Generate the LLVM IR representation of the coverage map and store it in a well-known global
@@ -112,15 +115,33 @@ struct CoverageMapGenerator {
}
impl CoverageMapGenerator {
- fn new() -> Self {
- Self { filenames: FxIndexSet::default() }
+ fn new(tcx: TyCtxt<'_>, version: u32) -> Self {
+ let mut filenames = FxIndexSet::default();
+ if version >= 5 {
+ // LLVM Coverage Mapping Format version 6 (zero-based encoded as 5)
+ // requires setting the first filename to the compilation directory.
+ // Since rustc generates coverage maps with relative paths, the
+ // compilation directory can be combined with the the relative paths
+ // to get absolute paths, if needed.
+ let working_dir = tcx
+ .sess
+ .opts
+ .working_dir
+ .remapped_path_if_available()
+ .to_string_lossy()
+ .to_string();
+ let c_filename =
+ CString::new(working_dir).expect("null error converting filename to C string");
+ filenames.insert(c_filename);
+ }
+ Self { filenames }
}
/// Using the `expressions` and `counter_regions` collected for the current function, generate
/// the `mapping_regions` and `virtual_file_mapping`, and capture any new filenames. Then use
/// LLVM APIs to encode the `virtual_file_mapping`, `expressions`, and `mapping_regions` into
/// the given `coverage_mapping` byte buffer, compliant with the LLVM Coverage Mapping format.
- fn write_coverage_mapping(
+ fn write_coverage_mapping<'a>(
&mut self,
expressions: Vec<CounterExpression>,
counter_regions: impl Iterator<Item = (Counter, &'a CodeRegion)>,
@@ -179,9 +200,9 @@ impl CoverageMapGenerator {
/// Construct coverage map header and the array of function records, and combine them into the
/// coverage map. Save the coverage map data into the LLVM IR as a static global using a
/// specific, well-known section and name.
- fn generate_coverage_map(
+ fn generate_coverage_map<'ll>(
self,
- cx: &CodegenCx<'ll, 'tcx>,
+ cx: &CodegenCx<'ll, '_>,
version: u32,
filenames_size: usize,
filenames_val: &'ll llvm::Value,
@@ -208,7 +229,7 @@ impl CoverageMapGenerator {
/// Save the function record into the LLVM IR as a static global using a
/// specific, well-known section and name.
fn save_function_record(
- cx: &CodegenCx<'ll, 'tcx>,
+ cx: &CodegenCx<'_, '_>,
mangled_function_name: String,
source_hash: u64,
filenames_ref: u64,
@@ -217,7 +238,7 @@ fn save_function_record(
) {
// Concatenate the encoded coverage mappings
let coverage_mapping_size = coverage_mapping_buffer.len();
- let coverage_mapping_val = cx.const_bytes(&coverage_mapping_buffer[..]);
+ let coverage_mapping_val = cx.const_bytes(&coverage_mapping_buffer);
let func_name_hash = coverageinfo::hash_str(&mangled_function_name);
let func_name_hash_val = cx.const_u64(func_name_hash);
diff --git a/compiler/rustc_codegen_llvm/src/coverageinfo/mod.rs b/compiler/rustc_codegen_llvm/src/coverageinfo/mod.rs
index ef11e2972ea..b2879ef4aea 100644
--- a/compiler/rustc_codegen_llvm/src/coverageinfo/mod.rs
+++ b/compiler/rustc_codegen_llvm/src/coverageinfo/mod.rs
@@ -56,7 +56,7 @@ impl<'ll, 'tcx> CrateCoverageContext<'ll, 'tcx> {
}
}
-impl CoverageInfoMethods<'tcx> for CodegenCx<'ll, 'tcx> {
+impl<'ll, 'tcx> CoverageInfoMethods<'tcx> for CodegenCx<'ll, 'tcx> {
fn coverageinfo_finalize(&self) {
mapgen::finalize(self)
}
@@ -96,7 +96,7 @@ impl CoverageInfoMethods<'tcx> for CodegenCx<'ll, 'tcx> {
}
}
-impl CoverageInfoBuilderMethods<'tcx> for Builder<'a, 'll, 'tcx> {
+impl<'tcx> CoverageInfoBuilderMethods<'tcx> for Builder<'_, '_, 'tcx> {
fn set_function_source_hash(
&mut self,
instance: Instance<'tcx>,
@@ -184,7 +184,7 @@ impl CoverageInfoBuilderMethods<'tcx> for Builder<'a, 'll, 'tcx> {
}
}
-fn declare_unused_fn(cx: &CodegenCx<'ll, 'tcx>, def_id: &DefId) -> Instance<'tcx> {
+fn declare_unused_fn<'tcx>(cx: &CodegenCx<'_, 'tcx>, def_id: &DefId) -> Instance<'tcx> {
let tcx = cx.tcx;
let instance = Instance::new(
@@ -212,15 +212,15 @@ fn declare_unused_fn(cx: &CodegenCx<'ll, 'tcx>, def_id: &DefId) -> Instance<'tcx
),
);
- llvm::set_linkage(llfn, llvm::Linkage::WeakAnyLinkage);
- llvm::set_visibility(llfn, llvm::Visibility::Hidden);
+ llvm::set_linkage(llfn, llvm::Linkage::PrivateLinkage);
+ llvm::set_visibility(llfn, llvm::Visibility::Default);
assert!(cx.instances.borrow_mut().insert(instance, llfn).is_none());
instance
}
-fn codegen_unused_fn_and_counter(cx: &CodegenCx<'ll, 'tcx>, instance: Instance<'tcx>) {
+fn codegen_unused_fn_and_counter<'tcx>(cx: &CodegenCx<'_, 'tcx>, instance: Instance<'tcx>) {
let llfn = cx.get_fn(instance);
let llbb = Builder::append_block(cx, llfn, "unused_function");
let mut bx = Builder::build(cx, llbb);
@@ -237,8 +237,8 @@ fn codegen_unused_fn_and_counter(cx: &CodegenCx<'ll, 'tcx>, instance: Instance<'
bx.ret_void();
}
-fn add_unused_function_coverage(
- cx: &CodegenCx<'ll, 'tcx>,
+fn add_unused_function_coverage<'tcx>(
+ cx: &CodegenCx<'_, 'tcx>,
instance: Instance<'tcx>,
def_id: DefId,
) {
@@ -268,7 +268,7 @@ fn add_unused_function_coverage(
/// required by LLVM InstrProf source-based coverage instrumentation. Use
/// `bx.get_pgo_func_name_var()` to ensure the variable is only created once per
/// `Instance`.
-fn create_pgo_func_name_var(
+fn create_pgo_func_name_var<'ll, 'tcx>(
cx: &CodegenCx<'ll, 'tcx>,
instance: Instance<'tcx>,
) -> &'ll llvm::Value {
diff --git a/compiler/rustc_codegen_llvm/src/debuginfo/create_scope_map.rs b/compiler/rustc_codegen_llvm/src/debuginfo/create_scope_map.rs
index 58f8573a2ac..39f53235e2c 100644
--- a/compiler/rustc_codegen_llvm/src/debuginfo/create_scope_map.rs
+++ b/compiler/rustc_codegen_llvm/src/debuginfo/create_scope_map.rs
@@ -16,7 +16,7 @@ use rustc_index::vec::Idx;
/// Produces DIScope DIEs for each MIR Scope which has variables defined in it.
// FIXME(eddyb) almost all of this should be in `rustc_codegen_ssa::mir::debuginfo`.
-pub fn compute_mir_scopes(
+pub fn compute_mir_scopes<'ll, 'tcx>(
cx: &CodegenCx<'ll, 'tcx>,
instance: Instance<'tcx>,
mir: &Body<'tcx>,
@@ -45,7 +45,7 @@ pub fn compute_mir_scopes(
}
}
-fn make_mir_scope(
+fn make_mir_scope<'ll, 'tcx>(
cx: &CodegenCx<'ll, 'tcx>,
instance: Instance<'tcx>,
mir: &Body<'tcx>,
diff --git a/compiler/rustc_codegen_llvm/src/debuginfo/gdb.rs b/compiler/rustc_codegen_llvm/src/debuginfo/gdb.rs
index ae1f83d944f..31a09242c5a 100644
--- a/compiler/rustc_codegen_llvm/src/debuginfo/gdb.rs
+++ b/compiler/rustc_codegen_llvm/src/debuginfo/gdb.rs
@@ -28,7 +28,7 @@ pub fn insert_reference_to_gdb_debug_scripts_section_global(bx: &mut Builder<'_,
/// Allocates the global variable responsible for the .debug_gdb_scripts binary
/// section.
-pub fn get_or_insert_gdb_debug_scripts_section_global(cx: &CodegenCx<'ll, '_>) -> &'ll Value {
+pub fn get_or_insert_gdb_debug_scripts_section_global<'ll>(cx: &CodegenCx<'ll, '_>) -> &'ll Value {
let c_section_var_name = "__rustc_debug_gdb_scripts_section__\0";
let section_var_name = &c_section_var_name[..c_section_var_name.len() - 1];
diff --git a/compiler/rustc_codegen_llvm/src/debuginfo/metadata.rs b/compiler/rustc_codegen_llvm/src/debuginfo/metadata.rs
index cd29f2af016..960b02bf910 100644
--- a/compiler/rustc_codegen_llvm/src/debuginfo/metadata.rs
+++ b/compiler/rustc_codegen_llvm/src/debuginfo/metadata.rs
@@ -155,7 +155,7 @@ pub struct TypeMap<'ll, 'tcx> {
type_to_unique_id: FxHashMap<Ty<'tcx>, UniqueTypeId>,
}
-impl TypeMap<'ll, 'tcx> {
+impl<'ll, 'tcx> TypeMap<'ll, 'tcx> {
/// Adds a Ty to metadata mapping to the TypeMap. The method will fail if
/// the mapping already exists.
fn register_type_with_metadata(&mut self, type_: Ty<'tcx>, metadata: &'ll DIType) {
@@ -291,7 +291,7 @@ enum RecursiveTypeDescription<'ll, 'tcx> {
FinalMetadata(&'ll DICompositeType),
}
-fn create_and_register_recursive_type_forward_declaration(
+fn create_and_register_recursive_type_forward_declaration<'ll, 'tcx>(
cx: &CodegenCx<'ll, 'tcx>,
unfinished_type: Ty<'tcx>,
unique_type_id: UniqueTypeId,
@@ -313,7 +313,7 @@ fn create_and_register_recursive_type_forward_declaration(
}
}
-impl RecursiveTypeDescription<'ll, 'tcx> {
+impl<'ll, 'tcx> RecursiveTypeDescription<'ll, 'tcx> {
/// Finishes up the description of the type in question (mostly by providing
/// descriptions of the fields of the given type) and returns the final type
/// metadata.
@@ -375,7 +375,7 @@ macro_rules! return_if_metadata_created_in_meantime {
};
}
-fn fixed_vec_metadata(
+fn fixed_vec_metadata<'ll, 'tcx>(
cx: &CodegenCx<'ll, 'tcx>,
unique_type_id: UniqueTypeId,
array_or_slice_type: Ty<'tcx>,
@@ -410,7 +410,7 @@ fn fixed_vec_metadata(
MetadataCreationResult::new(metadata, false)
}
-fn vec_slice_metadata(
+fn vec_slice_metadata<'ll, 'tcx>(
cx: &CodegenCx<'ll, 'tcx>,
slice_ptr_type: Ty<'tcx>,
element_type: Ty<'tcx>,
@@ -456,7 +456,7 @@ fn vec_slice_metadata(
let metadata = composite_type_metadata(
cx,
slice_ptr_type,
- &slice_type_name[..],
+ &slice_type_name,
unique_type_id,
member_descriptions,
NO_SCOPE_METADATA,
@@ -466,7 +466,7 @@ fn vec_slice_metadata(
MetadataCreationResult::new(metadata, false)
}
-fn subroutine_type_metadata(
+fn subroutine_type_metadata<'ll, 'tcx>(
cx: &CodegenCx<'ll, 'tcx>,
unique_type_id: UniqueTypeId,
signature: ty::PolyFnSig<'tcx>,
@@ -507,7 +507,7 @@ fn subroutine_type_metadata(
// `trait_type` should be the actual trait (e.g., `Trait`). Where the trait is part
// of a DST struct, there is no `trait_object_type` and the results of this
// function will be a little bit weird.
-fn trait_pointer_metadata(
+fn trait_pointer_metadata<'ll, 'tcx>(
cx: &CodegenCx<'ll, 'tcx>,
trait_type: Ty<'tcx>,
trait_object_type: Option<Ty<'tcx>>,
@@ -579,7 +579,7 @@ fn trait_pointer_metadata(
composite_type_metadata(
cx,
trait_object_type.unwrap_or(trait_type),
- &trait_type_name[..],
+ &trait_type_name,
unique_type_id,
member_descriptions,
containing_scope,
@@ -588,7 +588,11 @@ fn trait_pointer_metadata(
)
}
-pub fn type_metadata(cx: &CodegenCx<'ll, 'tcx>, t: Ty<'tcx>, usage_site_span: Span) -> &'ll DIType {
+pub fn type_metadata<'ll, 'tcx>(
+ cx: &CodegenCx<'ll, 'tcx>,
+ t: Ty<'tcx>,
+ usage_site_span: Span,
+) -> &'ll DIType {
// Get the unique type ID of this type.
let unique_type_id = {
let mut type_map = debug_context(cx).type_map.borrow_mut();
@@ -812,7 +816,7 @@ fn hex_encode(data: &[u8]) -> String {
hex_string
}
-pub fn file_metadata(cx: &CodegenCx<'ll, '_>, source_file: &SourceFile) -> &'ll DIFile {
+pub fn file_metadata<'ll>(cx: &CodegenCx<'ll, '_>, source_file: &SourceFile) -> &'ll DIFile {
debug!("file_metadata: file_name: {:?}", source_file.name);
let hash = Some(&source_file.src_hash);
@@ -833,11 +837,11 @@ pub fn file_metadata(cx: &CodegenCx<'ll, '_>, source_file: &SourceFile) -> &'ll
file_metadata_raw(cx, file_name, directory, hash)
}
-pub fn unknown_file_metadata(cx: &CodegenCx<'ll, '_>) -> &'ll DIFile {
+pub fn unknown_file_metadata<'ll>(cx: &CodegenCx<'ll, '_>) -> &'ll DIFile {
file_metadata_raw(cx, None, None, None)
}
-fn file_metadata_raw(
+fn file_metadata_raw<'ll>(
cx: &CodegenCx<'ll, '_>,
file_name: Option<String>,
directory: Option<String>,
@@ -924,7 +928,7 @@ impl MsvcBasicName for ty::FloatTy {
}
}
-fn basic_type_metadata(cx: &CodegenCx<'ll, 'tcx>, t: Ty<'tcx>) -> &'ll DIType {
+fn basic_type_metadata<'ll, 'tcx>(cx: &CodegenCx<'ll, 'tcx>, t: Ty<'tcx>) -> &'ll DIType {
debug!("basic_type_metadata: {:?}", t);
// When targeting MSVC, emit MSVC style type names for compatibility with
@@ -981,7 +985,7 @@ fn basic_type_metadata(cx: &CodegenCx<'ll, 'tcx>, t: Ty<'tcx>) -> &'ll DIType {
typedef_metadata
}
-fn foreign_type_metadata(
+fn foreign_type_metadata<'ll, 'tcx>(
cx: &CodegenCx<'ll, 'tcx>,
t: Ty<'tcx>,
unique_type_id: UniqueTypeId,
@@ -992,7 +996,7 @@ fn foreign_type_metadata(
create_struct_stub(cx, t, &name, unique_type_id, NO_SCOPE_METADATA, DIFlags::FlagZero)
}
-fn pointer_type_metadata(
+fn pointer_type_metadata<'ll, 'tcx>(
cx: &CodegenCx<'ll, 'tcx>,
pointer_type: Ty<'tcx>,
pointee_type_metadata: &'ll DIType,
@@ -1012,7 +1016,7 @@ fn pointer_type_metadata(
}
}
-fn param_type_metadata(cx: &CodegenCx<'ll, 'tcx>, t: Ty<'tcx>) -> &'ll DIType {
+fn param_type_metadata<'ll, 'tcx>(cx: &CodegenCx<'ll, 'tcx>, t: Ty<'tcx>) -> &'ll DIType {
debug!("param_type_metadata: {:?}", t);
let name = format!("{:?}", t);
unsafe {
@@ -1026,24 +1030,35 @@ fn param_type_metadata(cx: &CodegenCx<'ll, 'tcx>, t: Ty<'tcx>) -> &'ll DIType {
}
}
-pub fn compile_unit_metadata(
- tcx: TyCtxt<'_>,
+pub fn compile_unit_metadata<'ll, 'tcx>(
+ tcx: TyCtxt<'tcx>,
codegen_unit_name: &str,
- debug_context: &CrateDebugContext<'ll, '_>,
+ debug_context: &CrateDebugContext<'ll, 'tcx>,
) -> &'ll DIDescriptor {
let mut name_in_debuginfo = match tcx.sess.local_crate_source_file {
Some(ref path) => path.clone(),
None => PathBuf::from(&*tcx.crate_name(LOCAL_CRATE).as_str()),
};
- // The OSX linker has an idiosyncrasy where it will ignore some debuginfo
- // if multiple object files with the same `DW_AT_name` are linked together.
- // As a workaround we generate unique names for each object file. Those do
- // not correspond to an actual source file but that is harmless.
- if tcx.sess.target.is_like_osx {
- name_in_debuginfo.push("@");
- name_in_debuginfo.push(codegen_unit_name);
- }
+ // To avoid breaking split DWARF, we need to ensure that each codegen unit
+ // has a unique `DW_AT_name`. This is because there's a remote chance that
+ // different codegen units for the same module will have entirely
+ // identical DWARF entries for the purpose of the DWO ID, which would
+ // violate Appendix F ("Split Dwarf Object Files") of the DWARF 5
+ // specification. LLVM uses the algorithm specified in section 7.32 "Type
+ // Signature Computation" to compute the DWO ID, which does not include
+ // any fields that would distinguish compilation units. So we must embed
+ // the codegen unit name into the `DW_AT_name`. (Issue #88521.)
+ //
+ // Additionally, the OSX linker has an idiosyncrasy where it will ignore
+ // some debuginfo if multiple object files with the same `DW_AT_name` are
+ // linked together.
+ //
+ // As a workaround for these two issues, we generate unique names for each
+ // object file. Those do not correspond to an actual source file but that
+ // is harmless.
+ name_in_debuginfo.push("@");
+ name_in_debuginfo.push(codegen_unit_name);
debug!("compile_unit_metadata: {:?}", name_in_debuginfo);
let rustc_producer =
@@ -1055,11 +1070,11 @@ pub fn compile_unit_metadata(
let work_dir = tcx.sess.opts.working_dir.to_string_lossy(FileNameDisplayPreference::Remapped);
let flags = "\0";
let output_filenames = tcx.output_filenames(());
- let out_dir = &output_filenames.out_directory;
let split_name = if tcx.sess.target_can_use_split_dwarf() {
output_filenames
.split_dwarf_path(tcx.sess.split_debuginfo(), Some(codegen_unit_name))
- .map(|f| out_dir.join(f))
+ // We get a path relative to the working directory from split_dwarf_path
+ .map(|f| tcx.sess.source_map().path_mapping().map_prefix(f).0)
} else {
None
}
@@ -1159,7 +1174,7 @@ pub fn compile_unit_metadata(
return unit_metadata;
};
- fn path_to_mdstring(llcx: &'ll llvm::Context, path: &Path) -> &'ll Value {
+ fn path_to_mdstring<'ll>(llcx: &'ll llvm::Context, path: &Path) -> &'ll Value {
let path_str = path_to_c_string(path);
unsafe {
llvm::LLVMMDStringInContext(
@@ -1176,7 +1191,7 @@ struct MetadataCreationResult<'ll> {
already_stored_in_typemap: bool,
}
-impl MetadataCreationResult<'ll> {
+impl<'ll> MetadataCreationResult<'ll> {
fn new(metadata: &'ll DIType, already_stored_in_typemap: bool) -> Self {
MetadataCreationResult { metadata, already_stored_in_typemap }
}
@@ -1243,7 +1258,7 @@ enum MemberDescriptionFactory<'ll, 'tcx> {
VariantMDF(VariantMemberDescriptionFactory<'tcx>),
}
-impl MemberDescriptionFactory<'ll, 'tcx> {
+impl<'ll, 'tcx> MemberDescriptionFactory<'ll, 'tcx> {
fn create_member_descriptions(&self, cx: &CodegenCx<'ll, 'tcx>) -> Vec<MemberDescription<'ll>> {
match *self {
StructMDF(ref this) => this.create_member_descriptions(cx),
@@ -1267,7 +1282,10 @@ struct StructMemberDescriptionFactory<'tcx> {
}
impl<'tcx> StructMemberDescriptionFactory<'tcx> {
- fn create_member_descriptions(&self, cx: &CodegenCx<'ll, 'tcx>) -> Vec<MemberDescription<'ll>> {
+ fn create_member_descriptions<'ll>(
+ &self,
+ cx: &CodegenCx<'ll, 'tcx>,
+ ) -> Vec<MemberDescription<'ll>> {
let layout = cx.layout_of(self.ty);
self.variant
.fields
@@ -1295,7 +1313,7 @@ impl<'tcx> StructMemberDescriptionFactory<'tcx> {
}
}
-fn prepare_struct_metadata(
+fn prepare_struct_metadata<'ll, 'tcx>(
cx: &CodegenCx<'ll, 'tcx>,
struct_type: Ty<'tcx>,
unique_type_id: UniqueTypeId,
@@ -1338,7 +1356,7 @@ fn prepare_struct_metadata(
/// Here are some examples:
/// - `name__field1__field2` when the upvar is captured by value.
/// - `_ref__name__field` when the upvar is captured by reference.
-fn closure_saved_names_of_captured_variables(tcx: TyCtxt<'tcx>, def_id: DefId) -> Vec<String> {
+fn closure_saved_names_of_captured_variables(tcx: TyCtxt<'_>, def_id: DefId) -> Vec<String> {
let body = tcx.optimized_mir(def_id);
body.var_debug_info
@@ -1366,7 +1384,10 @@ struct TupleMemberDescriptionFactory<'tcx> {
}
impl<'tcx> TupleMemberDescriptionFactory<'tcx> {
- fn create_member_descriptions(&self, cx: &CodegenCx<'ll, 'tcx>) -> Vec<MemberDescription<'ll>> {
+ fn create_member_descriptions<'ll>(
+ &self,
+ cx: &CodegenCx<'ll, 'tcx>,
+ ) -> Vec<MemberDescription<'ll>> {
let mut capture_names = match *self.ty.kind() {
ty::Generator(def_id, ..) | ty::Closure(def_id, ..) => {
Some(closure_saved_names_of_captured_variables(cx.tcx, def_id).into_iter())
@@ -1399,7 +1420,7 @@ impl<'tcx> TupleMemberDescriptionFactory<'tcx> {
}
}
-fn prepare_tuple_metadata(
+fn prepare_tuple_metadata<'ll, 'tcx>(
cx: &CodegenCx<'ll, 'tcx>,
tuple_type: Ty<'tcx>,
component_types: &[Ty<'tcx>],
@@ -1443,7 +1464,10 @@ struct UnionMemberDescriptionFactory<'tcx> {
}
impl<'tcx> UnionMemberDescriptionFactory<'tcx> {
- fn create_member_descriptions(&self, cx: &CodegenCx<'ll, 'tcx>) -> Vec<MemberDescription<'ll>> {
+ fn create_member_descriptions<'ll>(
+ &self,
+ cx: &CodegenCx<'ll, 'tcx>,
+ ) -> Vec<MemberDescription<'ll>> {
self.variant
.fields
.iter()
@@ -1465,7 +1489,7 @@ impl<'tcx> UnionMemberDescriptionFactory<'tcx> {
}
}
-fn prepare_union_metadata(
+fn prepare_union_metadata<'ll, 'tcx>(
cx: &CodegenCx<'ll, 'tcx>,
union_type: Ty<'tcx>,
unique_type_id: UniqueTypeId,
@@ -1506,7 +1530,7 @@ fn use_enum_fallback(cx: &CodegenCx<'_, '_>) -> bool {
// FIXME(eddyb) maybe precompute this? Right now it's computed once
// per generator monomorphization, but it doesn't depend on substs.
-fn generator_layout_and_saved_local_names(
+fn generator_layout_and_saved_local_names<'tcx>(
tcx: TyCtxt<'tcx>,
def_id: DefId,
) -> (&'tcx GeneratorLayout<'tcx>, IndexVec<mir::GeneratorSavedLocal, Option<Symbol>>) {
@@ -1525,14 +1549,12 @@ fn generator_layout_and_saved_local_names(
// Deref of the `Pin<&mut Self>` state argument.
mir::ProjectionElem::Field(..),
mir::ProjectionElem::Deref,
-
// Field of a variant of the state.
mir::ProjectionElem::Downcast(_, variant),
mir::ProjectionElem::Field(field, _),
] => {
- let name = &mut generator_saved_local_names[
- generator_layout.variant_fields[variant][field]
- ];
+ let name = &mut generator_saved_local_names
+ [generator_layout.variant_fields[variant][field]];
if name.is_none() {
name.replace(var.name);
}
@@ -1556,7 +1578,7 @@ struct EnumMemberDescriptionFactory<'ll, 'tcx> {
span: Span,
}
-impl EnumMemberDescriptionFactory<'ll, 'tcx> {
+impl<'ll, 'tcx> EnumMemberDescriptionFactory<'ll, 'tcx> {
fn create_member_descriptions(&self, cx: &CodegenCx<'ll, 'tcx>) -> Vec<MemberDescription<'ll>> {
let generator_variant_info_data = match *self.enum_type.kind() {
ty::Generator(def_id, ..) => {
@@ -1888,8 +1910,11 @@ struct VariantMemberDescriptionFactory<'tcx> {
span: Span,
}
-impl VariantMemberDescriptionFactory<'tcx> {
- fn create_member_descriptions(&self, cx: &CodegenCx<'ll, 'tcx>) -> Vec<MemberDescription<'ll>> {
+impl<'tcx> VariantMemberDescriptionFactory<'tcx> {
+ fn create_member_descriptions<'ll>(
+ &self,
+ cx: &CodegenCx<'ll, 'tcx>,
+ ) -> Vec<MemberDescription<'ll>> {
self.args
.iter()
.enumerate()
@@ -1963,7 +1988,7 @@ impl<'tcx> VariantInfo<'_, 'tcx> {
field_name.map(|name| name.to_string()).unwrap_or_else(|| format!("__{}", i))
}
- fn source_info(&self, cx: &CodegenCx<'ll, 'tcx>) -> Option<SourceInfo<'ll>> {
+ fn source_info<'ll>(&self, cx: &CodegenCx<'ll, 'tcx>) -> Option<SourceInfo<'ll>> {
if let VariantInfo::Generator { def_id, variant_index, .. } = self {
let span =
cx.tcx.generator_layout(*def_id).unwrap().variant_source_info[*variant_index].span;
@@ -1980,7 +2005,7 @@ impl<'tcx> VariantInfo<'_, 'tcx> {
/// `MemberDescriptionFactory` for producing the descriptions of the
/// fields of the variant. This is a rudimentary version of a full
/// `RecursiveTypeDescription`.
-fn describe_enum_variant(
+fn describe_enum_variant<'ll, 'tcx>(
cx: &CodegenCx<'ll, 'tcx>,
layout: layout::TyAndLayout<'tcx>,
variant: VariantInfo<'_, 'tcx>,
@@ -2013,7 +2038,7 @@ fn describe_enum_variant(
(metadata_stub, member_description_factory)
}
-fn prepare_enum_metadata(
+fn prepare_enum_metadata<'ll, 'tcx>(
cx: &CodegenCx<'ll, 'tcx>,
enum_type: Ty<'tcx>,
enum_def_id: DefId,
@@ -2332,7 +2357,7 @@ fn prepare_enum_metadata(
/// results in a LLVM struct.
///
/// Examples of Rust types to use this are: structs, tuples, boxes, vecs, and enums.
-fn composite_type_metadata(
+fn composite_type_metadata<'ll, 'tcx>(
cx: &CodegenCx<'ll, 'tcx>,
composite_type: Ty<'tcx>,
composite_type_name: &str,
@@ -2366,7 +2391,7 @@ fn composite_type_metadata(
composite_type_metadata
}
-fn set_members_of_composite_type(
+fn set_members_of_composite_type<'ll, 'tcx>(
cx: &CodegenCx<'ll, 'tcx>,
composite_type: Ty<'tcx>,
composite_type_metadata: &'ll DICompositeType,
@@ -2400,7 +2425,7 @@ fn set_members_of_composite_type(
let type_params = compute_type_parameters(cx, composite_type);
unsafe {
- let type_array = create_DIArray(DIB(cx), &member_metadata[..]);
+ let type_array = create_DIArray(DIB(cx), &member_metadata);
llvm::LLVMRustDICompositeTypeReplaceArrays(
DIB(cx),
composite_type_metadata,
@@ -2411,7 +2436,7 @@ fn set_members_of_composite_type(
}
/// Computes the type parameters for a type, if any, for the given metadata.
-fn compute_type_parameters(cx: &CodegenCx<'ll, 'tcx>, ty: Ty<'tcx>) -> &'ll DIArray {
+fn compute_type_parameters<'ll, 'tcx>(cx: &CodegenCx<'ll, 'tcx>, ty: Ty<'tcx>) -> &'ll DIArray {
if let ty::Adt(def, substs) = *ty.kind() {
if substs.types().next().is_some() {
let generics = cx.tcx.generics_of(def.did);
@@ -2439,7 +2464,7 @@ fn compute_type_parameters(cx: &CodegenCx<'ll, 'tcx>, ty: Ty<'tcx>) -> &'ll DIAr
})
.collect();
- return create_DIArray(DIB(cx), &template_params[..]);
+ return create_DIArray(DIB(cx), &template_params);
}
}
return create_DIArray(DIB(cx), &[]);
@@ -2456,7 +2481,7 @@ fn compute_type_parameters(cx: &CodegenCx<'ll, 'tcx>, ty: Ty<'tcx>) -> &'ll DIAr
/// A convenience wrapper around `LLVMRustDIBuilderCreateStructType()`. Does not do
/// any caching, does not add any fields to the struct. This can be done later
/// with `set_members_of_composite_type()`.
-fn create_struct_stub(
+fn create_struct_stub<'ll, 'tcx>(
cx: &CodegenCx<'ll, 'tcx>,
struct_type: Ty<'tcx>,
struct_type_name: &str,
@@ -2497,7 +2522,7 @@ fn create_struct_stub(
metadata_stub
}
-fn create_union_stub(
+fn create_union_stub<'ll, 'tcx>(
cx: &CodegenCx<'ll, 'tcx>,
union_type: Ty<'tcx>,
union_type_name: &str,
@@ -2538,7 +2563,7 @@ fn create_union_stub(
/// Creates debug information for the given global variable.
///
/// Adds the created metadata nodes directly to the crate's IR.
-pub fn create_global_var_metadata(cx: &CodegenCx<'ll, '_>, def_id: DefId, global: &'ll Value) {
+pub fn create_global_var_metadata<'ll>(cx: &CodegenCx<'ll, '_>, def_id: DefId, global: &'ll Value) {
if cx.dbg_cx.is_none() {
return;
}
@@ -2593,7 +2618,7 @@ pub fn create_global_var_metadata(cx: &CodegenCx<'ll, '_>, def_id: DefId, global
}
/// Generates LLVM debuginfo for a vtable.
-fn vtable_type_metadata(
+fn vtable_type_metadata<'ll, 'tcx>(
cx: &CodegenCx<'ll, 'tcx>,
ty: Ty<'tcx>,
poly_trait_ref: Option<ty::PolyExistentialTraitRef<'tcx>>,
@@ -2625,7 +2650,7 @@ fn vtable_type_metadata(
/// given type.
///
/// Adds the created metadata nodes directly to the crate's IR.
-pub fn create_vtable_metadata(
+pub fn create_vtable_metadata<'ll, 'tcx>(
cx: &CodegenCx<'ll, 'tcx>,
ty: Ty<'tcx>,
poly_trait_ref: Option<ty::PolyExistentialTraitRef<'tcx>>,
@@ -2664,7 +2689,7 @@ pub fn create_vtable_metadata(
}
/// Creates an "extension" of an existing `DIScope` into another file.
-pub fn extend_scope_to_file(
+pub fn extend_scope_to_file<'ll>(
cx: &CodegenCx<'ll, '_>,
scope_metadata: &'ll DIScope,
file: &SourceFile,
diff --git a/compiler/rustc_codegen_llvm/src/debuginfo/mod.rs b/compiler/rustc_codegen_llvm/src/debuginfo/mod.rs
index 2a6bf7d9b1a..3e7371179cc 100644
--- a/compiler/rustc_codegen_llvm/src/debuginfo/mod.rs
+++ b/compiler/rustc_codegen_llvm/src/debuginfo/mod.rs
@@ -71,7 +71,7 @@ pub struct CrateDebugContext<'a, 'tcx> {
composite_types_completed: RefCell<FxHashSet<&'a DIType>>,
}
-impl Drop for CrateDebugContext<'a, 'tcx> {
+impl Drop for CrateDebugContext<'_, '_> {
fn drop(&mut self) {
unsafe {
llvm::LLVMRustDIBuilderDispose(&mut *(self.builder as *mut _));
@@ -144,7 +144,7 @@ pub fn finalize(cx: &CodegenCx<'_, '_>) {
}
}
-impl DebugInfoBuilderMethods for Builder<'a, 'll, 'tcx> {
+impl<'ll> DebugInfoBuilderMethods for Builder<'_, 'll, '_> {
// FIXME(eddyb) find a common convention for all of the debuginfo-related
// names (choose between `dbg`, `debug`, `debuginfo`, `debug_info` etc.).
fn dbg_var_addr(
@@ -236,7 +236,7 @@ pub struct DebugLoc {
pub col: u32,
}
-impl CodegenCx<'ll, '_> {
+impl CodegenCx<'_, '_> {
/// Looks up debug source information about a `BytePos`.
// FIXME(eddyb) rename this to better indicate it's a duplicate of
// `lookup_char_pos` rather than `dbg_loc`, perhaps by making
@@ -266,7 +266,7 @@ impl CodegenCx<'ll, '_> {
}
}
-impl DebugInfoMethods<'tcx> for CodegenCx<'ll, 'tcx> {
+impl<'ll, 'tcx> DebugInfoMethods<'tcx> for CodegenCx<'ll, 'tcx> {
fn create_function_debug_context(
&self,
instance: Instance<'tcx>,
@@ -474,7 +474,7 @@ impl DebugInfoMethods<'tcx> for CodegenCx<'ll, 'tcx> {
vec![]
};
- create_DIArray(DIB(cx), &template_params[..])
+ create_DIArray(DIB(cx), &template_params)
}
fn get_parameter_names(cx: &CodegenCx<'_, '_>, generics: &ty::Generics) -> Vec<Symbol> {
diff --git a/compiler/rustc_codegen_llvm/src/debuginfo/namespace.rs b/compiler/rustc_codegen_llvm/src/debuginfo/namespace.rs
index 1cbf5386996..d5ea48c311b 100644
--- a/compiler/rustc_codegen_llvm/src/debuginfo/namespace.rs
+++ b/compiler/rustc_codegen_llvm/src/debuginfo/namespace.rs
@@ -17,7 +17,7 @@ pub fn mangled_name_of_instance<'a, 'tcx>(
tcx.symbol_name(instance)
}
-pub fn item_namespace(cx: &CodegenCx<'ll, '_>, def_id: DefId) -> &'ll DIScope {
+pub fn item_namespace<'ll>(cx: &CodegenCx<'ll, '_>, def_id: DefId) -> &'ll DIScope {
if let Some(&scope) = debug_context(cx).namespace_map.borrow().get(&def_id) {
return scope;
}
diff --git a/compiler/rustc_codegen_llvm/src/debuginfo/utils.rs b/compiler/rustc_codegen_llvm/src/debuginfo/utils.rs
index ee188e69be1..953b6765a48 100644
--- a/compiler/rustc_codegen_llvm/src/debuginfo/utils.rs
+++ b/compiler/rustc_codegen_llvm/src/debuginfo/utils.rs
@@ -23,21 +23,26 @@ pub fn is_node_local_to_unit(cx: &CodegenCx<'_, '_>, def_id: DefId) -> bool {
}
#[allow(non_snake_case)]
-pub fn create_DIArray(builder: &DIBuilder<'ll>, arr: &[Option<&'ll DIDescriptor>]) -> &'ll DIArray {
+pub fn create_DIArray<'ll>(
+ builder: &DIBuilder<'ll>,
+ arr: &[Option<&'ll DIDescriptor>],
+) -> &'ll DIArray {
unsafe { llvm::LLVMRustDIBuilderGetOrCreateArray(builder, arr.as_ptr(), arr.len() as u32) }
}
#[inline]
-pub fn debug_context(cx: &'a CodegenCx<'ll, 'tcx>) -> &'a CrateDebugContext<'ll, 'tcx> {
+pub fn debug_context<'a, 'll, 'tcx>(
+ cx: &'a CodegenCx<'ll, 'tcx>,
+) -> &'a CrateDebugContext<'ll, 'tcx> {
cx.dbg_cx.as_ref().unwrap()
}
#[inline]
#[allow(non_snake_case)]
-pub fn DIB(cx: &'a CodegenCx<'ll, '_>) -> &'a DIBuilder<'ll> {
+pub fn DIB<'a, 'll>(cx: &'a CodegenCx<'ll, '_>) -> &'a DIBuilder<'ll> {
cx.dbg_cx.as_ref().unwrap().builder
}
-pub fn get_namespace_for_item(cx: &CodegenCx<'ll, '_>, def_id: DefId) -> &'ll DIScope {
+pub fn get_namespace_for_item<'ll>(cx: &CodegenCx<'ll, '_>, def_id: DefId) -> &'ll DIScope {
item_namespace(cx, cx.tcx.parent(def_id).expect("get_namespace_for_item: missing parent?"))
}
diff --git a/compiler/rustc_codegen_llvm/src/declare.rs b/compiler/rustc_codegen_llvm/src/declare.rs
index 8977fa085b9..90d0d5caba1 100644
--- a/compiler/rustc_codegen_llvm/src/declare.rs
+++ b/compiler/rustc_codegen_llvm/src/declare.rs
@@ -26,7 +26,7 @@ use tracing::debug;
///
/// If there’s a value with the same name already declared, the function will
/// update the declaration and return existing Value instead.
-fn declare_raw_fn(
+fn declare_raw_fn<'ll>(
cx: &CodegenCx<'ll, '_>,
name: &str,
callconv: llvm::CallConv,
@@ -50,7 +50,7 @@ fn declare_raw_fn(
llfn
}
-impl CodegenCx<'ll, 'tcx> {
+impl<'ll, 'tcx> CodegenCx<'ll, 'tcx> {
/// Declare a global value.
///
/// If there’s a value with the same name already declared, the function will
diff --git a/compiler/rustc_codegen_llvm/src/intrinsic.rs b/compiler/rustc_codegen_llvm/src/intrinsic.rs
index a7e34b08059..07d49b6e729 100644
--- a/compiler/rustc_codegen_llvm/src/intrinsic.rs
+++ b/compiler/rustc_codegen_llvm/src/intrinsic.rs
@@ -25,7 +25,10 @@ use rustc_target::spec::{HasTargetSpec, PanicStrategy};
use std::cmp::Ordering;
use std::iter;
-fn get_simple_intrinsic(cx: &CodegenCx<'ll, '_>, name: Symbol) -> Option<(&'ll Type, &'ll Value)> {
+fn get_simple_intrinsic<'ll>(
+ cx: &CodegenCx<'ll, '_>,
+ name: Symbol,
+) -> Option<(&'ll Type, &'ll Value)> {
let llvm_name = match name {
sym::sqrtf32 => "llvm.sqrt.f32",
sym::sqrtf64 => "llvm.sqrt.f64",
@@ -74,7 +77,7 @@ fn get_simple_intrinsic(cx: &CodegenCx<'ll, '_>, name: Symbol) -> Option<(&'ll T
Some(cx.get_intrinsic(llvm_name))
}
-impl IntrinsicCallMethods<'tcx> for Builder<'a, 'll, 'tcx> {
+impl<'ll, 'tcx> IntrinsicCallMethods<'tcx> for Builder<'_, 'll, 'tcx> {
fn codegen_intrinsic_call(
&mut self,
instance: ty::Instance<'tcx>,
@@ -350,6 +353,8 @@ impl IntrinsicCallMethods<'tcx> for Builder<'a, 'll, 'tcx> {
false,
ast::LlvmAsmDialect::Att,
&[span],
+ false,
+ None,
)
.unwrap_or_else(|| bug!("failed to generate inline asm call for `black_box`"));
@@ -409,8 +414,8 @@ impl IntrinsicCallMethods<'tcx> for Builder<'a, 'll, 'tcx> {
}
}
-fn try_intrinsic(
- bx: &mut Builder<'a, 'll, 'tcx>,
+fn try_intrinsic<'ll>(
+ bx: &mut Builder<'_, 'll, '_>,
try_func: &'ll Value,
data: &'ll Value,
catch_func: &'ll Value,
@@ -439,8 +444,8 @@ fn try_intrinsic(
// instructions are meant to work for all targets, as of the time of this
// writing, however, LLVM does not recommend the usage of these new instructions
// as the old ones are still more optimized.
-fn codegen_msvc_try(
- bx: &mut Builder<'a, 'll, 'tcx>,
+fn codegen_msvc_try<'ll>(
+ bx: &mut Builder<'_, 'll, '_>,
try_func: &'ll Value,
data: &'ll Value,
catch_func: &'ll Value,
@@ -591,8 +596,8 @@ fn codegen_msvc_try(
// function calling it, and that function may already have other personality
// functions in play. By calling a shim we're guaranteed that our shim will have
// the right personality function.
-fn codegen_gnu_try(
- bx: &mut Builder<'a, 'll, 'tcx>,
+fn codegen_gnu_try<'ll>(
+ bx: &mut Builder<'_, 'll, '_>,
try_func: &'ll Value,
data: &'ll Value,
catch_func: &'ll Value,
@@ -647,8 +652,8 @@ fn codegen_gnu_try(
// Variant of codegen_gnu_try used for emscripten where Rust panics are
// implemented using C++ exceptions. Here we use exceptions of a specific type
// (`struct rust_panic`) to represent Rust panics.
-fn codegen_emcc_try(
- bx: &mut Builder<'a, 'll, 'tcx>,
+fn codegen_emcc_try<'ll>(
+ bx: &mut Builder<'_, 'll, '_>,
try_func: &'ll Value,
data: &'ll Value,
catch_func: &'ll Value,
@@ -797,8 +802,8 @@ fn get_rust_try_fn<'ll, 'tcx>(
rust_try
}
-fn generic_simd_intrinsic(
- bx: &mut Builder<'a, 'll, 'tcx>,
+fn generic_simd_intrinsic<'ll, 'tcx>(
+ bx: &mut Builder<'_, 'll, 'tcx>,
name: Symbol,
callee_ty: Ty<'tcx>,
args: &[OperandRef<'tcx, &'ll Value>],
@@ -1127,12 +1132,12 @@ fn generic_simd_intrinsic(
}
}
- fn simd_simple_float_intrinsic(
+ fn simd_simple_float_intrinsic<'ll, 'tcx>(
name: Symbol,
in_elem: &::rustc_middle::ty::TyS<'_>,
in_ty: &::rustc_middle::ty::TyS<'_>,
in_len: u64,
- bx: &mut Builder<'a, 'll, 'tcx>,
+ bx: &mut Builder<'_, 'll, 'tcx>,
span: Span,
args: &[OperandRef<'tcx, &'ll Value>],
) -> Result<&'ll Value, ()> {
@@ -1230,7 +1235,7 @@ fn generic_simd_intrinsic(
elem_ty: Ty<'_>,
vec_len: u64,
no_pointers: usize,
- bx: &Builder<'a, 'll, 'tcx>,
+ bx: &Builder<'_, '_, '_>,
) -> String {
let p0s: String = "p0".repeat(no_pointers);
match *elem_ty.kind() {
@@ -1253,7 +1258,7 @@ fn generic_simd_intrinsic(
}
}
- fn llvm_vector_ty(
+ fn llvm_vector_ty<'ll>(
cx: &CodegenCx<'ll, '_>,
elem_ty: Ty<'_>,
vec_len: u64,
diff --git a/compiler/rustc_codegen_llvm/src/lib.rs b/compiler/rustc_codegen_llvm/src/lib.rs
index 64fedb7bc1a..cea4595fbbf 100644
--- a/compiler/rustc_codegen_llvm/src/lib.rs
+++ b/compiler/rustc_codegen_llvm/src/lib.rs
@@ -6,11 +6,8 @@
#![doc(html_root_url = "https://doc.rust-lang.org/nightly/nightly-rustc/")]
#![feature(bool_to_option)]
-#![feature(const_cstr_unchecked)]
#![feature(crate_visibility_modifier)]
#![feature(extern_types)]
-#![feature(in_band_lifetimes)]
-#![feature(iter_zip)]
#![feature(nll)]
#![recursion_limit = "256"]
@@ -102,14 +99,6 @@ impl ExtraBackendMethods for LlvmCodegenBackend {
ModuleLlvm::new_metadata(tcx, mod_name)
}
- fn write_compressed_metadata<'tcx>(
- &self,
- tcx: TyCtxt<'tcx>,
- metadata: &EncodedMetadata,
- llvm_module: &mut ModuleLlvm,
- ) {
- base::write_compressed_metadata(tcx, metadata, llvm_module)
- }
fn codegen_allocator<'tcx>(
&self,
tcx: TyCtxt<'tcx>,
@@ -288,6 +277,31 @@ impl CodegenBackend for LlvmCodegenBackend {
}
println!();
}
+ PrintRequest::StackProtectorStrategies => {
+ println!(
+ r#"Available stack protector strategies:
+ all
+ Generate stack canaries in all functions.
+
+ strong
+ Generate stack canaries in a function if it either:
+ - has a local variable of `[T; N]` type, regardless of `T` and `N`
+ - takes the address of a local variable.
+
+ (Note that a local variable being borrowed is not equivalent to its
+ address being taken: e.g. some borrows may be removed by optimization,
+ while by-value argument passing may be implemented with reference to a
+ local stack variable in the ABI.)
+
+ basic
+ Generate stack canaries in functions with:
+ - local variables of `[T; N]` type, where `T` is byte-sized and `N` > 8.
+
+ none
+ Do not generate stack canaries.
+"#
+ );
+ }
req => llvm_util::print(req, sess),
}
}
@@ -323,6 +337,7 @@ impl CodegenBackend for LlvmCodegenBackend {
&self,
ongoing_codegen: Box<dyn Any>,
sess: &Session,
+ outputs: &OutputFilenames,
) -> Result<(CodegenResults, FxHashMap<WorkProductId, WorkProduct>), ErrorReported> {
let (codegen_results, work_products) = ongoing_codegen
.downcast::<rustc_codegen_ssa::back::write::OngoingCodegen<LlvmCodegenBackend>>()
@@ -331,7 +346,8 @@ impl CodegenBackend for LlvmCodegenBackend {
sess.time("llvm_dump_timing_file", || {
if sess.opts.debugging_opts.llvm_time_trace {
- llvm_util::time_trace_profiler_finish("llvm_timings.json");
+ let file_name = outputs.with_extension("llvm_timings.json");
+ llvm_util::time_trace_profiler_finish(&file_name);
}
});
diff --git a/compiler/rustc_codegen_llvm/src/llvm/diagnostic.rs b/compiler/rustc_codegen_llvm/src/llvm/diagnostic.rs
index 36aa022d746..e2fa5e488ed 100644
--- a/compiler/rustc_codegen_llvm/src/llvm/diagnostic.rs
+++ b/compiler/rustc_codegen_llvm/src/llvm/diagnostic.rs
@@ -43,7 +43,7 @@ pub struct OptimizationDiagnostic<'ll> {
pub message: String,
}
-impl OptimizationDiagnostic<'ll> {
+impl<'ll> OptimizationDiagnostic<'ll> {
unsafe fn unpack(kind: OptimizationDiagnosticKind, di: &'ll DiagnosticInfo) -> Self {
let mut function = None;
let mut line = 0;
@@ -142,7 +142,7 @@ pub struct InlineAsmDiagnostic {
}
impl InlineAsmDiagnostic {
- unsafe fn unpackInlineAsm(di: &'ll DiagnosticInfo) -> Self {
+ unsafe fn unpackInlineAsm(di: &DiagnosticInfo) -> Self {
let mut cookie = 0;
let mut message = None;
let mut level = super::DiagnosticLevel::Error;
@@ -157,7 +157,7 @@ impl InlineAsmDiagnostic {
}
}
- unsafe fn unpackSrcMgr(di: &'ll DiagnosticInfo) -> Self {
+ unsafe fn unpackSrcMgr(di: &DiagnosticInfo) -> Self {
let mut cookie = 0;
let smdiag = SrcMgrDiagnostic::unpack(super::LLVMRustGetSMDiagnostic(di, &mut cookie));
InlineAsmDiagnostic {
@@ -180,7 +180,7 @@ pub enum Diagnostic<'ll> {
UnknownDiagnostic(&'ll DiagnosticInfo),
}
-impl Diagnostic<'ll> {
+impl<'ll> Diagnostic<'ll> {
pub unsafe fn unpack(di: &'ll DiagnosticInfo) -> Self {
use super::DiagnosticKind as Dk;
let kind = super::LLVMRustGetDiagInfoKind(di);
diff --git a/compiler/rustc_codegen_llvm/src/llvm/ffi.rs b/compiler/rustc_codegen_llvm/src/llvm/ffi.rs
index 749eec459ac..6c911938ccc 100644
--- a/compiler/rustc_codegen_llvm/src/llvm/ffi.rs
+++ b/compiler/rustc_codegen_llvm/src/llvm/ffi.rs
@@ -166,6 +166,9 @@ pub enum Attribute {
InaccessibleMemOnly = 27,
SanitizeHWAddress = 28,
WillReturn = 29,
+ StackProtectReq = 30,
+ StackProtectStrong = 31,
+ StackProtect = 32,
}
/// LLVMIntPredicate
@@ -672,13 +675,17 @@ pub struct OperandBundleDef<'a>(InvariantOpaque<'a>);
#[repr(C)]
pub struct Linker<'a>(InvariantOpaque<'a>);
-pub type DiagnosticHandler = unsafe extern "C" fn(&DiagnosticInfo, *mut c_void);
-pub type InlineAsmDiagHandler = unsafe extern "C" fn(&SMDiagnostic, *const c_void, c_uint);
+extern "C" {
+ pub type DiagnosticHandler;
+}
+
+pub type DiagnosticHandlerTy = unsafe extern "C" fn(&DiagnosticInfo, *mut c_void);
+pub type InlineAsmDiagHandlerTy = unsafe extern "C" fn(&SMDiagnostic, *const c_void, c_uint);
pub mod coverageinfo {
use super::coverage_map;
- /// Aligns with [llvm::coverage::CounterMappingRegion::RegionKind](https://github.com/rust-lang/llvm-project/blob/rustc/11.0-2020-10-12/llvm/include/llvm/ProfileData/Coverage/CoverageMapping.h#L206-L222)
+ /// Aligns with [llvm::coverage::CounterMappingRegion::RegionKind](https://github.com/rust-lang/llvm-project/blob/rustc/13.0-2021-09-30/llvm/include/llvm/ProfileData/Coverage/CoverageMapping.h#L209-L230)
#[derive(Copy, Clone, Debug)]
#[repr(C)]
pub enum RegionKind {
@@ -697,11 +704,16 @@ pub mod coverageinfo {
/// A GapRegion is like a CodeRegion, but its count is only set as the
/// line execution count when its the only region in the line.
GapRegion = 3,
+
+ /// A BranchRegion represents leaf-level boolean expressions and is
+ /// associated with two counters, each representing the number of times the
+ /// expression evaluates to true or false.
+ BranchRegion = 4,
}
/// This struct provides LLVM's representation of a "CoverageMappingRegion", encoded into the
/// coverage map, in accordance with the
- /// [LLVM Code Coverage Mapping Format](https://github.com/rust-lang/llvm-project/blob/rustc/11.0-2020-10-12/llvm/docs/CoverageMappingFormat.rst#llvm-code-coverage-mapping-format).
+ /// [LLVM Code Coverage Mapping Format](https://github.com/rust-lang/llvm-project/blob/rustc/13.0-2021-09-30/llvm/docs/CoverageMappingFormat.rst#llvm-code-coverage-mapping-format).
/// The struct composes fields representing the `Counter` type and value(s) (injected counter
/// ID, or expression type and operands), the source file (an indirect index into a "filenames
/// array", encoded separately), and source location (start and end positions of the represented
@@ -714,6 +726,10 @@ pub mod coverageinfo {
/// The counter type and type-dependent counter data, if any.
counter: coverage_map::Counter,
+ /// If the `RegionKind` is a `BranchRegion`, this represents the counter
+ /// for the false branch of the region.
+ false_counter: coverage_map::Counter,
+
/// An indirect reference to the source filename. In the LLVM Coverage Mapping Format, the
/// file_id is an index into a function-specific `virtual_file_mapping` array of indexes
/// that, in turn, are used to look up the filename for this region.
@@ -751,6 +767,7 @@ pub mod coverageinfo {
) -> Self {
Self {
counter,
+ false_counter: coverage_map::Counter::zero(),
file_id,
expanded_file_id: 0,
start_line,
@@ -764,6 +781,31 @@ pub mod coverageinfo {
// This function might be used in the future; the LLVM API is still evolving, as is coverage
// support.
#[allow(dead_code)]
+ crate fn branch_region(
+ counter: coverage_map::Counter,
+ false_counter: coverage_map::Counter,
+ file_id: u32,
+ start_line: u32,
+ start_col: u32,
+ end_line: u32,
+ end_col: u32,
+ ) -> Self {
+ Self {
+ counter,
+ false_counter,
+ file_id,
+ expanded_file_id: 0,
+ start_line,
+ start_col,
+ end_line,
+ end_col,
+ kind: RegionKind::BranchRegion,
+ }
+ }
+
+ // This function might be used in the future; the LLVM API is still evolving, as is coverage
+ // support.
+ #[allow(dead_code)]
crate fn expansion_region(
file_id: u32,
expanded_file_id: u32,
@@ -774,6 +816,7 @@ pub mod coverageinfo {
) -> Self {
Self {
counter: coverage_map::Counter::zero(),
+ false_counter: coverage_map::Counter::zero(),
file_id,
expanded_file_id,
start_line,
@@ -796,6 +839,7 @@ pub mod coverageinfo {
) -> Self {
Self {
counter: coverage_map::Counter::zero(),
+ false_counter: coverage_map::Counter::zero(),
file_id,
expanded_file_id: 0,
start_line,
@@ -819,6 +863,7 @@ pub mod coverageinfo {
) -> Self {
Self {
counter,
+ false_counter: coverage_map::Counter::zero(),
file_id,
expanded_file_id: 0,
start_line,
@@ -968,17 +1013,17 @@ extern "C" {
pub fn LLVMDoubleTypeInContext(C: &Context) -> &Type;
// Operations on function types
- pub fn LLVMFunctionType(
+ pub fn LLVMFunctionType<'a>(
ReturnType: &'a Type,
ParamTypes: *const &'a Type,
ParamCount: c_uint,
IsVarArg: Bool,
) -> &'a Type;
pub fn LLVMCountParamTypes(FunctionTy: &Type) -> c_uint;
- pub fn LLVMGetParamTypes(FunctionTy: &'a Type, Dest: *mut &'a Type);
+ pub fn LLVMGetParamTypes<'a>(FunctionTy: &'a Type, Dest: *mut &'a Type);
// Operations on struct types
- pub fn LLVMStructTypeInContext(
+ pub fn LLVMStructTypeInContext<'a>(
C: &'a Context,
ElementTypes: *const &'a Type,
ElementCount: c_uint,
@@ -1001,10 +1046,10 @@ extern "C" {
pub fn LLVMTypeOf(Val: &Value) -> &Type;
pub fn LLVMGetValueName2(Val: &Value, Length: *mut size_t) -> *const c_char;
pub fn LLVMSetValueName2(Val: &Value, Name: *const c_char, NameLen: size_t);
- pub fn LLVMReplaceAllUsesWith(OldVal: &'a Value, NewVal: &'a Value);
- pub fn LLVMSetMetadata(Val: &'a Value, KindID: c_uint, Node: &'a Value);
- pub fn LLVMGlobalSetMetadata(Val: &'a Value, KindID: c_uint, Metadata: &'a Metadata);
- pub fn LLVMValueAsMetadata(Node: &'a Value) -> &Metadata;
+ pub fn LLVMReplaceAllUsesWith<'a>(OldVal: &'a Value, NewVal: &'a Value);
+ pub fn LLVMSetMetadata<'a>(Val: &'a Value, KindID: c_uint, Node: &'a Value);
+ pub fn LLVMGlobalSetMetadata<'a>(Val: &'a Value, KindID: c_uint, Metadata: &'a Metadata);
+ pub fn LLVMValueAsMetadata(Node: &Value) -> &Metadata;
// Operations on constants of any type
pub fn LLVMConstNull(Ty: &Type) -> &Value;
@@ -1012,8 +1057,12 @@ extern "C" {
// Operations on metadata
pub fn LLVMMDStringInContext(C: &Context, Str: *const c_char, SLen: c_uint) -> &Value;
- pub fn LLVMMDNodeInContext(C: &'a Context, Vals: *const &'a Value, Count: c_uint) -> &'a Value;
- pub fn LLVMAddNamedMetadataOperand(M: &'a Module, Name: *const c_char, Val: &'a Value);
+ pub fn LLVMMDNodeInContext<'a>(
+ C: &'a Context,
+ Vals: *const &'a Value,
+ Count: c_uint,
+ ) -> &'a Value;
+ pub fn LLVMAddNamedMetadataOperand<'a>(M: &'a Module, Name: *const c_char, Val: &'a Value);
// Operations on scalar constants
pub fn LLVMConstInt(IntTy: &Type, N: c_ulonglong, SignExtend: Bool) -> &Value;
@@ -1034,14 +1083,14 @@ extern "C" {
Length: c_uint,
DontNullTerminate: Bool,
) -> &Value;
- pub fn LLVMConstStructInContext(
+ pub fn LLVMConstStructInContext<'a>(
C: &'a Context,
ConstantVals: *const &'a Value,
Count: c_uint,
Packed: Bool,
) -> &'a Value;
- pub fn LLVMConstArray(
+ pub fn LLVMConstArray<'a>(
ElementTy: &'a Type,
ConstantVals: *const &'a Value,
Length: c_uint,
@@ -1049,17 +1098,17 @@ extern "C" {
pub fn LLVMConstVector(ScalarConstantVals: *const &Value, Size: c_uint) -> &Value;
// Constant expressions
- pub fn LLVMRustConstInBoundsGEP2(
+ pub fn LLVMRustConstInBoundsGEP2<'a>(
ty: &'a Type,
ConstantVal: &'a Value,
ConstantIndices: *const &'a Value,
NumIndices: c_uint,
) -> &'a Value;
- pub fn LLVMConstZExt(ConstantVal: &'a Value, ToType: &'a Type) -> &'a Value;
- pub fn LLVMConstPtrToInt(ConstantVal: &'a Value, ToType: &'a Type) -> &'a Value;
- pub fn LLVMConstIntToPtr(ConstantVal: &'a Value, ToType: &'a Type) -> &'a Value;
- pub fn LLVMConstBitCast(ConstantVal: &'a Value, ToType: &'a Type) -> &'a Value;
- pub fn LLVMConstPointerCast(ConstantVal: &'a Value, ToType: &'a Type) -> &'a Value;
+ pub fn LLVMConstZExt<'a>(ConstantVal: &'a Value, ToType: &'a Type) -> &'a Value;
+ pub fn LLVMConstPtrToInt<'a>(ConstantVal: &'a Value, ToType: &'a Type) -> &'a Value;
+ pub fn LLVMConstIntToPtr<'a>(ConstantVal: &'a Value, ToType: &'a Type) -> &'a Value;
+ pub fn LLVMConstBitCast<'a>(ConstantVal: &'a Value, ToType: &'a Type) -> &'a Value;
+ pub fn LLVMConstPointerCast<'a>(ConstantVal: &'a Value, ToType: &'a Type) -> &'a Value;
pub fn LLVMConstExtractValue(
AggConstant: &Value,
IdxList: *const c_uint,
@@ -1080,20 +1129,20 @@ extern "C" {
// Operations on global variables
pub fn LLVMIsAGlobalVariable(GlobalVar: &Value) -> Option<&Value>;
- pub fn LLVMAddGlobal(M: &'a Module, Ty: &'a Type, Name: *const c_char) -> &'a Value;
+ pub fn LLVMAddGlobal<'a>(M: &'a Module, Ty: &'a Type, Name: *const c_char) -> &'a Value;
pub fn LLVMGetNamedGlobal(M: &Module, Name: *const c_char) -> Option<&Value>;
- pub fn LLVMRustGetOrInsertGlobal(
+ pub fn LLVMRustGetOrInsertGlobal<'a>(
M: &'a Module,
Name: *const c_char,
NameLen: size_t,
T: &'a Type,
) -> &'a Value;
- pub fn LLVMRustInsertPrivateGlobal(M: &'a Module, T: &'a Type) -> &'a Value;
+ pub fn LLVMRustInsertPrivateGlobal<'a>(M: &'a Module, T: &'a Type) -> &'a Value;
pub fn LLVMGetFirstGlobal(M: &Module) -> Option<&Value>;
pub fn LLVMGetNextGlobal(GlobalVar: &Value) -> Option<&Value>;
pub fn LLVMDeleteGlobal(GlobalVar: &Value);
pub fn LLVMGetInitializer(GlobalVar: &Value) -> Option<&Value>;
- pub fn LLVMSetInitializer(GlobalVar: &'a Value, ConstantVal: &'a Value);
+ pub fn LLVMSetInitializer<'a>(GlobalVar: &'a Value, ConstantVal: &'a Value);
pub fn LLVMIsThreadLocal(GlobalVar: &Value) -> Bool;
pub fn LLVMSetThreadLocal(GlobalVar: &Value, IsThreadLocal: Bool);
pub fn LLVMSetThreadLocalMode(GlobalVar: &Value, Mode: ThreadLocalMode);
@@ -1107,7 +1156,7 @@ extern "C" {
pub fn LLVMSetTailCall(CallInst: &Value, IsTailCall: Bool);
// Operations on functions
- pub fn LLVMRustGetOrInsertFunction(
+ pub fn LLVMRustGetOrInsertFunction<'a>(
M: &'a Module,
Name: *const c_char,
NameLen: size_t,
@@ -1135,7 +1184,7 @@ extern "C" {
// Operations on basic blocks
pub fn LLVMGetBasicBlockParent(BB: &BasicBlock) -> &Value;
- pub fn LLVMAppendBasicBlockInContext(
+ pub fn LLVMAppendBasicBlockInContext<'a>(
C: &'a Context,
Fn: &'a Value,
Name: *const c_char,
@@ -1159,7 +1208,7 @@ extern "C" {
pub fn LLVMSetVolatile(MemoryAccessInst: &Value, volatile: Bool);
// Operations on phi nodes
- pub fn LLVMAddIncoming(
+ pub fn LLVMAddIncoming<'a>(
PhiNode: &'a Value,
IncomingValues: *const &'a Value,
IncomingBlocks: *const &'a BasicBlock,
@@ -1167,31 +1216,31 @@ extern "C" {
);
// Instruction builders
- pub fn LLVMCreateBuilderInContext(C: &'a Context) -> &'a mut Builder<'a>;
- pub fn LLVMPositionBuilderAtEnd(Builder: &Builder<'a>, Block: &'a BasicBlock);
- pub fn LLVMGetInsertBlock(Builder: &Builder<'a>) -> &'a BasicBlock;
- pub fn LLVMDisposeBuilder(Builder: &'a mut Builder<'a>);
+ pub fn LLVMCreateBuilderInContext(C: &Context) -> &mut Builder<'_>;
+ pub fn LLVMPositionBuilderAtEnd<'a>(Builder: &Builder<'a>, Block: &'a BasicBlock);
+ pub fn LLVMGetInsertBlock<'a>(Builder: &Builder<'a>) -> &'a BasicBlock;
+ pub fn LLVMDisposeBuilder<'a>(Builder: &'a mut Builder<'a>);
// Metadata
- pub fn LLVMSetCurrentDebugLocation(Builder: &Builder<'a>, L: &'a Value);
+ pub fn LLVMSetCurrentDebugLocation<'a>(Builder: &Builder<'a>, L: &'a Value);
// Terminators
- pub fn LLVMBuildRetVoid(B: &Builder<'a>) -> &'a Value;
- pub fn LLVMBuildRet(B: &Builder<'a>, V: &'a Value) -> &'a Value;
- pub fn LLVMBuildBr(B: &Builder<'a>, Dest: &'a BasicBlock) -> &'a Value;
- pub fn LLVMBuildCondBr(
+ pub fn LLVMBuildRetVoid<'a>(B: &Builder<'a>) -> &'a Value;
+ pub fn LLVMBuildRet<'a>(B: &Builder<'a>, V: &'a Value) -> &'a Value;
+ pub fn LLVMBuildBr<'a>(B: &Builder<'a>, Dest: &'a BasicBlock) -> &'a Value;
+ pub fn LLVMBuildCondBr<'a>(
B: &Builder<'a>,
If: &'a Value,
Then: &'a BasicBlock,
Else: &'a BasicBlock,
) -> &'a Value;
- pub fn LLVMBuildSwitch(
+ pub fn LLVMBuildSwitch<'a>(
B: &Builder<'a>,
V: &'a Value,
Else: &'a BasicBlock,
NumCases: c_uint,
) -> &'a Value;
- pub fn LLVMRustBuildInvoke(
+ pub fn LLVMRustBuildInvoke<'a>(
B: &Builder<'a>,
Ty: &'a Type,
Fn: &'a Value,
@@ -1202,239 +1251,239 @@ extern "C" {
Bundle: Option<&OperandBundleDef<'a>>,
Name: *const c_char,
) -> &'a Value;
- pub fn LLVMBuildLandingPad(
+ pub fn LLVMBuildLandingPad<'a>(
B: &Builder<'a>,
Ty: &'a Type,
PersFn: Option<&'a Value>,
NumClauses: c_uint,
Name: *const c_char,
) -> &'a Value;
- pub fn LLVMBuildResume(B: &Builder<'a>, Exn: &'a Value) -> &'a Value;
- pub fn LLVMBuildUnreachable(B: &Builder<'a>) -> &'a Value;
+ pub fn LLVMBuildResume<'a>(B: &Builder<'a>, Exn: &'a Value) -> &'a Value;
+ pub fn LLVMBuildUnreachable<'a>(B: &Builder<'a>) -> &'a Value;
- pub fn LLVMRustBuildCleanupPad(
+ pub fn LLVMRustBuildCleanupPad<'a>(
B: &Builder<'a>,
ParentPad: Option<&'a Value>,
ArgCnt: c_uint,
Args: *const &'a Value,
Name: *const c_char,
) -> Option<&'a Value>;
- pub fn LLVMRustBuildCleanupRet(
+ pub fn LLVMRustBuildCleanupRet<'a>(
B: &Builder<'a>,
CleanupPad: &'a Value,
UnwindBB: Option<&'a BasicBlock>,
) -> Option<&'a Value>;
- pub fn LLVMRustBuildCatchPad(
+ pub fn LLVMRustBuildCatchPad<'a>(
B: &Builder<'a>,
ParentPad: &'a Value,
ArgCnt: c_uint,
Args: *const &'a Value,
Name: *const c_char,
) -> Option<&'a Value>;
- pub fn LLVMRustBuildCatchRet(
+ pub fn LLVMRustBuildCatchRet<'a>(
B: &Builder<'a>,
Pad: &'a Value,
BB: &'a BasicBlock,
) -> Option<&'a Value>;
- pub fn LLVMRustBuildCatchSwitch(
+ pub fn LLVMRustBuildCatchSwitch<'a>(
Builder: &Builder<'a>,
ParentPad: Option<&'a Value>,
BB: Option<&'a BasicBlock>,
NumHandlers: c_uint,
Name: *const c_char,
) -> Option<&'a Value>;
- pub fn LLVMRustAddHandler(CatchSwitch: &'a Value, Handler: &'a BasicBlock);
- pub fn LLVMSetPersonalityFn(Func: &'a Value, Pers: &'a Value);
+ pub fn LLVMRustAddHandler<'a>(CatchSwitch: &'a Value, Handler: &'a BasicBlock);
+ pub fn LLVMSetPersonalityFn<'a>(Func: &'a Value, Pers: &'a Value);
// Add a case to the switch instruction
- pub fn LLVMAddCase(Switch: &'a Value, OnVal: &'a Value, Dest: &'a BasicBlock);
+ pub fn LLVMAddCase<'a>(Switch: &'a Value, OnVal: &'a Value, Dest: &'a BasicBlock);
// Add a clause to the landing pad instruction
- pub fn LLVMAddClause(LandingPad: &'a Value, ClauseVal: &'a Value);
+ pub fn LLVMAddClause<'a>(LandingPad: &'a Value, ClauseVal: &'a Value);
// Set the cleanup on a landing pad instruction
pub fn LLVMSetCleanup(LandingPad: &Value, Val: Bool);
// Arithmetic
- pub fn LLVMBuildAdd(
+ pub fn LLVMBuildAdd<'a>(
B: &Builder<'a>,
LHS: &'a Value,
RHS: &'a Value,
Name: *const c_char,
) -> &'a Value;
- pub fn LLVMBuildFAdd(
+ pub fn LLVMBuildFAdd<'a>(
B: &Builder<'a>,
LHS: &'a Value,
RHS: &'a Value,
Name: *const c_char,
) -> &'a Value;
- pub fn LLVMBuildSub(
+ pub fn LLVMBuildSub<'a>(
B: &Builder<'a>,
LHS: &'a Value,
RHS: &'a Value,
Name: *const c_char,
) -> &'a Value;
- pub fn LLVMBuildFSub(
+ pub fn LLVMBuildFSub<'a>(
B: &Builder<'a>,
LHS: &'a Value,
RHS: &'a Value,
Name: *const c_char,
) -> &'a Value;
- pub fn LLVMBuildMul(
+ pub fn LLVMBuildMul<'a>(
B: &Builder<'a>,
LHS: &'a Value,
RHS: &'a Value,
Name: *const c_char,
) -> &'a Value;
- pub fn LLVMBuildFMul(
+ pub fn LLVMBuildFMul<'a>(
B: &Builder<'a>,
LHS: &'a Value,
RHS: &'a Value,
Name: *const c_char,
) -> &'a Value;
- pub fn LLVMBuildUDiv(
+ pub fn LLVMBuildUDiv<'a>(
B: &Builder<'a>,
LHS: &'a Value,
RHS: &'a Value,
Name: *const c_char,
) -> &'a Value;
- pub fn LLVMBuildExactUDiv(
+ pub fn LLVMBuildExactUDiv<'a>(
B: &Builder<'a>,
LHS: &'a Value,
RHS: &'a Value,
Name: *const c_char,
) -> &'a Value;
- pub fn LLVMBuildSDiv(
+ pub fn LLVMBuildSDiv<'a>(
B: &Builder<'a>,
LHS: &'a Value,
RHS: &'a Value,
Name: *const c_char,
) -> &'a Value;
- pub fn LLVMBuildExactSDiv(
+ pub fn LLVMBuildExactSDiv<'a>(
B: &Builder<'a>,
LHS: &'a Value,
RHS: &'a Value,
Name: *const c_char,
) -> &'a Value;
- pub fn LLVMBuildFDiv(
+ pub fn LLVMBuildFDiv<'a>(
B: &Builder<'a>,
LHS: &'a Value,
RHS: &'a Value,
Name: *const c_char,
) -> &'a Value;
- pub fn LLVMBuildURem(
+ pub fn LLVMBuildURem<'a>(
B: &Builder<'a>,
LHS: &'a Value,
RHS: &'a Value,
Name: *const c_char,
) -> &'a Value;
- pub fn LLVMBuildSRem(
+ pub fn LLVMBuildSRem<'a>(
B: &Builder<'a>,
LHS: &'a Value,
RHS: &'a Value,
Name: *const c_char,
) -> &'a Value;
- pub fn LLVMBuildFRem(
+ pub fn LLVMBuildFRem<'a>(
B: &Builder<'a>,
LHS: &'a Value,
RHS: &'a Value,
Name: *const c_char,
) -> &'a Value;
- pub fn LLVMBuildShl(
+ pub fn LLVMBuildShl<'a>(
B: &Builder<'a>,
LHS: &'a Value,
RHS: &'a Value,
Name: *const c_char,
) -> &'a Value;
- pub fn LLVMBuildLShr(
+ pub fn LLVMBuildLShr<'a>(
B: &Builder<'a>,
LHS: &'a Value,
RHS: &'a Value,
Name: *const c_char,
) -> &'a Value;
- pub fn LLVMBuildAShr(
+ pub fn LLVMBuildAShr<'a>(
B: &Builder<'a>,
LHS: &'a Value,
RHS: &'a Value,
Name: *const c_char,
) -> &'a Value;
- pub fn LLVMBuildNSWAdd(
+ pub fn LLVMBuildNSWAdd<'a>(
B: &Builder<'a>,
LHS: &'a Value,
RHS: &'a Value,
Name: *const c_char,
) -> &'a Value;
- pub fn LLVMBuildNUWAdd(
+ pub fn LLVMBuildNUWAdd<'a>(
B: &Builder<'a>,
LHS: &'a Value,
RHS: &'a Value,
Name: *const c_char,
) -> &'a Value;
- pub fn LLVMBuildNSWSub(
+ pub fn LLVMBuildNSWSub<'a>(
B: &Builder<'a>,
LHS: &'a Value,
RHS: &'a Value,
Name: *const c_char,
) -> &'a Value;
- pub fn LLVMBuildNUWSub(
+ pub fn LLVMBuildNUWSub<'a>(
B: &Builder<'a>,
LHS: &'a Value,
RHS: &'a Value,
Name: *const c_char,
) -> &'a Value;
- pub fn LLVMBuildNSWMul(
+ pub fn LLVMBuildNSWMul<'a>(
B: &Builder<'a>,
LHS: &'a Value,
RHS: &'a Value,
Name: *const c_char,
) -> &'a Value;
- pub fn LLVMBuildNUWMul(
+ pub fn LLVMBuildNUWMul<'a>(
B: &Builder<'a>,
LHS: &'a Value,
RHS: &'a Value,
Name: *const c_char,
) -> &'a Value;
- pub fn LLVMBuildAnd(
+ pub fn LLVMBuildAnd<'a>(
B: &Builder<'a>,
LHS: &'a Value,
RHS: &'a Value,
Name: *const c_char,
) -> &'a Value;
- pub fn LLVMBuildOr(
+ pub fn LLVMBuildOr<'a>(
B: &Builder<'a>,
LHS: &'a Value,
RHS: &'a Value,
Name: *const c_char,
) -> &'a Value;
- pub fn LLVMBuildXor(
+ pub fn LLVMBuildXor<'a>(
B: &Builder<'a>,
LHS: &'a Value,
RHS: &'a Value,
Name: *const c_char,
) -> &'a Value;
- pub fn LLVMBuildNeg(B: &Builder<'a>, V: &'a Value, Name: *const c_char) -> &'a Value;
- pub fn LLVMBuildFNeg(B: &Builder<'a>, V: &'a Value, Name: *const c_char) -> &'a Value;
- pub fn LLVMBuildNot(B: &Builder<'a>, V: &'a Value, Name: *const c_char) -> &'a Value;
+ pub fn LLVMBuildNeg<'a>(B: &Builder<'a>, V: &'a Value, Name: *const c_char) -> &'a Value;
+ pub fn LLVMBuildFNeg<'a>(B: &Builder<'a>, V: &'a Value, Name: *const c_char) -> &'a Value;
+ pub fn LLVMBuildNot<'a>(B: &Builder<'a>, V: &'a Value, Name: *const c_char) -> &'a Value;
pub fn LLVMRustSetFastMath(Instr: &Value);
// Memory
- pub fn LLVMBuildAlloca(B: &Builder<'a>, Ty: &'a Type, Name: *const c_char) -> &'a Value;
- pub fn LLVMBuildArrayAlloca(
+ pub fn LLVMBuildAlloca<'a>(B: &Builder<'a>, Ty: &'a Type, Name: *const c_char) -> &'a Value;
+ pub fn LLVMBuildArrayAlloca<'a>(
B: &Builder<'a>,
Ty: &'a Type,
Val: &'a Value,
Name: *const c_char,
) -> &'a Value;
- pub fn LLVMBuildLoad2(
+ pub fn LLVMBuildLoad2<'a>(
B: &Builder<'a>,
Ty: &'a Type,
PointerVal: &'a Value,
Name: *const c_char,
) -> &'a Value;
- pub fn LLVMBuildStore(B: &Builder<'a>, Val: &'a Value, Ptr: &'a Value) -> &'a Value;
+ pub fn LLVMBuildStore<'a>(B: &Builder<'a>, Val: &'a Value, Ptr: &'a Value) -> &'a Value;
- pub fn LLVMBuildGEP2(
+ pub fn LLVMBuildGEP2<'a>(
B: &Builder<'a>,
Ty: &'a Type,
Pointer: &'a Value,
@@ -1442,7 +1491,7 @@ extern "C" {
NumIndices: c_uint,
Name: *const c_char,
) -> &'a Value;
- pub fn LLVMBuildInBoundsGEP2(
+ pub fn LLVMBuildInBoundsGEP2<'a>(
B: &Builder<'a>,
Ty: &'a Type,
Pointer: &'a Value,
@@ -1450,7 +1499,7 @@ extern "C" {
NumIndices: c_uint,
Name: *const c_char,
) -> &'a Value;
- pub fn LLVMBuildStructGEP2(
+ pub fn LLVMBuildStructGEP2<'a>(
B: &Builder<'a>,
Ty: &'a Type,
Pointer: &'a Value,
@@ -1459,85 +1508,85 @@ extern "C" {
) -> &'a Value;
// Casts
- pub fn LLVMBuildTrunc(
+ pub fn LLVMBuildTrunc<'a>(
B: &Builder<'a>,
Val: &'a Value,
DestTy: &'a Type,
Name: *const c_char,
) -> &'a Value;
- pub fn LLVMBuildZExt(
+ pub fn LLVMBuildZExt<'a>(
B: &Builder<'a>,
Val: &'a Value,
DestTy: &'a Type,
Name: *const c_char,
) -> &'a Value;
- pub fn LLVMBuildSExt(
+ pub fn LLVMBuildSExt<'a>(
B: &Builder<'a>,
Val: &'a Value,
DestTy: &'a Type,
Name: *const c_char,
) -> &'a Value;
- pub fn LLVMBuildFPToUI(
+ pub fn LLVMBuildFPToUI<'a>(
B: &Builder<'a>,
Val: &'a Value,
DestTy: &'a Type,
Name: *const c_char,
) -> &'a Value;
- pub fn LLVMBuildFPToSI(
+ pub fn LLVMBuildFPToSI<'a>(
B: &Builder<'a>,
Val: &'a Value,
DestTy: &'a Type,
Name: *const c_char,
) -> &'a Value;
- pub fn LLVMBuildUIToFP(
+ pub fn LLVMBuildUIToFP<'a>(
B: &Builder<'a>,
Val: &'a Value,
DestTy: &'a Type,
Name: *const c_char,
) -> &'a Value;
- pub fn LLVMBuildSIToFP(
+ pub fn LLVMBuildSIToFP<'a>(
B: &Builder<'a>,
Val: &'a Value,
DestTy: &'a Type,
Name: *const c_char,
) -> &'a Value;
- pub fn LLVMBuildFPTrunc(
+ pub fn LLVMBuildFPTrunc<'a>(
B: &Builder<'a>,
Val: &'a Value,
DestTy: &'a Type,
Name: *const c_char,
) -> &'a Value;
- pub fn LLVMBuildFPExt(
+ pub fn LLVMBuildFPExt<'a>(
B: &Builder<'a>,
Val: &'a Value,
DestTy: &'a Type,
Name: *const c_char,
) -> &'a Value;
- pub fn LLVMBuildPtrToInt(
+ pub fn LLVMBuildPtrToInt<'a>(
B: &Builder<'a>,
Val: &'a Value,
DestTy: &'a Type,
Name: *const c_char,
) -> &'a Value;
- pub fn LLVMBuildIntToPtr(
+ pub fn LLVMBuildIntToPtr<'a>(
B: &Builder<'a>,
Val: &'a Value,
DestTy: &'a Type,
Name: *const c_char,
) -> &'a Value;
- pub fn LLVMBuildBitCast(
+ pub fn LLVMBuildBitCast<'a>(
B: &Builder<'a>,
Val: &'a Value,
DestTy: &'a Type,
Name: *const c_char,
) -> &'a Value;
- pub fn LLVMBuildPointerCast(
+ pub fn LLVMBuildPointerCast<'a>(
B: &Builder<'a>,
Val: &'a Value,
DestTy: &'a Type,
Name: *const c_char,
) -> &'a Value;
- pub fn LLVMRustBuildIntCast(
+ pub fn LLVMRustBuildIntCast<'a>(
B: &Builder<'a>,
Val: &'a Value,
DestTy: &'a Type,
@@ -1545,14 +1594,14 @@ extern "C" {
) -> &'a Value;
// Comparisons
- pub fn LLVMBuildICmp(
+ pub fn LLVMBuildICmp<'a>(
B: &Builder<'a>,
Op: c_uint,
LHS: &'a Value,
RHS: &'a Value,
Name: *const c_char,
) -> &'a Value;
- pub fn LLVMBuildFCmp(
+ pub fn LLVMBuildFCmp<'a>(
B: &Builder<'a>,
Op: c_uint,
LHS: &'a Value,
@@ -1561,9 +1610,9 @@ extern "C" {
) -> &'a Value;
// Miscellaneous instructions
- pub fn LLVMBuildPhi(B: &Builder<'a>, Ty: &'a Type, Name: *const c_char) -> &'a Value;
- pub fn LLVMRustGetInstrProfIncrementIntrinsic(M: &Module) -> &'a Value;
- pub fn LLVMRustBuildCall(
+ pub fn LLVMBuildPhi<'a>(B: &Builder<'a>, Ty: &'a Type, Name: *const c_char) -> &'a Value;
+ pub fn LLVMRustGetInstrProfIncrementIntrinsic(M: &Module) -> &Value;
+ pub fn LLVMRustBuildCall<'a>(
B: &Builder<'a>,
Ty: &'a Type,
Fn: &'a Value,
@@ -1571,7 +1620,7 @@ extern "C" {
NumArgs: c_uint,
Bundle: Option<&OperandBundleDef<'a>>,
) -> &'a Value;
- pub fn LLVMRustBuildMemCpy(
+ pub fn LLVMRustBuildMemCpy<'a>(
B: &Builder<'a>,
Dst: &'a Value,
DstAlign: c_uint,
@@ -1580,7 +1629,7 @@ extern "C" {
Size: &'a Value,
IsVolatile: bool,
) -> &'a Value;
- pub fn LLVMRustBuildMemMove(
+ pub fn LLVMRustBuildMemMove<'a>(
B: &Builder<'a>,
Dst: &'a Value,
DstAlign: c_uint,
@@ -1589,7 +1638,7 @@ extern "C" {
Size: &'a Value,
IsVolatile: bool,
) -> &'a Value;
- pub fn LLVMRustBuildMemSet(
+ pub fn LLVMRustBuildMemSet<'a>(
B: &Builder<'a>,
Dst: &'a Value,
DstAlign: c_uint,
@@ -1597,46 +1646,46 @@ extern "C" {
Size: &'a Value,
IsVolatile: bool,
) -> &'a Value;
- pub fn LLVMBuildSelect(
+ pub fn LLVMBuildSelect<'a>(
B: &Builder<'a>,
If: &'a Value,
Then: &'a Value,
Else: &'a Value,
Name: *const c_char,
) -> &'a Value;
- pub fn LLVMBuildVAArg(
+ pub fn LLVMBuildVAArg<'a>(
B: &Builder<'a>,
list: &'a Value,
Ty: &'a Type,
Name: *const c_char,
) -> &'a Value;
- pub fn LLVMBuildExtractElement(
+ pub fn LLVMBuildExtractElement<'a>(
B: &Builder<'a>,
VecVal: &'a Value,
Index: &'a Value,
Name: *const c_char,
) -> &'a Value;
- pub fn LLVMBuildInsertElement(
+ pub fn LLVMBuildInsertElement<'a>(
B: &Builder<'a>,
VecVal: &'a Value,
EltVal: &'a Value,
Index: &'a Value,
Name: *const c_char,
) -> &'a Value;
- pub fn LLVMBuildShuffleVector(
+ pub fn LLVMBuildShuffleVector<'a>(
B: &Builder<'a>,
V1: &'a Value,
V2: &'a Value,
Mask: &'a Value,
Name: *const c_char,
) -> &'a Value;
- pub fn LLVMBuildExtractValue(
+ pub fn LLVMBuildExtractValue<'a>(
B: &Builder<'a>,
AggVal: &'a Value,
Index: c_uint,
Name: *const c_char,
) -> &'a Value;
- pub fn LLVMBuildInsertValue(
+ pub fn LLVMBuildInsertValue<'a>(
B: &Builder<'a>,
AggVal: &'a Value,
EltVal: &'a Value,
@@ -1644,41 +1693,47 @@ extern "C" {
Name: *const c_char,
) -> &'a Value;
- pub fn LLVMRustBuildVectorReduceFAdd(
+ pub fn LLVMRustBuildVectorReduceFAdd<'a>(
B: &Builder<'a>,
Acc: &'a Value,
Src: &'a Value,
) -> &'a Value;
- pub fn LLVMRustBuildVectorReduceFMul(
+ pub fn LLVMRustBuildVectorReduceFMul<'a>(
B: &Builder<'a>,
Acc: &'a Value,
Src: &'a Value,
) -> &'a Value;
- pub fn LLVMRustBuildVectorReduceAdd(B: &Builder<'a>, Src: &'a Value) -> &'a Value;
- pub fn LLVMRustBuildVectorReduceMul(B: &Builder<'a>, Src: &'a Value) -> &'a Value;
- pub fn LLVMRustBuildVectorReduceAnd(B: &Builder<'a>, Src: &'a Value) -> &'a Value;
- pub fn LLVMRustBuildVectorReduceOr(B: &Builder<'a>, Src: &'a Value) -> &'a Value;
- pub fn LLVMRustBuildVectorReduceXor(B: &Builder<'a>, Src: &'a Value) -> &'a Value;
- pub fn LLVMRustBuildVectorReduceMin(
+ pub fn LLVMRustBuildVectorReduceAdd<'a>(B: &Builder<'a>, Src: &'a Value) -> &'a Value;
+ pub fn LLVMRustBuildVectorReduceMul<'a>(B: &Builder<'a>, Src: &'a Value) -> &'a Value;
+ pub fn LLVMRustBuildVectorReduceAnd<'a>(B: &Builder<'a>, Src: &'a Value) -> &'a Value;
+ pub fn LLVMRustBuildVectorReduceOr<'a>(B: &Builder<'a>, Src: &'a Value) -> &'a Value;
+ pub fn LLVMRustBuildVectorReduceXor<'a>(B: &Builder<'a>, Src: &'a Value) -> &'a Value;
+ pub fn LLVMRustBuildVectorReduceMin<'a>(
B: &Builder<'a>,
Src: &'a Value,
IsSigned: bool,
) -> &'a Value;
- pub fn LLVMRustBuildVectorReduceMax(
+ pub fn LLVMRustBuildVectorReduceMax<'a>(
B: &Builder<'a>,
Src: &'a Value,
IsSigned: bool,
) -> &'a Value;
- pub fn LLVMRustBuildVectorReduceFMin(B: &Builder<'a>, Src: &'a Value, IsNaN: bool)
- -> &'a Value;
- pub fn LLVMRustBuildVectorReduceFMax(B: &Builder<'a>, Src: &'a Value, IsNaN: bool)
- -> &'a Value;
+ pub fn LLVMRustBuildVectorReduceFMin<'a>(
+ B: &Builder<'a>,
+ Src: &'a Value,
+ IsNaN: bool,
+ ) -> &'a Value;
+ pub fn LLVMRustBuildVectorReduceFMax<'a>(
+ B: &Builder<'a>,
+ Src: &'a Value,
+ IsNaN: bool,
+ ) -> &'a Value;
- pub fn LLVMRustBuildMinNum(B: &Builder<'a>, LHS: &'a Value, LHS: &'a Value) -> &'a Value;
- pub fn LLVMRustBuildMaxNum(B: &Builder<'a>, LHS: &'a Value, LHS: &'a Value) -> &'a Value;
+ pub fn LLVMRustBuildMinNum<'a>(B: &Builder<'a>, LHS: &'a Value, LHS: &'a Value) -> &'a Value;
+ pub fn LLVMRustBuildMaxNum<'a>(B: &Builder<'a>, LHS: &'a Value, LHS: &'a Value) -> &'a Value;
// Atomic Operations
- pub fn LLVMRustBuildAtomicLoad(
+ pub fn LLVMRustBuildAtomicLoad<'a>(
B: &Builder<'a>,
ElementType: &'a Type,
PointerVal: &'a Value,
@@ -1686,14 +1741,14 @@ extern "C" {
Order: AtomicOrdering,
) -> &'a Value;
- pub fn LLVMRustBuildAtomicStore(
+ pub fn LLVMRustBuildAtomicStore<'a>(
B: &Builder<'a>,
Val: &'a Value,
Ptr: &'a Value,
Order: AtomicOrdering,
) -> &'a Value;
- pub fn LLVMRustBuildAtomicCmpXchg(
+ pub fn LLVMRustBuildAtomicCmpXchg<'a>(
B: &Builder<'a>,
LHS: &'a Value,
CMP: &'a Value,
@@ -1703,7 +1758,7 @@ extern "C" {
Weak: Bool,
) -> &'a Value;
- pub fn LLVMBuildAtomicRMW(
+ pub fn LLVMBuildAtomicRMW<'a>(
B: &Builder<'a>,
Op: AtomicRmwBinOp,
LHS: &'a Value,
@@ -1722,16 +1777,16 @@ extern "C" {
pub fn LLVMWriteBitcodeToFile(M: &Module, Path: *const c_char) -> c_int;
/// Creates a pass manager.
- pub fn LLVMCreatePassManager() -> &'a mut PassManager<'a>;
+ pub fn LLVMCreatePassManager<'a>() -> &'a mut PassManager<'a>;
/// Creates a function-by-function pass manager
- pub fn LLVMCreateFunctionPassManagerForModule(M: &'a Module) -> &'a mut PassManager<'a>;
+ pub fn LLVMCreateFunctionPassManagerForModule(M: &Module) -> &mut PassManager<'_>;
/// Disposes a pass manager.
- pub fn LLVMDisposePassManager(PM: &'a mut PassManager<'a>);
+ pub fn LLVMDisposePassManager<'a>(PM: &'a mut PassManager<'a>);
/// Runs a pass manager on a module.
- pub fn LLVMRunPassManager(PM: &PassManager<'a>, M: &'a Module) -> Bool;
+ pub fn LLVMRunPassManager<'a>(PM: &PassManager<'a>, M: &'a Module) -> Bool;
pub fn LLVMInitializePasses();
@@ -1741,7 +1796,7 @@ extern "C" {
pub fn LLVMTimeTraceProfilerFinish(FileName: *const c_char);
- pub fn LLVMAddAnalysisPasses(T: &'a TargetMachine, PM: &PassManager<'a>);
+ pub fn LLVMAddAnalysisPasses<'a>(T: &'a TargetMachine, PM: &PassManager<'a>);
pub fn LLVMPassManagerBuilderCreate() -> &'static mut PassManagerBuilder;
pub fn LLVMPassManagerBuilderDispose(PMB: &'static mut PassManagerBuilder);
@@ -1785,7 +1840,7 @@ extern "C" {
pub fn LLVMStructCreateNamed(C: &Context, Name: *const c_char) -> &Type;
- pub fn LLVMStructSetBody(
+ pub fn LLVMStructSetBody<'a>(
StructTy: &'a Type,
ElementTypes: *const &'a Type,
ElementCount: c_uint,
@@ -1802,6 +1857,7 @@ extern "C" {
SideEffects: Bool,
AlignStack: Bool,
Dialect: AsmDialect,
+ CanThrow: Bool,
) -> &Value;
pub fn LLVMRustInlineAsmVerify(
Ty: &Type,
@@ -1827,8 +1883,7 @@ extern "C" {
BufferOut: &RustString,
);
- pub fn LLVMRustCoverageCreatePGOFuncNameVar(F: &'a Value, FuncName: *const c_char)
- -> &'a Value;
+ pub fn LLVMRustCoverageCreatePGOFuncNameVar(F: &Value, FuncName: *const c_char) -> &Value;
pub fn LLVMRustCoverageHashCString(StrVal: *const c_char) -> u64;
pub fn LLVMRustCoverageHashByteArray(Bytes: *const c_char, NumBytes: size_t) -> u64;
@@ -1849,15 +1904,15 @@ extern "C" {
pub fn LLVMRustAddModuleFlag(M: &Module, name: *const c_char, value: u32);
- pub fn LLVMRustMetadataAsValue(C: &'a Context, MD: &'a Metadata) -> &'a Value;
+ pub fn LLVMRustMetadataAsValue<'a>(C: &'a Context, MD: &'a Metadata) -> &'a Value;
- pub fn LLVMRustDIBuilderCreate(M: &'a Module) -> &'a mut DIBuilder<'a>;
+ pub fn LLVMRustDIBuilderCreate(M: &Module) -> &mut DIBuilder<'_>;
- pub fn LLVMRustDIBuilderDispose(Builder: &'a mut DIBuilder<'a>);
+ pub fn LLVMRustDIBuilderDispose<'a>(Builder: &'a mut DIBuilder<'a>);
pub fn LLVMRustDIBuilderFinalize(Builder: &DIBuilder<'_>);
- pub fn LLVMRustDIBuilderCreateCompileUnit(
+ pub fn LLVMRustDIBuilderCreateCompileUnit<'a>(
Builder: &DIBuilder<'a>,
Lang: c_uint,
File: &'a DIFile,
@@ -1873,7 +1928,7 @@ extern "C" {
SplitDebugInlining: bool,
) -> &'a DIDescriptor;
- pub fn LLVMRustDIBuilderCreateFile(
+ pub fn LLVMRustDIBuilderCreateFile<'a>(
Builder: &DIBuilder<'a>,
Filename: *const c_char,
FilenameLen: size_t,
@@ -1884,12 +1939,12 @@ extern "C" {
ChecksumLen: size_t,
) -> &'a DIFile;
- pub fn LLVMRustDIBuilderCreateSubroutineType(
+ pub fn LLVMRustDIBuilderCreateSubroutineType<'a>(
Builder: &DIBuilder<'a>,
ParameterTypes: &'a DIArray,
) -> &'a DICompositeType;
- pub fn LLVMRustDIBuilderCreateFunction(
+ pub fn LLVMRustDIBuilderCreateFunction<'a>(
Builder: &DIBuilder<'a>,
Scope: &'a DIDescriptor,
Name: *const c_char,
@@ -1907,7 +1962,7 @@ extern "C" {
Decl: Option<&'a DIDescriptor>,
) -> &'a DISubprogram;
- pub fn LLVMRustDIBuilderCreateBasicType(
+ pub fn LLVMRustDIBuilderCreateBasicType<'a>(
Builder: &DIBuilder<'a>,
Name: *const c_char,
NameLen: size_t,
@@ -1915,7 +1970,7 @@ extern "C" {
Encoding: c_uint,
) -> &'a DIBasicType;
- pub fn LLVMRustDIBuilderCreateTypedef(
+ pub fn LLVMRustDIBuilderCreateTypedef<'a>(
Builder: &DIBuilder<'a>,
Type: &'a DIBasicType,
Name: *const c_char,
@@ -1925,7 +1980,7 @@ extern "C" {
Scope: Option<&'a DIScope>,
) -> &'a DIDerivedType;
- pub fn LLVMRustDIBuilderCreatePointerType(
+ pub fn LLVMRustDIBuilderCreatePointerType<'a>(
Builder: &DIBuilder<'a>,
PointeeTy: &'a DIType,
SizeInBits: u64,
@@ -1935,7 +1990,7 @@ extern "C" {
NameLen: size_t,
) -> &'a DIDerivedType;
- pub fn LLVMRustDIBuilderCreateStructType(
+ pub fn LLVMRustDIBuilderCreateStructType<'a>(
Builder: &DIBuilder<'a>,
Scope: Option<&'a DIDescriptor>,
Name: *const c_char,
@@ -1953,7 +2008,7 @@ extern "C" {
UniqueIdLen: size_t,
) -> &'a DICompositeType;
- pub fn LLVMRustDIBuilderCreateMemberType(
+ pub fn LLVMRustDIBuilderCreateMemberType<'a>(
Builder: &DIBuilder<'a>,
Scope: &'a DIDescriptor,
Name: *const c_char,
@@ -1967,7 +2022,7 @@ extern "C" {
Ty: &'a DIType,
) -> &'a DIDerivedType;
- pub fn LLVMRustDIBuilderCreateVariantMemberType(
+ pub fn LLVMRustDIBuilderCreateVariantMemberType<'a>(
Builder: &DIBuilder<'a>,
Scope: &'a DIScope,
Name: *const c_char,
@@ -1982,7 +2037,7 @@ extern "C" {
Ty: &'a DIType,
) -> &'a DIType;
- pub fn LLVMRustDIBuilderCreateLexicalBlock(
+ pub fn LLVMRustDIBuilderCreateLexicalBlock<'a>(
Builder: &DIBuilder<'a>,
Scope: &'a DIScope,
File: &'a DIFile,
@@ -1990,13 +2045,13 @@ extern "C" {
Col: c_uint,
) -> &'a DILexicalBlock;
- pub fn LLVMRustDIBuilderCreateLexicalBlockFile(
+ pub fn LLVMRustDIBuilderCreateLexicalBlockFile<'a>(
Builder: &DIBuilder<'a>,
Scope: &'a DIScope,
File: &'a DIFile,
) -> &'a DILexicalBlock;
- pub fn LLVMRustDIBuilderCreateStaticVariable(
+ pub fn LLVMRustDIBuilderCreateStaticVariable<'a>(
Builder: &DIBuilder<'a>,
Context: Option<&'a DIScope>,
Name: *const c_char,
@@ -2012,7 +2067,7 @@ extern "C" {
AlignInBits: u32,
) -> &'a DIGlobalVariableExpression;
- pub fn LLVMRustDIBuilderCreateVariable(
+ pub fn LLVMRustDIBuilderCreateVariable<'a>(
Builder: &DIBuilder<'a>,
Tag: c_uint,
Scope: &'a DIDescriptor,
@@ -2027,7 +2082,7 @@ extern "C" {
AlignInBits: u32,
) -> &'a DIVariable;
- pub fn LLVMRustDIBuilderCreateArrayType(
+ pub fn LLVMRustDIBuilderCreateArrayType<'a>(
Builder: &DIBuilder<'a>,
Size: u64,
AlignInBits: u32,
@@ -2035,19 +2090,19 @@ extern "C" {
Subscripts: &'a DIArray,
) -> &'a DIType;
- pub fn LLVMRustDIBuilderGetOrCreateSubrange(
+ pub fn LLVMRustDIBuilderGetOrCreateSubrange<'a>(
Builder: &DIBuilder<'a>,
Lo: i64,
Count: i64,
) -> &'a DISubrange;
- pub fn LLVMRustDIBuilderGetOrCreateArray(
+ pub fn LLVMRustDIBuilderGetOrCreateArray<'a>(
Builder: &DIBuilder<'a>,
Ptr: *const Option<&'a DIDescriptor>,
Count: c_uint,
) -> &'a DIArray;
- pub fn LLVMRustDIBuilderInsertDeclareAtEnd(
+ pub fn LLVMRustDIBuilderInsertDeclareAtEnd<'a>(
Builder: &DIBuilder<'a>,
Val: &'a Value,
VarInfo: &'a DIVariable,
@@ -2057,7 +2112,7 @@ extern "C" {
InsertAtEnd: &'a BasicBlock,
) -> &'a Value;
- pub fn LLVMRustDIBuilderCreateEnumerator(
+ pub fn LLVMRustDIBuilderCreateEnumerator<'a>(
Builder: &DIBuilder<'a>,
Name: *const c_char,
NameLen: size_t,
@@ -2065,7 +2120,7 @@ extern "C" {
IsUnsigned: bool,
) -> &'a DIEnumerator;
- pub fn LLVMRustDIBuilderCreateEnumerationType(
+ pub fn LLVMRustDIBuilderCreateEnumerationType<'a>(
Builder: &DIBuilder<'a>,
Scope: &'a DIScope,
Name: *const c_char,
@@ -2079,7 +2134,7 @@ extern "C" {
IsScoped: bool,
) -> &'a DIType;
- pub fn LLVMRustDIBuilderCreateUnionType(
+ pub fn LLVMRustDIBuilderCreateUnionType<'a>(
Builder: &DIBuilder<'a>,
Scope: Option<&'a DIScope>,
Name: *const c_char,
@@ -2095,7 +2150,7 @@ extern "C" {
UniqueIdLen: size_t,
) -> &'a DIType;
- pub fn LLVMRustDIBuilderCreateVariantPart(
+ pub fn LLVMRustDIBuilderCreateVariantPart<'a>(
Builder: &DIBuilder<'a>,
Scope: &'a DIScope,
Name: *const c_char,
@@ -2113,7 +2168,7 @@ extern "C" {
pub fn LLVMSetUnnamedAddress(Global: &Value, UnnamedAddr: UnnamedAddr);
- pub fn LLVMRustDIBuilderCreateTemplateTypeParameter(
+ pub fn LLVMRustDIBuilderCreateTemplateTypeParameter<'a>(
Builder: &DIBuilder<'a>,
Scope: Option<&'a DIScope>,
Name: *const c_char,
@@ -2121,7 +2176,7 @@ extern "C" {
Ty: &'a DIType,
) -> &'a DITemplateTypeParameter;
- pub fn LLVMRustDIBuilderCreateNameSpace(
+ pub fn LLVMRustDIBuilderCreateNameSpace<'a>(
Builder: &DIBuilder<'a>,
Scope: Option<&'a DIScope>,
Name: *const c_char,
@@ -2129,14 +2184,14 @@ extern "C" {
ExportSymbols: bool,
) -> &'a DINameSpace;
- pub fn LLVMRustDICompositeTypeReplaceArrays(
+ pub fn LLVMRustDICompositeTypeReplaceArrays<'a>(
Builder: &DIBuilder<'a>,
CompositeType: &'a DIType,
Elements: Option<&'a DIArray>,
Params: Option<&'a DIArray>,
);
- pub fn LLVMRustDIBuilderCreateDebugLocation(
+ pub fn LLVMRustDIBuilderCreateDebugLocation<'a>(
Line: c_uint,
Column: c_uint,
Scope: &'a DIScope,
@@ -2202,7 +2257,7 @@ extern "C" {
SplitDwarfFile: *const c_char,
) -> Option<&'static mut TargetMachine>;
pub fn LLVMRustDisposeTargetMachine(T: &'static mut TargetMachine);
- pub fn LLVMRustAddBuilderLibraryInfo(
+ pub fn LLVMRustAddBuilderLibraryInfo<'a>(
PMB: &'a PassManagerBuilder,
M: &'a Module,
DisableSimplifyLibCalls: bool,
@@ -2218,13 +2273,13 @@ extern "C" {
PGOUsePath: *const c_char,
PGOSampleUsePath: *const c_char,
);
- pub fn LLVMRustAddLibraryInfo(
+ pub fn LLVMRustAddLibraryInfo<'a>(
PM: &PassManager<'a>,
M: &'a Module,
DisableSimplifyLibCalls: bool,
);
- pub fn LLVMRustRunFunctionPassManager(PM: &PassManager<'a>, M: &'a Module);
- pub fn LLVMRustWriteOutputFile(
+ pub fn LLVMRustRunFunctionPassManager<'a>(PM: &PassManager<'a>, M: &'a Module);
+ pub fn LLVMRustWriteOutputFile<'a>(
T: &'a TargetMachine,
PM: &PassManager<'a>,
M: &'a Module,
@@ -2232,7 +2287,7 @@ extern "C" {
DwoOutput: *const c_char,
FileType: FileType,
) -> LLVMRustResult;
- pub fn LLVMRustOptimizeWithNewPassManager(
+ pub fn LLVMRustOptimizeWithNewPassManager<'a>(
M: &'a Module,
TM: &'a TargetMachine,
OptLevel: PassBuilderOptLevel,
@@ -2260,7 +2315,7 @@ extern "C" {
ExtraPassesLen: size_t,
) -> LLVMRustResult;
pub fn LLVMRustPrintModule(
- M: &'a Module,
+ M: &Module,
Output: *const c_char,
Demangle: extern "C" fn(*const c_char, size_t, *mut c_char, size_t) -> size_t,
) -> LLVMRustResult;
@@ -2273,27 +2328,21 @@ extern "C" {
pub fn LLVMRustMarkAllFunctionsNounwind(M: &Module);
pub fn LLVMRustOpenArchive(path: *const c_char) -> Option<&'static mut Archive>;
- pub fn LLVMRustArchiveIteratorNew(AR: &'a Archive) -> &'a mut ArchiveIterator<'a>;
- pub fn LLVMRustArchiveIteratorNext(
+ pub fn LLVMRustArchiveIteratorNew(AR: &Archive) -> &mut ArchiveIterator<'_>;
+ pub fn LLVMRustArchiveIteratorNext<'a>(
AIR: &ArchiveIterator<'a>,
) -> Option<&'a mut ArchiveChild<'a>>;
pub fn LLVMRustArchiveChildName(ACR: &ArchiveChild<'_>, size: &mut size_t) -> *const c_char;
pub fn LLVMRustArchiveChildData(ACR: &ArchiveChild<'_>, size: &mut size_t) -> *const c_char;
- pub fn LLVMRustArchiveChildFree(ACR: &'a mut ArchiveChild<'a>);
- pub fn LLVMRustArchiveIteratorFree(AIR: &'a mut ArchiveIterator<'a>);
+ pub fn LLVMRustArchiveChildFree<'a>(ACR: &'a mut ArchiveChild<'a>);
+ pub fn LLVMRustArchiveIteratorFree<'a>(AIR: &'a mut ArchiveIterator<'a>);
pub fn LLVMRustDestroyArchive(AR: &'static mut Archive);
#[allow(improper_ctypes)]
pub fn LLVMRustWriteTwineToString(T: &Twine, s: &RustString);
- pub fn LLVMContextSetDiagnosticHandler(
- C: &Context,
- Handler: DiagnosticHandler,
- DiagnosticContext: *mut c_void,
- );
-
#[allow(improper_ctypes)]
- pub fn LLVMRustUnpackOptimizationDiagnostic(
+ pub fn LLVMRustUnpackOptimizationDiagnostic<'a>(
DI: &'a DiagnosticInfo,
pass_name_out: &RustString,
function_out: &mut Option<&'a Value>,
@@ -2303,7 +2352,7 @@ extern "C" {
message_out: &RustString,
);
- pub fn LLVMRustUnpackInlineAsmDiagnostic(
+ pub fn LLVMRustUnpackInlineAsmDiagnostic<'a>(
DI: &'a DiagnosticInfo,
level_out: &mut DiagnosticLevel,
cookie_out: &mut c_uint,
@@ -2314,14 +2363,14 @@ extern "C" {
pub fn LLVMRustWriteDiagnosticInfoToString(DI: &DiagnosticInfo, s: &RustString);
pub fn LLVMRustGetDiagInfoKind(DI: &DiagnosticInfo) -> DiagnosticKind;
- pub fn LLVMRustGetSMDiagnostic(
+ pub fn LLVMRustGetSMDiagnostic<'a>(
DI: &'a DiagnosticInfo,
cookie_out: &mut c_uint,
) -> &'a SMDiagnostic;
pub fn LLVMRustSetInlineAsmDiagnosticHandler(
C: &Context,
- H: InlineAsmDiagHandler,
+ H: InlineAsmDiagHandlerTy,
CX: *mut c_void,
);
@@ -2343,12 +2392,12 @@ extern "C" {
WriteSymbtab: bool,
Kind: ArchiveKind,
) -> LLVMRustResult;
- pub fn LLVMRustArchiveMemberNew(
+ pub fn LLVMRustArchiveMemberNew<'a>(
Filename: *const c_char,
Name: *const c_char,
Child: Option<&ArchiveChild<'a>>,
) -> &'a mut RustArchiveMember<'a>;
- pub fn LLVMRustArchiveMemberFree(Member: &'a mut RustArchiveMember<'a>);
+ pub fn LLVMRustArchiveMemberFree<'a>(Member: &'a mut RustArchiveMember<'a>);
pub fn LLVMRustWriteImportLibrary(
ImportName: *const c_char,
@@ -2359,18 +2408,18 @@ extern "C" {
MinGW: bool,
) -> LLVMRustResult;
- pub fn LLVMRustSetDataLayoutFromTargetMachine(M: &'a Module, TM: &'a TargetMachine);
+ pub fn LLVMRustSetDataLayoutFromTargetMachine<'a>(M: &'a Module, TM: &'a TargetMachine);
- pub fn LLVMRustBuildOperandBundleDef(
+ pub fn LLVMRustBuildOperandBundleDef<'a>(
Name: *const c_char,
Inputs: *const &'a Value,
NumInputs: c_uint,
) -> &'a mut OperandBundleDef<'a>;
- pub fn LLVMRustFreeOperandBundleDef(Bundle: &'a mut OperandBundleDef<'a>);
+ pub fn LLVMRustFreeOperandBundleDef<'a>(Bundle: &'a mut OperandBundleDef<'a>);
- pub fn LLVMRustPositionBuilderAtStart(B: &Builder<'a>, BB: &'a BasicBlock);
+ pub fn LLVMRustPositionBuilderAtStart<'a>(B: &Builder<'a>, BB: &'a BasicBlock);
- pub fn LLVMRustSetComdat(M: &'a Module, V: &'a Value, Name: *const c_char, NameLen: size_t);
+ pub fn LLVMRustSetComdat<'a>(M: &'a Module, V: &'a Value, Name: *const c_char, NameLen: size_t);
pub fn LLVMRustUnsetComdat(V: &Value);
pub fn LLVMRustSetModulePICLevel(M: &Module);
pub fn LLVMRustSetModulePIELevel(M: &Module);
@@ -2423,17 +2472,32 @@ extern "C" {
pub fn LLVMRustLTOGetDICompileUnit(M: &Module, CU1: &mut *mut c_void, CU2: &mut *mut c_void);
pub fn LLVMRustLTOPatchDICompileUnit(M: &Module, CU: *mut c_void);
- pub fn LLVMRustLinkerNew(M: &'a Module) -> &'a mut Linker<'a>;
+ pub fn LLVMRustLinkerNew(M: &Module) -> &mut Linker<'_>;
pub fn LLVMRustLinkerAdd(
linker: &Linker<'_>,
bytecode: *const c_char,
bytecode_len: usize,
) -> bool;
- pub fn LLVMRustLinkerFree(linker: &'a mut Linker<'a>);
+ pub fn LLVMRustLinkerFree<'a>(linker: &'a mut Linker<'a>);
#[allow(improper_ctypes)]
pub fn LLVMRustComputeLTOCacheKey(
key_out: &RustString,
mod_id: *const c_char,
data: &ThinLTOData,
);
+
+ pub fn LLVMRustContextGetDiagnosticHandler(Context: &Context) -> Option<&DiagnosticHandler>;
+ pub fn LLVMRustContextSetDiagnosticHandler(
+ context: &Context,
+ diagnostic_handler: Option<&DiagnosticHandler>,
+ );
+ pub fn LLVMRustContextConfigureDiagnosticHandler(
+ context: &Context,
+ diagnostic_handler_callback: DiagnosticHandlerTy,
+ diagnostic_handler_context: *mut c_void,
+ remark_all_passes: bool,
+ remark_passes: *const *const c_char,
+ remark_passes_len: usize,
+ );
+
}
diff --git a/compiler/rustc_codegen_llvm/src/llvm/mod.rs b/compiler/rustc_codegen_llvm/src/llvm/mod.rs
index c1521a760b0..a1117a11fc7 100644
--- a/compiler/rustc_codegen_llvm/src/llvm/mod.rs
+++ b/compiler/rustc_codegen_llvm/src/llvm/mod.rs
@@ -31,13 +31,13 @@ impl LLVMRustResult {
}
}
-pub fn AddFunctionAttrStringValue(llfn: &'a Value, idx: AttributePlace, attr: &CStr, value: &CStr) {
+pub fn AddFunctionAttrStringValue(llfn: &Value, idx: AttributePlace, attr: &CStr, value: &CStr) {
unsafe {
LLVMRustAddFunctionAttrStringValue(llfn, idx.as_uint(), attr.as_ptr(), value.as_ptr())
}
}
-pub fn AddFunctionAttrString(llfn: &'a Value, idx: AttributePlace, attr: &CStr) {
+pub fn AddFunctionAttrString(llfn: &Value, idx: AttributePlace, attr: &CStr) {
unsafe {
LLVMRustAddFunctionAttrStringValue(llfn, idx.as_uint(), attr.as_ptr(), std::ptr::null())
}
@@ -86,12 +86,12 @@ impl FromStr for ArchiveKind {
}
}
-pub fn SetInstructionCallConv(instr: &'a Value, cc: CallConv) {
+pub fn SetInstructionCallConv(instr: &Value, cc: CallConv) {
unsafe {
LLVMSetInstructionCallConv(instr, cc as c_uint);
}
}
-pub fn SetFunctionCallConv(fn_: &'a Value, cc: CallConv) {
+pub fn SetFunctionCallConv(fn_: &Value, cc: CallConv) {
unsafe {
LLVMSetFunctionCallConv(fn_, cc as c_uint);
}
@@ -103,26 +103,26 @@ pub fn SetFunctionCallConv(fn_: &'a Value, cc: CallConv) {
// value's name as the comdat value to make sure that it is in a 1-to-1 relationship to the
// function.
// For more details on COMDAT sections see e.g., https://www.airs.com/blog/archives/52
-pub fn SetUniqueComdat(llmod: &Module, val: &'a Value) {
+pub fn SetUniqueComdat(llmod: &Module, val: &Value) {
unsafe {
let name = get_value_name(val);
LLVMRustSetComdat(llmod, val, name.as_ptr().cast(), name.len());
}
}
-pub fn UnsetComdat(val: &'a Value) {
+pub fn UnsetComdat(val: &Value) {
unsafe {
LLVMRustUnsetComdat(val);
}
}
-pub fn SetUnnamedAddress(global: &'a Value, unnamed: UnnamedAddr) {
+pub fn SetUnnamedAddress(global: &Value, unnamed: UnnamedAddr) {
unsafe {
LLVMSetUnnamedAddress(global, unnamed);
}
}
-pub fn set_thread_local_mode(global: &'a Value, mode: ThreadLocalMode) {
+pub fn set_thread_local_mode(global: &Value, mode: ThreadLocalMode) {
unsafe {
LLVMSetThreadLocalMode(global, mode);
}
@@ -264,7 +264,7 @@ pub struct OperandBundleDef<'a> {
pub raw: &'a mut ffi::OperandBundleDef<'a>,
}
-impl OperandBundleDef<'a> {
+impl<'a> OperandBundleDef<'a> {
pub fn new(name: &str, vals: &[&'a Value]) -> Self {
let name = SmallCStr::new(name);
let def = unsafe {
@@ -274,7 +274,7 @@ impl OperandBundleDef<'a> {
}
}
-impl Drop for OperandBundleDef<'a> {
+impl Drop for OperandBundleDef<'_> {
fn drop(&mut self) {
unsafe {
LLVMRustFreeOperandBundleDef(&mut *(self.raw as *mut _));
diff --git a/compiler/rustc_codegen_llvm/src/llvm_util.rs b/compiler/rustc_codegen_llvm/src/llvm_util.rs
index 3393c9baa28..e4935ac431c 100644
--- a/compiler/rustc_codegen_llvm/src/llvm_util.rs
+++ b/compiler/rustc_codegen_llvm/src/llvm_util.rs
@@ -1,9 +1,10 @@
use crate::back::write::create_informational_target_machine;
use crate::{llvm, llvm_util};
use libc::c_int;
+use libloading::Library;
use rustc_codegen_ssa::target_features::supported_target_features;
use rustc_data_structures::fx::FxHashSet;
-use rustc_metadata::dynamic_lib::DynamicLibrary;
+use rustc_fs_util::path_to_c_string;
use rustc_middle::bug;
use rustc_session::config::PrintRequest;
use rustc_session::Session;
@@ -120,14 +121,14 @@ unsafe fn configure_llvm(sess: &Session) {
llvm::LLVMInitializePasses();
+ // Register LLVM plugins by loading them into the compiler process.
for plugin in &sess.opts.debugging_opts.llvm_plugins {
- let path = Path::new(plugin);
- let res = DynamicLibrary::open(path);
- match res {
- Ok(_) => debug!("LLVM plugin loaded succesfully {} ({})", path.display(), plugin),
- Err(e) => bug!("couldn't load plugin: {}", e),
- }
- mem::forget(res);
+ let lib = Library::new(plugin).unwrap_or_else(|e| bug!("couldn't load plugin: {}", e));
+ debug!("LLVM plugin loaded successfully {:?} ({})", lib, plugin);
+
+ // Intentionally leak the dynamic library. We can't ever unload it
+ // since the library can make things that will live arbitrarily long.
+ mem::forget(lib);
}
rustc_llvm::initialize_available_targets();
@@ -135,9 +136,9 @@ unsafe fn configure_llvm(sess: &Session) {
llvm::LLVMRustSetLLVMOptions(llvm_args.len() as c_int, llvm_args.as_ptr());
}
-pub fn time_trace_profiler_finish(file_name: &str) {
+pub fn time_trace_profiler_finish(file_name: &Path) {
unsafe {
- let file_name = CString::new(file_name).unwrap();
+ let file_name = path_to_c_string(file_name);
llvm::LLVMTimeTraceProfilerFinish(file_name.as_ptr());
}
}
diff --git a/compiler/rustc_codegen_llvm/src/mono_item.rs b/compiler/rustc_codegen_llvm/src/mono_item.rs
index 88498cf47d8..a3053742aad 100644
--- a/compiler/rustc_codegen_llvm/src/mono_item.rs
+++ b/compiler/rustc_codegen_llvm/src/mono_item.rs
@@ -13,7 +13,7 @@ use rustc_session::config::CrateType;
use rustc_target::spec::RelocModel;
use tracing::debug;
-impl PreDefineMethods<'tcx> for CodegenCx<'ll, 'tcx> {
+impl<'tcx> PreDefineMethods<'tcx> for CodegenCx<'_, 'tcx> {
fn predefine_static(
&self,
def_id: DefId,
@@ -92,7 +92,7 @@ impl PreDefineMethods<'tcx> for CodegenCx<'ll, 'tcx> {
}
}
-impl CodegenCx<'ll, 'tcx> {
+impl CodegenCx<'_, '_> {
/// Whether a definition or declaration can be assumed to be local to a group of
/// libraries that form a single DSO or executable.
pub(crate) unsafe fn should_assume_dso_local(
diff --git a/compiler/rustc_codegen_llvm/src/type_.rs b/compiler/rustc_codegen_llvm/src/type_.rs
index 2ae0a08f192..21b77f7dea6 100644
--- a/compiler/rustc_codegen_llvm/src/type_.rs
+++ b/compiler/rustc_codegen_llvm/src/type_.rs
@@ -38,7 +38,7 @@ impl fmt::Debug for Type {
}
}
-impl CodegenCx<'ll, 'tcx> {
+impl<'ll> CodegenCx<'ll, '_> {
crate fn type_named_struct(&self, name: &str) -> &'ll Type {
let name = SmallCStr::new(name);
unsafe { llvm::LLVMStructCreateNamed(self.llcx, name.as_ptr()) }
@@ -133,7 +133,7 @@ impl CodegenCx<'ll, 'tcx> {
}
}
-impl BaseTypeMethods<'tcx> for CodegenCx<'ll, 'tcx> {
+impl<'ll, 'tcx> BaseTypeMethods<'tcx> for CodegenCx<'ll, 'tcx> {
fn type_i1(&self) -> &'ll Type {
unsafe { llvm::LLVMInt1TypeInContext(self.llcx) }
}
@@ -252,7 +252,7 @@ impl Type {
}
}
-impl LayoutTypeMethods<'tcx> for CodegenCx<'ll, 'tcx> {
+impl<'ll, 'tcx> LayoutTypeMethods<'tcx> for CodegenCx<'ll, 'tcx> {
fn backend_type(&self, layout: TyAndLayout<'tcx>) -> &'ll Type {
layout.llvm_type(self)
}
diff --git a/compiler/rustc_codegen_llvm/src/va_arg.rs b/compiler/rustc_codegen_llvm/src/va_arg.rs
index 591f659f11b..f090ae6ecb4 100644
--- a/compiler/rustc_codegen_llvm/src/va_arg.rs
+++ b/compiler/rustc_codegen_llvm/src/va_arg.rs
@@ -11,8 +11,8 @@ use rustc_middle::ty::layout::{HasTyCtxt, LayoutOf};
use rustc_middle::ty::Ty;
use rustc_target::abi::{Align, Endian, HasDataLayout, Size};
-fn round_pointer_up_to_alignment(
- bx: &mut Builder<'a, 'll, 'tcx>,
+fn round_pointer_up_to_alignment<'ll>(
+ bx: &mut Builder<'_, 'll, '_>,
addr: &'ll Value,
align: Align,
ptr_ty: &'ll Type,
@@ -23,8 +23,8 @@ fn round_pointer_up_to_alignment(
bx.inttoptr(ptr_as_int, ptr_ty)
}
-fn emit_direct_ptr_va_arg(
- bx: &mut Builder<'a, 'll, 'tcx>,
+fn emit_direct_ptr_va_arg<'ll, 'tcx>(
+ bx: &mut Builder<'_, 'll, 'tcx>,
list: OperandRef<'tcx, &'ll Value>,
llty: &'ll Type,
size: Size,
@@ -62,8 +62,8 @@ fn emit_direct_ptr_va_arg(
}
}
-fn emit_ptr_va_arg(
- bx: &mut Builder<'a, 'll, 'tcx>,
+fn emit_ptr_va_arg<'ll, 'tcx>(
+ bx: &mut Builder<'_, 'll, 'tcx>,
list: OperandRef<'tcx, &'ll Value>,
target_ty: Ty<'tcx>,
indirect: bool,
@@ -90,8 +90,8 @@ fn emit_ptr_va_arg(
}
}
-fn emit_aapcs_va_arg(
- bx: &mut Builder<'a, 'll, 'tcx>,
+fn emit_aapcs_va_arg<'ll, 'tcx>(
+ bx: &mut Builder<'_, 'll, 'tcx>,
list: OperandRef<'tcx, &'ll Value>,
target_ty: Ty<'tcx>,
) -> &'ll Value {
@@ -175,8 +175,8 @@ fn emit_aapcs_va_arg(
val
}
-pub(super) fn emit_va_arg(
- bx: &mut Builder<'a, 'll, 'tcx>,
+pub(super) fn emit_va_arg<'ll, 'tcx>(
+ bx: &mut Builder<'_, 'll, 'tcx>,
addr: OperandRef<'tcx, &'ll Value>,
target_ty: Ty<'tcx>,
) -> &'ll Value {
diff --git a/compiler/rustc_codegen_ssa/Cargo.toml b/compiler/rustc_codegen_ssa/Cargo.toml
index 83dd6256110..18dbcd8e52d 100644
--- a/compiler/rustc_codegen_ssa/Cargo.toml
+++ b/compiler/rustc_codegen_ssa/Cargo.toml
@@ -15,6 +15,7 @@ libc = "0.2.50"
jobserver = "0.1.22"
tempfile = "3.2"
pathdiff = "0.2.0"
+snap = "1"
smallvec = { version = "1.6.1", features = ["union", "may_dangle"] }
regex = "1.4"
diff --git a/compiler/rustc_codegen_ssa/src/back/link.rs b/compiler/rustc_codegen_ssa/src/back/link.rs
index 638b2a7b5a9..6271d75e635 100644
--- a/compiler/rustc_codegen_ssa/src/back/link.rs
+++ b/compiler/rustc_codegen_ssa/src/back/link.rs
@@ -14,7 +14,6 @@ use rustc_session::utils::NativeLibKind;
/// need out of the shared crate context before we get rid of it.
use rustc_session::{filesearch, Session};
use rustc_span::symbol::Symbol;
-use rustc_target::abi::Endian;
use rustc_target::spec::crt_objects::{CrtObjects, CrtObjectsFallback};
use rustc_target::spec::{LinkOutputKind, LinkerFlavor, LldFlavor, SplitDebuginfo};
use rustc_target::spec::{PanicStrategy, RelocModel, RelroLevel, SanitizerSet, Target};
@@ -22,6 +21,7 @@ use rustc_target::spec::{PanicStrategy, RelocModel, RelroLevel, SanitizerSet, Ta
use super::archive::{find_library, ArchiveBuilder};
use super::command::Command;
use super::linker::{self, Linker};
+use super::metadata::create_rmeta_file;
use super::rpath::{self, RPathConfig};
use crate::{
looks_like_rust_object_file, CodegenResults, CompiledModule, CrateInfo, NativeLib,
@@ -29,13 +29,10 @@ use crate::{
};
use cc::windows_registry;
-use object::elf;
-use object::write::Object;
-use object::{Architecture, BinaryFormat, Endianness, FileFlags, SectionFlags, SectionKind};
use regex::Regex;
use tempfile::Builder as TempFileBuilder;
-use std::ffi::OsString;
+use std::ffi::{OsStr, OsString};
use std::lazy::OnceCell;
use std::path::{Path, PathBuf};
use std::process::{ExitStatus, Output, Stdio};
@@ -339,7 +336,7 @@ fn link_rlib<'a, B: ArchiveBuilder<'a>>(
// metadata in rlib files is wrapped in a "dummy" object file for
// the target platform so the rlib can be processed entirely by
// normal linkers for the platform.
- let metadata = create_metadata_file(sess, codegen_results.metadata.raw_data());
+ let metadata = create_rmeta_file(sess, codegen_results.metadata.raw_data());
ab.add_file(&emit_metadata(sess, &metadata, tmpdir));
// After adding all files to the archive, we need to update the
@@ -358,136 +355,6 @@ fn link_rlib<'a, B: ArchiveBuilder<'a>>(
}
}
return Ok(ab);
-
- // For rlibs we "pack" rustc metadata into a dummy object file. When rustc
- // creates a dylib crate type it will pass `--whole-archive` (or the
- // platform equivalent) to include all object files from an rlib into the
- // final dylib itself. This causes linkers to iterate and try to include all
- // files located in an archive, so if metadata is stored in an archive then
- // it needs to be of a form that the linker will be able to process.
- //
- // Note, though, that we don't actually want this metadata to show up in any
- // final output of the compiler. Instead this is purely for rustc's own
- // metadata tracking purposes.
- //
- // With the above in mind, each "flavor" of object format gets special
- // handling here depending on the target:
- //
- // * MachO - macos-like targets will insert the metadata into a section that
- // is sort of fake dwarf debug info. Inspecting the source of the macos
- // linker this causes these sections to be skipped automatically because
- // it's not in an allowlist of otherwise well known dwarf section names to
- // go into the final artifact.
- //
- // * WebAssembly - we actually don't have any container format for this
- // target. WebAssembly doesn't support the `dylib` crate type anyway so
- // there's no need for us to support this at this time. Consequently the
- // metadata bytes are simply stored as-is into an rlib.
- //
- // * COFF - Windows-like targets create an object with a section that has
- // the `IMAGE_SCN_LNK_REMOVE` flag set which ensures that if the linker
- // ever sees the section it doesn't process it and it's removed.
- //
- // * ELF - All other targets are similar to Windows in that there's a
- // `SHF_EXCLUDE` flag we can set on sections in an object file to get
- // automatically removed from the final output.
- //
- // Note that this metdata format is kept in sync with
- // `rustc_codegen_ssa/src/back/metadata.rs`.
- fn create_metadata_file(sess: &Session, metadata: &[u8]) -> Vec<u8> {
- let endianness = match sess.target.options.endian {
- Endian::Little => Endianness::Little,
- Endian::Big => Endianness::Big,
- };
- let architecture = match &sess.target.arch[..] {
- "arm" => Architecture::Arm,
- "aarch64" => Architecture::Aarch64,
- "x86" => Architecture::I386,
- "s390x" => Architecture::S390x,
- "mips" => Architecture::Mips,
- "mips64" => Architecture::Mips64,
- "x86_64" => {
- if sess.target.pointer_width == 32 {
- Architecture::X86_64_X32
- } else {
- Architecture::X86_64
- }
- }
- "powerpc" => Architecture::PowerPc,
- "powerpc64" => Architecture::PowerPc64,
- "riscv32" => Architecture::Riscv32,
- "riscv64" => Architecture::Riscv64,
- "sparc64" => Architecture::Sparc64,
-
- // This is used to handle all "other" targets. This includes targets
- // in two categories:
- //
- // * Some targets don't have support in the `object` crate just yet
- // to write an object file. These targets are likely to get filled
- // out over time.
- //
- // * Targets like WebAssembly don't support dylibs, so the purpose
- // of putting metadata in object files, to support linking rlibs
- // into dylibs, is moot.
- //
- // In both of these cases it means that linking into dylibs will
- // not be supported by rustc. This doesn't matter for targets like
- // WebAssembly and for targets not supported by the `object` crate
- // yet it means that work will need to be done in the `object` crate
- // to add a case above.
- _ => return metadata.to_vec(),
- };
-
- if sess.target.is_like_osx {
- let mut file = Object::new(BinaryFormat::MachO, architecture, endianness);
-
- let section =
- file.add_section(b"__DWARF".to_vec(), b".rmeta".to_vec(), SectionKind::Debug);
- file.append_section_data(section, metadata, 1);
- file.write().unwrap()
- } else if sess.target.is_like_windows {
- const IMAGE_SCN_LNK_REMOVE: u32 = 0;
- let mut file = Object::new(BinaryFormat::Coff, architecture, endianness);
-
- let section = file.add_section(Vec::new(), b".rmeta".to_vec(), SectionKind::Debug);
- file.section_mut(section).flags =
- SectionFlags::Coff { characteristics: IMAGE_SCN_LNK_REMOVE };
- file.append_section_data(section, metadata, 1);
- file.write().unwrap()
- } else {
- const SHF_EXCLUDE: u64 = 0x80000000;
- let mut file = Object::new(BinaryFormat::Elf, architecture, endianness);
-
- match &sess.target.arch[..] {
- // copied from `mipsel-linux-gnu-gcc foo.c -c` and
- // inspecting the resulting `e_flags` field.
- "mips" => {
- let e_flags = elf::EF_MIPS_ARCH_32R2 | elf::EF_MIPS_CPIC | elf::EF_MIPS_PIC;
- file.flags = FileFlags::Elf { e_flags };
- }
- // copied from `mips64el-linux-gnuabi64-gcc foo.c -c`
- "mips64" => {
- let e_flags = elf::EF_MIPS_ARCH_64R2 | elf::EF_MIPS_CPIC | elf::EF_MIPS_PIC;
- file.flags = FileFlags::Elf { e_flags };
- }
-
- // copied from `riscv64-linux-gnu-gcc foo.c -c`, note though
- // that the `+d` target feature represents whether the double
- // float abi is enabled.
- "riscv64" if sess.target.options.features.contains("+d") => {
- let e_flags = elf::EF_RISCV_RVC | elf::EF_RISCV_FLOAT_ABI_DOUBLE;
- file.flags = FileFlags::Elf { e_flags };
- }
-
- _ => {}
- }
-
- let section = file.add_section(Vec::new(), b".rmeta".to_vec(), SectionKind::Debug);
- file.section_mut(section).flags = SectionFlags::Elf { sh_flags: SHF_EXCLUDE };
- file.append_section_data(section, metadata, 1);
- file.write().unwrap()
- }
- }
}
/// Extract all symbols defined in raw-dylib libraries, collated by library name.
@@ -637,17 +504,19 @@ fn escape_stdout_stderr_string(s: &[u8]) -> String {
const LLVM_DWP_EXECUTABLE: &'static str = "rust-llvm-dwp";
-/// Invoke `llvm-dwp` (shipped alongside rustc) to link `dwo` files from Split DWARF into a `dwp`
+/// Invoke `llvm-dwp` (shipped alongside rustc) to link debuginfo in object files into a `dwp`
/// file.
-fn link_dwarf_object<'a>(sess: &'a Session, executable_out_filename: &Path) {
+fn link_dwarf_object<'a, I>(sess: &'a Session, executable_out_filename: &Path, object_files: I)
+where
+ I: IntoIterator<Item: AsRef<OsStr>>,
+{
info!("preparing dwp to {}.dwp", executable_out_filename.to_str().unwrap());
let dwp_out_filename = executable_out_filename.with_extension("dwp");
let mut cmd = Command::new(LLVM_DWP_EXECUTABLE);
- cmd.arg("-e");
- cmd.arg(executable_out_filename);
cmd.arg("-o");
cmd.arg(&dwp_out_filename);
+ cmd.args(object_files);
let mut new_path = sess.get_tools_search_paths(false);
if let Some(path) = env::var_os("PATH") {
@@ -1031,7 +900,14 @@ fn link_natively<'a, B: ArchiveBuilder<'a>>(
SplitDebuginfo::Packed if sess.target.is_like_msvc => {}
// ... and otherwise we're processing a `*.dwp` packed dwarf file.
- SplitDebuginfo::Packed => link_dwarf_object(sess, &out_filename),
+ // We cannot rely on the .o paths in the exectuable because they may have been
+ // remapped by --remap-path-prefix and therefore invalid. So we need to provide
+ // the .o paths explicitly
+ SplitDebuginfo::Packed => link_dwarf_object(
+ sess,
+ &out_filename,
+ codegen_results.modules.iter().filter_map(|m| m.object.as_ref()),
+ ),
}
let strip = strip_value(sess);
@@ -2359,8 +2235,8 @@ fn add_upstream_rust_crates<'a, B: ArchiveBuilder<'a>>(
continue;
}
- let canonical = f.replace("-", "_");
- let canonical_name = name.replace("-", "_");
+ let canonical = f.replace('-', "_");
+ let canonical_name = name.replace('-', "_");
let is_rust_object =
canonical.starts_with(&canonical_name) && looks_like_rust_object_file(&f);
diff --git a/compiler/rustc_codegen_ssa/src/back/metadata.rs b/compiler/rustc_codegen_ssa/src/back/metadata.rs
index ffeb926e648..1df5540e3b8 100644
--- a/compiler/rustc_codegen_ssa/src/back/metadata.rs
+++ b/compiler/rustc_codegen_ssa/src/back/metadata.rs
@@ -1,14 +1,25 @@
//! Reading of the rustc metadata for rlibs and dylibs
use std::fs::File;
+use std::io::Write;
use std::path::Path;
-use object::{Object, ObjectSection};
+use object::write::{self, StandardSegment, Symbol, SymbolSection};
+use object::{
+ elf, Architecture, BinaryFormat, Endianness, FileFlags, Object, ObjectSection, SectionFlags,
+ SectionKind, SymbolFlags, SymbolKind, SymbolScope,
+};
+
+use snap::write::FrameEncoder;
+
use rustc_data_structures::memmap::Mmap;
use rustc_data_structures::owning_ref::OwningRef;
use rustc_data_structures::rustc_erase_owner;
use rustc_data_structures::sync::MetadataRef;
+use rustc_metadata::EncodedMetadata;
use rustc_session::cstore::MetadataLoader;
+use rustc_session::Session;
+use rustc_target::abi::Endian;
use rustc_target::spec::Target;
use crate::METADATA_FILENAME;
@@ -83,3 +94,187 @@ fn search_for_metadata<'a>(
.data()
.map_err(|e| format!("failed to read {} section in '{}': {}", section, path.display(), e))
}
+
+fn create_object_file(sess: &Session) -> Option<write::Object> {
+ let endianness = match sess.target.options.endian {
+ Endian::Little => Endianness::Little,
+ Endian::Big => Endianness::Big,
+ };
+ let architecture = match &sess.target.arch[..] {
+ "arm" => Architecture::Arm,
+ "aarch64" => Architecture::Aarch64,
+ "x86" => Architecture::I386,
+ "s390x" => Architecture::S390x,
+ "mips" => Architecture::Mips,
+ "mips64" => Architecture::Mips64,
+ "x86_64" => {
+ if sess.target.pointer_width == 32 {
+ Architecture::X86_64_X32
+ } else {
+ Architecture::X86_64
+ }
+ }
+ "powerpc" => Architecture::PowerPc,
+ "powerpc64" => Architecture::PowerPc64,
+ "riscv32" => Architecture::Riscv32,
+ "riscv64" => Architecture::Riscv64,
+ "sparc64" => Architecture::Sparc64,
+ // Unsupported architecture.
+ _ => return None,
+ };
+ let binary_format = if sess.target.is_like_osx {
+ BinaryFormat::MachO
+ } else if sess.target.is_like_windows {
+ BinaryFormat::Coff
+ } else {
+ BinaryFormat::Elf
+ };
+
+ let mut file = write::Object::new(binary_format, architecture, endianness);
+ match architecture {
+ Architecture::Mips => {
+ // copied from `mipsel-linux-gnu-gcc foo.c -c` and
+ // inspecting the resulting `e_flags` field.
+ let e_flags = elf::EF_MIPS_ARCH_32R2 | elf::EF_MIPS_CPIC | elf::EF_MIPS_PIC;
+ file.flags = FileFlags::Elf { e_flags };
+ }
+ Architecture::Mips64 => {
+ // copied from `mips64el-linux-gnuabi64-gcc foo.c -c`
+ let e_flags = elf::EF_MIPS_ARCH_64R2 | elf::EF_MIPS_CPIC | elf::EF_MIPS_PIC;
+ file.flags = FileFlags::Elf { e_flags };
+ }
+ Architecture::Riscv64 if sess.target.options.features.contains("+d") => {
+ // copied from `riscv64-linux-gnu-gcc foo.c -c`, note though
+ // that the `+d` target feature represents whether the double
+ // float abi is enabled.
+ let e_flags = elf::EF_RISCV_RVC | elf::EF_RISCV_FLOAT_ABI_DOUBLE;
+ file.flags = FileFlags::Elf { e_flags };
+ }
+ _ => {}
+ };
+ Some(file)
+}
+
+// For rlibs we "pack" rustc metadata into a dummy object file. When rustc
+// creates a dylib crate type it will pass `--whole-archive` (or the
+// platform equivalent) to include all object files from an rlib into the
+// final dylib itself. This causes linkers to iterate and try to include all
+// files located in an archive, so if metadata is stored in an archive then
+// it needs to be of a form that the linker will be able to process.
+//
+// Note, though, that we don't actually want this metadata to show up in any
+// final output of the compiler. Instead this is purely for rustc's own
+// metadata tracking purposes.
+//
+// With the above in mind, each "flavor" of object format gets special
+// handling here depending on the target:
+//
+// * MachO - macos-like targets will insert the metadata into a section that
+// is sort of fake dwarf debug info. Inspecting the source of the macos
+// linker this causes these sections to be skipped automatically because
+// it's not in an allowlist of otherwise well known dwarf section names to
+// go into the final artifact.
+//
+// * WebAssembly - we actually don't have any container format for this
+// target. WebAssembly doesn't support the `dylib` crate type anyway so
+// there's no need for us to support this at this time. Consequently the
+// metadata bytes are simply stored as-is into an rlib.
+//
+// * COFF - Windows-like targets create an object with a section that has
+// the `IMAGE_SCN_LNK_REMOVE` flag set which ensures that if the linker
+// ever sees the section it doesn't process it and it's removed.
+//
+// * ELF - All other targets are similar to Windows in that there's a
+// `SHF_EXCLUDE` flag we can set on sections in an object file to get
+// automatically removed from the final output.
+pub fn create_rmeta_file(sess: &Session, metadata: &[u8]) -> Vec<u8> {
+ let mut file = if let Some(file) = create_object_file(sess) {
+ file
+ } else {
+ // This is used to handle all "other" targets. This includes targets
+ // in two categories:
+ //
+ // * Some targets don't have support in the `object` crate just yet
+ // to write an object file. These targets are likely to get filled
+ // out over time.
+ //
+ // * Targets like WebAssembly don't support dylibs, so the purpose
+ // of putting metadata in object files, to support linking rlibs
+ // into dylibs, is moot.
+ //
+ // In both of these cases it means that linking into dylibs will
+ // not be supported by rustc. This doesn't matter for targets like
+ // WebAssembly and for targets not supported by the `object` crate
+ // yet it means that work will need to be done in the `object` crate
+ // to add a case above.
+ return metadata.to_vec();
+ };
+ let section = file.add_section(
+ file.segment_name(StandardSegment::Debug).to_vec(),
+ b".rmeta".to_vec(),
+ SectionKind::Debug,
+ );
+ match file.format() {
+ BinaryFormat::Coff => {
+ const IMAGE_SCN_LNK_REMOVE: u32 = 0;
+ file.section_mut(section).flags =
+ SectionFlags::Coff { characteristics: IMAGE_SCN_LNK_REMOVE };
+ }
+ BinaryFormat::Elf => {
+ const SHF_EXCLUDE: u64 = 0x80000000;
+ file.section_mut(section).flags = SectionFlags::Elf { sh_flags: SHF_EXCLUDE };
+ }
+ _ => {}
+ };
+ file.append_section_data(section, metadata, 1);
+ file.write().unwrap()
+}
+
+// Historical note:
+//
+// When using link.exe it was seen that the section name `.note.rustc`
+// was getting shortened to `.note.ru`, and according to the PE and COFF
+// specification:
+//
+// > Executable images do not use a string table and do not support
+// > section names longer than 8 characters
+//
+// https://docs.microsoft.com/en-us/windows/win32/debug/pe-format
+//
+// As a result, we choose a slightly shorter name! As to why
+// `.note.rustc` works on MinGW, see
+// https://github.com/llvm/llvm-project/blob/llvmorg-12.0.0/lld/COFF/Writer.cpp#L1190-L1197
+pub fn create_compressed_metadata_file(
+ sess: &Session,
+ metadata: &EncodedMetadata,
+ symbol_name: &str,
+) -> Vec<u8> {
+ let mut compressed = rustc_metadata::METADATA_HEADER.to_vec();
+ FrameEncoder::new(&mut compressed).write_all(metadata.raw_data()).unwrap();
+ let mut file = if let Some(file) = create_object_file(sess) {
+ file
+ } else {
+ return compressed.to_vec();
+ };
+ let section = file.add_section(
+ file.segment_name(StandardSegment::Data).to_vec(),
+ b".rustc".to_vec(),
+ SectionKind::Data,
+ );
+ let offset = file.append_section_data(section, &compressed, 1);
+
+ // For MachO and probably PE this is necessary to prevent the linker from throwing away the
+ // .rustc section. For ELF this isn't necessary, but it also doesn't harm.
+ file.add_symbol(Symbol {
+ name: symbol_name.as_bytes().to_vec(),
+ value: offset,
+ size: compressed.len() as u64,
+ kind: SymbolKind::Data,
+ scope: SymbolScope::Dynamic,
+ weak: false,
+ section: SymbolSection::Section(section),
+ flags: SymbolFlags::None,
+ });
+
+ file.write().unwrap()
+}
diff --git a/compiler/rustc_codegen_ssa/src/back/rpath.rs b/compiler/rustc_codegen_ssa/src/back/rpath.rs
index 61c3ef62fb1..0b5656c9ad1 100644
--- a/compiler/rustc_codegen_ssa/src/back/rpath.rs
+++ b/compiler/rustc_codegen_ssa/src/back/rpath.rs
@@ -23,9 +23,12 @@ pub fn get_rpath_flags(config: &mut RPathConfig<'_>) -> Vec<String> {
let rpaths = get_rpaths(config);
let mut flags = rpaths_to_flags(&rpaths);
- // Use DT_RUNPATH instead of DT_RPATH if available
if config.linker_is_gnu {
+ // Use DT_RUNPATH instead of DT_RPATH if available
flags.push("-Wl,--enable-new-dtags".to_owned());
+
+ // Set DF_ORIGIN for substitute $ORIGIN
+ flags.push("-Wl,-z,origin".to_owned());
}
flags
diff --git a/compiler/rustc_codegen_ssa/src/back/symbol_export.rs b/compiler/rustc_codegen_ssa/src/back/symbol_export.rs
index f80f9965f4d..baafa74b131 100644
--- a/compiler/rustc_codegen_ssa/src/back/symbol_export.rs
+++ b/compiler/rustc_codegen_ssa/src/back/symbol_export.rs
@@ -154,7 +154,7 @@ fn is_reachable_non_generic_provider_extern(tcx: TyCtxt<'_>, def_id: DefId) -> b
tcx.reachable_non_generics(def_id.krate).contains_key(&def_id)
}
-fn exported_symbols_provider_local(
+fn exported_symbols_provider_local<'tcx>(
tcx: TyCtxt<'tcx>,
cnum: CrateNum,
) -> &'tcx [(ExportedSymbol<'tcx>, SymbolExportLevel)] {
diff --git a/compiler/rustc_codegen_ssa/src/back/write.rs b/compiler/rustc_codegen_ssa/src/back/write.rs
index 85d51ea9a20..d6af6104155 100644
--- a/compiler/rustc_codegen_ssa/src/back/write.rs
+++ b/compiler/rustc_codegen_ssa/src/back/write.rs
@@ -397,7 +397,6 @@ fn generate_lto_work<B: ExtraBackendMethods>(
pub struct CompiledModules {
pub modules: Vec<CompiledModule>,
- pub metadata_module: Option<CompiledModule>,
pub allocator_module: Option<CompiledModule>,
}
@@ -425,6 +424,7 @@ pub fn start_async_codegen<B: ExtraBackendMethods>(
tcx: TyCtxt<'_>,
target_cpu: String,
metadata: EncodedMetadata,
+ metadata_module: Option<CompiledModule>,
total_cgus: usize,
) -> OngoingCodegen<B> {
let (coordinator_send, coordinator_receive) = channel();
@@ -464,6 +464,7 @@ pub fn start_async_codegen<B: ExtraBackendMethods>(
OngoingCodegen {
backend,
metadata,
+ metadata_module,
crate_info,
coordinator_send,
@@ -640,12 +641,6 @@ fn produce_final_output_artifacts(
}
if !user_wants_bitcode {
- if let Some(ref metadata_module) = compiled_modules.metadata_module {
- if let Some(ref path) = metadata_module.bytecode {
- ensure_removed(sess.diagnostic(), &path);
- }
- }
-
if let Some(ref allocator_module) = compiled_modules.allocator_module {
if let Some(ref path) = allocator_module.bytecode {
ensure_removed(sess.diagnostic(), path);
@@ -682,11 +677,11 @@ impl<B: WriteBackendMethods> WorkItem<B> {
fn start_profiling<'a>(&self, cgcx: &'a CodegenContext<B>) -> TimingGuard<'a> {
match *self {
WorkItem::Optimize(ref m) => {
- cgcx.prof.generic_activity_with_arg("codegen_module_optimize", &m.name[..])
+ cgcx.prof.generic_activity_with_arg("codegen_module_optimize", &*m.name)
}
WorkItem::CopyPostLtoArtifacts(ref m) => cgcx
.prof
- .generic_activity_with_arg("codegen_copy_artifacts_from_incr_cache", &m.name[..]),
+ .generic_activity_with_arg("codegen_copy_artifacts_from_incr_cache", &*m.name),
WorkItem::LTO(ref m) => {
cgcx.prof.generic_activity_with_arg("codegen_module_perform_lto", m.name())
}
@@ -1216,7 +1211,6 @@ fn start_executing_work<B: ExtraBackendMethods>(
// This is where we collect codegen units that have gone all the way
// through codegen and LLVM.
let mut compiled_modules = vec![];
- let mut compiled_metadata_module = None;
let mut compiled_allocator_module = None;
let mut needs_link = Vec::new();
let mut needs_fat_lto = Vec::new();
@@ -1475,14 +1469,11 @@ fn start_executing_work<B: ExtraBackendMethods>(
ModuleKind::Regular => {
compiled_modules.push(compiled_module);
}
- ModuleKind::Metadata => {
- assert!(compiled_metadata_module.is_none());
- compiled_metadata_module = Some(compiled_module);
- }
ModuleKind::Allocator => {
assert!(compiled_allocator_module.is_none());
compiled_allocator_module = Some(compiled_module);
}
+ ModuleKind::Metadata => bug!("Should be handled separately"),
}
}
Message::NeedsLink { module, worker_id } => {
@@ -1539,7 +1530,6 @@ fn start_executing_work<B: ExtraBackendMethods>(
Ok(CompiledModules {
modules: compiled_modules,
- metadata_module: compiled_metadata_module,
allocator_module: compiled_allocator_module,
})
});
@@ -1800,6 +1790,7 @@ impl SharedEmitterMain {
pub struct OngoingCodegen<B: ExtraBackendMethods> {
pub backend: B,
pub metadata: EncodedMetadata,
+ pub metadata_module: Option<CompiledModule>,
pub crate_info: CrateInfo,
pub coordinator_send: Sender<Box<dyn Any + Send>>,
pub codegen_worker_receive: Receiver<Message<B>>,
@@ -1846,7 +1837,7 @@ impl<B: ExtraBackendMethods> OngoingCodegen<B> {
modules: compiled_modules.modules,
allocator_module: compiled_modules.allocator_module,
- metadata_module: compiled_modules.metadata_module,
+ metadata_module: self.metadata_module,
},
work_products,
)
diff --git a/compiler/rustc_codegen_ssa/src/base.rs b/compiler/rustc_codegen_ssa/src/base.rs
index 9bb4982754c..1dac528481d 100644
--- a/compiler/rustc_codegen_ssa/src/base.rs
+++ b/compiler/rustc_codegen_ssa/src/base.rs
@@ -1,3 +1,4 @@
+use crate::back::metadata::create_compressed_metadata_file;
use crate::back::write::{
compute_per_cgu_lto_type, start_async_codegen, submit_codegened_module_to_llvm,
submit_post_lto_module_to_llvm, submit_pre_lto_module_to_llvm, ComputedLtoType, OngoingCodegen,
@@ -8,7 +9,7 @@ use crate::mir;
use crate::mir::operand::OperandValue;
use crate::mir::place::PlaceRef;
use crate::traits::*;
-use crate::{CachedModuleCodegen, CrateInfo, MemFlags, ModuleCodegen, ModuleKind};
+use crate::{CachedModuleCodegen, CompiledModule, CrateInfo, MemFlags, ModuleCodegen, ModuleKind};
use rustc_attr as attr;
use rustc_data_structures::fx::FxHashMap;
@@ -20,13 +21,14 @@ use rustc_hir::lang_items::LangItem;
use rustc_index::vec::Idx;
use rustc_metadata::EncodedMetadata;
use rustc_middle::middle::codegen_fn_attrs::CodegenFnAttrs;
+use rustc_middle::middle::exported_symbols;
use rustc_middle::middle::lang_items;
use rustc_middle::mir::mono::{CodegenUnit, CodegenUnitNameBuilder, MonoItem};
use rustc_middle::ty::layout::{HasTyCtxt, LayoutOf, TyAndLayout};
use rustc_middle::ty::query::Providers;
use rustc_middle::ty::{self, Instance, Ty, TyCtxt};
use rustc_session::cgu_reuse_tracker::CguReuse;
-use rustc_session::config::{self, EntryFnType};
+use rustc_session::config::{self, EntryFnType, OutputType};
use rustc_session::Session;
use rustc_span::symbol::sym;
use rustc_target::abi::{Align, VariantIdx};
@@ -484,14 +486,14 @@ fn get_argc_argv<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>(
pub fn codegen_crate<B: ExtraBackendMethods>(
backend: B,
- tcx: TyCtxt<'tcx>,
+ tcx: TyCtxt<'_>,
target_cpu: String,
metadata: EncodedMetadata,
need_metadata_module: bool,
) -> OngoingCodegen<B> {
// Skip crate items and just output metadata in -Z no-codegen mode.
if tcx.sess.opts.debugging_opts.no_codegen || !tcx.sess.opts.output_types.should_codegen() {
- let ongoing_codegen = start_async_codegen(backend, tcx, target_cpu, metadata, 1);
+ let ongoing_codegen = start_async_codegen(backend, tcx, target_cpu, metadata, None, 1);
ongoing_codegen.codegen_finished(tcx);
@@ -517,8 +519,41 @@ pub fn codegen_crate<B: ExtraBackendMethods>(
}
}
- let ongoing_codegen =
- start_async_codegen(backend.clone(), tcx, target_cpu, metadata, codegen_units.len());
+ let metadata_module = if need_metadata_module {
+ // Emit compressed metadata object.
+ let metadata_cgu_name =
+ cgu_name_builder.build_cgu_name(LOCAL_CRATE, &["crate"], Some("metadata")).to_string();
+ tcx.sess.time("write_compressed_metadata", || {
+ let file_name =
+ tcx.output_filenames(()).temp_path(OutputType::Metadata, Some(&metadata_cgu_name));
+ let data = create_compressed_metadata_file(
+ tcx.sess,
+ &metadata,
+ &exported_symbols::metadata_symbol_name(tcx),
+ );
+ if let Err(err) = std::fs::write(&file_name, data) {
+ tcx.sess.fatal(&format!("error writing metadata object file: {}", err));
+ }
+ Some(CompiledModule {
+ name: metadata_cgu_name,
+ kind: ModuleKind::Metadata,
+ object: Some(file_name),
+ dwarf_object: None,
+ bytecode: None,
+ })
+ })
+ } else {
+ None
+ };
+
+ let ongoing_codegen = start_async_codegen(
+ backend.clone(),
+ tcx,
+ target_cpu,
+ metadata,
+ metadata_module,
+ codegen_units.len(),
+ );
let ongoing_codegen = AbortCodegenOnDrop::<B>(Some(ongoing_codegen));
// Codegen an allocator shim, if necessary.
@@ -558,27 +593,6 @@ pub fn codegen_crate<B: ExtraBackendMethods>(
ongoing_codegen.submit_pre_codegened_module_to_llvm(tcx, allocator_module);
}
- if need_metadata_module {
- // Codegen the encoded metadata.
- let metadata_cgu_name =
- cgu_name_builder.build_cgu_name(LOCAL_CRATE, &["crate"], Some("metadata")).to_string();
- let mut metadata_llvm_module = backend.new_metadata(tcx, &metadata_cgu_name);
- tcx.sess.time("write_compressed_metadata", || {
- backend.write_compressed_metadata(
- tcx,
- &ongoing_codegen.metadata,
- &mut metadata_llvm_module,
- );
- });
-
- let metadata_module = ModuleCodegen {
- name: metadata_cgu_name,
- module_llvm: metadata_llvm_module,
- kind: ModuleKind::Metadata,
- };
- ongoing_codegen.submit_pre_codegened_module_to_llvm(tcx, metadata_module);
- }
-
// For better throughput during parallel processing by LLVM, we used to sort
// CGUs largest to smallest. This would lead to better thread utilization
// by, for example, preventing a large CGU from being processed last and
diff --git a/compiler/rustc_codegen_ssa/src/common.rs b/compiler/rustc_codegen_ssa/src/common.rs
index 1fa60612d26..2df58ecc9f6 100644
--- a/compiler/rustc_codegen_ssa/src/common.rs
+++ b/compiler/rustc_codegen_ssa/src/common.rs
@@ -122,8 +122,8 @@ pub fn langcall(tcx: TyCtxt<'_>, span: Option<Span>, msg: &str, li: LangItem) ->
tcx.lang_items().require(li).unwrap_or_else(|s| {
let msg = format!("{} {}", msg, s);
match span {
- Some(span) => tcx.sess.span_fatal(span, &msg[..]),
- None => tcx.sess.fatal(&msg[..]),
+ Some(span) => tcx.sess.span_fatal(span, &msg),
+ None => tcx.sess.fatal(&msg),
}
})
}
diff --git a/compiler/rustc_codegen_ssa/src/coverageinfo/ffi.rs b/compiler/rustc_codegen_ssa/src/coverageinfo/ffi.rs
index 962c01c2ee7..e288760a02b 100644
--- a/compiler/rustc_codegen_ssa/src/coverageinfo/ffi.rs
+++ b/compiler/rustc_codegen_ssa/src/coverageinfo/ffi.rs
@@ -1,6 +1,6 @@
use rustc_middle::mir::coverage::{CounterValueReference, MappedExpressionIndex};
-/// Aligns with [llvm::coverage::Counter::CounterKind](https://github.com/rust-lang/llvm-project/blob/rustc/11.0-2020-10-12/llvm/include/llvm/ProfileData/Coverage/CoverageMapping.h#L206-L222)
+/// Aligns with [llvm::coverage::Counter::CounterKind](https://github.com/rust-lang/llvm-project/blob/rustc/13.0-2021-09-30/llvm/include/llvm/ProfileData/Coverage/CoverageMapping.h#L95)
#[derive(Copy, Clone, Debug)]
#[repr(C)]
pub enum CounterKind {
@@ -17,7 +17,7 @@ pub enum CounterKind {
/// `instrprof.increment()`)
/// * For `CounterKind::Expression`, `id` is the index into the coverage map's array of
/// counter expressions.
-/// Aligns with [llvm::coverage::Counter](https://github.com/rust-lang/llvm-project/blob/rustc/11.0-2020-10-12/llvm/include/llvm/ProfileData/Coverage/CoverageMapping.h#L99-L100)
+/// Aligns with [llvm::coverage::Counter](https://github.com/rust-lang/llvm-project/blob/rustc/13.0-2021-09-30/llvm/include/llvm/ProfileData/Coverage/CoverageMapping.h#L102-L103)
/// Important: The Rust struct layout (order and types of fields) must match its C++ counterpart.
#[derive(Copy, Clone, Debug)]
#[repr(C)]
@@ -59,7 +59,7 @@ impl Counter {
}
}
-/// Aligns with [llvm::coverage::CounterExpression::ExprKind](https://github.com/rust-lang/llvm-project/blob/rustc/11.0-2020-10-12/llvm/include/llvm/ProfileData/Coverage/CoverageMapping.h#L147)
+/// Aligns with [llvm::coverage::CounterExpression::ExprKind](https://github.com/rust-lang/llvm-project/blob/rustc/13.0-2021-09-30/llvm/include/llvm/ProfileData/Coverage/CoverageMapping.h#L150)
#[derive(Copy, Clone, Debug)]
#[repr(C)]
pub enum ExprKind {
@@ -67,7 +67,7 @@ pub enum ExprKind {
Add = 1,
}
-/// Aligns with [llvm::coverage::CounterExpression](https://github.com/rust-lang/llvm-project/blob/rustc/11.0-2020-10-12/llvm/include/llvm/ProfileData/Coverage/CoverageMapping.h#L148-L149)
+/// Aligns with [llvm::coverage::CounterExpression](https://github.com/rust-lang/llvm-project/blob/rustc/13.0-2021-09-30/llvm/include/llvm/ProfileData/Coverage/CoverageMapping.h#L151-L152)
/// Important: The Rust struct layout (order and types of fields) must match its C++
/// counterpart.
#[derive(Copy, Clone, Debug)]
diff --git a/compiler/rustc_codegen_ssa/src/coverageinfo/map.rs b/compiler/rustc_codegen_ssa/src/coverageinfo/map.rs
index c1dfe1ef856..1a6495cb15c 100644
--- a/compiler/rustc_codegen_ssa/src/coverageinfo/map.rs
+++ b/compiler/rustc_codegen_ssa/src/coverageinfo/map.rs
@@ -150,9 +150,9 @@ impl<'tcx> FunctionCoverage<'tcx> {
/// Generate an array of CounterExpressions, and an iterator over all `Counter`s and their
/// associated `Regions` (from which the LLVM-specific `CoverageMapGenerator` will create
/// `CounterMappingRegion`s.
- pub fn get_expressions_and_counter_regions<'a>(
- &'a self,
- ) -> (Vec<CounterExpression>, impl Iterator<Item = (Counter, &'a CodeRegion)>) {
+ pub fn get_expressions_and_counter_regions(
+ &self,
+ ) -> (Vec<CounterExpression>, impl Iterator<Item = (Counter, &CodeRegion)>) {
assert!(
self.source_hash != 0 || !self.is_used,
"No counters provided the source_hash for used function: {:?}",
@@ -168,7 +168,7 @@ impl<'tcx> FunctionCoverage<'tcx> {
(counter_expressions, counter_regions)
}
- fn counter_regions<'a>(&'a self) -> impl Iterator<Item = (Counter, &'a CodeRegion)> {
+ fn counter_regions(&self) -> impl Iterator<Item = (Counter, &CodeRegion)> {
self.counters.iter_enumerated().filter_map(|(index, entry)| {
// Option::map() will return None to filter out missing counters. This may happen
// if, for example, a MIR-instrumented counter is removed during an optimization.
@@ -177,8 +177,8 @@ impl<'tcx> FunctionCoverage<'tcx> {
}
fn expressions_with_regions(
- &'a self,
- ) -> (Vec<CounterExpression>, impl Iterator<Item = (Counter, &'a CodeRegion)>) {
+ &self,
+ ) -> (Vec<CounterExpression>, impl Iterator<Item = (Counter, &CodeRegion)>) {
let mut counter_expressions = Vec::with_capacity(self.expressions.len());
let mut expression_regions = Vec::with_capacity(self.expressions.len());
let mut new_indexes = IndexVec::from_elem_n(None, self.expressions.len());
@@ -336,7 +336,7 @@ impl<'tcx> FunctionCoverage<'tcx> {
(counter_expressions, expression_regions.into_iter())
}
- fn unreachable_regions<'a>(&'a self) -> impl Iterator<Item = (Counter, &'a CodeRegion)> {
+ fn unreachable_regions(&self) -> impl Iterator<Item = (Counter, &CodeRegion)> {
self.unreachable_regions.iter().map(|region| (Counter::zero(), region))
}
diff --git a/compiler/rustc_codegen_ssa/src/debuginfo/type_names.rs b/compiler/rustc_codegen_ssa/src/debuginfo/type_names.rs
index ab119ae25f5..b03124769a0 100644
--- a/compiler/rustc_codegen_ssa/src/debuginfo/type_names.rs
+++ b/compiler/rustc_codegen_ssa/src/debuginfo/type_names.rs
@@ -376,7 +376,7 @@ fn push_debuginfo_type_name<'tcx>(
// format (natvis) is able to understand enums and render the active variant correctly in the
// debugger. For more information, look in `src/etc/natvis/intrinsic.natvis` and
// `EnumMemberDescriptionFactor::create_member_descriptions`.
- fn msvc_enum_fallback(
+ fn msvc_enum_fallback<'tcx>(
tcx: TyCtxt<'tcx>,
ty: Ty<'tcx>,
def: &AdtDef,
@@ -496,7 +496,7 @@ pub fn compute_debuginfo_vtable_name<'tcx>(
vtable_name
}
-pub fn push_item_name(tcx: TyCtxt<'tcx>, def_id: DefId, qualified: bool, output: &mut String) {
+pub fn push_item_name(tcx: TyCtxt<'_>, def_id: DefId, qualified: bool, output: &mut String) {
let def_key = tcx.def_key(def_id);
if qualified {
if let Some(parent) = def_key.parent {
@@ -509,7 +509,7 @@ pub fn push_item_name(tcx: TyCtxt<'tcx>, def_id: DefId, qualified: bool, output:
}
fn push_unqualified_item_name(
- tcx: TyCtxt<'tcx>,
+ tcx: TyCtxt<'_>,
def_id: DefId,
disambiguated_data: DisambiguatedDefPathData,
output: &mut String,
diff --git a/compiler/rustc_codegen_ssa/src/glue.rs b/compiler/rustc_codegen_ssa/src/glue.rs
index cf217b52c86..2c4e6bbe9a5 100644
--- a/compiler/rustc_codegen_ssa/src/glue.rs
+++ b/compiler/rustc_codegen_ssa/src/glue.rs
@@ -6,6 +6,7 @@ use crate::common::IntPredicate;
use crate::meth;
use crate::traits::*;
use rustc_middle::ty::{self, Ty};
+use rustc_target::abi::WrappingRange;
pub fn size_and_align_of_dst<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>(
bx: &mut Bx,
@@ -21,14 +22,17 @@ pub fn size_and_align_of_dst<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>(
}
match t.kind() {
ty::Dynamic(..) => {
- // load size/align from vtable
+ // Load size/align from vtable.
let vtable = info.unwrap();
- (
- meth::VirtualIndex::from_index(ty::COMMON_VTABLE_ENTRIES_SIZE)
- .get_usize(bx, vtable),
- meth::VirtualIndex::from_index(ty::COMMON_VTABLE_ENTRIES_ALIGN)
- .get_usize(bx, vtable),
- )
+ let size = meth::VirtualIndex::from_index(ty::COMMON_VTABLE_ENTRIES_SIZE)
+ .get_usize(bx, vtable);
+ let align = meth::VirtualIndex::from_index(ty::COMMON_VTABLE_ENTRIES_ALIGN)
+ .get_usize(bx, vtable);
+
+ // Alignment is always nonzero.
+ bx.range_metadata(align, WrappingRange { start: 1, end: !0 });
+
+ (size, align)
}
ty::Slice(_) | ty::Str => {
let unit = layout.field(bx, 0);
diff --git a/compiler/rustc_codegen_ssa/src/lib.rs b/compiler/rustc_codegen_ssa/src/lib.rs
index 4c87d4d896e..350199f4e98 100644
--- a/compiler/rustc_codegen_ssa/src/lib.rs
+++ b/compiler/rustc_codegen_ssa/src/lib.rs
@@ -2,7 +2,6 @@
#![feature(bool_to_option)]
#![feature(box_patterns)]
#![feature(try_blocks)]
-#![feature(in_band_lifetimes)]
#![feature(let_else)]
#![feature(once_cell)]
#![feature(nll)]
diff --git a/compiler/rustc_codegen_ssa/src/mir/analyze.rs b/compiler/rustc_codegen_ssa/src/mir/analyze.rs
index 8d75b2e7a3d..b1b3f1d6d81 100644
--- a/compiler/rustc_codegen_ssa/src/mir/analyze.rs
+++ b/compiler/rustc_codegen_ssa/src/mir/analyze.rs
@@ -73,7 +73,7 @@ struct LocalAnalyzer<'mir, 'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> {
locals: IndexVec<mir::Local, LocalKind>,
}
-impl<Bx: BuilderMethods<'a, 'tcx>> LocalAnalyzer<'mir, 'a, 'tcx, Bx> {
+impl<'mir, 'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> LocalAnalyzer<'mir, 'a, 'tcx, Bx> {
fn assign(&mut self, local: mir::Local, location: Location) {
let kind = &mut self.locals[local];
match *kind {
@@ -211,6 +211,7 @@ impl<'mir, 'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> Visitor<'tcx>
PlaceContext::MutatingUse(
MutatingUseContext::Store
+ | MutatingUseContext::LlvmAsmOutput
| MutatingUseContext::AsmOutput
| MutatingUseContext::Borrow
| MutatingUseContext::AddressOf
@@ -275,9 +276,9 @@ pub fn cleanup_kinds(mir: &mir::Body<'_>) -> IndexVec<mir::BasicBlock, CleanupKi
| TerminatorKind::SwitchInt { .. }
| TerminatorKind::Yield { .. }
| TerminatorKind::FalseEdge { .. }
- | TerminatorKind::FalseUnwind { .. }
- | TerminatorKind::InlineAsm { .. } => { /* nothing to do */ }
+ | TerminatorKind::FalseUnwind { .. } => { /* nothing to do */ }
TerminatorKind::Call { cleanup: unwind, .. }
+ | TerminatorKind::InlineAsm { cleanup: unwind, .. }
| TerminatorKind::Assert { cleanup: unwind, .. }
| TerminatorKind::DropAndReplace { unwind, .. }
| TerminatorKind::Drop { unwind, .. } => {
diff --git a/compiler/rustc_codegen_ssa/src/mir/block.rs b/compiler/rustc_codegen_ssa/src/mir/block.rs
index c8f388bfa1d..e914e493269 100644
--- a/compiler/rustc_codegen_ssa/src/mir/block.rs
+++ b/compiler/rustc_codegen_ssa/src/mir/block.rs
@@ -10,6 +10,7 @@ use crate::traits::*;
use crate::MemFlags;
use rustc_ast as ast;
+use rustc_ast::{InlineAsmOptions, InlineAsmTemplatePiece};
use rustc_hir::lang_items::LangItem;
use rustc_index::vec::Idx;
use rustc_middle::mir::AssertKind;
@@ -174,6 +175,45 @@ impl<'a, 'tcx> TerminatorCodegenHelper<'tcx> {
}
}
}
+
+ /// Generates inline assembly with optional `destination` and `cleanup`.
+ fn do_inlineasm<Bx: BuilderMethods<'a, 'tcx>>(
+ &self,
+ fx: &mut FunctionCx<'a, 'tcx, Bx>,
+ bx: &mut Bx,
+ template: &[InlineAsmTemplatePiece],
+ operands: &[InlineAsmOperandRef<'tcx, Bx>],
+ options: InlineAsmOptions,
+ line_spans: &[Span],
+ destination: Option<mir::BasicBlock>,
+ cleanup: Option<mir::BasicBlock>,
+ instance: Instance<'_>,
+ ) {
+ if let Some(cleanup) = cleanup {
+ let ret_llbb = if let Some(target) = destination {
+ fx.llbb(target)
+ } else {
+ fx.unreachable_block()
+ };
+
+ bx.codegen_inline_asm(
+ template,
+ &operands,
+ options,
+ line_spans,
+ instance,
+ Some((ret_llbb, self.llblock(fx, cleanup), self.funclet(fx))),
+ );
+ } else {
+ bx.codegen_inline_asm(template, &operands, options, line_spans, instance, None);
+
+ if let Some(target) = destination {
+ self.funclet_br(fx, bx, target);
+ } else {
+ bx.unreachable();
+ }
+ }
+ }
}
/// Codegen implementations for some terminator variants.
@@ -877,6 +917,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
options: ast::InlineAsmOptions,
line_spans: &[Span],
destination: Option<mir::BasicBlock>,
+ cleanup: Option<mir::BasicBlock>,
instance: Instance<'_>,
) {
let span = terminator.source_info.span;
@@ -931,13 +972,17 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
})
.collect();
- bx.codegen_inline_asm(template, &operands, options, line_spans, instance);
-
- if let Some(target) = destination {
- helper.funclet_br(self, &mut bx, target);
- } else {
- bx.unreachable();
- }
+ helper.do_inlineasm(
+ self,
+ &mut bx,
+ template,
+ &operands,
+ options,
+ line_spans,
+ destination,
+ cleanup,
+ instance,
+ );
}
}
@@ -1041,6 +1086,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
options,
line_spans,
destination,
+ cleanup,
} => {
self.codegen_asm_terminator(
helper,
@@ -1051,6 +1097,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
options,
line_spans,
destination,
+ cleanup,
self.instance,
);
}
diff --git a/compiler/rustc_codegen_ssa/src/mir/operand.rs b/compiler/rustc_codegen_ssa/src/mir/operand.rs
index bea55bbc879..0c526ff13f2 100644
--- a/compiler/rustc_codegen_ssa/src/mir/operand.rs
+++ b/compiler/rustc_codegen_ssa/src/mir/operand.rs
@@ -47,7 +47,7 @@ pub struct OperandRef<'tcx, V> {
pub layout: TyAndLayout<'tcx>,
}
-impl<V: CodegenObject> fmt::Debug for OperandRef<'tcx, V> {
+impl<V: CodegenObject> fmt::Debug for OperandRef<'_, V> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "OperandRef({:?} @ {:?})", self.val, self.layout)
}
diff --git a/compiler/rustc_codegen_ssa/src/target_features.rs b/compiler/rustc_codegen_ssa/src/target_features.rs
index b4420df5df4..63cc6faf9ec 100644
--- a/compiler/rustc_codegen_ssa/src/target_features.rs
+++ b/compiler/rustc_codegen_ssa/src/target_features.rs
@@ -35,6 +35,8 @@ const ARM_ALLOWED_FEATURES: &[(&str, Option<Symbol>)] = &[
// since it should be enabled per-function using #[instruction_set], not
// #[target_feature].
("thumb-mode", Some(sym::arm_target_feature)),
+ ("thumb2", Some(sym::arm_target_feature)),
+ ("reserve-r9", Some(sym::arm_target_feature)),
];
const AARCH64_ALLOWED_FEATURES: &[(&str, Option<Symbol>)] = &[
diff --git a/compiler/rustc_codegen_ssa/src/traits/abi.rs b/compiler/rustc_codegen_ssa/src/traits/abi.rs
index dd8495850bd..a00d78daf4d 100644
--- a/compiler/rustc_codegen_ssa/src/traits/abi.rs
+++ b/compiler/rustc_codegen_ssa/src/traits/abi.rs
@@ -4,5 +4,5 @@ use rustc_target::abi::call::FnAbi;
pub trait AbiBuilderMethods<'tcx>: BackendTypes {
fn apply_attrs_callsite(&mut self, fn_abi: &FnAbi<'tcx, Ty<'tcx>>, callsite: Self::Value);
- fn get_param(&self, index: usize) -> Self::Value;
+ fn get_param(&mut self, index: usize) -> Self::Value;
}
diff --git a/compiler/rustc_codegen_ssa/src/traits/asm.rs b/compiler/rustc_codegen_ssa/src/traits/asm.rs
index 31f539e1b03..65f3c754d2d 100644
--- a/compiler/rustc_codegen_ssa/src/traits/asm.rs
+++ b/compiler/rustc_codegen_ssa/src/traits/asm.rs
@@ -59,6 +59,7 @@ pub trait AsmBuilderMethods<'tcx>: BackendTypes {
options: InlineAsmOptions,
line_spans: &[Span],
instance: Instance<'_>,
+ dest_catch_funclet: Option<(Self::BasicBlock, Self::BasicBlock, Option<&Self::Funclet>)>,
);
}
diff --git a/compiler/rustc_codegen_ssa/src/traits/backend.rs b/compiler/rustc_codegen_ssa/src/traits/backend.rs
index 9c8bc3b2109..c6abb3f6eb4 100644
--- a/compiler/rustc_codegen_ssa/src/traits/backend.rs
+++ b/compiler/rustc_codegen_ssa/src/traits/backend.rs
@@ -97,6 +97,7 @@ pub trait CodegenBackend {
&self,
ongoing_codegen: Box<dyn Any>,
sess: &Session,
+ outputs: &OutputFilenames,
) -> Result<(CodegenResults, FxHashMap<WorkProductId, WorkProduct>), ErrorReported>;
/// This is called on the returned `Box<dyn Any>` from `join_codegen`
@@ -114,12 +115,6 @@ pub trait CodegenBackend {
pub trait ExtraBackendMethods: CodegenBackend + WriteBackendMethods + Sized + Send + Sync {
fn new_metadata(&self, sess: TyCtxt<'_>, mod_name: &str) -> Self::Module;
- fn write_compressed_metadata<'tcx>(
- &self,
- tcx: TyCtxt<'tcx>,
- metadata: &EncodedMetadata,
- llvm_module: &mut Self::Module,
- );
fn codegen_allocator<'tcx>(
&self,
tcx: TyCtxt<'tcx>,
diff --git a/compiler/rustc_codegen_ssa/src/traits/type_.rs b/compiler/rustc_codegen_ssa/src/traits/type_.rs
index b94fb1e10db..5d3f07317a3 100644
--- a/compiler/rustc_codegen_ssa/src/traits/type_.rs
+++ b/compiler/rustc_codegen_ssa/src/traits/type_.rs
@@ -97,7 +97,7 @@ pub trait DerivedTypeMethods<'tcx>: BaseTypeMethods<'tcx> + MiscMethods<'tcx> {
}
}
-impl<T> DerivedTypeMethods<'tcx> for T where Self: BaseTypeMethods<'tcx> + MiscMethods<'tcx> {}
+impl<'tcx, T> DerivedTypeMethods<'tcx> for T where Self: BaseTypeMethods<'tcx> + MiscMethods<'tcx> {}
pub trait LayoutTypeMethods<'tcx>: Backend<'tcx> {
fn backend_type(&self, layout: TyAndLayout<'tcx>) -> Self::Type;
@@ -135,4 +135,4 @@ pub trait ArgAbiMethods<'tcx>: HasCodegen<'tcx> {
pub trait TypeMethods<'tcx>: DerivedTypeMethods<'tcx> + LayoutTypeMethods<'tcx> {}
-impl<T> TypeMethods<'tcx> for T where Self: DerivedTypeMethods<'tcx> + LayoutTypeMethods<'tcx> {}
+impl<'tcx, T> TypeMethods<'tcx> for T where Self: DerivedTypeMethods<'tcx> + LayoutTypeMethods<'tcx> {}
diff --git a/compiler/rustc_const_eval/src/const_eval/eval_queries.rs b/compiler/rustc_const_eval/src/const_eval/eval_queries.rs
index 6d3a89c0a8a..c5412affafe 100644
--- a/compiler/rustc_const_eval/src/const_eval/eval_queries.rs
+++ b/compiler/rustc_const_eval/src/const_eval/eval_queries.rs
@@ -7,6 +7,7 @@ use crate::interpret::{
};
use rustc_errors::ErrorReported;
+use rustc_hir as hir;
use rustc_hir::def::DefKind;
use rustc_middle::mir;
use rustc_middle::mir::interpret::ErrorHandled;
@@ -215,6 +216,7 @@ pub fn eval_to_const_value_raw_provider<'tcx>(
tcx: TyCtxt<'tcx>,
key: ty::ParamEnvAnd<'tcx, GlobalId<'tcx>>,
) -> ::rustc_middle::mir::interpret::EvalToConstValueResult<'tcx> {
+ assert!(key.param_env.constness() == hir::Constness::Const);
// see comment in eval_to_allocation_raw_provider for what we're doing here
if key.param_env.reveal() == Reveal::All {
let mut key = key;
@@ -249,6 +251,7 @@ pub fn eval_to_allocation_raw_provider<'tcx>(
tcx: TyCtxt<'tcx>,
key: ty::ParamEnvAnd<'tcx, GlobalId<'tcx>>,
) -> ::rustc_middle::mir::interpret::EvalToAllocationRawResult<'tcx> {
+ assert!(key.param_env.constness() == hir::Constness::Const);
// Because the constant is computed twice (once per value of `Reveal`), we are at risk of
// reporting the same error twice here. To resolve this, we check whether we can evaluate the
// constant in the more restrictive `Reveal::UserFacing`, which most likely already was
diff --git a/compiler/rustc_const_eval/src/const_eval/machine.rs b/compiler/rustc_const_eval/src/const_eval/machine.rs
index dacd8f7c12c..550715abc10 100644
--- a/compiler/rustc_const_eval/src/const_eval/machine.rs
+++ b/compiler/rustc_const_eval/src/const_eval/machine.rs
@@ -423,14 +423,14 @@ impl<'mir, 'tcx> interpret::Machine<'mir, 'tcx> for CompileTimeInterpreter<'mir,
}
#[inline(always)]
- fn stack(
+ fn stack<'a>(
ecx: &'a InterpCx<'mir, 'tcx, Self>,
) -> &'a [Frame<'mir, 'tcx, Self::PointerTag, Self::FrameExtra>] {
&ecx.machine.stack
}
#[inline(always)]
- fn stack_mut(
+ fn stack_mut<'a>(
ecx: &'a mut InterpCx<'mir, 'tcx, Self>,
) -> &'a mut Vec<Frame<'mir, 'tcx, Self::PointerTag, Self::FrameExtra>> {
&mut ecx.machine.stack
diff --git a/compiler/rustc_const_eval/src/const_eval/mod.rs b/compiler/rustc_const_eval/src/const_eval/mod.rs
index a334165df4c..91b17d1ac1e 100644
--- a/compiler/rustc_const_eval/src/const_eval/mod.rs
+++ b/compiler/rustc_const_eval/src/const_eval/mod.rs
@@ -25,9 +25,9 @@ pub use fn_queries::*;
pub use machine::*;
pub(crate) fn const_caller_location(
- tcx: TyCtxt<'tcx>,
+ tcx: TyCtxt<'_>,
(file, line, col): (Symbol, u32, u32),
-) -> ConstValue<'tcx> {
+) -> ConstValue<'_> {
trace!("const_caller_location: {}:{}:{}", file, line, col);
let mut ecx = mk_eval_cx(tcx, DUMMY_SP, ty::ParamEnv::reveal_all(), false);
diff --git a/compiler/rustc_const_eval/src/interpret/eval_context.rs b/compiler/rustc_const_eval/src/interpret/eval_context.rs
index cf084faade8..d9faa6777ea 100644
--- a/compiler/rustc_const_eval/src/interpret/eval_context.rs
+++ b/compiler/rustc_const_eval/src/interpret/eval_context.rs
@@ -7,6 +7,7 @@ use rustc_hir::{self as hir, def_id::DefId, definitions::DefPathData};
use rustc_index::vec::IndexVec;
use rustc_macros::HashStable;
use rustc_middle::mir;
+use rustc_middle::mir::interpret::{InterpError, InvalidProgramInfo};
use rustc_middle::ty::layout::{self, LayoutError, LayoutOf, LayoutOfHelpers, TyAndLayout};
use rustc_middle::ty::{
self, query::TyCtxtAt, subst::SubstsRef, ParamEnv, Ty, TyCtxt, TypeFoldable,
@@ -508,7 +509,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
pub(super) fn subst_from_current_frame_and_normalize_erasing_regions<T: TypeFoldable<'tcx>>(
&self,
value: T,
- ) -> T {
+ ) -> Result<T, InterpError<'tcx>> {
self.subst_from_frame_and_normalize_erasing_regions(self.frame(), value)
}
@@ -518,8 +519,18 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
&self,
frame: &Frame<'mir, 'tcx, M::PointerTag, M::FrameExtra>,
value: T,
- ) -> T {
- frame.instance.subst_mir_and_normalize_erasing_regions(*self.tcx, self.param_env, value)
+ ) -> Result<T, InterpError<'tcx>> {
+ frame
+ .instance
+ .try_subst_mir_and_normalize_erasing_regions(*self.tcx, self.param_env, value)
+ .or_else(|e| {
+ self.tcx.sess.delay_span_bug(
+ self.cur_span(),
+ format!("failed to normalize {}", e.get_type_for_failure()).as_str(),
+ );
+
+ Err(InterpError::InvalidProgram(InvalidProgramInfo::TooGeneric))
+ })
}
/// The `substs` are assumed to already be in our interpreter "universe" (param_env).
@@ -554,7 +565,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
let layout = from_known_layout(self.tcx, self.param_env, layout, || {
let local_ty = frame.body.local_decls[local].ty;
let local_ty =
- self.subst_from_frame_and_normalize_erasing_regions(frame, local_ty);
+ self.subst_from_frame_and_normalize_erasing_regions(frame, local_ty)?;
self.layout_of(local_ty)
})?;
if let Some(state) = frame.locals.get(local) {
@@ -605,19 +616,9 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
match self.size_and_align_of(metadata, &field)? {
Some(size_and_align) => size_and_align,
None => {
- // A field with extern type. If this field is at offset 0, we behave
- // like the underlying extern type.
- // FIXME: Once we have made decisions for how to handle size and alignment
- // of `extern type`, this should be adapted. It is just a temporary hack
- // to get some code to work that probably ought to work.
- if sized_size == Size::ZERO {
- return Ok(None);
- } else {
- span_bug!(
- self.cur_span(),
- "Fields cannot be extern types, unless they are at offset 0"
- )
- }
+ // A field with an extern type. We don't know the actual dynamic size
+ // or the alignment.
+ return Ok(None);
}
};
@@ -702,7 +703,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
for const_ in &body.required_consts {
let span = const_.span;
let const_ =
- self.subst_from_current_frame_and_normalize_erasing_regions(const_.literal);
+ self.subst_from_current_frame_and_normalize_erasing_regions(const_.literal)?;
self.mir_const_to_op(&const_, None).map_err(|err| {
// If there was an error, set the span of the current frame to this constant.
// Avoiding doing this when evaluation succeeds.
@@ -918,12 +919,13 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
} else {
self.param_env
};
+ let param_env = param_env.with_const();
let val = self.tcx.eval_to_allocation_raw(param_env.and(gid))?;
self.raw_const_to_mplace(val)
}
#[must_use]
- pub fn dump_place(&'a self, place: Place<M::PointerTag>) -> PlacePrinter<'a, 'mir, 'tcx, M> {
+ pub fn dump_place(&self, place: Place<M::PointerTag>) -> PlacePrinter<'_, 'mir, 'tcx, M> {
PlacePrinter { ecx: self, place }
}
diff --git a/compiler/rustc_const_eval/src/interpret/intern.rs b/compiler/rustc_const_eval/src/interpret/intern.rs
index 84e79408397..a1dd587c17a 100644
--- a/compiler/rustc_const_eval/src/interpret/intern.rs
+++ b/compiler/rustc_const_eval/src/interpret/intern.rs
@@ -292,14 +292,15 @@ pub enum InternKind {
/// Any errors here would anyway be turned into `const_err` lints, whereas validation failures
/// are hard errors.
#[tracing::instrument(level = "debug", skip(ecx))]
-pub fn intern_const_alloc_recursive<M: CompileTimeMachine<'mir, 'tcx, const_eval::MemoryKind>>(
+pub fn intern_const_alloc_recursive<
+ 'mir,
+ 'tcx: 'mir,
+ M: CompileTimeMachine<'mir, 'tcx, const_eval::MemoryKind>,
+>(
ecx: &mut InterpCx<'mir, 'tcx, M>,
intern_kind: InternKind,
ret: &MPlaceTy<'tcx>,
-) -> Result<(), ErrorReported>
-where
- 'tcx: 'mir,
-{
+) -> Result<(), ErrorReported> {
let tcx = ecx.tcx;
let base_intern_mode = match intern_kind {
InternKind::Static(mutbl) => InternMode::Static(mutbl),
diff --git a/compiler/rustc_const_eval/src/interpret/intrinsics.rs b/compiler/rustc_const_eval/src/interpret/intrinsics.rs
index 44da27a43db..d6f856a6f0a 100644
--- a/compiler/rustc_const_eval/src/interpret/intrinsics.rs
+++ b/compiler/rustc_const_eval/src/interpret/intrinsics.rs
@@ -140,7 +140,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
sym::min_align_of_val | sym::size_of_val => {
// Avoid `deref_operand` -- this is not a deref, the ptr does not have to be
- // dereferencable!
+ // dereferenceable!
let place = self.ref_to_mplace(&self.read_immediate(&args[0])?)?;
let (size, align) = self
.size_and_align_of_mplace(&place)?
@@ -322,6 +322,9 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
sym::copy => {
self.copy_intrinsic(&args[0], &args[1], &args[2], /*nonoverlapping*/ false)?;
}
+ sym::write_bytes => {
+ self.write_bytes_intrinsic(&args[0], &args[1], &args[2])?;
+ }
sym::offset => {
let ptr = self.read_pointer(&args[0])?;
let offset_count = self.read_scalar(&args[1])?.to_machine_isize(self)?;
@@ -394,10 +397,12 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
sym::transmute => {
self.copy_op_transmute(&args[0], dest)?;
}
- sym::assert_inhabited => {
+ sym::assert_inhabited | sym::assert_zero_valid | sym::assert_uninit_valid => {
let ty = instance.substs.type_at(0);
let layout = self.layout_of(ty)?;
+ // For *all* intrinsics we first check `is_uninhabited` to give a more specific
+ // error message.
if layout.abi.is_uninhabited() {
// The run-time intrinsic panics just to get a good backtrace; here we abort
// since there is no problem showing a backtrace even for aborts.
@@ -409,6 +414,28 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
),
)?;
}
+ if intrinsic_name == sym::assert_zero_valid
+ && !layout.might_permit_raw_init(self, /*zero:*/ true)
+ {
+ M::abort(
+ self,
+ format!(
+ "aborted execution: attempted to zero-initialize type `{}`, which is invalid",
+ ty
+ ),
+ )?;
+ }
+ if intrinsic_name == sym::assert_uninit_valid
+ && !layout.might_permit_raw_init(self, /*zero:*/ false)
+ {
+ M::abort(
+ self,
+ format!(
+ "aborted execution: attempted to leave type `{}` uninitialized, which is invalid",
+ ty
+ ),
+ )?;
+ }
}
sym::simd_insert => {
let index = u64::from(self.read_scalar(&args[1])?.to_u32()?);
@@ -543,6 +570,27 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
self.memory.copy(src, align, dst, align, size, nonoverlapping)
}
+ pub(crate) fn write_bytes_intrinsic(
+ &mut self,
+ dst: &OpTy<'tcx, <M as Machine<'mir, 'tcx>>::PointerTag>,
+ byte: &OpTy<'tcx, <M as Machine<'mir, 'tcx>>::PointerTag>,
+ count: &OpTy<'tcx, <M as Machine<'mir, 'tcx>>::PointerTag>,
+ ) -> InterpResult<'tcx> {
+ let layout = self.layout_of(dst.layout.ty.builtin_deref(true).unwrap().ty)?;
+
+ let dst = self.read_pointer(&dst)?;
+ let byte = self.read_scalar(&byte)?.to_u8()?;
+ let count = self.read_scalar(&count)?.to_machine_usize(self)?;
+
+ let len = layout
+ .size
+ .checked_mul(count, self)
+ .ok_or_else(|| err_ub_format!("overflow computing total size of `write_bytes`"))?;
+
+ let bytes = std::iter::repeat(byte).take(len.bytes_usize());
+ self.memory.write_bytes(dst, bytes)
+ }
+
pub(crate) fn raw_eq_intrinsic(
&mut self,
lhs: &OpTy<'tcx, <M as Machine<'mir, 'tcx>>::PointerTag>,
diff --git a/compiler/rustc_const_eval/src/interpret/intrinsics/type_name.rs b/compiler/rustc_const_eval/src/interpret/intrinsics/type_name.rs
index 5b4a5ac3577..b77c1c71a15 100644
--- a/compiler/rustc_const_eval/src/interpret/intrinsics/type_name.rs
+++ b/compiler/rustc_const_eval/src/interpret/intrinsics/type_name.rs
@@ -148,7 +148,7 @@ impl<'tcx> Printer<'tcx> for AbsolutePathPrinter<'tcx> {
}
}
-impl PrettyPrinter<'tcx> for AbsolutePathPrinter<'tcx> {
+impl<'tcx> PrettyPrinter<'tcx> for AbsolutePathPrinter<'tcx> {
fn region_should_not_be_omitted(&self, _region: ty::Region<'_>) -> bool {
false
}
diff --git a/compiler/rustc_const_eval/src/interpret/machine.rs b/compiler/rustc_const_eval/src/interpret/machine.rs
index 51207828935..727099848a4 100644
--- a/compiler/rustc_const_eval/src/interpret/machine.rs
+++ b/compiler/rustc_const_eval/src/interpret/machine.rs
@@ -374,12 +374,12 @@ pub trait Machine<'mir, 'tcx>: Sized {
) -> InterpResult<'tcx, Frame<'mir, 'tcx, Self::PointerTag, Self::FrameExtra>>;
/// Borrow the current thread's stack.
- fn stack(
+ fn stack<'a>(
ecx: &'a InterpCx<'mir, 'tcx, Self>,
) -> &'a [Frame<'mir, 'tcx, Self::PointerTag, Self::FrameExtra>];
/// Mutably borrow the current thread's stack.
- fn stack_mut(
+ fn stack_mut<'a>(
ecx: &'a mut InterpCx<'mir, 'tcx, Self>,
) -> &'a mut Vec<Frame<'mir, 'tcx, Self::PointerTag, Self::FrameExtra>>;
diff --git a/compiler/rustc_const_eval/src/interpret/operand.rs b/compiler/rustc_const_eval/src/interpret/operand.rs
index de9e94ce2ac..dfec4509685 100644
--- a/compiler/rustc_const_eval/src/interpret/operand.rs
+++ b/compiler/rustc_const_eval/src/interpret/operand.rs
@@ -106,7 +106,7 @@ pub struct ImmTy<'tcx, Tag: Provenance = AllocId> {
#[cfg(all(target_arch = "x86_64", target_pointer_width = "64"))]
rustc_data_structures::static_assert_size!(ImmTy<'_>, 72);
-impl<Tag: Provenance> std::fmt::Display for ImmTy<'tcx, Tag> {
+impl<Tag: Provenance> std::fmt::Display for ImmTy<'_, Tag> {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
/// Helper function for printing a scalar to a FmtPrinter
fn p<'a, 'tcx, F: std::fmt::Write, Tag: Provenance>(
@@ -512,7 +512,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
self.param_env,
self.layout_of(self.subst_from_current_frame_and_normalize_erasing_regions(
place.ty(&self.frame().body.local_decls, *self.tcx).ty
- ))?,
+ )?)?,
op.layout,
));
Ok(op)
@@ -534,7 +534,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
Constant(ref constant) => {
let val =
- self.subst_from_current_frame_and_normalize_erasing_regions(constant.literal);
+ self.subst_from_current_frame_and_normalize_erasing_regions(constant.literal)?;
// This can still fail:
// * During ConstProp, with `TooGeneric` or since the `requried_consts` were not all
// checked yet.
diff --git a/compiler/rustc_const_eval/src/interpret/operator.rs b/compiler/rustc_const_eval/src/interpret/operator.rs
index ac000b1bb56..48c90e1881a 100644
--- a/compiler/rustc_const_eval/src/interpret/operator.rs
+++ b/compiler/rustc_const_eval/src/interpret/operator.rs
@@ -130,7 +130,12 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
let signed = left_layout.abi.is_signed();
let size = u128::from(left_layout.size.bits());
let overflow = r >= size;
- let r = r % size; // mask to type size
+ // The shift offset is implicitly masked to the type size, to make sure this operation
+ // is always defined. This is the one MIR operator that does *not* directly map to a
+ // single LLVM operation. See
+ // <https://github.com/rust-lang/rust/blob/a3b9405ae7bb6ab4e8103b414e75c44598a10fd2/compiler/rustc_codegen_ssa/src/common.rs#L131-L158>
+ // for the corresponding truncation in our codegen backends.
+ let r = r % size;
let r = u32::try_from(r).unwrap(); // we masked so this will always fit
let result = if signed {
let l = self.sign_extend(l, left_layout) as i128;
@@ -323,9 +328,10 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
self.binary_int_op(bin_op, l, left.layout, r, right.layout)
}
_ if left.layout.ty.is_any_ptr() => {
- // The RHS type must be the same *or an integer type* (for `Offset`).
+ // The RHS type must be a `pointer` *or an integer type* (for `Offset`).
+ // (Even when both sides are pointers, their type might differ, see issue #91636)
assert!(
- right.layout.ty == left.layout.ty || right.layout.ty.is_integral(),
+ right.layout.ty.is_any_ptr() || right.layout.ty.is_integral(),
"Unexpected types for BinOp: {:?} {:?} {:?}",
left.layout.ty,
bin_op,
diff --git a/compiler/rustc_const_eval/src/interpret/place.rs b/compiler/rustc_const_eval/src/interpret/place.rs
index d7f2853fc86..818b95b7fc4 100644
--- a/compiler/rustc_const_eval/src/interpret/place.rs
+++ b/compiler/rustc_const_eval/src/interpret/place.rs
@@ -150,7 +150,7 @@ impl<Tag: Provenance> MemPlace<Tag> {
}
#[inline]
- pub fn offset(
+ pub fn offset<'tcx>(
self,
offset: Size,
meta: MemPlaceMeta<Tag>,
@@ -327,7 +327,7 @@ where
self.memory.get_mut(place.ptr, size, place.align)
}
- /// Check if this mplace is dereferencable and sufficiently aligned.
+ /// Check if this mplace is dereferenceable and sufficiently aligned.
fn check_mplace_access(
&self,
mplace: MPlaceTy<'tcx, M::PointerTag>,
@@ -362,21 +362,15 @@ where
// Re-use parent metadata to determine dynamic field layout.
// With custom DSTS, this *will* execute user-defined code, but the same
// happens at run-time so that's okay.
- let align = match self.size_and_align_of(&base.meta, &field_layout)? {
- Some((_, align)) => align,
- None if offset == Size::ZERO => {
- // An extern type at offset 0, we fall back to its static alignment.
- // FIXME: Once we have made decisions for how to handle size and alignment
- // of `extern type`, this should be adapted. It is just a temporary hack
- // to get some code to work that probably ought to work.
- field_layout.align.abi
+ match self.size_and_align_of(&base.meta, &field_layout)? {
+ Some((_, align)) => (base.meta, offset.align_to(align)),
+ None => {
+ // For unsized types with an extern type tail we perform no adjustments.
+ // NOTE: keep this in sync with `PlaceRef::project_field` in the codegen backend.
+ assert!(matches!(base.meta, MemPlaceMeta::None));
+ (base.meta, offset)
}
- None => span_bug!(
- self.cur_span(),
- "cannot compute offset for extern type field at non-0 offset"
- ),
- };
- (base.meta, offset.align_to(align))
+ }
} else {
// base.meta could be present; we might be accessing a sized field of an unsized
// struct.
@@ -420,7 +414,7 @@ where
// Iterates over all fields of an array. Much more efficient than doing the
// same by repeatedly calling `mplace_array`.
- pub(super) fn mplace_array_fields(
+ pub(super) fn mplace_array_fields<'a>(
&self,
base: &'a MPlaceTy<'tcx, Tag>,
) -> InterpResult<'tcx, impl Iterator<Item = InterpResult<'tcx, MPlaceTy<'tcx, Tag>>> + 'a>
@@ -643,7 +637,7 @@ where
self.param_env,
self.layout_of(self.subst_from_current_frame_and_normalize_erasing_regions(
place.ty(&self.frame().body.local_decls, *self.tcx).ty
- ))?,
+ )?)?,
place_ty.layout,
));
Ok(place_ty)
diff --git a/compiler/rustc_const_eval/src/interpret/step.rs b/compiler/rustc_const_eval/src/interpret/step.rs
index e6037d561de..992cef1cb6a 100644
--- a/compiler/rustc_const_eval/src/interpret/step.rs
+++ b/compiler/rustc_const_eval/src/interpret/step.rs
@@ -242,11 +242,15 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
let elem_size = first.layout.size;
let first_ptr = first.ptr;
let rest_ptr = first_ptr.offset(elem_size, self)?;
+ // For the alignment of `rest_ptr`, we crucially do *not* use `first.align` as
+ // that place might be more aligned than its type mandates (a `u8` array could
+ // be 4-aligned if it sits at the right spot in a struct). Instead we use
+ // `first.layout.align`, i.e., the alignment given by the type.
self.memory.copy_repeatedly(
first_ptr,
first.align,
rest_ptr,
- first.align,
+ first.layout.align.abi,
elem_size,
length - 1,
/*nonoverlapping:*/ true,
@@ -272,7 +276,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
}
NullaryOp(null_op, ty) => {
- let ty = self.subst_from_current_frame_and_normalize_erasing_regions(ty);
+ let ty = self.subst_from_current_frame_and_normalize_erasing_regions(ty)?;
let layout = self.layout_of(ty)?;
if layout.is_unsized() {
// FIXME: This should be a span_bug (#80742)
@@ -298,7 +302,8 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
Cast(cast_kind, ref operand, cast_ty) => {
let src = self.eval_operand(operand, None)?;
- let cast_ty = self.subst_from_current_frame_and_normalize_erasing_regions(cast_ty);
+ let cast_ty =
+ self.subst_from_current_frame_and_normalize_erasing_regions(cast_ty)?;
self.cast(&src, cast_kind, cast_ty, &dest)?;
}
diff --git a/compiler/rustc_const_eval/src/interpret/terminator.rs b/compiler/rustc_const_eval/src/interpret/terminator.rs
index 00208574c55..df177fd9679 100644
--- a/compiler/rustc_const_eval/src/interpret/terminator.rs
+++ b/compiler/rustc_const_eval/src/interpret/terminator.rs
@@ -103,7 +103,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
self.eval_fn_call(
fn_val,
abi,
- &args[..],
+ &args,
ret,
match (cleanup, caller_can_unwind) {
(Some(cleanup), true) => StackPopUnwind::Cleanup(*cleanup),
diff --git a/compiler/rustc_const_eval/src/lib.rs b/compiler/rustc_const_eval/src/lib.rs
index f308e764e86..92854af55bb 100644
--- a/compiler/rustc_const_eval/src/lib.rs
+++ b/compiler/rustc_const_eval/src/lib.rs
@@ -11,8 +11,6 @@ Rust MIR: a lowered representation of Rust.
#![feature(crate_visibility_modifier)]
#![feature(decl_macro)]
#![feature(exact_size_is_empty)]
-#![feature(in_band_lifetimes)]
-#![feature(iter_zip)]
#![feature(let_else)]
#![feature(map_try_insert)]
#![feature(min_specialization)]
diff --git a/compiler/rustc_const_eval/src/transform/check_consts/check.rs b/compiler/rustc_const_eval/src/transform/check_consts/check.rs
index 2854e6fd396..1d5f4630152 100644
--- a/compiler/rustc_const_eval/src/transform/check_consts/check.rs
+++ b/compiler/rustc_const_eval/src/transform/check_consts/check.rs
@@ -1,8 +1,8 @@
//! The `Visitor` responsible for actually checking a `mir::Body` for invalid operations.
use rustc_errors::{Applicability, Diagnostic, ErrorReported};
+use rustc_hir as hir;
use rustc_hir::def_id::DefId;
-use rustc_hir::{self as hir, HirId, LangItem};
use rustc_index::bit_set::BitSet;
use rustc_infer::infer::TyCtxtInferExt;
use rustc_infer::traits::{ImplSource, Obligation, ObligationCause};
@@ -14,8 +14,7 @@ use rustc_middle::ty::{self, adjustment::PointerCast, Instance, InstanceDef, Ty,
use rustc_middle::ty::{Binder, TraitPredicate, TraitRef};
use rustc_mir_dataflow::{self, Analysis};
use rustc_span::{sym, Span, Symbol};
-use rustc_trait_selection::traits::error_reporting::InferCtxtExt;
-use rustc_trait_selection::traits::{self, SelectionContext, TraitEngine};
+use rustc_trait_selection::traits::SelectionContext;
use std::mem;
use std::ops::Deref;
@@ -36,7 +35,7 @@ pub struct Qualifs<'mir, 'tcx> {
needs_non_const_drop: Option<QualifResults<'mir, 'tcx, NeedsNonConstDrop>>,
}
-impl Qualifs<'mir, 'tcx> {
+impl<'mir, 'tcx> Qualifs<'mir, 'tcx> {
/// Returns `true` if `local` is `NeedsDrop` at the given `Location`.
///
/// Only updates the cursor if absolutely necessary
@@ -186,7 +185,7 @@ pub struct Checker<'mir, 'tcx> {
secondary_errors: Vec<Diagnostic>,
}
-impl Deref for Checker<'mir, 'tcx> {
+impl<'mir, 'tcx> Deref for Checker<'mir, 'tcx> {
type Target = ConstCx<'mir, 'tcx>;
fn deref(&self) -> &Self::Target {
@@ -194,7 +193,7 @@ impl Deref for Checker<'mir, 'tcx> {
}
}
-impl Checker<'mir, 'tcx> {
+impl<'mir, 'tcx> Checker<'mir, 'tcx> {
pub fn new(ccx: &'mir ConstCx<'mir, 'tcx>) -> Self {
Checker {
span: ccx.body.span,
@@ -255,16 +254,6 @@ impl Checker<'mir, 'tcx> {
self.visit_body(&body);
}
- // Ensure that the end result is `Sync` in a non-thread local `static`.
- let should_check_for_sync = self.const_kind()
- == hir::ConstContext::Static(hir::Mutability::Not)
- && !tcx.is_thread_local_static(def_id.to_def_id());
-
- if should_check_for_sync {
- let hir_id = tcx.hir().local_def_id_to_hir_id(def_id);
- check_return_ty_is_sync(tcx, &body, hir_id);
- }
-
// If we got through const-checking without emitting any "primary" errors, emit any
// "secondary" errors if they occurred.
let secondary_errors = mem::take(&mut self.secondary_errors);
@@ -284,7 +273,7 @@ impl Checker<'mir, 'tcx> {
struct StorageDeads {
locals: BitSet<Local>,
}
- impl Visitor<'tcx> for StorageDeads {
+ impl<'tcx> Visitor<'tcx> for StorageDeads {
fn visit_statement(&mut self, stmt: &Statement<'tcx>, _: Location) {
if let StatementKind::StorageDead(l) = stmt.kind {
self.locals.insert(l);
@@ -471,7 +460,7 @@ impl Checker<'mir, 'tcx> {
}
}
-impl Visitor<'tcx> for Checker<'mir, 'tcx> {
+impl<'tcx> Visitor<'tcx> for Checker<'_, 'tcx> {
fn visit_basic_block_data(&mut self, bb: BasicBlock, block: &BasicBlockData<'tcx>) {
trace!("visit_basic_block_data: bb={:?} is_cleanup={:?}", bb, block.is_cleanup);
@@ -812,7 +801,7 @@ impl Visitor<'tcx> for Checker<'mir, 'tcx> {
if let Some(trait_id) = tcx.trait_of_item(callee) {
trace!("attempting to call a trait method");
if !self.tcx.features().const_trait_impl {
- self.check_op(ops::FnCallNonConst);
+ self.check_op(ops::FnCallNonConst(Some((callee, substs))));
return;
}
@@ -828,8 +817,7 @@ impl Visitor<'tcx> for Checker<'mir, 'tcx> {
);
let implsrc = tcx.infer_ctxt().enter(|infcx| {
- let mut selcx =
- SelectionContext::with_constness(&infcx, hir::Constness::Const);
+ let mut selcx = SelectionContext::new(&infcx);
selcx.select(&obligation)
});
@@ -868,7 +856,7 @@ impl Visitor<'tcx> for Checker<'mir, 'tcx> {
}
if !nonconst_call_permission {
- self.check_op(ops::FnCallNonConst);
+ self.check_op(ops::FnCallNonConst(None));
return;
}
}
@@ -937,7 +925,7 @@ impl Visitor<'tcx> for Checker<'mir, 'tcx> {
}
if !nonconst_call_permission {
- self.check_op(ops::FnCallNonConst);
+ self.check_op(ops::FnCallNonConst(None));
return;
}
}
@@ -1004,11 +992,12 @@ impl Visitor<'tcx> for Checker<'mir, 'tcx> {
}
let mut err_span = self.span;
+ let ty_of_dropped_place = dropped_place.ty(self.body, self.tcx).ty;
- let ty_needs_non_const_drop = qualifs::NeedsNonConstDrop::in_any_value_of_ty(
- self.ccx,
- dropped_place.ty(self.body, self.tcx).ty,
- );
+ let ty_needs_non_const_drop =
+ qualifs::NeedsNonConstDrop::in_any_value_of_ty(self.ccx, ty_of_dropped_place);
+
+ debug!(?ty_of_dropped_place, ?ty_needs_non_const_drop);
if !ty_needs_non_const_drop {
return;
@@ -1053,21 +1042,7 @@ impl Visitor<'tcx> for Checker<'mir, 'tcx> {
}
}
-fn check_return_ty_is_sync(tcx: TyCtxt<'tcx>, body: &Body<'tcx>, hir_id: HirId) {
- let ty = body.return_ty();
- tcx.infer_ctxt().enter(|infcx| {
- let cause = traits::ObligationCause::new(body.span, hir_id, traits::SharedStatic);
- let mut fulfillment_cx = traits::FulfillmentContext::new();
- let sync_def_id = tcx.require_lang_item(LangItem::Sync, Some(body.span));
- fulfillment_cx.register_bound(&infcx, ty::ParamEnv::empty(), ty, sync_def_id, cause);
- let errors = fulfillment_cx.select_all_or_error(&infcx);
- if !errors.is_empty() {
- infcx.report_fulfillment_errors(&errors, None, false);
- }
- });
-}
-
-fn place_as_reborrow(
+fn place_as_reborrow<'tcx>(
tcx: TyCtxt<'tcx>,
body: &Body<'tcx>,
place: Place<'tcx>,
diff --git a/compiler/rustc_const_eval/src/transform/check_consts/mod.rs b/compiler/rustc_const_eval/src/transform/check_consts/mod.rs
index dc44409d500..b026bb2bad6 100644
--- a/compiler/rustc_const_eval/src/transform/check_consts/mod.rs
+++ b/compiler/rustc_const_eval/src/transform/check_consts/mod.rs
@@ -28,7 +28,7 @@ pub struct ConstCx<'mir, 'tcx> {
pub const_kind: Option<hir::ConstContext>,
}
-impl ConstCx<'mir, 'tcx> {
+impl<'mir, 'tcx> ConstCx<'mir, 'tcx> {
pub fn new(tcx: TyCtxt<'tcx>, body: &'mir mir::Body<'tcx>) -> Self {
let def_id = body.source.def_id().expect_local();
let param_env = tcx.param_env(def_id);
@@ -72,11 +72,7 @@ impl ConstCx<'mir, 'tcx> {
}
}
-pub fn rustc_allow_const_fn_unstable(
- tcx: TyCtxt<'tcx>,
- def_id: DefId,
- feature_gate: Symbol,
-) -> bool {
+pub fn rustc_allow_const_fn_unstable(tcx: TyCtxt<'_>, def_id: DefId, feature_gate: Symbol) -> bool {
let attrs = tcx.get_attrs(def_id);
attr::rustc_allow_const_fn_unstable(&tcx.sess, attrs).any(|name| name == feature_gate)
}
@@ -89,7 +85,7 @@ pub fn rustc_allow_const_fn_unstable(
// functions can be called in a const-context by users of the stable compiler. "const-stable"
// functions are subject to more stringent restrictions than "const-unstable" functions: They
// cannot use unstable features and can only call other "const-stable" functions.
-pub fn is_const_stable_const_fn(tcx: TyCtxt<'tcx>, def_id: DefId) -> bool {
+pub fn is_const_stable_const_fn(tcx: TyCtxt<'_>, def_id: DefId) -> bool {
use attr::{ConstStability, Stability, StabilityLevel};
// A default body marked const is not const-stable because const
diff --git a/compiler/rustc_const_eval/src/transform/check_consts/ops.rs b/compiler/rustc_const_eval/src/transform/check_consts/ops.rs
index 6391c886009..24c4a4915e5 100644
--- a/compiler/rustc_const_eval/src/transform/check_consts/ops.rs
+++ b/compiler/rustc_const_eval/src/transform/check_consts/ops.rs
@@ -1,12 +1,14 @@
//! Concrete error types for all operations which may be invalid in a certain const context.
-use rustc_errors::{struct_span_err, DiagnosticBuilder};
+use rustc_errors::{struct_span_err, Applicability, DiagnosticBuilder};
use rustc_hir as hir;
use rustc_hir::def_id::DefId;
-use rustc_middle::mir;
+use rustc_middle::ty::subst::{GenericArgKind, SubstsRef};
+use rustc_middle::{mir, ty::AssocKind};
use rustc_session::parse::feature_err;
use rustc_span::symbol::sym;
-use rustc_span::{Span, Symbol};
+use rustc_span::{symbol::Ident, Span, Symbol};
+use rustc_span::{BytePos, Pos};
use super::ConstCx;
@@ -37,7 +39,7 @@ pub trait NonConstOp: std::fmt::Debug {
DiagnosticImportance::Primary
}
- fn build_error(&self, ccx: &ConstCx<'_, 'tcx>, span: Span) -> DiagnosticBuilder<'tcx>;
+ fn build_error<'tcx>(&self, ccx: &ConstCx<'_, 'tcx>, span: Span) -> DiagnosticBuilder<'tcx>;
}
#[derive(Debug)]
@@ -51,7 +53,7 @@ impl NonConstOp for FloatingPointOp {
}
}
- fn build_error(&self, ccx: &ConstCx<'_, 'tcx>, span: Span) -> DiagnosticBuilder<'tcx> {
+ fn build_error<'tcx>(&self, ccx: &ConstCx<'_, 'tcx>, span: Span) -> DiagnosticBuilder<'tcx> {
feature_err(
&ccx.tcx.sess.parse_sess,
sym::const_fn_floating_point_arithmetic,
@@ -65,24 +67,78 @@ impl NonConstOp for FloatingPointOp {
#[derive(Debug)]
pub struct FnCallIndirect;
impl NonConstOp for FnCallIndirect {
- fn build_error(&self, ccx: &ConstCx<'_, 'tcx>, span: Span) -> DiagnosticBuilder<'tcx> {
+ fn build_error<'tcx>(&self, ccx: &ConstCx<'_, 'tcx>, span: Span) -> DiagnosticBuilder<'tcx> {
ccx.tcx.sess.struct_span_err(span, "function pointers are not allowed in const fn")
}
}
/// A function call where the callee is not marked as `const`.
#[derive(Debug)]
-pub struct FnCallNonConst;
-impl NonConstOp for FnCallNonConst {
- fn build_error(&self, ccx: &ConstCx<'_, 'tcx>, span: Span) -> DiagnosticBuilder<'tcx> {
- struct_span_err!(
+pub struct FnCallNonConst<'tcx>(pub Option<(DefId, SubstsRef<'tcx>)>);
+impl<'a> NonConstOp for FnCallNonConst<'a> {
+ fn build_error<'tcx>(&self, ccx: &ConstCx<'_, 'tcx>, span: Span) -> DiagnosticBuilder<'tcx> {
+ let mut err = struct_span_err!(
ccx.tcx.sess,
span,
E0015,
"calls in {}s are limited to constant functions, \
tuple structs and tuple variants",
ccx.const_kind(),
- )
+ );
+
+ if let FnCallNonConst(Some((callee, substs))) = *self {
+ if let Some(trait_def_id) = ccx.tcx.lang_items().eq_trait() {
+ if let Some(eq_item) = ccx.tcx.associated_items(trait_def_id).find_by_name_and_kind(
+ ccx.tcx,
+ Ident::with_dummy_span(sym::eq),
+ AssocKind::Fn,
+ trait_def_id,
+ ) {
+ if callee == eq_item.def_id && substs.len() == 2 {
+ match (substs[0].unpack(), substs[1].unpack()) {
+ (GenericArgKind::Type(self_ty), GenericArgKind::Type(rhs_ty))
+ if self_ty == rhs_ty
+ && self_ty.is_ref()
+ && self_ty.peel_refs().is_primitive() =>
+ {
+ let mut num_refs = 0;
+ let mut tmp_ty = self_ty;
+ while let rustc_middle::ty::Ref(_, inner_ty, _) = tmp_ty.kind() {
+ num_refs += 1;
+ tmp_ty = inner_ty;
+ }
+ let deref = "*".repeat(num_refs);
+
+ if let Ok(call_str) =
+ ccx.tcx.sess.source_map().span_to_snippet(span)
+ {
+ if let Some(eq_idx) = call_str.find("==") {
+ if let Some(rhs_idx) = call_str[(eq_idx + 2)..]
+ .find(|c: char| !c.is_whitespace())
+ {
+ let rhs_pos = span.lo()
+ + BytePos::from_usize(eq_idx + 2 + rhs_idx);
+ let rhs_span = span.with_lo(rhs_pos).with_hi(rhs_pos);
+ err.multipart_suggestion(
+ "consider dereferencing here",
+ vec![
+ (span.shrink_to_lo(), deref.clone()),
+ (rhs_span, deref),
+ ],
+ Applicability::MachineApplicable,
+ );
+ }
+ }
+ }
+ }
+ _ => {}
+ }
+ }
+ }
+ }
+ }
+
+ err
}
}
@@ -93,7 +149,7 @@ impl NonConstOp for FnCallNonConst {
pub struct FnCallUnstable(pub DefId, pub Option<Symbol>);
impl NonConstOp for FnCallUnstable {
- fn build_error(&self, ccx: &ConstCx<'_, 'tcx>, span: Span) -> DiagnosticBuilder<'tcx> {
+ fn build_error<'tcx>(&self, ccx: &ConstCx<'_, 'tcx>, span: Span) -> DiagnosticBuilder<'tcx> {
let FnCallUnstable(def_id, feature) = *self;
let mut err = ccx.tcx.sess.struct_span_err(
@@ -127,7 +183,7 @@ impl NonConstOp for FnPtrCast {
}
}
- fn build_error(&self, ccx: &ConstCx<'_, 'tcx>, span: Span) -> DiagnosticBuilder<'tcx> {
+ fn build_error<'tcx>(&self, ccx: &ConstCx<'_, 'tcx>, span: Span) -> DiagnosticBuilder<'tcx> {
feature_err(
&ccx.tcx.sess.parse_sess,
sym::const_fn_fn_ptr_basics,
@@ -148,7 +204,7 @@ impl NonConstOp for Generator {
}
}
- fn build_error(&self, ccx: &ConstCx<'_, 'tcx>, span: Span) -> DiagnosticBuilder<'tcx> {
+ fn build_error<'tcx>(&self, ccx: &ConstCx<'_, 'tcx>, span: Span) -> DiagnosticBuilder<'tcx> {
let msg = format!("{}s are not allowed in {}s", self.0, ccx.const_kind());
if let hir::GeneratorKind::Async(hir::AsyncGeneratorKind::Block) = self.0 {
feature_err(&ccx.tcx.sess.parse_sess, sym::const_async_blocks, span, &msg)
@@ -161,7 +217,7 @@ impl NonConstOp for Generator {
#[derive(Debug)]
pub struct HeapAllocation;
impl NonConstOp for HeapAllocation {
- fn build_error(&self, ccx: &ConstCx<'_, 'tcx>, span: Span) -> DiagnosticBuilder<'tcx> {
+ fn build_error<'tcx>(&self, ccx: &ConstCx<'_, 'tcx>, span: Span) -> DiagnosticBuilder<'tcx> {
let mut err = struct_span_err!(
ccx.tcx.sess,
span,
@@ -185,7 +241,7 @@ impl NonConstOp for HeapAllocation {
#[derive(Debug)]
pub struct InlineAsm;
impl NonConstOp for InlineAsm {
- fn build_error(&self, ccx: &ConstCx<'_, 'tcx>, span: Span) -> DiagnosticBuilder<'tcx> {
+ fn build_error<'tcx>(&self, ccx: &ConstCx<'_, 'tcx>, span: Span) -> DiagnosticBuilder<'tcx> {
struct_span_err!(
ccx.tcx.sess,
span,
@@ -201,7 +257,7 @@ pub struct LiveDrop {
pub dropped_at: Option<Span>,
}
impl NonConstOp for LiveDrop {
- fn build_error(&self, ccx: &ConstCx<'_, 'tcx>, span: Span) -> DiagnosticBuilder<'tcx> {
+ fn build_error<'tcx>(&self, ccx: &ConstCx<'_, 'tcx>, span: Span) -> DiagnosticBuilder<'tcx> {
let mut err = struct_span_err!(
ccx.tcx.sess,
span,
@@ -229,7 +285,7 @@ impl NonConstOp for TransientCellBorrow {
// not additionally emit a feature gate error if activating the feature gate won't work.
DiagnosticImportance::Secondary
}
- fn build_error(&self, ccx: &ConstCx<'_, 'tcx>, span: Span) -> DiagnosticBuilder<'tcx> {
+ fn build_error<'tcx>(&self, ccx: &ConstCx<'_, 'tcx>, span: Span) -> DiagnosticBuilder<'tcx> {
feature_err(
&ccx.tcx.sess.parse_sess,
sym::const_refs_to_cell,
@@ -245,7 +301,7 @@ impl NonConstOp for TransientCellBorrow {
/// it in the future for static items.
pub struct CellBorrow;
impl NonConstOp for CellBorrow {
- fn build_error(&self, ccx: &ConstCx<'_, 'tcx>, span: Span) -> DiagnosticBuilder<'tcx> {
+ fn build_error<'tcx>(&self, ccx: &ConstCx<'_, 'tcx>, span: Span) -> DiagnosticBuilder<'tcx> {
let mut err = struct_span_err!(
ccx.tcx.sess,
span,
@@ -292,7 +348,7 @@ impl NonConstOp for MutBorrow {
DiagnosticImportance::Secondary
}
- fn build_error(&self, ccx: &ConstCx<'_, 'tcx>, span: Span) -> DiagnosticBuilder<'tcx> {
+ fn build_error<'tcx>(&self, ccx: &ConstCx<'_, 'tcx>, span: Span) -> DiagnosticBuilder<'tcx> {
let raw = match self.0 {
hir::BorrowKind::Raw => "raw ",
hir::BorrowKind::Ref => "",
@@ -331,7 +387,7 @@ impl NonConstOp for TransientMutBorrow {
Status::Unstable(sym::const_mut_refs)
}
- fn build_error(&self, ccx: &ConstCx<'_, 'tcx>, span: Span) -> DiagnosticBuilder<'tcx> {
+ fn build_error<'tcx>(&self, ccx: &ConstCx<'_, 'tcx>, span: Span) -> DiagnosticBuilder<'tcx> {
let raw = match self.0 {
hir::BorrowKind::Raw => "raw ",
hir::BorrowKind::Ref => "",
@@ -358,7 +414,7 @@ impl NonConstOp for MutDeref {
DiagnosticImportance::Secondary
}
- fn build_error(&self, ccx: &ConstCx<'_, 'tcx>, span: Span) -> DiagnosticBuilder<'tcx> {
+ fn build_error<'tcx>(&self, ccx: &ConstCx<'_, 'tcx>, span: Span) -> DiagnosticBuilder<'tcx> {
feature_err(
&ccx.tcx.sess.parse_sess,
sym::const_mut_refs,
@@ -372,7 +428,7 @@ impl NonConstOp for MutDeref {
#[derive(Debug)]
pub struct PanicNonStr;
impl NonConstOp for PanicNonStr {
- fn build_error(&self, ccx: &ConstCx<'_, 'tcx>, span: Span) -> DiagnosticBuilder<'tcx> {
+ fn build_error<'tcx>(&self, ccx: &ConstCx<'_, 'tcx>, span: Span) -> DiagnosticBuilder<'tcx> {
ccx.tcx.sess.struct_span_err(
span,
"argument to `panic!()` in a const context must have type `&str`",
@@ -386,7 +442,7 @@ impl NonConstOp for PanicNonStr {
#[derive(Debug)]
pub struct RawPtrComparison;
impl NonConstOp for RawPtrComparison {
- fn build_error(&self, ccx: &ConstCx<'_, 'tcx>, span: Span) -> DiagnosticBuilder<'tcx> {
+ fn build_error<'tcx>(&self, ccx: &ConstCx<'_, 'tcx>, span: Span) -> DiagnosticBuilder<'tcx> {
let mut err = ccx
.tcx
.sess
@@ -406,7 +462,7 @@ impl NonConstOp for RawMutPtrDeref {
Status::Unstable(sym::const_mut_refs)
}
- fn build_error(&self, ccx: &ConstCx<'_, 'tcx>, span: Span) -> DiagnosticBuilder<'tcx> {
+ fn build_error<'tcx>(&self, ccx: &ConstCx<'_, 'tcx>, span: Span) -> DiagnosticBuilder<'tcx> {
feature_err(
&ccx.tcx.sess.parse_sess,
sym::const_mut_refs,
@@ -422,7 +478,7 @@ impl NonConstOp for RawMutPtrDeref {
#[derive(Debug)]
pub struct RawPtrToIntCast;
impl NonConstOp for RawPtrToIntCast {
- fn build_error(&self, ccx: &ConstCx<'_, 'tcx>, span: Span) -> DiagnosticBuilder<'tcx> {
+ fn build_error<'tcx>(&self, ccx: &ConstCx<'_, 'tcx>, span: Span) -> DiagnosticBuilder<'tcx> {
let mut err = ccx
.tcx
.sess
@@ -447,7 +503,7 @@ impl NonConstOp for StaticAccess {
}
}
- fn build_error(&self, ccx: &ConstCx<'_, 'tcx>, span: Span) -> DiagnosticBuilder<'tcx> {
+ fn build_error<'tcx>(&self, ccx: &ConstCx<'_, 'tcx>, span: Span) -> DiagnosticBuilder<'tcx> {
let mut err = struct_span_err!(
ccx.tcx.sess,
span,
@@ -473,7 +529,7 @@ impl NonConstOp for StaticAccess {
#[derive(Debug)]
pub struct ThreadLocalAccess;
impl NonConstOp for ThreadLocalAccess {
- fn build_error(&self, ccx: &ConstCx<'_, 'tcx>, span: Span) -> DiagnosticBuilder<'tcx> {
+ fn build_error<'tcx>(&self, ccx: &ConstCx<'_, 'tcx>, span: Span) -> DiagnosticBuilder<'tcx> {
struct_span_err!(
ccx.tcx.sess,
span,
@@ -504,7 +560,11 @@ pub mod ty {
}
}
- fn build_error(&self, ccx: &ConstCx<'_, 'tcx>, span: Span) -> DiagnosticBuilder<'tcx> {
+ fn build_error<'tcx>(
+ &self,
+ ccx: &ConstCx<'_, 'tcx>,
+ span: Span,
+ ) -> DiagnosticBuilder<'tcx> {
feature_err(
&ccx.tcx.sess.parse_sess,
sym::const_mut_refs,
@@ -534,7 +594,11 @@ pub mod ty {
}
}
- fn build_error(&self, ccx: &ConstCx<'_, 'tcx>, span: Span) -> DiagnosticBuilder<'tcx> {
+ fn build_error<'tcx>(
+ &self,
+ ccx: &ConstCx<'_, 'tcx>,
+ span: Span,
+ ) -> DiagnosticBuilder<'tcx> {
feature_err(
&ccx.tcx.sess.parse_sess,
sym::const_fn_fn_ptr_basics,
@@ -551,7 +615,11 @@ pub mod ty {
Status::Unstable(sym::const_impl_trait)
}
- fn build_error(&self, ccx: &ConstCx<'_, 'tcx>, span: Span) -> DiagnosticBuilder<'tcx> {
+ fn build_error<'tcx>(
+ &self,
+ ccx: &ConstCx<'_, 'tcx>,
+ span: Span,
+ ) -> DiagnosticBuilder<'tcx> {
feature_err(
&ccx.tcx.sess.parse_sess,
sym::const_impl_trait,
@@ -581,7 +649,11 @@ pub mod ty {
}
}
- fn build_error(&self, ccx: &ConstCx<'_, 'tcx>, span: Span) -> DiagnosticBuilder<'tcx> {
+ fn build_error<'tcx>(
+ &self,
+ ccx: &ConstCx<'_, 'tcx>,
+ span: Span,
+ ) -> DiagnosticBuilder<'tcx> {
let mut err = feature_err(
&ccx.tcx.sess.parse_sess,
sym::const_fn_trait_bound,
@@ -620,7 +692,11 @@ pub mod ty {
}
}
- fn build_error(&self, ccx: &ConstCx<'_, 'tcx>, span: Span) -> DiagnosticBuilder<'tcx> {
+ fn build_error<'tcx>(
+ &self,
+ ccx: &ConstCx<'_, 'tcx>,
+ span: Span,
+ ) -> DiagnosticBuilder<'tcx> {
let mut err = feature_err(
&ccx.tcx.sess.parse_sess,
sym::const_fn_trait_bound,
@@ -647,7 +723,11 @@ pub mod ty {
Status::Unstable(sym::const_trait_bound_opt_out)
}
- fn build_error(&self, ccx: &ConstCx<'_, 'tcx>, span: Span) -> DiagnosticBuilder<'tcx> {
+ fn build_error<'tcx>(
+ &self,
+ ccx: &ConstCx<'_, 'tcx>,
+ span: Span,
+ ) -> DiagnosticBuilder<'tcx> {
feature_err(
&ccx.tcx.sess.parse_sess,
sym::const_trait_bound_opt_out,
diff --git a/compiler/rustc_const_eval/src/transform/check_consts/post_drop_elaboration.rs b/compiler/rustc_const_eval/src/transform/check_consts/post_drop_elaboration.rs
index 7a2be3c3bad..4e210f66353 100644
--- a/compiler/rustc_const_eval/src/transform/check_consts/post_drop_elaboration.rs
+++ b/compiler/rustc_const_eval/src/transform/check_consts/post_drop_elaboration.rs
@@ -23,7 +23,7 @@ pub fn checking_enabled(ccx: &ConstCx<'_, '_>) -> bool {
///
/// This is separate from the rest of the const checking logic because it must run after drop
/// elaboration.
-pub fn check_live_drops(tcx: TyCtxt<'tcx>, body: &mir::Body<'tcx>) {
+pub fn check_live_drops<'tcx>(tcx: TyCtxt<'tcx>, body: &mir::Body<'tcx>) {
let def_id = body.source.def_id().expect_local();
let const_kind = tcx.hir().body_const_context(def_id);
if const_kind.is_none() {
@@ -50,7 +50,7 @@ struct CheckLiveDrops<'mir, 'tcx> {
}
// So we can access `body` and `tcx`.
-impl std::ops::Deref for CheckLiveDrops<'mir, 'tcx> {
+impl<'mir, 'tcx> std::ops::Deref for CheckLiveDrops<'mir, 'tcx> {
type Target = ConstCx<'mir, 'tcx>;
fn deref(&self) -> &Self::Target {
@@ -58,13 +58,13 @@ impl std::ops::Deref for CheckLiveDrops<'mir, 'tcx> {
}
}
-impl CheckLiveDrops<'mir, 'tcx> {
+impl CheckLiveDrops<'_, '_> {
fn check_live_drop(&self, span: Span) {
ops::LiveDrop { dropped_at: None }.build_error(self.ccx, span).emit();
}
}
-impl Visitor<'tcx> for CheckLiveDrops<'mir, 'tcx> {
+impl<'tcx> Visitor<'tcx> for CheckLiveDrops<'_, 'tcx> {
fn visit_basic_block_data(&mut self, bb: BasicBlock, block: &mir::BasicBlockData<'tcx>) {
trace!("visit_basic_block_data: bb={:?} is_cleanup={:?}", bb, block.is_cleanup);
@@ -80,7 +80,8 @@ impl Visitor<'tcx> for CheckLiveDrops<'mir, 'tcx> {
trace!("visit_terminator: terminator={:?} location={:?}", terminator, location);
match &terminator.kind {
- mir::TerminatorKind::Drop { place: dropped_place, .. } => {
+ mir::TerminatorKind::Drop { place: dropped_place, .. }
+ | mir::TerminatorKind::DropAndReplace { place: dropped_place, .. } => {
let dropped_ty = dropped_place.ty(self.body, self.tcx).ty;
if !NeedsNonConstDrop::in_any_value_of_ty(self.ccx, dropped_ty) {
// Instead of throwing a bug, we just return here. This is because we have to
@@ -104,11 +105,6 @@ impl Visitor<'tcx> for CheckLiveDrops<'mir, 'tcx> {
}
}
- mir::TerminatorKind::DropAndReplace { .. } => span_bug!(
- terminator.source_info.span,
- "`DropAndReplace` should be removed by drop elaboration",
- ),
-
mir::TerminatorKind::Abort
| mir::TerminatorKind::Call { .. }
| mir::TerminatorKind::Assert { .. }
diff --git a/compiler/rustc_const_eval/src/transform/check_consts/qualifs.rs b/compiler/rustc_const_eval/src/transform/check_consts/qualifs.rs
index abc5a3c6a52..a8077b258bb 100644
--- a/compiler/rustc_const_eval/src/transform/check_consts/qualifs.rs
+++ b/compiler/rustc_const_eval/src/transform/check_consts/qualifs.rs
@@ -3,7 +3,6 @@
//! See the `Qualif` trait for more info.
use rustc_errors::ErrorReported;
-use rustc_hir as hir;
use rustc_infer::infer::TyCtxtInferExt;
use rustc_middle::mir::*;
use rustc_middle::ty::{self, subst::SubstsRef, AdtDef, Ty};
@@ -14,7 +13,7 @@ use rustc_trait_selection::traits::{
use super::ConstCx;
-pub fn in_any_value_of_ty(
+pub fn in_any_value_of_ty<'tcx>(
cx: &ConstCx<'_, 'tcx>,
ty: Ty<'tcx>,
error_occured: Option<ErrorReported>,
@@ -59,7 +58,7 @@ pub trait Qualif {
/// from a call to another function.
///
/// It also determines the `Qualif`s for primitive types.
- fn in_any_value_of_ty(cx: &ConstCx<'_, 'tcx>, ty: Ty<'tcx>) -> bool;
+ fn in_any_value_of_ty<'tcx>(cx: &ConstCx<'_, 'tcx>, ty: Ty<'tcx>) -> bool;
/// Returns `true` if this `Qualif` is inherent to the given struct or enum.
///
@@ -69,7 +68,7 @@ pub trait Qualif {
/// with a custom `Drop` impl is inherently `NeedsDrop`.
///
/// Returning `true` for `in_adt_inherently` but `false` for `in_any_value_of_ty` is unsound.
- fn in_adt_inherently(
+ fn in_adt_inherently<'tcx>(
cx: &ConstCx<'_, 'tcx>,
adt: &'tcx AdtDef,
substs: SubstsRef<'tcx>,
@@ -90,11 +89,15 @@ impl Qualif for HasMutInterior {
qualifs.has_mut_interior
}
- fn in_any_value_of_ty(cx: &ConstCx<'_, 'tcx>, ty: Ty<'tcx>) -> bool {
+ fn in_any_value_of_ty<'tcx>(cx: &ConstCx<'_, 'tcx>, ty: Ty<'tcx>) -> bool {
!ty.is_freeze(cx.tcx.at(DUMMY_SP), cx.param_env)
}
- fn in_adt_inherently(cx: &ConstCx<'_, 'tcx>, adt: &'tcx AdtDef, _: SubstsRef<'tcx>) -> bool {
+ fn in_adt_inherently<'tcx>(
+ cx: &ConstCx<'_, 'tcx>,
+ adt: &'tcx AdtDef,
+ _: SubstsRef<'tcx>,
+ ) -> bool {
// Exactly one type, `UnsafeCell`, has the `HasMutInterior` qualif inherently.
// It arises structurally for all other types.
Some(adt.did) == cx.tcx.lang_items().unsafe_cell_type()
@@ -116,11 +119,15 @@ impl Qualif for NeedsDrop {
qualifs.needs_drop
}
- fn in_any_value_of_ty(cx: &ConstCx<'_, 'tcx>, ty: Ty<'tcx>) -> bool {
+ fn in_any_value_of_ty<'tcx>(cx: &ConstCx<'_, 'tcx>, ty: Ty<'tcx>) -> bool {
ty.needs_drop(cx.tcx, cx.param_env)
}
- fn in_adt_inherently(cx: &ConstCx<'_, 'tcx>, adt: &'tcx AdtDef, _: SubstsRef<'tcx>) -> bool {
+ fn in_adt_inherently<'tcx>(
+ cx: &ConstCx<'_, 'tcx>,
+ adt: &'tcx AdtDef,
+ _: SubstsRef<'tcx>,
+ ) -> bool {
adt.has_dtor(cx.tcx)
}
}
@@ -138,7 +145,7 @@ impl Qualif for NeedsNonConstDrop {
qualifs.needs_non_const_drop
}
- fn in_any_value_of_ty(cx: &ConstCx<'_, 'tcx>, mut ty: Ty<'tcx>) -> bool {
+ fn in_any_value_of_ty<'tcx>(cx: &ConstCx<'_, 'tcx>, mut ty: Ty<'tcx>) -> bool {
// Avoid selecting for simple cases.
match ty::util::needs_drop_components(ty, &cx.tcx.data_layout).as_deref() {
Ok([]) => return false,
@@ -167,7 +174,7 @@ impl Qualif for NeedsNonConstDrop {
);
let implsrc = cx.tcx.infer_ctxt().enter(|infcx| {
- let mut selcx = SelectionContext::with_constness(&infcx, hir::Constness::Const);
+ let mut selcx = SelectionContext::new(&infcx);
selcx.select(&obligation)
});
!matches!(
@@ -178,7 +185,11 @@ impl Qualif for NeedsNonConstDrop {
)
}
- fn in_adt_inherently(cx: &ConstCx<'_, 'tcx>, adt: &'tcx AdtDef, _: SubstsRef<'tcx>) -> bool {
+ fn in_adt_inherently<'tcx>(
+ cx: &ConstCx<'_, 'tcx>,
+ adt: &'tcx AdtDef,
+ _: SubstsRef<'tcx>,
+ ) -> bool {
adt.has_non_const_dtor(cx.tcx)
}
}
@@ -193,7 +204,7 @@ impl Qualif for CustomEq {
qualifs.custom_eq
}
- fn in_any_value_of_ty(cx: &ConstCx<'_, 'tcx>, ty: Ty<'tcx>) -> bool {
+ fn in_any_value_of_ty<'tcx>(cx: &ConstCx<'_, 'tcx>, ty: Ty<'tcx>) -> bool {
// If *any* component of a composite data type does not implement `Structural{Partial,}Eq`,
// we know that at least some values of that type are not structural-match. I say "some"
// because that component may be part of an enum variant (e.g.,
@@ -203,7 +214,7 @@ impl Qualif for CustomEq {
traits::search_for_structural_match_violation(id, cx.body.span, cx.tcx, ty).is_some()
}
- fn in_adt_inherently(
+ fn in_adt_inherently<'tcx>(
cx: &ConstCx<'_, 'tcx>,
adt: &'tcx AdtDef,
substs: SubstsRef<'tcx>,
@@ -216,7 +227,11 @@ impl Qualif for CustomEq {
// FIXME: Use `mir::visit::Visitor` for the `in_*` functions if/when it supports early return.
/// Returns `true` if this `Rvalue` contains qualif `Q`.
-pub fn in_rvalue<Q, F>(cx: &ConstCx<'_, 'tcx>, in_local: &mut F, rvalue: &Rvalue<'tcx>) -> bool
+pub fn in_rvalue<'tcx, Q, F>(
+ cx: &ConstCx<'_, 'tcx>,
+ in_local: &mut F,
+ rvalue: &Rvalue<'tcx>,
+) -> bool
where
Q: Qualif,
F: FnMut(Local) -> bool,
@@ -271,7 +286,7 @@ where
}
/// Returns `true` if this `Place` contains qualif `Q`.
-pub fn in_place<Q, F>(cx: &ConstCx<'_, 'tcx>, in_local: &mut F, place: PlaceRef<'tcx>) -> bool
+pub fn in_place<'tcx, Q, F>(cx: &ConstCx<'_, 'tcx>, in_local: &mut F, place: PlaceRef<'tcx>) -> bool
where
Q: Qualif,
F: FnMut(Local) -> bool,
@@ -303,7 +318,11 @@ where
}
/// Returns `true` if this `Operand` contains qualif `Q`.
-pub fn in_operand<Q, F>(cx: &ConstCx<'_, 'tcx>, in_local: &mut F, operand: &Operand<'tcx>) -> bool
+pub fn in_operand<'tcx, Q, F>(
+ cx: &ConstCx<'_, 'tcx>,
+ in_local: &mut F,
+ operand: &Operand<'tcx>,
+) -> bool
where
Q: Qualif,
F: FnMut(Local) -> bool,
diff --git a/compiler/rustc_const_eval/src/transform/check_consts/resolver.rs b/compiler/rustc_const_eval/src/transform/check_consts/resolver.rs
index b70b38754c9..fd7febc17a3 100644
--- a/compiler/rustc_const_eval/src/transform/check_consts/resolver.rs
+++ b/compiler/rustc_const_eval/src/transform/check_consts/resolver.rs
@@ -7,6 +7,7 @@ use rustc_middle::mir::visit::Visitor;
use rustc_middle::mir::{self, BasicBlock, Local, Location, Statement, StatementKind};
use rustc_mir_dataflow::fmt::DebugWithContext;
use rustc_mir_dataflow::JoinSemiLattice;
+use rustc_mir_dataflow::{Analysis, AnalysisDomain, CallReturnPlaces};
use rustc_span::DUMMY_SP;
use std::fmt;
@@ -27,7 +28,7 @@ struct TransferFunction<'a, 'mir, 'tcx, Q> {
_qualif: PhantomData<Q>,
}
-impl<Q> TransferFunction<'a, 'mir, 'tcx, Q>
+impl<'a, 'mir, 'tcx, Q> TransferFunction<'a, 'mir, 'tcx, Q>
where
Q: Qualif,
{
@@ -80,18 +81,18 @@ where
fn apply_call_return_effect(
&mut self,
_block: BasicBlock,
- _func: &mir::Operand<'tcx>,
- _args: &[mir::Operand<'tcx>],
- return_place: mir::Place<'tcx>,
+ return_places: CallReturnPlaces<'_, 'tcx>,
) {
- // We cannot reason about another function's internals, so use conservative type-based
- // qualification for the result of a function call.
- let return_ty = return_place.ty(self.ccx.body, self.ccx.tcx).ty;
- let qualif = Q::in_any_value_of_ty(self.ccx, return_ty);
+ return_places.for_each(|place| {
+ // We cannot reason about another function's internals, so use conservative type-based
+ // qualification for the result of a function call.
+ let return_ty = place.ty(self.ccx.body, self.ccx.tcx).ty;
+ let qualif = Q::in_any_value_of_ty(self.ccx, return_ty);
- if !return_place.is_indirect() {
- self.assign_qualif_direct(&return_place, qualif);
- }
+ if !place.is_indirect() {
+ self.assign_qualif_direct(&place, qualif);
+ }
+ });
}
fn address_of_allows_mutation(&self, _mt: mir::Mutability, _place: mir::Place<'tcx>) -> bool {
@@ -126,7 +127,7 @@ where
}
}
-impl<Q> Visitor<'tcx> for TransferFunction<'_, '_, 'tcx, Q>
+impl<'tcx, Q> Visitor<'tcx> for TransferFunction<'_, '_, 'tcx, Q>
where
Q: Qualif,
{
@@ -329,7 +330,7 @@ impl JoinSemiLattice for State {
}
}
-impl<Q> rustc_mir_dataflow::AnalysisDomain<'tcx> for FlowSensitiveAnalysis<'_, '_, 'tcx, Q>
+impl<'tcx, Q> AnalysisDomain<'tcx> for FlowSensitiveAnalysis<'_, '_, 'tcx, Q>
where
Q: Qualif,
{
@@ -349,7 +350,7 @@ where
}
}
-impl<Q> rustc_mir_dataflow::Analysis<'tcx> for FlowSensitiveAnalysis<'_, '_, 'tcx, Q>
+impl<'tcx, Q> Analysis<'tcx> for FlowSensitiveAnalysis<'_, '_, 'tcx, Q>
where
Q: Qualif,
{
@@ -375,10 +376,8 @@ where
&self,
state: &mut Self::Domain,
block: BasicBlock,
- func: &mir::Operand<'tcx>,
- args: &[mir::Operand<'tcx>],
- return_place: mir::Place<'tcx>,
+ return_places: CallReturnPlaces<'_, 'tcx>,
) {
- self.transfer_function(state).apply_call_return_effect(block, func, args, return_place)
+ self.transfer_function(state).apply_call_return_effect(block, return_places)
}
}
diff --git a/compiler/rustc_const_eval/src/transform/mod.rs b/compiler/rustc_const_eval/src/transform/mod.rs
index 38c28f34934..a2928bdf51b 100644
--- a/compiler/rustc_const_eval/src/transform/mod.rs
+++ b/compiler/rustc_const_eval/src/transform/mod.rs
@@ -1,5 +1,3 @@
pub mod check_consts;
pub mod promote_consts;
pub mod validate;
-
-pub use rustc_middle::mir::MirPass;
diff --git a/compiler/rustc_const_eval/src/transform/promote_consts.rs b/compiler/rustc_const_eval/src/transform/promote_consts.rs
index a92b20f5cb5..1537de993d1 100644
--- a/compiler/rustc_const_eval/src/transform/promote_consts.rs
+++ b/compiler/rustc_const_eval/src/transform/promote_consts.rs
@@ -27,7 +27,6 @@ use std::cell::Cell;
use std::{cmp, iter, mem};
use crate::transform::check_consts::{qualifs, ConstCx};
-use crate::transform::MirPass;
/// A `MirPass` for promotion.
///
@@ -42,6 +41,10 @@ pub struct PromoteTemps<'tcx> {
}
impl<'tcx> MirPass<'tcx> for PromoteTemps<'tcx> {
+ fn phase_change(&self) -> Option<MirPhase> {
+ Some(MirPhase::ConstPromotion)
+ }
+
fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
// There's not really any point in promoting errorful MIR.
//
@@ -165,8 +168,8 @@ impl<'tcx> Visitor<'tcx> for Collector<'_, 'tcx> {
}
}
-pub fn collect_temps_and_candidates(
- ccx: &ConstCx<'mir, 'tcx>,
+pub fn collect_temps_and_candidates<'tcx>(
+ ccx: &ConstCx<'_, 'tcx>,
rpo: &mut ReversePostorder<'_, 'tcx>,
) -> (IndexVec<Local, TempState>, Vec<Candidate>) {
let mut collector = Collector {
@@ -188,7 +191,7 @@ struct Validator<'a, 'tcx> {
temps: &'a IndexVec<Local, TempState>,
}
-impl std::ops::Deref for Validator<'a, 'tcx> {
+impl<'a, 'tcx> std::ops::Deref for Validator<'a, 'tcx> {
type Target = ConstCx<'a, 'tcx>;
fn deref(&self) -> &Self::Target {
diff --git a/compiler/rustc_const_eval/src/transform/validate.rs b/compiler/rustc_const_eval/src/transform/validate.rs
index b09b2227f3e..c3f81a3ab83 100644
--- a/compiler/rustc_const_eval/src/transform/validate.rs
+++ b/compiler/rustc_const_eval/src/transform/validate.rs
@@ -1,14 +1,13 @@
//! Validates the MIR to ensure that invariants are upheld.
-use super::MirPass;
use rustc_index::bit_set::BitSet;
use rustc_infer::infer::TyCtxtInferExt;
use rustc_middle::mir::interpret::Scalar;
use rustc_middle::mir::traversal;
use rustc_middle::mir::visit::{PlaceContext, Visitor};
use rustc_middle::mir::{
- AggregateKind, BasicBlock, Body, BorrowKind, Local, Location, MirPhase, Operand, PlaceElem,
- PlaceRef, ProjectionElem, Rvalue, SourceScope, Statement, StatementKind, Terminator,
+ AggregateKind, BasicBlock, Body, BorrowKind, Local, Location, MirPass, MirPhase, Operand,
+ PlaceElem, PlaceRef, ProjectionElem, Rvalue, SourceScope, Statement, StatementKind, Terminator,
TerminatorKind, START_BLOCK,
};
use rustc_middle::ty::fold::BottomUpFolder;
@@ -67,7 +66,7 @@ impl<'tcx> MirPass<'tcx> for Validator {
///
/// The point of this function is to approximate "equal up to subtyping". However,
/// the approximation is incorrect as variance is ignored.
-pub fn equal_up_to_regions(
+pub fn equal_up_to_regions<'tcx>(
tcx: TyCtxt<'tcx>,
param_env: ParamEnv<'tcx>,
src: Ty<'tcx>,
@@ -496,10 +495,13 @@ impl<'a, 'tcx> Visitor<'tcx> for TypeChecker<'a, 'tcx> {
self.check_edge(location, *unwind, EdgeKind::Unwind);
}
}
- TerminatorKind::InlineAsm { destination, .. } => {
+ TerminatorKind::InlineAsm { destination, cleanup, .. } => {
if let Some(destination) = destination {
self.check_edge(location, *destination, EdgeKind::Normal);
}
+ if let Some(cleanup) = cleanup {
+ self.check_edge(location, *cleanup, EdgeKind::Unwind);
+ }
}
// Nothing to validate for these.
TerminatorKind::Resume
diff --git a/compiler/rustc_data_structures/src/binary_search_util/mod.rs b/compiler/rustc_data_structures/src/binary_search_util/mod.rs
index ede5757a479..bf09b2f8eef 100644
--- a/compiler/rustc_data_structures/src/binary_search_util/mod.rs
+++ b/compiler/rustc_data_structures/src/binary_search_util/mod.rs
@@ -6,7 +6,7 @@ mod tests;
/// function finds the range of elements that match the key. `data`
/// must have been sorted as if by a call to `sort_by_key` for this to
/// work.
-pub fn binary_search_slice<E, K>(data: &'d [E], key_fn: impl Fn(&E) -> K, key: &K) -> &'d [E]
+pub fn binary_search_slice<'d, E, K>(data: &'d [E], key_fn: impl Fn(&E) -> K, key: &K) -> &'d [E]
where
K: Ord,
{
diff --git a/compiler/rustc_data_structures/src/fingerprint.rs b/compiler/rustc_data_structures/src/fingerprint.rs
index c0c0e7be3ca..c9af35da4bc 100644
--- a/compiler/rustc_data_structures/src/fingerprint.rs
+++ b/compiler/rustc_data_structures/src/fingerprint.rs
@@ -142,7 +142,7 @@ impl_stable_hash_via_hash!(Fingerprint);
impl<E: rustc_serialize::Encoder> Encodable<E> for Fingerprint {
#[inline]
fn encode(&self, s: &mut E) -> Result<(), E::Error> {
- s.emit_raw_bytes(&self.to_le_bytes()[..])?;
+ s.emit_raw_bytes(&self.to_le_bytes())?;
Ok(())
}
}
@@ -151,7 +151,7 @@ impl<D: rustc_serialize::Decoder> Decodable<D> for Fingerprint {
#[inline]
fn decode(d: &mut D) -> Result<Self, D::Error> {
let mut bytes = [0u8; 16];
- d.read_raw_bytes_into(&mut bytes[..])?;
+ d.read_raw_bytes_into(&mut bytes)?;
Ok(Fingerprint::from_le_bytes(bytes))
}
}
diff --git a/compiler/rustc_data_structures/src/functor.rs b/compiler/rustc_data_structures/src/functor.rs
index 5b83ae31247..a3d3f988344 100644
--- a/compiler/rustc_data_structures/src/functor.rs
+++ b/compiler/rustc_data_structures/src/functor.rs
@@ -1,35 +1,32 @@
use rustc_index::vec::{Idx, IndexVec};
use std::mem;
-use std::ptr;
-pub trait IdFunctor {
+pub trait IdFunctor: Sized {
type Inner;
- fn map_id<F>(self, f: F) -> Self
+ fn try_map_id<F, E>(self, f: F) -> Result<Self, E>
where
- F: FnMut(Self::Inner) -> Self::Inner;
+ F: FnMut(Self::Inner) -> Result<Self::Inner, E>;
}
impl<T> IdFunctor for Box<T> {
type Inner = T;
#[inline]
- fn map_id<F>(self, mut f: F) -> Self
+ fn try_map_id<F, E>(self, mut f: F) -> Result<Self, E>
where
- F: FnMut(Self::Inner) -> Self::Inner,
+ F: FnMut(Self::Inner) -> Result<Self::Inner, E>,
{
let raw = Box::into_raw(self);
- unsafe {
+ Ok(unsafe {
// SAFETY: The raw pointer points to a valid value of type `T`.
- let value = ptr::read(raw);
+ let value = raw.read();
// SAFETY: Converts `Box<T>` to `Box<MaybeUninit<T>>` which is the
// inverse of `Box::assume_init()` and should be safe.
- let mut raw: Box<mem::MaybeUninit<T>> = Box::from_raw(raw.cast());
+ let raw: Box<mem::MaybeUninit<T>> = Box::from_raw(raw.cast());
// SAFETY: Write the mapped value back into the `Box`.
- raw.write(f(value));
- // SAFETY: We just initialized `raw`.
- raw.assume_init()
- }
+ Box::write(raw, f(value)?)
+ })
}
}
@@ -37,23 +34,43 @@ impl<T> IdFunctor for Vec<T> {
type Inner = T;
#[inline]
- fn map_id<F>(mut self, mut f: F) -> Self
+ fn try_map_id<F, E>(self, mut f: F) -> Result<Self, E>
where
- F: FnMut(Self::Inner) -> Self::Inner,
+ F: FnMut(Self::Inner) -> Result<Self::Inner, E>,
{
- // FIXME: We don't really care about panics here and leak
- // far more than we should, but that should be fine for now.
- let len = self.len();
+ struct HoleVec<T> {
+ vec: Vec<mem::ManuallyDrop<T>>,
+ hole: Option<usize>,
+ }
+
+ impl<T> Drop for HoleVec<T> {
+ fn drop(&mut self) {
+ unsafe {
+ for (index, slot) in self.vec.iter_mut().enumerate() {
+ if self.hole != Some(index) {
+ mem::ManuallyDrop::drop(slot);
+ }
+ }
+ }
+ }
+ }
+
unsafe {
- self.set_len(0);
- let start = self.as_mut_ptr();
- for i in 0..len {
- let p = start.add(i);
- ptr::write(p, f(ptr::read(p)));
+ let (ptr, length, capacity) = self.into_raw_parts();
+ let vec = Vec::from_raw_parts(ptr.cast(), length, capacity);
+ let mut hole_vec = HoleVec { vec, hole: None };
+
+ for (index, slot) in hole_vec.vec.iter_mut().enumerate() {
+ hole_vec.hole = Some(index);
+ let original = mem::ManuallyDrop::take(slot);
+ let mapped = f(original)?;
+ *slot = mem::ManuallyDrop::new(mapped);
+ hole_vec.hole = None;
}
- self.set_len(len);
+
+ mem::forget(hole_vec);
+ Ok(Vec::from_raw_parts(ptr, length, capacity))
}
- self
}
}
@@ -61,11 +78,11 @@ impl<T> IdFunctor for Box<[T]> {
type Inner = T;
#[inline]
- fn map_id<F>(self, f: F) -> Self
+ fn try_map_id<F, E>(self, f: F) -> Result<Self, E>
where
- F: FnMut(Self::Inner) -> Self::Inner,
+ F: FnMut(Self::Inner) -> Result<Self::Inner, E>,
{
- Vec::from(self).map_id(f).into()
+ Vec::from(self).try_map_id(f).map(Into::into)
}
}
@@ -73,10 +90,10 @@ impl<I: Idx, T> IdFunctor for IndexVec<I, T> {
type Inner = T;
#[inline]
- fn map_id<F>(self, f: F) -> Self
+ fn try_map_id<F, E>(self, f: F) -> Result<Self, E>
where
- F: FnMut(Self::Inner) -> Self::Inner,
+ F: FnMut(Self::Inner) -> Result<Self::Inner, E>,
{
- IndexVec::from_raw(self.raw.map_id(f))
+ self.raw.try_map_id(f).map(IndexVec::from_raw)
}
}
diff --git a/compiler/rustc_data_structures/src/graph/dominators/mod.rs b/compiler/rustc_data_structures/src/graph/dominators/mod.rs
index 1cd170599ba..0d2ae115cb0 100644
--- a/compiler/rustc_data_structures/src/graph/dominators/mod.rs
+++ b/compiler/rustc_data_structures/src/graph/dominators/mod.rs
@@ -1,11 +1,14 @@
//! Finding the dominators in a control-flow graph.
//!
-//! Algorithm based on Keith D. Cooper, Timothy J. Harvey, and Ken Kennedy,
-//! "A Simple, Fast Dominance Algorithm",
-//! Rice Computer Science TS-06-33870,
-//! <https://www.cs.rice.edu/~keith/EMBED/dom.pdf>.
+//! Algorithm based on Loukas Georgiadis,
+//! "Linear-Time Algorithms for Dominators and Related Problems",
+//! <ftp://ftp.cs.princeton.edu/techreports/2005/737.pdf>
+//!
+//! Additionally useful is the original Lengauer-Tarjan paper on this subject,
+//! "A Fast Algorithm for Finding Dominators in a Flowgraph"
+//! Thomas Lengauer and Robert Endre Tarjan.
+//! <https://www.cs.princeton.edu/courses/archive/spr03/cs423/download/dominators.pdf>
-use super::iterate::reverse_post_order;
use super::ControlFlowGraph;
use rustc_index::vec::{Idx, IndexVec};
use std::cmp::Ordering;
@@ -13,69 +16,239 @@ use std::cmp::Ordering;
#[cfg(test)]
mod tests;
-pub fn dominators<G: ControlFlowGraph>(graph: G) -> Dominators<G::Node> {
- let start_node = graph.start_node();
- let rpo = reverse_post_order(&graph, start_node);
- dominators_given_rpo(graph, &rpo)
+struct PreOrderFrame<Iter> {
+ pre_order_idx: PreorderIndex,
+ iter: Iter,
}
-fn dominators_given_rpo<G: ControlFlowGraph>(graph: G, rpo: &[G::Node]) -> Dominators<G::Node> {
- let start_node = graph.start_node();
- assert_eq!(rpo[0], start_node);
+rustc_index::newtype_index! {
+ struct PreorderIndex { .. }
+}
+pub fn dominators<G: ControlFlowGraph>(graph: G) -> Dominators<G::Node> {
// compute the post order index (rank) for each node
let mut post_order_rank = IndexVec::from_elem_n(0, graph.num_nodes());
- for (index, node) in rpo.iter().rev().cloned().enumerate() {
- post_order_rank[node] = index;
- }
- let mut immediate_dominators = IndexVec::from_elem_n(None, graph.num_nodes());
- immediate_dominators[start_node] = Some(start_node);
-
- let mut changed = true;
- while changed {
- changed = false;
-
- for &node in &rpo[1..] {
- let mut new_idom = None;
- for pred in graph.predecessors(node) {
- if immediate_dominators[pred].is_some() {
- // (*) dominators for `pred` have been calculated
- new_idom = Some(if let Some(new_idom) = new_idom {
- intersect(&post_order_rank, &immediate_dominators, new_idom, pred)
- } else {
- pred
- });
- }
- }
+ // We allocate capacity for the full set of nodes, because most of the time
+ // most of the nodes *are* reachable.
+ let mut parent: IndexVec<PreorderIndex, PreorderIndex> =
+ IndexVec::with_capacity(graph.num_nodes());
+
+ let mut stack = vec![PreOrderFrame {
+ pre_order_idx: PreorderIndex::new(0),
+ iter: graph.successors(graph.start_node()),
+ }];
+ let mut pre_order_to_real: IndexVec<PreorderIndex, G::Node> =
+ IndexVec::with_capacity(graph.num_nodes());
+ let mut real_to_pre_order: IndexVec<G::Node, Option<PreorderIndex>> =
+ IndexVec::from_elem_n(None, graph.num_nodes());
+ pre_order_to_real.push(graph.start_node());
+ parent.push(PreorderIndex::new(0)); // the parent of the root node is the root for now.
+ real_to_pre_order[graph.start_node()] = Some(PreorderIndex::new(0));
+ let mut post_order_idx = 0;
+
+ // Traverse the graph, collecting a number of things:
+ //
+ // * Preorder mapping (to it, and back to the actual ordering)
+ // * Postorder mapping (used exclusively for rank_partial_cmp on the final product)
+ // * Parents for each vertex in the preorder tree
+ //
+ // These are all done here rather than through one of the 'standard'
+ // graph traversals to help make this fast.
+ 'recurse: while let Some(frame) = stack.last_mut() {
+ while let Some(successor) = frame.iter.next() {
+ if real_to_pre_order[successor].is_none() {
+ let pre_order_idx = pre_order_to_real.push(successor);
+ real_to_pre_order[successor] = Some(pre_order_idx);
+ parent.push(frame.pre_order_idx);
+ stack.push(PreOrderFrame { pre_order_idx, iter: graph.successors(successor) });
- if new_idom != immediate_dominators[node] {
- immediate_dominators[node] = new_idom;
- changed = true;
+ continue 'recurse;
}
}
+ post_order_rank[pre_order_to_real[frame.pre_order_idx]] = post_order_idx;
+ post_order_idx += 1;
+
+ stack.pop();
}
- Dominators { post_order_rank, immediate_dominators }
-}
+ let reachable_vertices = pre_order_to_real.len();
+
+ let mut idom = IndexVec::from_elem_n(PreorderIndex::new(0), reachable_vertices);
+ let mut semi = IndexVec::from_fn_n(std::convert::identity, reachable_vertices);
+ let mut label = semi.clone();
+ let mut bucket = IndexVec::from_elem_n(vec![], reachable_vertices);
+ let mut lastlinked = None;
+
+ // We loop over vertices in reverse preorder. This implements the pseudocode
+ // of the simple Lengauer-Tarjan algorithm. A few key facts are noted here
+ // which are helpful for understanding the code (full proofs and such are
+ // found in various papers, including one cited at the top of this file).
+ //
+ // For each vertex w (which is not the root),
+ // * semi[w] is a proper ancestor of the vertex w (i.e., semi[w] != w)
+ // * idom[w] is an ancestor of semi[w] (i.e., idom[w] may equal semi[w])
+ //
+ // An immediate dominator of w (idom[w]) is a vertex v where v dominates w
+ // and every other dominator of w dominates v. (Every vertex except the root has
+ // a unique immediate dominator.)
+ //
+ // A semidominator for a given vertex w (semi[w]) is the vertex v with minimum
+ // preorder number such that there exists a path from v to w in which all elements (other than w) have
+ // preorder numbers greater than w (i.e., this path is not the tree path to
+ // w).
+ for w in (PreorderIndex::new(1)..PreorderIndex::new(reachable_vertices)).rev() {
+ // Optimization: process buckets just once, at the start of the
+ // iteration. Do not explicitly empty the bucket (even though it will
+ // not be used again), to save some instructions.
+ //
+ // The bucket here contains the vertices whose semidominator is the
+ // vertex w, which we are guaranteed to have found: all vertices who can
+ // be semidominated by w must have a preorder number exceeding w, so
+ // they have been placed in the bucket.
+ //
+ // We compute a partial set of immediate dominators here.
+ let z = parent[w];
+ for &v in bucket[z].iter() {
+ // This uses the result of Lemma 5 from section 2 from the original
+ // 1979 paper, to compute either the immediate or relative dominator
+ // for a given vertex v.
+ //
+ // eval returns a vertex y, for which semi[y] is minimum among
+ // vertices semi[v] +> y *> v. Note that semi[v] = z as we're in the
+ // z bucket.
+ //
+ // Given such a vertex y, semi[y] <= semi[v] and idom[y] = idom[v].
+ // If semi[y] = semi[v], though, idom[v] = semi[v].
+ //
+ // Using this, we can either set idom[v] to be:
+ // * semi[v] (i.e. z), if semi[y] is z
+ // * idom[y], otherwise
+ //
+ // We don't directly set to idom[y] though as it's not necessarily
+ // known yet. The second preorder traversal will cleanup by updating
+ // the idom for any that were missed in this pass.
+ let y = eval(&mut parent, lastlinked, &semi, &mut label, v);
+ idom[v] = if semi[y] < z { y } else { z };
+ }
+
+ // This loop computes the semi[w] for w.
+ semi[w] = w;
+ for v in graph.predecessors(pre_order_to_real[w]) {
+ let v = real_to_pre_order[v].unwrap();
+
+ // eval returns a vertex x from which semi[x] is minimum among
+ // vertices semi[v] +> x *> v.
+ //
+ // From Lemma 4 from section 2, we know that the semidominator of a
+ // vertex w is the minimum (by preorder number) vertex of the
+ // following:
+ //
+ // * direct predecessors of w with preorder number less than w
+ // * semidominators of u such that u > w and there exists (v, w)
+ // such that u *> v
+ //
+ // This loop therefore identifies such a minima. Note that any
+ // semidominator path to w must have all but the first vertex go
+ // through vertices numbered greater than w, so the reverse preorder
+ // traversal we are using guarantees that all of the information we
+ // might need is available at this point.
+ //
+ // The eval call will give us semi[x], which is either:
+ //
+ // * v itself, if v has not yet been processed
+ // * A possible 'best' semidominator for w.
+ let x = eval(&mut parent, lastlinked, &semi, &mut label, v);
+ semi[w] = std::cmp::min(semi[w], semi[x]);
+ }
+ // semi[w] is now semidominator(w) and won't change any more.
-fn intersect<Node: Idx>(
- post_order_rank: &IndexVec<Node, usize>,
- immediate_dominators: &IndexVec<Node, Option<Node>>,
- mut node1: Node,
- mut node2: Node,
-) -> Node {
- while node1 != node2 {
- while post_order_rank[node1] < post_order_rank[node2] {
- node1 = immediate_dominators[node1].unwrap();
+ // Optimization: Do not insert into buckets if parent[w] = semi[w], as
+ // we then immediately know the idom.
+ //
+ // If we don't yet know the idom directly, then push this vertex into
+ // our semidominator's bucket, where it will get processed at a later
+ // stage to compute its immediate dominator.
+ if parent[w] != semi[w] {
+ bucket[semi[w]].push(w);
+ } else {
+ idom[w] = parent[w];
}
- while post_order_rank[node2] < post_order_rank[node1] {
- node2 = immediate_dominators[node2].unwrap();
+ // Optimization: We share the parent array between processed and not
+ // processed elements; lastlinked represents the divider.
+ lastlinked = Some(w);
+ }
+
+ // Finalize the idoms for any that were not fully settable during initial
+ // traversal.
+ //
+ // If idom[w] != semi[w] then we know that we've stored vertex y from above
+ // into idom[w]. It is known to be our 'relative dominator', which means
+ // that it's one of w's ancestors and has the same immediate dominator as w,
+ // so use that idom.
+ for w in PreorderIndex::new(1)..PreorderIndex::new(reachable_vertices) {
+ if idom[w] != semi[w] {
+ idom[w] = idom[idom[w]];
}
}
- node1
+ let mut immediate_dominators = IndexVec::from_elem_n(None, graph.num_nodes());
+ for (idx, node) in pre_order_to_real.iter_enumerated() {
+ immediate_dominators[*node] = Some(pre_order_to_real[idom[idx]]);
+ }
+
+ Dominators { post_order_rank, immediate_dominators }
+}
+
+/// Evaluate the link-eval virtual forest, providing the currently minimum semi
+/// value for the passed `node` (which may be itself).
+///
+/// This maintains that for every vertex v, `label[v]` is such that:
+///
+/// ```text
+/// semi[eval(v)] = min { semi[label[u]] | root_in_forest(v) +> u *> v }
+/// ```
+///
+/// where `+>` is a proper ancestor and `*>` is just an ancestor.
+#[inline]
+fn eval(
+ ancestor: &mut IndexVec<PreorderIndex, PreorderIndex>,
+ lastlinked: Option<PreorderIndex>,
+ semi: &IndexVec<PreorderIndex, PreorderIndex>,
+ label: &mut IndexVec<PreorderIndex, PreorderIndex>,
+ node: PreorderIndex,
+) -> PreorderIndex {
+ if is_processed(node, lastlinked) {
+ compress(ancestor, lastlinked, semi, label, node);
+ label[node]
+ } else {
+ node
+ }
+}
+
+#[inline]
+fn is_processed(v: PreorderIndex, lastlinked: Option<PreorderIndex>) -> bool {
+ if let Some(ll) = lastlinked { v >= ll } else { false }
+}
+
+#[inline]
+fn compress(
+ ancestor: &mut IndexVec<PreorderIndex, PreorderIndex>,
+ lastlinked: Option<PreorderIndex>,
+ semi: &IndexVec<PreorderIndex, PreorderIndex>,
+ label: &mut IndexVec<PreorderIndex, PreorderIndex>,
+ v: PreorderIndex,
+) {
+ assert!(is_processed(v, lastlinked));
+ let u = ancestor[v];
+ if is_processed(u, lastlinked) {
+ compress(ancestor, lastlinked, semi, label, u);
+ if semi[label[u]] < semi[label[v]] {
+ label[v] = label[u];
+ }
+ ancestor[v] = ancestor[u];
+ }
}
#[derive(Clone, Debug)]
diff --git a/compiler/rustc_data_structures/src/graph/dominators/tests.rs b/compiler/rustc_data_structures/src/graph/dominators/tests.rs
index 1160df5186b..ff31d8f7fdc 100644
--- a/compiler/rustc_data_structures/src/graph/dominators/tests.rs
+++ b/compiler/rustc_data_structures/src/graph/dominators/tests.rs
@@ -32,3 +32,14 @@ fn paper() {
assert_eq!(immediate_dominators[5], Some(6));
assert_eq!(immediate_dominators[6], Some(6));
}
+
+#[test]
+fn paper_slt() {
+ // example from the paper:
+ let graph = TestGraph::new(
+ 1,
+ &[(1, 2), (1, 3), (2, 3), (2, 7), (3, 4), (3, 6), (4, 5), (5, 4), (6, 7), (7, 8), (8, 5)],
+ );
+
+ dominators(&graph);
+}
diff --git a/compiler/rustc_data_structures/src/graph/iterate/mod.rs b/compiler/rustc_data_structures/src/graph/iterate/mod.rs
index a9db3497b23..57007611a76 100644
--- a/compiler/rustc_data_structures/src/graph/iterate/mod.rs
+++ b/compiler/rustc_data_structures/src/graph/iterate/mod.rs
@@ -79,7 +79,7 @@ where
visited: BitSet<G::Node>,
}
-impl<G> DepthFirstSearch<'graph, G>
+impl<'graph, G> DepthFirstSearch<'graph, G>
where
G: ?Sized + DirectedGraph + WithNumNodes + WithSuccessors,
{
@@ -209,7 +209,7 @@ where
settled: BitSet<G::Node>,
}
-impl<G> TriColorDepthFirstSearch<'graph, G>
+impl<'graph, G> TriColorDepthFirstSearch<'graph, G>
where
G: ?Sized + DirectedGraph + WithNumNodes + WithSuccessors,
{
@@ -276,7 +276,7 @@ where
}
}
-impl<G> TriColorDepthFirstSearch<'graph, G>
+impl<G> TriColorDepthFirstSearch<'_, G>
where
G: ?Sized + DirectedGraph + WithNumNodes + WithSuccessors + WithStartNode,
{
diff --git a/compiler/rustc_data_structures/src/graph/scc/mod.rs b/compiler/rustc_data_structures/src/graph/scc/mod.rs
index b84f28b6a9e..508a084b311 100644
--- a/compiler/rustc_data_structures/src/graph/scc/mod.rs
+++ b/compiler/rustc_data_structures/src/graph/scc/mod.rs
@@ -97,7 +97,7 @@ impl<N: Idx, S: Idx> WithNumEdges for Sccs<N, S> {
}
}
-impl<N: Idx, S: Idx> GraphSuccessors<'graph> for Sccs<N, S> {
+impl<'graph, N: Idx, S: Idx> GraphSuccessors<'graph> for Sccs<N, S> {
type Item = S;
type Iter = std::iter::Cloned<std::slice::Iter<'graph, S>>;
diff --git a/compiler/rustc_data_structures/src/graph/vec_graph/mod.rs b/compiler/rustc_data_structures/src/graph/vec_graph/mod.rs
index 4ed88878418..5d9bc1b2e51 100644
--- a/compiler/rustc_data_structures/src/graph/vec_graph/mod.rs
+++ b/compiler/rustc_data_structures/src/graph/vec_graph/mod.rs
@@ -94,7 +94,7 @@ impl<N: Idx> WithNumEdges for VecGraph<N> {
}
}
-impl<N: Idx> GraphSuccessors<'graph> for VecGraph<N> {
+impl<'graph, N: Idx> GraphSuccessors<'graph> for VecGraph<N> {
type Item = N;
type Iter = std::iter::Cloned<std::slice::Iter<'graph, N>>;
diff --git a/compiler/rustc_data_structures/src/lib.rs b/compiler/rustc_data_structures/src/lib.rs
index 77784bf1705..181e5180d53 100644
--- a/compiler/rustc_data_structures/src/lib.rs
+++ b/compiler/rustc_data_structures/src/lib.rs
@@ -15,16 +15,15 @@
#![feature(core_intrinsics)]
#![feature(extend_one)]
#![feature(hash_raw_entry)]
-#![feature(in_band_lifetimes)]
#![feature(maybe_uninit_uninit_array)]
#![feature(min_specialization)]
#![feature(never_type)]
#![feature(type_alias_impl_trait)]
#![feature(new_uninit)]
-#![feature(nll)]
#![feature(once_cell)]
#![feature(test)]
#![feature(thread_id_value)]
+#![feature(vec_into_raw_parts)]
#![allow(rustc::default_hash_types)]
#![deny(unaligned_references)]
diff --git a/compiler/rustc_data_structures/src/profiling.rs b/compiler/rustc_data_structures/src/profiling.rs
index c21939209fc..fd6ff086b08 100644
--- a/compiler/rustc_data_structures/src/profiling.rs
+++ b/compiler/rustc_data_structures/src/profiling.rs
@@ -649,7 +649,7 @@ impl Drop for VerboseTimingGuard<'_> {
fn drop(&mut self) {
if let Some((start_time, start_rss, ref message)) = self.start_and_message {
let end_rss = get_resident_set_size();
- print_time_passes_entry(&message[..], start_time.elapsed(), start_rss, end_rss);
+ print_time_passes_entry(&message, start_time.elapsed(), start_rss, end_rss);
}
}
}
diff --git a/compiler/rustc_data_structures/src/small_c_str.rs b/compiler/rustc_data_structures/src/small_c_str.rs
index 4a089398ce6..33e72914e19 100644
--- a/compiler/rustc_data_structures/src/small_c_str.rs
+++ b/compiler/rustc_data_structures/src/small_c_str.rs
@@ -46,7 +46,7 @@ impl SmallCStr {
#[inline]
pub fn as_c_str(&self) -> &ffi::CStr {
- unsafe { ffi::CStr::from_bytes_with_nul_unchecked(&self.data[..]) }
+ unsafe { ffi::CStr::from_bytes_with_nul_unchecked(&self.data) }
}
#[inline]
diff --git a/compiler/rustc_data_structures/src/sorted_map/index_map.rs b/compiler/rustc_data_structures/src/sorted_map/index_map.rs
index 61c7239c55f..593316e2699 100644
--- a/compiler/rustc_data_structures/src/sorted_map/index_map.rs
+++ b/compiler/rustc_data_structures/src/sorted_map/index_map.rs
@@ -84,7 +84,7 @@ impl<I: Idx, K: Ord, V> SortedIndexMultiMap<I, K, V> {
/// If there are multiple items that are equivalent to `key`, they will be yielded in
/// insertion order.
#[inline]
- pub fn get_by_key(&'a self, key: K) -> impl 'a + Iterator<Item = &'a V> {
+ pub fn get_by_key(&self, key: K) -> impl Iterator<Item = &V> + '_ {
self.get_by_key_enumerated(key).map(|(_, v)| v)
}
@@ -94,7 +94,7 @@ impl<I: Idx, K: Ord, V> SortedIndexMultiMap<I, K, V> {
/// If there are multiple items that are equivalent to `key`, they will be yielded in
/// insertion order.
#[inline]
- pub fn get_by_key_enumerated(&'a self, key: K) -> impl '_ + Iterator<Item = (I, &V)> {
+ pub fn get_by_key_enumerated(&self, key: K) -> impl Iterator<Item = (I, &V)> + '_ {
let lower_bound = self.idx_sorted_by_item_key.partition_point(|&i| self.items[i].0 < key);
self.idx_sorted_by_item_key[lower_bound..].iter().map_while(move |&i| {
let (k, v) = &self.items[i];
diff --git a/compiler/rustc_data_structures/src/sso/map.rs b/compiler/rustc_data_structures/src/sso/map.rs
index 2de05cd4e56..ec6a62016a8 100644
--- a/compiler/rustc_data_structures/src/sso/map.rs
+++ b/compiler/rustc_data_structures/src/sso/map.rs
@@ -423,14 +423,14 @@ impl<K, V> IntoIterator for SsoHashMap<K, V> {
/// adapts Item of array reference iterator to Item of hashmap reference iterator.
#[inline(always)]
-fn adapt_array_ref_it<K, V>(pair: &'a (K, V)) -> (&'a K, &'a V) {
+fn adapt_array_ref_it<K, V>(pair: &(K, V)) -> (&K, &V) {
let (a, b) = pair;
(a, b)
}
/// adapts Item of array mut reference iterator to Item of hashmap mut reference iterator.
#[inline(always)]
-fn adapt_array_mut_it<K, V>(pair: &'a mut (K, V)) -> (&'a K, &'a mut V) {
+fn adapt_array_mut_it<K, V>(pair: &mut (K, V)) -> (&K, &mut V) {
let (a, b) = pair;
(a, b)
}
diff --git a/compiler/rustc_data_structures/src/sso/set.rs b/compiler/rustc_data_structures/src/sso/set.rs
index 29baf4e1ddb..f71522d3714 100644
--- a/compiler/rustc_data_structures/src/sso/set.rs
+++ b/compiler/rustc_data_structures/src/sso/set.rs
@@ -75,7 +75,7 @@ impl<T> SsoHashSet<T> {
/// An iterator visiting all elements in arbitrary order.
/// The iterator element type is `&'a T`.
#[inline]
- pub fn iter(&'a self) -> impl Iterator<Item = &'a T> {
+ pub fn iter(&self) -> impl Iterator<Item = &T> {
self.into_iter()
}
diff --git a/compiler/rustc_data_structures/src/stable_hasher.rs b/compiler/rustc_data_structures/src/stable_hasher.rs
index f800ec6a6a1..144eaed7e07 100644
--- a/compiler/rustc_data_structures/src/stable_hasher.rs
+++ b/compiler/rustc_data_structures/src/stable_hasher.rs
@@ -42,6 +42,7 @@ impl StableHasher {
}
impl StableHasherResult for u128 {
+ #[inline]
fn finish(hasher: StableHasher) -> Self {
let (_0, _1) = hasher.finalize();
u128::from(_0) | (u128::from(_1) << 64)
@@ -49,6 +50,7 @@ impl StableHasherResult for u128 {
}
impl StableHasherResult for u64 {
+ #[inline]
fn finish(hasher: StableHasher) -> Self {
hasher.finalize().0
}
@@ -507,7 +509,11 @@ where
{
#[inline]
fn hash_stable(&self, hcx: &mut HCX, hasher: &mut StableHasher) {
- hash_stable_hashmap(hcx, hasher, self, ToStableHashKey::to_stable_hash_key);
+ stable_hash_reduce(hcx, hasher, self.iter(), self.len(), |hasher, hcx, (key, value)| {
+ let key = key.to_stable_hash_key(hcx);
+ key.hash_stable(hcx, hasher);
+ value.hash_stable(hcx, hasher);
+ });
}
}
@@ -517,9 +523,10 @@ where
R: BuildHasher,
{
fn hash_stable(&self, hcx: &mut HCX, hasher: &mut StableHasher) {
- let mut keys: Vec<_> = self.iter().map(|k| k.to_stable_hash_key(hcx)).collect();
- keys.sort_unstable();
- keys.hash_stable(hcx, hasher);
+ stable_hash_reduce(hcx, hasher, self.iter(), self.len(), |hasher, hcx, key| {
+ let key = key.to_stable_hash_key(hcx);
+ key.hash_stable(hcx, hasher);
+ });
}
}
@@ -529,10 +536,11 @@ where
V: HashStable<HCX>,
{
fn hash_stable(&self, hcx: &mut HCX, hasher: &mut StableHasher) {
- let mut entries: Vec<_> =
- self.iter().map(|(k, v)| (k.to_stable_hash_key(hcx), v)).collect();
- entries.sort_unstable_by(|&(ref sk1, _), &(ref sk2, _)| sk1.cmp(sk2));
- entries.hash_stable(hcx, hasher);
+ stable_hash_reduce(hcx, hasher, self.iter(), self.len(), |hasher, hcx, (key, value)| {
+ let key = key.to_stable_hash_key(hcx);
+ key.hash_stable(hcx, hasher);
+ value.hash_stable(hcx, hasher);
+ });
}
}
@@ -541,25 +549,38 @@ where
K: ToStableHashKey<HCX>,
{
fn hash_stable(&self, hcx: &mut HCX, hasher: &mut StableHasher) {
- let mut keys: Vec<_> = self.iter().map(|k| k.to_stable_hash_key(hcx)).collect();
- keys.sort_unstable();
- keys.hash_stable(hcx, hasher);
+ stable_hash_reduce(hcx, hasher, self.iter(), self.len(), |hasher, hcx, key| {
+ let key = key.to_stable_hash_key(hcx);
+ key.hash_stable(hcx, hasher);
+ });
}
}
-pub fn hash_stable_hashmap<HCX, K, V, R, SK, F>(
+fn stable_hash_reduce<HCX, I, C, F>(
hcx: &mut HCX,
hasher: &mut StableHasher,
- map: &::std::collections::HashMap<K, V, R>,
- to_stable_hash_key: F,
+ mut collection: C,
+ length: usize,
+ hash_function: F,
) where
- K: Eq,
- V: HashStable<HCX>,
- R: BuildHasher,
- SK: HashStable<HCX> + Ord,
- F: Fn(&K, &HCX) -> SK,
+ C: Iterator<Item = I>,
+ F: Fn(&mut StableHasher, &mut HCX, I),
{
- let mut entries: Vec<_> = map.iter().map(|(k, v)| (to_stable_hash_key(k, hcx), v)).collect();
- entries.sort_unstable_by(|&(ref sk1, _), &(ref sk2, _)| sk1.cmp(sk2));
- entries.hash_stable(hcx, hasher);
+ length.hash_stable(hcx, hasher);
+
+ match length {
+ 1 => {
+ hash_function(hasher, hcx, collection.next().unwrap());
+ }
+ _ => {
+ let hash = collection
+ .map(|value| {
+ let mut hasher = StableHasher::new();
+ hash_function(&mut hasher, hcx, value);
+ hasher.finish::<u128>()
+ })
+ .reduce(|accum, value| accum.wrapping_add(value));
+ hash.hash_stable(hcx, hasher);
+ }
+ }
}
diff --git a/compiler/rustc_data_structures/src/tagged_ptr/copy.rs b/compiler/rustc_data_structures/src/tagged_ptr/copy.rs
index d63bcdb3c2b..e1d3e0bd35a 100644
--- a/compiler/rustc_data_structures/src/tagged_ptr/copy.rs
+++ b/compiler/rustc_data_structures/src/tagged_ptr/copy.rs
@@ -94,9 +94,11 @@ where
// SAFETY: pointer_raw returns the original pointer
unsafe { std::mem::transmute_copy(&self.pointer_raw()) }
}
+ #[inline]
pub fn tag(&self) -> T {
unsafe { T::from_usize(self.packed.get() >> Self::TAG_BIT_SHIFT) }
}
+ #[inline]
pub fn set_tag(&mut self, tag: T) {
let mut packed = self.packed.get();
let new_tag = T::into_usize(tag) << Self::TAG_BIT_SHIFT;
diff --git a/compiler/rustc_data_structures/src/vec_linked_list.rs b/compiler/rustc_data_structures/src/vec_linked_list.rs
index 1cf030d852e..ce60d40b24b 100644
--- a/compiler/rustc_data_structures/src/vec_linked_list.rs
+++ b/compiler/rustc_data_structures/src/vec_linked_list.rs
@@ -2,8 +2,8 @@ use rustc_index::vec::{Idx, IndexVec};
pub fn iter<Ls>(
first: Option<Ls::LinkIndex>,
- links: &'a Ls,
-) -> impl Iterator<Item = Ls::LinkIndex> + 'a
+ links: &Ls,
+) -> impl Iterator<Item = Ls::LinkIndex> + '_
where
Ls: Links,
{
diff --git a/compiler/rustc_driver/src/lib.rs b/compiler/rustc_driver/src/lib.rs
index 09fe3a552a0..12e0b7a4977 100644
--- a/compiler/rustc_driver/src/lib.rs
+++ b/compiler/rustc_driver/src/lib.rs
@@ -736,7 +736,12 @@ impl RustcDefaultCalls {
println!("{}", cfg);
}
}
- RelocationModels | CodeModels | TlsModels | TargetCPUs | TargetFeatures => {
+ RelocationModels
+ | CodeModels
+ | TlsModels
+ | TargetCPUs
+ | StackProtectorStrategies
+ | TargetFeatures => {
codegen_backend.print(*req, sess);
}
// Any output here interferes with Cargo's parsing of other printed output
@@ -867,7 +872,7 @@ Available lint options:
let print_lints = |lints: Vec<&Lint>| {
for lint in lints {
- let name = lint.name_lower().replace("_", "-");
+ let name = lint.name_lower().replace('_', "-");
println!(
" {} {:7.7} {}",
padded(&name),
@@ -903,10 +908,10 @@ Available lint options:
let print_lint_groups = |lints: Vec<(&'static str, Vec<LintId>)>| {
for (name, to) in lints {
- let name = name.to_lowercase().replace("_", "-");
+ let name = name.to_lowercase().replace('_', "-");
let desc = to
.into_iter()
- .map(|x| x.to_string().replace("_", "-"))
+ .map(|x| x.to_string().replace('_', "-"))
.collect::<Vec<String>>()
.join(", ");
println!(" {} {}", padded(&name), desc);
@@ -955,7 +960,7 @@ fn print_flag_list<T>(
println!(
" {} {:>width$}=val -- {}",
cmdline_opt,
- name.replace("_", "-"),
+ name.replace('_', "-"),
desc,
width = max_len
);
@@ -1010,7 +1015,7 @@ pub fn handle_options(args: &[String]) -> Option<getopts::Matches> {
.iter()
.map(|&(name, ..)| ('C', name))
.chain(DB_OPTIONS.iter().map(|&(name, ..)| ('Z', name)))
- .find(|&(_, name)| *opt == name.replace("_", "-"))
+ .find(|&(_, name)| *opt == name.replace('_', "-"))
.map(|(flag, _)| format!("{}. Did you mean `-{} {}`?", e, flag, opt)),
_ => None,
};
diff --git a/compiler/rustc_error_codes/src/error_codes/E0038.md b/compiler/rustc_error_codes/src/error_codes/E0038.md
index 019d54b6202..ca2eaa54057 100644
--- a/compiler/rustc_error_codes/src/error_codes/E0038.md
+++ b/compiler/rustc_error_codes/src/error_codes/E0038.md
@@ -1,34 +1,64 @@
-Trait objects like `Box<Trait>` can only be constructed when certain
-requirements are satisfied by the trait in question.
-
-Trait objects are a form of dynamic dispatch and use a dynamically sized type
-for the inner type. So, for a given trait `Trait`, when `Trait` is treated as a
-type, as in `Box<Trait>`, the inner type is 'unsized'. In such cases the boxed
-pointer is a 'fat pointer' that contains an extra pointer to a table of methods
-(among other things) for dynamic dispatch. This design mandates some
-restrictions on the types of traits that are allowed to be used in trait
-objects, which are collectively termed as 'object safety' rules.
-
-Attempting to create a trait object for a non object-safe trait will trigger
-this error.
-
-There are various rules:
-
-### The trait cannot require `Self: Sized`
-
-When `Trait` is treated as a type, the type does not implement the special
-`Sized` trait, because the type does not have a known size at compile time and
-can only be accessed behind a pointer. Thus, if we have a trait like the
-following:
+For any given trait `Trait` there may be a related _type_ called the _trait
+object type_ which is typically written as `dyn Trait`. In earlier editions of
+Rust, trait object types were written as plain `Trait` (just the name of the
+trait, written in type positions) but this was a bit too confusing, so we now
+write `dyn Trait`.
+
+Some traits are not allowed to be used as trait object types. The traits that
+are allowed to be used as trait object types are called "object-safe" traits.
+Attempting to use a trait object type for a trait that is not object-safe will
+trigger error E0038.
+
+Two general aspects of trait object types give rise to the restrictions:
+
+ 1. Trait object types are dynamically sized types (DSTs), and trait objects of
+ these types can only be accessed through pointers, such as `&dyn Trait` or
+ `Box<dyn Trait>`. The size of such a pointer is known, but the size of the
+ `dyn Trait` object pointed-to by the pointer is _opaque_ to code working
+ with it, and different tait objects with the same trait object type may
+ have different sizes.
+
+ 2. The pointer used to access a trait object is paired with an extra pointer
+ to a "virtual method table" or "vtable", which is used to implement dynamic
+ dispatch to the object's implementations of the trait's methods. There is a
+ single such vtable for each trait implementation, but different trait
+ objects with the same trait object type may point to vtables from different
+ implementations.
+
+The specific conditions that violate object-safety follow, most of which relate
+to missing size information and vtable polymorphism arising from these aspects.
+
+### The trait requires `Self: Sized`
+
+Traits that are declared as `Trait: Sized` or which otherwise inherit a
+constraint of `Self:Sized` are not object-safe.
+
+The reasoning behind this is somewhat subtle. It derives from the fact that Rust
+requires (and defines) that every trait object type `dyn Trait` automatically
+implements `Trait`. Rust does this to simplify error reporting and ease
+interoperation between static and dynamic polymorphism. For example, this code
+works:
```
-trait Foo where Self: Sized {
+trait Trait {
+}
+
+fn static_foo<T:Trait + ?Sized>(b: &T) {
+}
+fn dynamic_bar(a: &dyn Trait) {
+ static_foo(a)
}
```
-We cannot create an object of type `Box<Foo>` or `&Foo` since in this case
-`Self` would not be `Sized`.
+This code works because `dyn Trait`, if it exists, always implements `Trait`.
+
+However as we know, any `dyn Trait` is also unsized, and so it can never
+implement a sized trait like `Trait:Sized`. So, rather than allow an exception
+to the rule that `dyn Trait` always implements `Trait`, Rust chooses to prohibit
+such a `dyn Trait` from existing at all.
+
+Only unsized traits are considered object-safe.
Generally, `Self: Sized` is used to indicate that the trait should not be used
as a trait object. If the trait comes from your own crate, consider removing
@@ -67,7 +97,7 @@ trait Trait {
fn foo(&self) -> Self;
}
-fn call_foo(x: Box<Trait>) {
+fn call_foo(x: Box<dyn Trait>) {
let y = x.foo(); // What type is y?
// ...
}
@@ -76,7 +106,8 @@ fn call_foo(x: Box<Trait>) {
If only some methods aren't object-safe, you can add a `where Self: Sized` bound
on them to mark them as explicitly unavailable to trait objects. The
functionality will still be available to all other implementers, including
-`Box<Trait>` which is itself sized (assuming you `impl Trait for Box<Trait>`).
+`Box<dyn Trait>` which is itself sized (assuming you `impl Trait for Box<dyn
+Trait>`).
```
trait Trait {
@@ -115,7 +146,9 @@ impl Trait for u8 {
```
At compile time each implementation of `Trait` will produce a table containing
-the various methods (and other items) related to the implementation.
+the various methods (and other items) related to the implementation, which will
+be used as the virtual method table for a `dyn Trait` object derived from that
+implementation.
This works fine, but when the method gains generic parameters, we can have a
problem.
@@ -174,7 +207,7 @@ Now, if we have the following code:
# impl Trait for u8 { fn foo<T>(&self, on: T) {} }
# impl Trait for bool { fn foo<T>(&self, on: T) {} }
# // etc.
-fn call_foo(thing: Box<Trait>) {
+fn call_foo(thing: Box<dyn Trait>) {
thing.foo(true); // this could be any one of the 8 types above
thing.foo(1);
thing.foo("hello");
@@ -200,7 +233,7 @@ trait Trait {
```
If this is not an option, consider replacing the type parameter with another
-trait object (e.g., if `T: OtherTrait`, use `on: Box<OtherTrait>`). If the
+trait object (e.g., if `T: OtherTrait`, use `on: Box<dyn OtherTrait>`). If the
number of types you intend to feed to this method is limited, consider manually
listing out the methods of different types.
@@ -226,7 +259,7 @@ trait Foo {
}
```
-### The trait cannot contain associated constants
+### Trait contains associated constants
Just like static functions, associated constants aren't stored on the method
table. If the trait or any subtrait contain an associated constant, they cannot
@@ -248,7 +281,7 @@ trait Foo {
}
```
-### The trait cannot use `Self` as a type parameter in the supertrait listing
+### Trait uses `Self` as a type parameter in the supertrait listing
This is similar to the second sub-error, but subtler. It happens in situations
like the following:
diff --git a/compiler/rustc_errors/src/emitter.rs b/compiler/rustc_errors/src/emitter.rs
index 6b79962ddd6..3104bc185e7 100644
--- a/compiler/rustc_errors/src/emitter.rs
+++ b/compiler/rustc_errors/src/emitter.rs
@@ -214,7 +214,7 @@ pub trait Emitter {
/// Formats the substitutions of the primary_span
///
- /// The are a lot of conditions to this method, but in short:
+ /// There are a lot of conditions to this method, but in short:
///
/// * If the current `Diagnostic` has only one visible `CodeSuggestion`,
/// we format the `help` suggestion depending on the content of the
@@ -730,13 +730,15 @@ impl EmitterWriter {
}
let source_string = match file.get_line(line.line_index - 1) {
- Some(s) => replace_tabs(&*s),
+ Some(s) => normalize_whitespace(&*s),
None => return Vec::new(),
};
let line_offset = buffer.num_lines();
- let left = margin.left(source_string.len()); // Left trim
+ // Left trim
+ let left = margin.left(source_string.len());
+
// Account for unicode characters of width !=0 that were removed.
let left = source_string
.chars()
@@ -1286,7 +1288,7 @@ impl EmitterWriter {
}
for &(ref text, _) in msg.iter() {
// Account for newlines to align output to its label.
- for (line, text) in replace_tabs(text).lines().enumerate() {
+ for (line, text) in normalize_whitespace(text).lines().enumerate() {
buffer.append(
0 + line,
&format!(
@@ -1550,7 +1552,7 @@ impl EmitterWriter {
self.draw_line(
&mut buffer,
- &replace_tabs(&unannotated_line),
+ &normalize_whitespace(&unannotated_line),
annotated_file.lines[line_idx + 1].line_index - 1,
last_buffer_line_num,
width_offset,
@@ -1623,18 +1625,27 @@ impl EmitterWriter {
suggestions.iter().take(MAX_SUGGESTIONS)
{
notice_capitalization |= only_capitalization;
- // Only show underline if the suggestion spans a single line and doesn't cover the
- // entirety of the code output. If you have multiple replacements in the same line
- // of code, show the underline.
- let show_underline = !(parts.len() == 1 && parts[0].snippet.trim() == complete.trim())
- && complete.lines().count() == 1;
let has_deletion = parts.iter().any(|p| p.is_deletion());
let is_multiline = complete.lines().count() > 1;
- let show_diff = has_deletion && !is_multiline;
+ enum DisplaySuggestion {
+ Underline,
+ Diff,
+ None,
+ }
+
+ let show_code_change = if has_deletion && !is_multiline {
+ DisplaySuggestion::Diff
+ } else if (parts.len() != 1 || parts[0].snippet.trim() != complete.trim())
+ && !is_multiline
+ {
+ DisplaySuggestion::Underline
+ } else {
+ DisplaySuggestion::None
+ };
- if show_diff {
+ if let DisplaySuggestion::Diff = show_code_change {
row_num += 1;
}
@@ -1657,7 +1668,7 @@ impl EmitterWriter {
&self.maybe_anonymized(line_start + line_pos),
Style::LineNumber,
);
- if show_diff {
+ if let DisplaySuggestion::Diff = show_code_change {
// Add the line number for both addition and removal to drive the point home.
//
// N - fn foo<A: T>(bar: A) {
@@ -1672,7 +1683,7 @@ impl EmitterWriter {
buffer.puts(
row_num - 1,
max_line_num_len + 3,
- &replace_tabs(
+ &normalize_whitespace(
&*file_lines
.file
.get_line(file_lines.lines[line_pos].line_index)
@@ -1698,7 +1709,7 @@ impl EmitterWriter {
}
// print the suggestion
- buffer.append(row_num, &replace_tabs(line), Style::NoStyle);
+ buffer.append(row_num, &normalize_whitespace(line), Style::NoStyle);
// Colorize addition/replacements with green.
for &SubstitutionHighlight { start, end } in highlight_parts {
@@ -1727,7 +1738,7 @@ impl EmitterWriter {
let mut offsets: Vec<(usize, isize)> = Vec::new();
// Only show an underline in the suggestions if the suggestion is not the
// entirety of the code being shown and the displayed code is not multiline.
- if show_underline {
+ if let DisplaySuggestion::Diff | DisplaySuggestion::Underline = show_code_change {
draw_col_separator(&mut buffer, row_num, max_line_num_len + 1);
for part in parts {
let span_start_pos = sm.lookup_char_pos(part.span.lo()).col_display;
@@ -1755,7 +1766,7 @@ impl EmitterWriter {
assert!(underline_start >= 0 && underline_end >= 0);
let padding: usize = max_line_num_len + 3;
for p in underline_start..underline_end {
- if !show_diff {
+ if let DisplaySuggestion::Underline = show_code_change {
// If this is a replacement, underline with `^`, if this is an addition
// underline with `+`.
buffer.putc(
@@ -1766,7 +1777,7 @@ impl EmitterWriter {
);
}
}
- if show_diff {
+ if let DisplaySuggestion::Diff = show_code_change {
// Colorize removal with red in diff format.
buffer.set_style_range(
row_num - 2,
@@ -1797,7 +1808,7 @@ impl EmitterWriter {
// if we elided some lines, add an ellipsis
if lines.next().is_some() {
buffer.puts(row_num, max_line_num_len - 1, "...", Style::LineNumber);
- } else if !show_underline {
+ } else if let DisplaySuggestion::None = show_code_change {
draw_col_separator_no_space(&mut buffer, row_num, max_line_num_len + 1);
row_num += 1;
}
@@ -2081,8 +2092,9 @@ fn num_decimal_digits(num: usize) -> usize {
// We replace some characters so the CLI output is always consistent and underlines aligned.
const OUTPUT_REPLACEMENTS: &[(char, &str)] = &[
('\t', " "), // We do our own tab replacement
+ ('\u{200D}', ""), // Replace ZWJ with nothing for consistent terminal output of grapheme clusters.
('\u{202A}', ""), // The following unicode text flow control characters are inconsistently
- ('\u{202B}', ""), // supported accross CLIs and can cause confusion due to the bytes on disk
+ ('\u{202B}', ""), // supported across CLIs and can cause confusion due to the bytes on disk
('\u{202D}', ""), // not corresponding to the visible source code, so we replace them always.
('\u{202E}', ""),
('\u{2066}', ""),
@@ -2092,7 +2104,7 @@ const OUTPUT_REPLACEMENTS: &[(char, &str)] = &[
('\u{2069}', ""),
];
-fn replace_tabs(str: &str) -> String {
+fn normalize_whitespace(str: &str) -> String {
let mut s = str.to_string();
for (c, replacement) in OUTPUT_REPLACEMENTS {
s = s.replace(*c, replacement);
diff --git a/compiler/rustc_errors/src/lib.rs b/compiler/rustc_errors/src/lib.rs
index bb3d3a415e7..a681298301a 100644
--- a/compiler/rustc_errors/src/lib.rs
+++ b/compiler/rustc_errors/src/lib.rs
@@ -6,8 +6,6 @@
#![feature(crate_visibility_modifier)]
#![feature(backtrace)]
#![feature(if_let_guard)]
-#![cfg_attr(bootstrap, feature(format_args_capture))]
-#![feature(iter_zip)]
#![feature(let_else)]
#![feature(nll)]
@@ -1013,7 +1011,9 @@ impl HandlerInner {
}
fn treat_err_as_bug(&self) -> bool {
- self.flags.treat_err_as_bug.map_or(false, |c| self.err_count() >= c.get())
+ self.flags
+ .treat_err_as_bug
+ .map_or(false, |c| self.err_count() + self.lint_err_count >= c.get())
}
fn print_error_count(&mut self, registry: &Registry) {
@@ -1205,7 +1205,10 @@ impl HandlerInner {
fn panic_if_treat_err_as_bug(&self) {
if self.treat_err_as_bug() {
- match (self.err_count(), self.flags.treat_err_as_bug.map(|c| c.get()).unwrap_or(0)) {
+ match (
+ self.err_count() + self.lint_err_count,
+ self.flags.treat_err_as_bug.map(|c| c.get()).unwrap_or(0),
+ ) {
(1, 1) => panic!("aborting due to `-Z treat-err-as-bug=1`"),
(0, _) | (1, _) => {}
(count, as_bug) => panic!(
diff --git a/compiler/rustc_expand/src/base.rs b/compiler/rustc_expand/src/base.rs
index b630bc1f473..07b5e20b2dd 100644
--- a/compiler/rustc_expand/src/base.rs
+++ b/compiler/rustc_expand/src/base.rs
@@ -48,6 +48,7 @@ pub enum Annotatable {
Param(ast::Param),
FieldDef(ast::FieldDef),
Variant(ast::Variant),
+ Crate(ast::Crate),
}
impl Annotatable {
@@ -66,6 +67,7 @@ impl Annotatable {
Annotatable::Param(ref p) => p.span,
Annotatable::FieldDef(ref sf) => sf.span,
Annotatable::Variant(ref v) => v.span,
+ Annotatable::Crate(ref c) => c.span,
}
}
@@ -84,6 +86,7 @@ impl Annotatable {
Annotatable::Param(p) => p.visit_attrs(f),
Annotatable::FieldDef(sf) => sf.visit_attrs(f),
Annotatable::Variant(v) => v.visit_attrs(f),
+ Annotatable::Crate(c) => c.visit_attrs(f),
}
}
@@ -102,6 +105,7 @@ impl Annotatable {
Annotatable::Param(p) => visitor.visit_param(p),
Annotatable::FieldDef(sf) => visitor.visit_field_def(sf),
Annotatable::Variant(v) => visitor.visit_variant(v),
+ Annotatable::Crate(c) => visitor.visit_crate(c),
}
}
@@ -122,7 +126,8 @@ impl Annotatable {
| Annotatable::GenericParam(..)
| Annotatable::Param(..)
| Annotatable::FieldDef(..)
- | Annotatable::Variant(..) => panic!("unexpected annotatable"),
+ | Annotatable::Variant(..)
+ | Annotatable::Crate(..) => panic!("unexpected annotatable"),
}
}
@@ -220,6 +225,13 @@ impl Annotatable {
_ => panic!("expected variant"),
}
}
+
+ pub fn expect_crate(self) -> ast::Crate {
+ match self {
+ Annotatable::Crate(krate) => krate,
+ _ => panic!("expected krate"),
+ }
+ }
}
/// Result of an expansion that may need to be retried.
@@ -419,6 +431,11 @@ pub trait MacResult {
fn make_variants(self: Box<Self>) -> Option<SmallVec<[ast::Variant; 1]>> {
None
}
+
+ fn make_crate(self: Box<Self>) -> Option<ast::Crate> {
+ // Fn-like macros cannot produce a crate.
+ unreachable!()
+ }
}
macro_rules! make_MacEager {
diff --git a/compiler/rustc_expand/src/config.rs b/compiler/rustc_expand/src/config.rs
index 1b123520961..5221ab4b613 100644
--- a/compiler/rustc_expand/src/config.rs
+++ b/compiler/rustc_expand/src/config.rs
@@ -402,7 +402,24 @@ impl<'a> StripUnconfigured<'a> {
);
trees.push((bracket_group, Spacing::Alone));
let tokens = Some(LazyTokenStream::new(AttrAnnotatedTokenStream::new(trees)));
- self.process_cfg_attr(attr::mk_attr_from_item(item, tokens, attr.style, span))
+ let attr = attr::mk_attr_from_item(item, tokens, attr.style, span);
+ if attr.has_name(sym::crate_type) {
+ self.sess.parse_sess.buffer_lint(
+ rustc_lint_defs::builtin::DEPRECATED_CFG_ATTR_CRATE_TYPE_NAME,
+ attr.span,
+ ast::CRATE_NODE_ID,
+ "`crate_type` within an `#![cfg_attr] attribute is deprecated`",
+ );
+ }
+ if attr.has_name(sym::crate_name) {
+ self.sess.parse_sess.buffer_lint(
+ rustc_lint_defs::builtin::DEPRECATED_CFG_ATTR_CRATE_TYPE_NAME,
+ attr.span,
+ ast::CRATE_NODE_ID,
+ "`crate_name` within an `#![cfg_attr] attribute is deprecated`",
+ );
+ }
+ self.process_cfg_attr(attr)
})
.collect()
}
diff --git a/compiler/rustc_expand/src/expand.rs b/compiler/rustc_expand/src/expand.rs
index 89dbd64ed81..ba675daac41 100644
--- a/compiler/rustc_expand/src/expand.rs
+++ b/compiler/rustc_expand/src/expand.rs
@@ -14,13 +14,13 @@ use rustc_ast::tokenstream::TokenStream;
use rustc_ast::visit::{self, AssocCtxt, Visitor};
use rustc_ast::{AstLike, Block, Inline, ItemKind, MacArgs, MacCall};
use rustc_ast::{MacCallStmt, MacStmtStyle, MetaItemKind, ModKind, NestedMetaItem};
-use rustc_ast::{NodeId, PatKind, Path, StmtKind, Unsafe};
+use rustc_ast::{NodeId, PatKind, Path, StmtKind};
use rustc_ast_pretty::pprust;
use rustc_attr::is_builtin_attr;
use rustc_data_structures::map_in_place::MapInPlace;
use rustc_data_structures::stack::ensure_sufficient_stack;
use rustc_data_structures::sync::Lrc;
-use rustc_errors::{Applicability, FatalError, PResult};
+use rustc_errors::{Applicability, PResult};
use rustc_feature::Features;
use rustc_parse::parser::{
AttemptLocalParseRecovery, ForceCollect, Parser, RecoverColon, RecoverComma,
@@ -33,7 +33,7 @@ use rustc_session::Limit;
use rustc_span::symbol::{sym, Ident};
use rustc_span::{FileName, LocalExpnId, Span};
-use smallvec::{smallvec, SmallVec};
+use smallvec::SmallVec;
use std::ops::DerefMut;
use std::path::PathBuf;
use std::rc::Rc;
@@ -205,6 +205,7 @@ ast_fragments! {
Variants(SmallVec<[ast::Variant; 1]>) {
"variant"; many fn flat_map_variant; fn visit_variant(); fn make_variants;
}
+ Crate(ast::Crate) { "crate"; one fn visit_crate; fn visit_crate; fn make_crate; }
}
pub enum SupportsMacroExpansion {
@@ -227,9 +228,8 @@ impl AstFragmentKind {
AstFragmentKind::Items
| AstFragmentKind::TraitItems
| AstFragmentKind::ImplItems
- | AstFragmentKind::ForeignItems => {
- SupportsMacroExpansion::Yes { supports_inner_attrs: true }
- }
+ | AstFragmentKind::ForeignItems
+ | AstFragmentKind::Crate => SupportsMacroExpansion::Yes { supports_inner_attrs: true },
AstFragmentKind::Arms
| AstFragmentKind::Fields
| AstFragmentKind::FieldPats
@@ -288,6 +288,9 @@ impl AstFragmentKind {
AstFragmentKind::OptExpr => {
AstFragment::OptExpr(items.next().map(Annotatable::expect_expr))
}
+ AstFragmentKind::Crate => {
+ AstFragment::Crate(items.next().expect("expected exactly one crate").expect_crate())
+ }
AstFragmentKind::Pat | AstFragmentKind::Ty => {
panic!("patterns and types aren't annotatable")
}
@@ -359,9 +362,7 @@ impl<'a, 'b> MacroExpander<'a, 'b> {
MacroExpander { cx, monotonic }
}
- // FIXME: Avoid visiting the crate as a `Mod` item,
- // make crate a first class expansion target instead.
- pub fn expand_crate(&mut self, mut krate: ast::Crate) -> ast::Crate {
+ pub fn expand_crate(&mut self, krate: ast::Crate) -> ast::Crate {
let file_path = match self.cx.source_map().span_to_filename(krate.span) {
FileName::Real(name) => name
.into_local_path()
@@ -375,52 +376,7 @@ impl<'a, 'b> MacroExpander<'a, 'b> {
file_path_stack: vec![file_path],
dir_path,
});
-
- let krate_item = AstFragment::Items(smallvec![P(ast::Item {
- attrs: krate.attrs,
- span: krate.span,
- kind: ast::ItemKind::Mod(
- Unsafe::No,
- ModKind::Loaded(krate.items, Inline::Yes, krate.span)
- ),
- ident: Ident::empty(),
- id: ast::DUMMY_NODE_ID,
- vis: ast::Visibility {
- span: krate.span.shrink_to_lo(),
- kind: ast::VisibilityKind::Public,
- tokens: None,
- },
- tokens: None,
- })]);
-
- match self.fully_expand_fragment(krate_item).make_items().pop().map(P::into_inner) {
- Some(ast::Item {
- attrs,
- kind: ast::ItemKind::Mod(_, ModKind::Loaded(items, ..)),
- ..
- }) => {
- krate.attrs = attrs;
- krate.items = items;
- }
- None => {
- // Resolution failed so we return an empty expansion
- krate.attrs = vec![];
- krate.items = vec![];
- }
- Some(ast::Item { span, kind, .. }) => {
- krate.attrs = vec![];
- krate.items = vec![];
- self.cx.span_err(
- span,
- &format!(
- "expected crate top-level item to be a module after macro expansion, found {} {}",
- kind.article(), kind.descr()
- ),
- );
- // FIXME: this workaround issue #84569
- FatalError.raise();
- }
- };
+ let krate = self.fully_expand_fragment(AstFragment::Crate(krate)).make_crate();
self.cx.trace_macros_diag();
krate
}
@@ -708,26 +664,32 @@ impl<'a, 'b> MacroExpander<'a, 'b> {
SyntaxExtensionKind::Attr(expander) => {
self.gate_proc_macro_input(&item);
self.gate_proc_macro_attr_item(span, &item);
- let mut fake_tokens = false;
- if let Annotatable::Item(item_inner) = &item {
- if let ItemKind::Mod(_, mod_kind) = &item_inner.kind {
- // FIXME: Collect tokens and use them instead of generating
- // fake ones. These are unstable, so it needs to be
- // fixed prior to stabilization
- // Fake tokens when we are invoking an inner attribute, and:
- fake_tokens = matches!(attr.style, ast::AttrStyle::Inner) &&
- // We are invoking an attribute on the crate root, or an outline
- // module
- (item_inner.ident.name.is_empty() || !matches!(mod_kind, ast::ModKind::Loaded(_, Inline::Yes, _)));
- }
- }
- let tokens = if fake_tokens {
- rustc_parse::fake_token_stream(
+ let tokens = match &item {
+ // FIXME: Collect tokens and use them instead of generating
+ // fake ones. These are unstable, so it needs to be
+ // fixed prior to stabilization
+ // Fake tokens when we are invoking an inner attribute, and
+ // we are invoking it on an out-of-line module or crate.
+ Annotatable::Crate(krate) => rustc_parse::fake_token_stream_for_crate(
&self.cx.sess.parse_sess,
- &item.into_nonterminal(),
- )
- } else {
- item.into_tokens(&self.cx.sess.parse_sess)
+ krate,
+ ),
+ Annotatable::Item(item_inner)
+ if matches!(attr.style, ast::AttrStyle::Inner)
+ && matches!(
+ item_inner.kind,
+ ItemKind::Mod(
+ _,
+ ModKind::Unloaded | ModKind::Loaded(_, Inline::No, _),
+ )
+ ) =>
+ {
+ rustc_parse::fake_token_stream(
+ &self.cx.sess.parse_sess,
+ &item.into_nonterminal(),
+ )
+ }
+ _ => item.into_tokens(&self.cx.sess.parse_sess),
};
let attr_item = attr.unwrap_normal_item();
if let MacArgs::Eq(..) = attr_item.args {
@@ -804,7 +766,8 @@ impl<'a, 'b> MacroExpander<'a, 'b> {
Annotatable::Item(_)
| Annotatable::TraitItem(_)
| Annotatable::ImplItem(_)
- | Annotatable::ForeignItem(_) => return,
+ | Annotatable::ForeignItem(_)
+ | Annotatable::Crate(..) => return,
Annotatable::Stmt(stmt) => {
// Attributes are stable on item statements,
// but unstable on all other kinds of statements
@@ -949,6 +912,7 @@ pub fn parse_ast_fragment<'a>(
RecoverComma::No,
RecoverColon::Yes,
)?),
+ AstFragmentKind::Crate => AstFragment::Crate(this.parse_crate_mod()?),
AstFragmentKind::Arms
| AstFragmentKind::Fields
| AstFragmentKind::FieldPats
@@ -1195,6 +1159,30 @@ macro_rules! assign_id {
}
impl<'a, 'b> MutVisitor for InvocationCollector<'a, 'b> {
+ fn visit_crate(&mut self, krate: &mut ast::Crate) {
+ let span = krate.span;
+ let empty_crate =
+ || ast::Crate { attrs: Vec::new(), items: Vec::new(), span, is_placeholder: None };
+ let mut fold_crate = |krate: ast::Crate| {
+ let mut krate = match self.configure(krate) {
+ Some(krate) => krate,
+ None => return empty_crate(),
+ };
+
+ if let Some(attr) = self.take_first_attr(&mut krate) {
+ return self
+ .collect_attr(attr, Annotatable::Crate(krate), AstFragmentKind::Crate)
+ .make_crate();
+ }
+
+ noop_visit_crate(&mut krate, self);
+ krate
+ };
+
+ // Cannot use `visit_clobber` here, see the FIXME on it.
+ *krate = fold_crate(mem::replace(krate, empty_crate()));
+ }
+
fn visit_expr(&mut self, expr: &mut P<ast::Expr>) {
self.cfg.configure_expr(expr);
visit_clobber(expr.deref_mut(), |mut expr| {
diff --git a/compiler/rustc_expand/src/lib.rs b/compiler/rustc_expand/src/lib.rs
index 4e84a9df6c9..47a64b457d0 100644
--- a/compiler/rustc_expand/src/lib.rs
+++ b/compiler/rustc_expand/src/lib.rs
@@ -1,9 +1,7 @@
#![feature(crate_visibility_modifier)]
#![feature(decl_macro)]
-#![feature(destructuring_assignment)]
-#![cfg_attr(bootstrap, feature(format_args_capture))]
+#![cfg_attr(bootstrap, feature(destructuring_assignment))]
#![feature(if_let_guard)]
-#![feature(iter_zip)]
#![feature(let_else)]
#![feature(proc_macro_diagnostic)]
#![feature(proc_macro_internals)]
diff --git a/compiler/rustc_expand/src/mbe/macro_parser.rs b/compiler/rustc_expand/src/mbe/macro_parser.rs
index a7434d73abe..dd82add08dd 100644
--- a/compiler/rustc_expand/src/mbe/macro_parser.rs
+++ b/compiler/rustc_expand/src/mbe/macro_parser.rs
@@ -584,9 +584,7 @@ fn inner_parse_loop<'root, 'tt>(
//
// At the beginning of the loop, if we reach the end of the delimited submatcher,
// we pop the stack to backtrack out of the descent.
- seq
- @
- (TokenTree::Delimited(..)
+ seq @ (TokenTree::Delimited(..)
| TokenTree::Token(Token { kind: DocComment(..), .. })) => {
let lower_elts = mem::replace(&mut item.top_elts, Tt(seq));
let idx = item.idx;
diff --git a/compiler/rustc_expand/src/mbe/macro_rules.rs b/compiler/rustc_expand/src/mbe/macro_rules.rs
index f8491654f39..8065911afb9 100644
--- a/compiler/rustc_expand/src/mbe/macro_rules.rs
+++ b/compiler/rustc_expand/src/mbe/macro_rules.rs
@@ -253,7 +253,7 @@ fn generic_extension<'cx>(
for (i, lhs) in lhses.iter().enumerate() {
// try each arm's matchers
let lhs_tt = match *lhs {
- mbe::TokenTree::Delimited(_, ref delim) => &delim.tts[..],
+ mbe::TokenTree::Delimited(_, ref delim) => &delim.tts,
_ => cx.span_bug(sp, "malformed macro lhs"),
};
@@ -353,7 +353,7 @@ fn generic_extension<'cx>(
for lhs in lhses {
// try each arm's matchers
let lhs_tt = match *lhs {
- mbe::TokenTree::Delimited(_, ref delim) => &delim.tts[..],
+ mbe::TokenTree::Delimited(_, ref delim) => &delim.tts,
_ => continue,
};
if let Success(_) =
@@ -677,11 +677,11 @@ impl FirstSets {
first.replace_with(tt.clone());
}
TokenTree::Delimited(span, ref delimited) => {
- build_recur(sets, &delimited.tts[..]);
+ build_recur(sets, &delimited.tts);
first.replace_with(delimited.open_tt(span));
}
TokenTree::Sequence(sp, ref seq_rep) => {
- let subfirst = build_recur(sets, &seq_rep.tts[..]);
+ let subfirst = build_recur(sets, &seq_rep.tts);
match sets.first.entry(sp.entire()) {
Entry::Vacant(vac) => {
@@ -748,7 +748,7 @@ impl FirstSets {
let subfirst = match self.first.get(&sp.entire()) {
Some(&Some(ref subfirst)) => subfirst,
Some(&None) => {
- subfirst_owned = self.first(&seq_rep.tts[..]);
+ subfirst_owned = self.first(&seq_rep.tts);
&subfirst_owned
}
None => {
@@ -1027,6 +1027,24 @@ fn check_matcher_core(
),
);
err.span_label(sp, format!("not allowed after `{}` fragments", kind));
+
+ if kind == NonterminalKind::PatWithOr
+ && sess.edition == Edition::Edition2021
+ && next_token.is_token(&BinOp(token::BinOpToken::Or))
+ {
+ let suggestion = quoted_tt_to_string(&TokenTree::MetaVarDecl(
+ span,
+ name,
+ Some(NonterminalKind::PatParam { inferred: false }),
+ ));
+ err.span_suggestion(
+ span,
+ &format!("try a `pat_param` fragment specifier instead"),
+ suggestion,
+ Applicability::MaybeIncorrect,
+ );
+ }
+
let msg = "allowed there are: ";
match possible {
&[] => {}
diff --git a/compiler/rustc_expand/src/mbe/transcribe.rs b/compiler/rustc_expand/src/mbe/transcribe.rs
index 88e1623012b..01a7f726617 100644
--- a/compiler/rustc_expand/src/mbe/transcribe.rs
+++ b/compiler/rustc_expand/src/mbe/transcribe.rs
@@ -175,12 +175,12 @@ pub(super) fn transcribe<'a>(
));
}
- LockstepIterSize::Contradiction(ref msg) => {
+ LockstepIterSize::Contradiction(msg) => {
// FIXME: this really ought to be caught at macro definition time... It
// happens when two meta-variables are used in the same repetition in a
// sequence, but they come from different sequence matchers and repeat
// different amounts.
- return Err(cx.struct_span_err(seq.span(), &msg[..]));
+ return Err(cx.struct_span_err(seq.span(), &msg));
}
LockstepIterSize::Constraint(len, _) => {
diff --git a/compiler/rustc_expand/src/parse/tests.rs b/compiler/rustc_expand/src/parse/tests.rs
index 6402a81e7c1..4a8236b2cf3 100644
--- a/compiler/rustc_expand/src/parse/tests.rs
+++ b/compiler/rustc_expand/src/parse/tests.rs
@@ -65,24 +65,33 @@ fn string_to_tts_macro() {
let tts: &[TokenTree] = &tts[..];
match tts {
- [TokenTree::Token(Token { kind: token::Ident(name_macro_rules, false), .. }), TokenTree::Token(Token { kind: token::Not, .. }), TokenTree::Token(Token { kind: token::Ident(name_zip, false), .. }), TokenTree::Delimited(_, macro_delim, macro_tts)]
- if name_macro_rules == &kw::MacroRules && name_zip.as_str() == "zip" =>
- {
+ [
+ TokenTree::Token(Token { kind: token::Ident(name_macro_rules, false), .. }),
+ TokenTree::Token(Token { kind: token::Not, .. }),
+ TokenTree::Token(Token { kind: token::Ident(name_zip, false), .. }),
+ TokenTree::Delimited(_, macro_delim, macro_tts),
+ ] if name_macro_rules == &kw::MacroRules && name_zip.as_str() == "zip" => {
let tts = &macro_tts.trees().collect::<Vec<_>>();
match &tts[..] {
- [TokenTree::Delimited(_, first_delim, first_tts), TokenTree::Token(Token { kind: token::FatArrow, .. }), TokenTree::Delimited(_, second_delim, second_tts)]
- if macro_delim == &token::Paren =>
- {
+ [
+ TokenTree::Delimited(_, first_delim, first_tts),
+ TokenTree::Token(Token { kind: token::FatArrow, .. }),
+ TokenTree::Delimited(_, second_delim, second_tts),
+ ] if macro_delim == &token::Paren => {
let tts = &first_tts.trees().collect::<Vec<_>>();
match &tts[..] {
- [TokenTree::Token(Token { kind: token::Dollar, .. }), TokenTree::Token(Token { kind: token::Ident(name, false), .. })]
- if first_delim == &token::Paren && name.as_str() == "a" => {}
+ [
+ TokenTree::Token(Token { kind: token::Dollar, .. }),
+ TokenTree::Token(Token { kind: token::Ident(name, false), .. }),
+ ] if first_delim == &token::Paren && name.as_str() == "a" => {}
_ => panic!("value 3: {:?} {:?}", first_delim, first_tts),
}
let tts = &second_tts.trees().collect::<Vec<_>>();
match &tts[..] {
- [TokenTree::Token(Token { kind: token::Dollar, .. }), TokenTree::Token(Token { kind: token::Ident(name, false), .. })]
- if second_delim == &token::Paren && name.as_str() == "a" => {}
+ [
+ TokenTree::Token(Token { kind: token::Dollar, .. }),
+ TokenTree::Token(Token { kind: token::Ident(name, false), .. }),
+ ] if second_delim == &token::Paren && name.as_str() == "a" => {}
_ => panic!("value 4: {:?} {:?}", second_delim, second_tts),
}
}
diff --git a/compiler/rustc_expand/src/placeholders.rs b/compiler/rustc_expand/src/placeholders.rs
index 12b6bc7bbe7..25b3a5820e6 100644
--- a/compiler/rustc_expand/src/placeholders.rs
+++ b/compiler/rustc_expand/src/placeholders.rs
@@ -46,6 +46,12 @@ pub fn placeholder(
|| P(ast::Pat { id, kind: ast::PatKind::MacCall(mac_placeholder()), span, tokens: None });
match kind {
+ AstFragmentKind::Crate => AstFragment::Crate(ast::Crate {
+ attrs: Default::default(),
+ items: Default::default(),
+ span,
+ is_placeholder: Some(id),
+ }),
AstFragmentKind::Expr => AstFragment::Expr(expr_placeholder()),
AstFragmentKind::OptExpr => AstFragment::OptExpr(Some(expr_placeholder())),
AstFragmentKind::Items => AstFragment::Items(smallvec![P(ast::Item {
@@ -354,4 +360,12 @@ impl MutVisitor for PlaceholderExpander {
_ => noop_visit_ty(ty, self),
}
}
+
+ fn visit_crate(&mut self, krate: &mut ast::Crate) {
+ if let Some(id) = krate.is_placeholder {
+ *krate = self.remove(id).make_crate();
+ } else {
+ noop_visit_crate(krate, self)
+ }
+ }
}
diff --git a/compiler/rustc_expand/src/proc_macro_server.rs b/compiler/rustc_expand/src/proc_macro_server.rs
index fa9e98be9e8..b7e47e4da6f 100644
--- a/compiler/rustc_expand/src/proc_macro_server.rs
+++ b/compiler/rustc_expand/src/proc_macro_server.rs
@@ -466,13 +466,12 @@ impl server::TokenStream for Rustc<'_, '_> {
ast::ExprKind::Unary(ast::UnOp::Neg, e) => match &e.kind {
ast::ExprKind::Lit(l) => match l.token {
token::Lit { kind: token::Integer | token::Float, .. } => {
- Ok(std::array::IntoIter::new([
+ Ok(Self::TokenStream::from_iter([
// FIXME: The span of the `-` token is lost when
// parsing, so we cannot faithfully recover it here.
tokenstream::TokenTree::token(token::BinOp(token::Minus), e.span),
tokenstream::TokenTree::token(token::Literal(l.token), l.span),
- ])
- .collect())
+ ]))
}
_ => Err(()),
},
diff --git a/compiler/rustc_feature/src/accepted.rs b/compiler/rustc_feature/src/accepted.rs
index 6950fae898f..32a9d081ed8 100644
--- a/compiler/rustc_feature/src/accepted.rs
+++ b/compiler/rustc_feature/src/accepted.rs
@@ -90,6 +90,8 @@ declare_features! (
(accepted, const_fn_union, "1.56.0", Some(51909), None),
/// Allows unsizing coercions in `const fn`.
(accepted, const_fn_unsize, "1.54.0", Some(64992), None),
+ /// Allows const generics to have default values (e.g. `struct Foo<const N: usize = 3>(...);`).
+ (accepted, const_generics_defaults, "1.59.0", Some(44580), None),
/// Allows the use of `if` and `match` in constants.
(accepted, const_if_match, "1.46.0", Some(49146), None),
/// Allows indexing into constant arrays.
@@ -112,6 +114,8 @@ declare_features! (
(accepted, default_type_params, "1.0.0", None, None),
/// Allows `#[deprecated]` attribute.
(accepted, deprecated, "1.9.0", Some(29935), None),
+ /// Allows the use of destructuring assignments.
+ (accepted, destructuring_assignment, "1.59.0", Some(71126), None),
/// Allows `#[doc(alias = "...")]`.
(accepted, doc_alias, "1.48.0", Some(50146), None),
/// Allows `..` in tuple (struct) patterns.
diff --git a/compiler/rustc_feature/src/active.rs b/compiler/rustc_feature/src/active.rs
index 608581306be..ebd12d6ab4e 100644
--- a/compiler/rustc_feature/src/active.rs
+++ b/compiler/rustc_feature/src/active.rs
@@ -69,10 +69,6 @@ macro_rules! declare_features {
}
}
- pub fn unordered_const_ty_params(&self) -> bool {
- self.const_generics_defaults || self.generic_const_exprs || self.adt_const_params
- }
-
/// Some features are known to be incomplete and using them is likely to have
/// unanticipated results, such as compiler crashes. We warn the user about these
/// to alert them.
@@ -206,6 +202,8 @@ declare_features! (
(active, rustc_allow_const_fn_unstable, "1.49.0", Some(69399), None),
/// Allows using compiler's own crates.
(active, rustc_private, "1.0.0", Some(27812), None),
+ /// Allows using internal rustdoc features like `doc(primitive)` or `doc(keyword)`.
+ (active, rustdoc_internals, "1.58.0", Some(90418), None),
/// Allows using `#[start]` on a function indicating that it is the program entrypoint.
(active, start, "1.0.0", Some(29633), None),
/// Allows using `#[structural_match]` which indicates that a type is structurally matchable.
@@ -288,6 +286,8 @@ declare_features! (
(active, asm_experimental_arch, "1.58.0", Some(72016), None),
/// Allows using `sym` operands in inline assembly.
(active, asm_sym, "1.58.0", Some(72016), None),
+ /// Allows the `may_unwind` option in inline assembly.
+ (active, asm_unwind, "1.58.0", Some(72016), None),
/// Allows the user of associated type bounds.
(active, associated_type_bounds, "1.34.0", Some(52662), None),
/// Allows associated type defaults.
@@ -330,8 +330,6 @@ declare_features! (
(active, const_fn_trait_bound, "1.53.0", Some(57563), None),
/// Allows `for _ in _` loops in const contexts.
(active, const_for, "1.56.0", Some(87575), None),
- /// Allows const generics to have default values (e.g. `struct Foo<const N: usize = 3>(...);`).
- (active, const_generics_defaults, "1.51.0", Some(44580), None),
/// Allows argument and return position `impl Trait` in a `const fn`.
(active, const_impl_trait, "1.48.0", Some(77463), None),
/// Allows using `&mut` in constant functions.
@@ -358,20 +356,14 @@ declare_features! (
(active, default_type_parameter_fallback, "1.3.0", Some(27336), None),
/// Allows `#[derive(Default)]` and `#[default]` on enums.
(active, derive_default_enum, "1.56.0", Some(86985), None),
- /// Allows the use of destructuring assignments.
- (active, destructuring_assignment, "1.49.0", Some(71126), None),
/// Tells rustdoc to automatically generate `#[doc(cfg(...))]`.
(active, doc_auto_cfg, "1.58.0", Some(43781), None),
/// Allows `#[doc(cfg(...))]`.
(active, doc_cfg, "1.21.0", Some(43781), None),
/// Allows `#[doc(cfg_hide(...))]`.
(active, doc_cfg_hide, "1.57.0", Some(43781), None),
- /// Allows using `#[doc(keyword = "...")]`.
- (active, doc_keyword, "1.28.0", Some(51315), None),
/// Allows `#[doc(masked)]`.
(active, doc_masked, "1.21.0", Some(44027), None),
- /// Allows using doc(primitive) without a future-incompat warning
- (active, doc_primitive, "1.56.0", Some(88070), None),
/// Allows `X..Y` patterns.
(active, exclusive_range_pattern, "1.11.0", Some(37854), None),
/// Allows exhaustive pattern matching on types that contain uninhabited types.
@@ -409,7 +401,9 @@ declare_features! (
/// Allows associated types in inherent impls.
(incomplete, inherent_associated_types, "1.52.0", Some(8995), None),
/// Allow anonymous constants from an inline `const` block
- (incomplete, inline_const, "1.49.0", Some(76001), None),
+ (active, inline_const, "1.49.0", Some(76001), None),
+ /// Allow anonymous constants from an inline `const` block in pattern position
+ (incomplete, inline_const_pat, "1.58.0", Some(76001), None),
/// Allows using `pointer` and `reference` in intra-doc links
(active, intra_doc_pointers, "1.51.0", Some(80896), None),
/// Allows `#[instruction_set(_)]` attribute
diff --git a/compiler/rustc_feature/src/removed.rs b/compiler/rustc_feature/src/removed.rs
index 4b40040a036..b9f3b5ad1b1 100644
--- a/compiler/rustc_feature/src/removed.rs
+++ b/compiler/rustc_feature/src/removed.rs
@@ -76,6 +76,12 @@ declare_features! (
/// Allows the use of `#[derive(Anything)]` as sugar for `#[derive_Anything]`.
(removed, custom_derive, "1.32.0", Some(29644), None,
Some("subsumed by `#[proc_macro_derive]`")),
+ /// Allows using `#[doc(keyword = "...")]`.
+ (removed, doc_keyword, "1.28.0", Some(51315), None,
+ Some("merged into `#![feature(rustdoc_internals)]`")),
+ /// Allows using `doc(primitive)` without a future-incompat warning.
+ (removed, doc_primitive, "1.56.0", Some(88070), None,
+ Some("merged into `#![feature(rustdoc_internals)]`")),
/// Allows `#[doc(spotlight)]`.
/// The attribute was renamed to `#[doc(notable_trait)]`
/// and the feature to `doc_notable_trait`.
diff --git a/compiler/rustc_graphviz/src/lib.rs b/compiler/rustc_graphviz/src/lib.rs
index 27390fd2e4d..e318090ebe1 100644
--- a/compiler/rustc_graphviz/src/lib.rs
+++ b/compiler/rustc_graphviz/src/lib.rs
@@ -472,7 +472,7 @@ pub trait Labeller<'a> {
/// Escape tags in such a way that it is suitable for inclusion in a
/// Graphviz HTML label.
pub fn escape_html(s: &str) -> String {
- s.replace("&", "&amp;").replace("\"", "&quot;").replace("<", "&lt;").replace(">", "&gt;")
+ s.replace('&', "&amp;").replace('\"', "&quot;").replace('<', "&lt;").replace('>', "&gt;")
}
impl<'a> LabelText<'a> {
@@ -659,7 +659,7 @@ where
}
writeln!(text, ";").unwrap();
- w.write_all(&text[..])?;
+ w.write_all(&text)?;
text.clear();
}
@@ -684,7 +684,7 @@ where
}
writeln!(text, ";").unwrap();
- w.write_all(&text[..])?;
+ w.write_all(&text)?;
text.clear();
}
diff --git a/compiler/rustc_hir/src/arena.rs b/compiler/rustc_hir/src/arena.rs
index f19ca497d8b..edad00ed6a2 100644
--- a/compiler/rustc_hir/src/arena.rs
+++ b/compiler/rustc_hir/src/arena.rs
@@ -20,6 +20,7 @@ macro_rules! arena_types {
[] generic_bound: rustc_hir::GenericBound<'tcx>,
[] generic_param: rustc_hir::GenericParam<'tcx>,
[] expr: rustc_hir::Expr<'tcx>,
+ [] let_expr: rustc_hir::Let<'tcx>,
[] expr_field: rustc_hir::ExprField<'tcx>,
[] pat_field: rustc_hir::PatField<'tcx>,
[] fn_decl: rustc_hir::FnDecl<'tcx>,
diff --git a/compiler/rustc_hir/src/def.rs b/compiler/rustc_hir/src/def.rs
index 60761a05de8..a43cb0203dd 100644
--- a/compiler/rustc_hir/src/def.rs
+++ b/compiler/rustc_hir/src/def.rs
@@ -113,7 +113,7 @@ pub enum DefKind {
Field,
/// Lifetime parameter: the `'a` in `struct Foo<'a> { ... }`
LifetimeParam,
- /// A use of [`global_asm!`].
+ /// A use of `global_asm!`.
GlobalAsm,
Impl,
Closure,
@@ -443,11 +443,11 @@ impl<T> PerNS<T> {
}
pub fn into_iter(self) -> IntoIter<T, 3> {
- IntoIter::new([self.value_ns, self.type_ns, self.macro_ns])
+ [self.value_ns, self.type_ns, self.macro_ns].into_iter()
}
pub fn iter(&self) -> IntoIter<&T, 3> {
- IntoIter::new([&self.value_ns, &self.type_ns, &self.macro_ns])
+ [&self.value_ns, &self.type_ns, &self.macro_ns].into_iter()
}
}
@@ -481,7 +481,7 @@ impl<T> PerNS<Option<T>> {
/// Returns an iterator over the items which are `Some`.
pub fn present_items(self) -> impl Iterator<Item = T> {
- IntoIter::new([self.type_ns, self.value_ns, self.macro_ns]).flatten()
+ [self.type_ns, self.value_ns, self.macro_ns].into_iter().flatten()
}
}
diff --git a/compiler/rustc_hir/src/definitions.rs b/compiler/rustc_hir/src/definitions.rs
index ca29351455e..40071c6df8c 100644
--- a/compiler/rustc_hir/src/definitions.rs
+++ b/compiler/rustc_hir/src/definitions.rs
@@ -267,6 +267,8 @@ pub enum DefPathData {
// Different kinds of items and item-like things:
/// An impl.
Impl,
+ /// An `extern` block.
+ ForeignMod,
/// Something in the type namespace.
TypeNs(Symbol),
/// Something in the value namespace.
@@ -469,7 +471,9 @@ impl DefPathData {
match *self {
TypeNs(name) | ValueNs(name) | MacroNs(name) | LifetimeNs(name) => Some(name),
- Impl | CrateRoot | Misc | ClosureExpr | Ctor | AnonConst | ImplTrait => None,
+ Impl | ForeignMod | CrateRoot | Misc | ClosureExpr | Ctor | AnonConst | ImplTrait => {
+ None
+ }
}
}
@@ -482,6 +486,7 @@ impl DefPathData {
// Note that this does not show up in user print-outs.
CrateRoot => DefPathDataName::Anon { namespace: kw::Crate },
Impl => DefPathDataName::Anon { namespace: kw::Impl },
+ ForeignMod => DefPathDataName::Anon { namespace: kw::Extern },
Misc => DefPathDataName::Anon { namespace: sym::misc },
ClosureExpr => DefPathDataName::Anon { namespace: sym::closure },
Ctor => DefPathDataName::Anon { namespace: sym::constructor },
diff --git a/compiler/rustc_hir/src/hir.rs b/compiler/rustc_hir/src/hir.rs
index c67d3df3ded..64bd32b8ddc 100644
--- a/compiler/rustc_hir/src/hir.rs
+++ b/compiler/rustc_hir/src/hir.rs
@@ -17,8 +17,7 @@ use rustc_index::vec::IndexVec;
use rustc_macros::HashStable_Generic;
use rustc_span::source_map::Spanned;
use rustc_span::symbol::{kw, sym, Ident, Symbol};
-use rustc_span::{def_id::LocalDefId, BytePos};
-use rustc_span::{MultiSpan, Span, DUMMY_SP};
+use rustc_span::{def_id::LocalDefId, BytePos, MultiSpan, Span, DUMMY_SP};
use rustc_target::asm::InlineAsmRegOrRegClass;
use rustc_target::spec::abi::Abi;
@@ -92,7 +91,9 @@ pub enum LifetimeName {
Param(ParamName),
/// User wrote nothing (e.g., the lifetime in `&u32`).
- Implicit,
+ ///
+ /// The bool indicates whether the user should have written something.
+ Implicit(bool),
/// Implicit lifetime in a context like `dyn Foo`. This is
/// distinguished from implicit lifetimes elsewhere because the
@@ -122,7 +123,7 @@ impl LifetimeName {
pub fn ident(&self) -> Ident {
match *self {
LifetimeName::ImplicitObjectLifetimeDefault
- | LifetimeName::Implicit
+ | LifetimeName::Implicit(_)
| LifetimeName::Error => Ident::empty(),
LifetimeName::Underscore => Ident::with_dummy_span(kw::UnderscoreLifetime),
LifetimeName::Static => Ident::with_dummy_span(kw::StaticLifetime),
@@ -133,7 +134,7 @@ impl LifetimeName {
pub fn is_elided(&self) -> bool {
match self {
LifetimeName::ImplicitObjectLifetimeDefault
- | LifetimeName::Implicit
+ | LifetimeName::Implicit(_)
| LifetimeName::Underscore => true,
// It might seem surprising that `Fresh(_)` counts as
@@ -254,23 +255,9 @@ pub struct ConstArg {
pub span: Span,
}
-#[derive(Copy, Clone, Encodable, Debug, HashStable_Generic)]
-pub enum InferKind {
- Const,
- Type,
-}
-
-impl InferKind {
- #[inline]
- pub fn is_type(self) -> bool {
- matches!(self, InferKind::Type)
- }
-}
-
#[derive(Encodable, Debug, HashStable_Generic)]
pub struct InferArg {
pub hir_id: HirId,
- pub kind: InferKind,
pub span: Span,
}
@@ -324,13 +311,11 @@ impl GenericArg<'_> {
}
}
- pub fn to_ord(&self, feats: &rustc_feature::Features) -> ast::ParamKindOrd {
+ pub fn to_ord(&self) -> ast::ParamKindOrd {
match self {
GenericArg::Lifetime(_) => ast::ParamKindOrd::Lifetime,
GenericArg::Type(_) => ast::ParamKindOrd::Type,
- GenericArg::Const(_) => {
- ast::ParamKindOrd::Const { unordered: feats.unordered_const_ty_params() }
- }
+ GenericArg::Const(_) => ast::ParamKindOrd::Const,
GenericArg::Infer(_) => ast::ParamKindOrd::Infer,
}
}
@@ -523,13 +508,21 @@ pub struct GenericParam<'hir> {
pub kind: GenericParamKind<'hir>,
}
-impl GenericParam<'hir> {
- pub fn bounds_span(&self) -> Option<Span> {
- self.bounds.iter().fold(None, |span, bound| {
- let span = span.map(|s| s.to(bound.span())).unwrap_or_else(|| bound.span());
-
- Some(span)
- })
+impl<'hir> GenericParam<'hir> {
+ pub fn bounds_span_for_suggestions(&self) -> Option<Span> {
+ self.bounds
+ .iter()
+ .fold(None, |span: Option<Span>, bound| {
+ // We include bounds that come from a `#[derive(_)]` but point at the user's code,
+ // as we use this method to get a span appropriate for suggestions.
+ if !bound.span().can_be_used_for_suggestions() {
+ None
+ } else {
+ let span = span.map(|s| s.to(bound.span())).unwrap_or_else(|| bound.span());
+ Some(span)
+ }
+ })
+ .map(|sp| sp.shrink_to_hi())
}
}
@@ -550,7 +543,7 @@ pub struct Generics<'hir> {
pub span: Span,
}
-impl Generics<'hir> {
+impl<'hir> Generics<'hir> {
pub const fn empty() -> Generics<'hir> {
Generics {
params: &[],
@@ -615,7 +608,7 @@ pub enum WherePredicate<'hir> {
EqPredicate(WhereEqPredicate<'hir>),
}
-impl WherePredicate<'_> {
+impl<'hir> WherePredicate<'hir> {
pub fn span(&self) -> Span {
match self {
WherePredicate::BoundPredicate(p) => p.span,
@@ -637,7 +630,7 @@ pub struct WhereBoundPredicate<'hir> {
pub bounds: GenericBounds<'hir>,
}
-impl WhereBoundPredicate<'hir> {
+impl<'hir> WhereBoundPredicate<'hir> {
/// Returns `true` if `param_def_id` matches the `bounded_ty` of this predicate.
pub fn is_param_bound(&self, param_def_id: DefId) -> bool {
let path = match self.bounded_ty.kind {
@@ -1167,10 +1160,24 @@ pub struct Arm<'hir> {
pub body: &'hir Expr<'hir>,
}
+/// Represents a `let <pat>[: <ty>] = <expr>` expression (not a Local), occurring in an `if-let` or
+/// `let-else`, evaluating to a boolean. Typically the pattern is refutable.
+///
+/// In an if-let, imagine it as `if (let <pat> = <expr>) { ... }`; in a let-else, it is part of the
+/// desugaring to if-let. Only let-else supports the type annotation at present.
+#[derive(Debug, HashStable_Generic)]
+pub struct Let<'hir> {
+ pub hir_id: HirId,
+ pub span: Span,
+ pub pat: &'hir Pat<'hir>,
+ pub ty: Option<&'hir Ty<'hir>>,
+ pub init: &'hir Expr<'hir>,
+}
+
#[derive(Debug, HashStable_Generic)]
pub enum Guard<'hir> {
If(&'hir Expr<'hir>),
- // FIXME use ExprKind::Let for this.
+ // FIXME use hir::Let for this.
IfLet(&'hir Pat<'hir>, &'hir Expr<'hir>),
}
@@ -1229,7 +1236,7 @@ pub struct Body<'hir> {
pub generator_kind: Option<GeneratorKind>,
}
-impl Body<'hir> {
+impl<'hir> Body<'hir> {
pub fn id(&self) -> BodyId {
BodyId { hir_id: self.value.hir_id }
}
@@ -1620,13 +1627,13 @@ pub fn is_range_literal(expr: &Expr<'_>) -> bool {
| LangItem::RangeFrom
| LangItem::RangeFull
| LangItem::RangeToInclusive,
- _,
+ ..
)
),
// `..=` desugars into `::std::ops::RangeInclusive::new(...)`.
ExprKind::Call(ref func, _) => {
- matches!(func.kind, ExprKind::Path(QPath::LangItem(LangItem::RangeInclusiveNew, _)))
+ matches!(func.kind, ExprKind::Path(QPath::LangItem(LangItem::RangeInclusiveNew, ..)))
}
_ => false,
@@ -1687,7 +1694,7 @@ pub enum ExprKind<'hir> {
///
/// These are not `Local` and only occur as expressions.
/// The `let Some(x) = foo()` in `if let Some(x) = foo()` is an example of `Let(..)`.
- Let(&'hir Pat<'hir>, &'hir Expr<'hir>, Span),
+ Let(&'hir Let<'hir>),
/// An `if` block, with an optional else block.
///
/// I.e., `if <expr> { <expr> } else { <expr> }`.
@@ -1781,8 +1788,8 @@ pub enum QPath<'hir> {
/// the `X` and `Y` nodes each being a `TyKind::Path(QPath::TypeRelative(..))`.
TypeRelative(&'hir Ty<'hir>, &'hir PathSegment<'hir>),
- /// Reference to a `#[lang = "foo"]` item.
- LangItem(LangItem, Span),
+ /// Reference to a `#[lang = "foo"]` item. `HirId` of the inner expr.
+ LangItem(LangItem, Span, Option<HirId>),
}
impl<'hir> QPath<'hir> {
@@ -1791,7 +1798,7 @@ impl<'hir> QPath<'hir> {
match *self {
QPath::Resolved(_, path) => path.span,
QPath::TypeRelative(qself, ps) => qself.span.to(ps.ident.span),
- QPath::LangItem(_, span) => span,
+ QPath::LangItem(_, span, _) => span,
}
}
@@ -1801,7 +1808,7 @@ impl<'hir> QPath<'hir> {
match *self {
QPath::Resolved(_, path) => path.span,
QPath::TypeRelative(qself, _) => qself.span,
- QPath::LangItem(_, span) => span,
+ QPath::LangItem(_, span, _) => span,
}
}
@@ -1811,7 +1818,7 @@ impl<'hir> QPath<'hir> {
match *self {
QPath::Resolved(_, path) => path.segments.last().unwrap().ident.span,
QPath::TypeRelative(_, segment) => segment.ident.span,
- QPath::LangItem(_, span) => span,
+ QPath::LangItem(_, span, _) => span,
}
}
}
@@ -2239,7 +2246,6 @@ pub struct BareFnTy<'hir> {
pub struct OpaqueTy<'hir> {
pub generics: Generics<'hir>,
pub bounds: GenericBounds<'hir>,
- pub impl_trait_fn: Option<DefId>,
pub origin: OpaqueTyOrigin,
}
@@ -2247,9 +2253,9 @@ pub struct OpaqueTy<'hir> {
#[derive(Copy, Clone, PartialEq, Eq, Encodable, Decodable, Debug, HashStable_Generic)]
pub enum OpaqueTyOrigin {
/// `-> impl Trait`
- FnReturn,
+ FnReturn(LocalDefId),
/// `async fn`
- AsyncFn,
+ AsyncFn(LocalDefId),
/// type aliases: `type Foo = impl Trait;`
TyAlias,
}
@@ -2617,7 +2623,7 @@ pub enum VariantData<'hir> {
Unit(HirId),
}
-impl VariantData<'hir> {
+impl<'hir> VariantData<'hir> {
/// Return the fields of this variant.
pub fn fields(&self) -> &'hir [FieldDef<'hir>] {
match *self {
@@ -2800,7 +2806,9 @@ impl ItemKind<'_> {
Some(match *self {
ItemKind::Fn(_, ref generics, _)
| ItemKind::TyAlias(_, ref generics)
- | ItemKind::OpaqueTy(OpaqueTy { ref generics, impl_trait_fn: None, .. })
+ | ItemKind::OpaqueTy(OpaqueTy {
+ ref generics, origin: OpaqueTyOrigin::TyAlias, ..
+ })
| ItemKind::Enum(_, ref generics)
| ItemKind::Struct(_, ref generics)
| ItemKind::Union(_, ref generics)
@@ -3200,59 +3208,6 @@ impl<'hir> Node<'hir> {
}
}
- pub fn hir_id(&self) -> Option<HirId> {
- match self {
- Node::Item(Item { def_id, .. })
- | Node::TraitItem(TraitItem { def_id, .. })
- | Node::ImplItem(ImplItem { def_id, .. })
- | Node::ForeignItem(ForeignItem { def_id, .. }) => Some(HirId::make_owner(*def_id)),
- Node::Field(FieldDef { hir_id, .. })
- | Node::AnonConst(AnonConst { hir_id, .. })
- | Node::Expr(Expr { hir_id, .. })
- | Node::Stmt(Stmt { hir_id, .. })
- | Node::Ty(Ty { hir_id, .. })
- | Node::Binding(Pat { hir_id, .. })
- | Node::Pat(Pat { hir_id, .. })
- | Node::Arm(Arm { hir_id, .. })
- | Node::Block(Block { hir_id, .. })
- | Node::Local(Local { hir_id, .. })
- | Node::Lifetime(Lifetime { hir_id, .. })
- | Node::Param(Param { hir_id, .. })
- | Node::Infer(InferArg { hir_id, .. })
- | Node::GenericParam(GenericParam { hir_id, .. }) => Some(*hir_id),
- Node::TraitRef(TraitRef { hir_ref_id, .. }) => Some(*hir_ref_id),
- Node::PathSegment(PathSegment { hir_id, .. }) => *hir_id,
- Node::Variant(Variant { id, .. }) => Some(*id),
- Node::Ctor(variant) => variant.ctor_hir_id(),
- Node::Crate(_) | Node::Visibility(_) => None,
- }
- }
-
- /// Returns `Constness::Const` when this node is a const fn/impl/item.
- pub fn constness_for_typeck(&self) -> Constness {
- match self {
- Node::Item(Item {
- kind: ItemKind::Fn(FnSig { header: FnHeader { constness, .. }, .. }, ..),
- ..
- })
- | Node::TraitItem(TraitItem {
- kind: TraitItemKind::Fn(FnSig { header: FnHeader { constness, .. }, .. }, ..),
- ..
- })
- | Node::ImplItem(ImplItem {
- kind: ImplItemKind::Fn(FnSig { header: FnHeader { constness, .. }, .. }, ..),
- ..
- })
- | Node::Item(Item { kind: ItemKind::Impl(Impl { constness, .. }), .. }) => *constness,
-
- Node::Item(Item { kind: ItemKind::Const(..), .. })
- | Node::TraitItem(TraitItem { kind: TraitItemKind::Const(..), .. })
- | Node::ImplItem(ImplItem { kind: ImplItemKind::Const(..), .. }) => Constness::Const,
-
- _ => Constness::NotConst,
- }
- }
-
pub fn as_owner(self) -> Option<OwnerNode<'hir>> {
match self {
Node::Item(i) => Some(OwnerNode::Item(i)),
@@ -3298,7 +3253,7 @@ mod size_asserts {
rustc_data_structures::static_assert_size!(super::Expr<'static>, 64);
rustc_data_structures::static_assert_size!(super::Pat<'static>, 88);
rustc_data_structures::static_assert_size!(super::QPath<'static>, 24);
- rustc_data_structures::static_assert_size!(super::Ty<'static>, 72);
+ rustc_data_structures::static_assert_size!(super::Ty<'static>, 80);
rustc_data_structures::static_assert_size!(super::Item<'static>, 184);
rustc_data_structures::static_assert_size!(super::TraitItem<'static>, 128);
diff --git a/compiler/rustc_hir/src/intravisit.rs b/compiler/rustc_hir/src/intravisit.rs
index cff543760f4..0fab7cbfeea 100644
--- a/compiler/rustc_hir/src/intravisit.rs
+++ b/compiler/rustc_hir/src/intravisit.rs
@@ -139,7 +139,7 @@ pub trait Map<'hir> {
}
// Used when no map is actually available, forcing manual implementation of nested visitors.
-impl Map<'hir> for ! {
+impl<'hir> Map<'hir> for ! {
fn find(&self, _: HirId) -> Option<Node<'hir>> {
unreachable!()
}
@@ -389,6 +389,9 @@ pub trait Visitor<'v>: Sized {
fn visit_expr(&mut self, ex: &'v Expr<'v>) {
walk_expr(self, ex)
}
+ fn visit_let_expr(&mut self, lex: &'v Let<'v>) {
+ walk_let_expr(self, lex)
+ }
fn visit_ty(&mut self, t: &'v Ty<'v>) {
walk_ty(self, t)
}
@@ -545,7 +548,7 @@ pub fn walk_lifetime<'v, V: Visitor<'v>>(visitor: &mut V, lifetime: &'v Lifetime
| LifetimeName::Param(ParamName::Error)
| LifetimeName::Static
| LifetimeName::Error
- | LifetimeName::Implicit
+ | LifetimeName::Implicit(_)
| LifetimeName::ImplicitObjectLifetimeDefault
| LifetimeName::Underscore => {}
}
@@ -1126,6 +1129,14 @@ pub fn walk_anon_const<'v, V: Visitor<'v>>(visitor: &mut V, constant: &'v AnonCo
visitor.visit_nested_body(constant.body);
}
+pub fn walk_let_expr<'v, V: Visitor<'v>>(visitor: &mut V, let_expr: &'v Let<'v>) {
+ // match the visit order in walk_local
+ visitor.visit_expr(let_expr.init);
+ visitor.visit_id(let_expr.hir_id);
+ visitor.visit_pat(let_expr.pat);
+ walk_list!(visitor, visit_ty, let_expr.ty);
+}
+
pub fn walk_expr<'v, V: Visitor<'v>>(visitor: &mut V, expression: &'v Expr<'v>) {
visitor.visit_id(expression.hir_id);
match expression.kind {
@@ -1172,10 +1183,7 @@ pub fn walk_expr<'v, V: Visitor<'v>>(visitor: &mut V, expression: &'v Expr<'v>)
ExprKind::DropTemps(ref subexpression) => {
visitor.visit_expr(subexpression);
}
- ExprKind::Let(ref pat, ref expr, _) => {
- visitor.visit_expr(expr);
- visitor.visit_pat(pat);
- }
+ ExprKind::Let(ref let_expr) => visitor.visit_let_expr(let_expr),
ExprKind::If(ref cond, ref then, ref else_opt) => {
visitor.visit_expr(cond);
visitor.visit_expr(then);
diff --git a/compiler/rustc_hir/src/lang_items.rs b/compiler/rustc_hir/src/lang_items.rs
index 3037996d48b..a03c561861e 100644
--- a/compiler/rustc_hir/src/lang_items.rs
+++ b/compiler/rustc_hir/src/lang_items.rs
@@ -268,6 +268,7 @@ language_item_table! {
Future, sym::future_trait, future_trait, Target::Trait, GenericRequirement::Exact(0);
GeneratorState, sym::generator_state, gen_state, Target::Enum, GenericRequirement::None;
Generator, sym::generator, gen_trait, Target::Trait, GenericRequirement::Minimum(1);
+ GeneratorReturn, sym::generator_return, generator_return, Target::AssocTy, GenericRequirement::None;
Unpin, sym::unpin, unpin_trait, Target::Trait, GenericRequirement::None;
Pin, sym::pin, pin_type, Target::Struct, GenericRequirement::None;
@@ -347,6 +348,7 @@ language_item_table! {
ControlFlowContinue, sym::Continue, cf_continue_variant, Target::Variant, GenericRequirement::None;
ControlFlowBreak, sym::Break, cf_break_variant, Target::Variant, GenericRequirement::None;
+ IntoFutureIntoFuture, sym::into_future, into_future_fn, Target::Method(MethodKind::Trait { body: false }), GenericRequirement::None;
IntoIterIntoIter, sym::into_iter, into_iter_fn, Target::Method(MethodKind::Trait { body: false }), GenericRequirement::None;
IteratorNext, sym::next, next_fn, Target::Method(MethodKind::Trait { body: false}), GenericRequirement::None;
diff --git a/compiler/rustc_hir/src/lib.rs b/compiler/rustc_hir/src/lib.rs
index 93224d388c0..1df9b5f9c78 100644
--- a/compiler/rustc_hir/src/lib.rs
+++ b/compiler/rustc_hir/src/lib.rs
@@ -4,7 +4,6 @@
#![feature(const_btree_new)]
#![feature(crate_visibility_modifier)]
-#![feature(in_band_lifetimes)]
#![feature(once_cell)]
#![feature(min_specialization)]
#![feature(never_type)]
diff --git a/compiler/rustc_hir/src/stable_hash_impls.rs b/compiler/rustc_hir/src/stable_hash_impls.rs
index 6e7b765a0c4..c8d729a999e 100644
--- a/compiler/rustc_hir/src/stable_hash_impls.rs
+++ b/compiler/rustc_hir/src/stable_hash_impls.rs
@@ -211,7 +211,7 @@ impl<HirCtx: crate::HashStableContext> HashStable<HirCtx> for Item<'_> {
}
}
-impl<HirCtx: crate::HashStableContext> HashStable<HirCtx> for OwnerNodes<'tcx> {
+impl<'tcx, HirCtx: crate::HashStableContext> HashStable<HirCtx> for OwnerNodes<'tcx> {
fn hash_stable(&self, hcx: &mut HirCtx, hasher: &mut StableHasher) {
// We ignore the `nodes` and `bodies` fields since these refer to information included in
// `hash` which is hashed in the collector and used for the crate hash.
@@ -221,7 +221,7 @@ impl<HirCtx: crate::HashStableContext> HashStable<HirCtx> for OwnerNodes<'tcx> {
}
}
-impl<HirCtx: crate::HashStableContext> HashStable<HirCtx> for AttributeMap<'tcx> {
+impl<'tcx, HirCtx: crate::HashStableContext> HashStable<HirCtx> for AttributeMap<'tcx> {
fn hash_stable(&self, hcx: &mut HirCtx, hasher: &mut StableHasher) {
// We ignore the `map` since it refers to information included in `hash` which is hashed in
// the collector and used for the crate hash.
diff --git a/compiler/rustc_hir_pretty/src/lib.rs b/compiler/rustc_hir_pretty/src/lib.rs
index 9c2927111a6..2f5f158856f 100644
--- a/compiler/rustc_hir_pretty/src/lib.rs
+++ b/compiler/rustc_hir_pretty/src/lib.rs
@@ -10,7 +10,7 @@ use rustc_hir::{GenericArg, GenericParam, GenericParamKind, Node};
use rustc_hir::{GenericBound, PatKind, RangeEnd, TraitBoundModifier};
use rustc_span::source_map::{SourceMap, Spanned};
use rustc_span::symbol::{kw, Ident, IdentPrinter, Symbol};
-use rustc_span::{self, BytePos, FileName};
+use rustc_span::{self, FileName};
use rustc_target::spec::abi::Abi;
use std::borrow::Cow;
@@ -89,7 +89,7 @@ impl<'a> State<'a> {
Node::TraitRef(a) => self.print_trait_ref(&a),
Node::Binding(a) | Node::Pat(a) => self.print_pat(&a),
Node::Arm(a) => self.print_arm(&a),
- Node::Infer(_) => self.s.word("_"),
+ Node::Infer(_) => self.word("_"),
Node::Block(a) => {
// Containing cbox, will be closed by print-block at `}`.
self.cbox(INDENT_UNIT);
@@ -130,7 +130,7 @@ impl<'a> PrintState<'a> for State<'a> {
}
fn print_ident(&mut self, ident: Ident) {
- self.s.word(IdentPrinter::for_ast_ident(ident, ident.is_raw_guess()).to_string());
+ self.word(IdentPrinter::for_ast_ident(ident, ident.is_raw_guess()).to_string());
self.ann.post(self, AnnNode::Name(&ident.name))
}
@@ -194,7 +194,7 @@ where
pub fn visibility_qualified<S: Into<Cow<'static, str>>>(vis: &hir::Visibility<'_>, w: S) -> String {
to_string(NO_ANN, |s| {
s.print_visibility(vis);
- s.s.word(w)
+ s.word(w)
})
}
@@ -241,40 +241,10 @@ pub fn enum_def_to_string(
}
impl<'a> State<'a> {
- pub fn cbox(&mut self, u: usize) {
- self.s.cbox(u);
- }
-
- pub fn nbsp(&mut self) {
- self.s.word(" ")
- }
-
- pub fn word_nbsp<S: Into<Cow<'static, str>>>(&mut self, w: S) {
- self.s.word(w);
- self.nbsp()
- }
-
- pub fn head<S: Into<Cow<'static, str>>>(&mut self, w: S) {
- let w = w.into();
- // outer-box is consistent
- self.cbox(INDENT_UNIT);
- // head-box is inconsistent
- self.ibox(w.len() + 1);
- // keyword that starts the head
- if !w.is_empty() {
- self.word_nbsp(w);
- }
- }
-
- pub fn bopen(&mut self) {
- self.s.word("{");
- self.end(); // close the head-box
- }
-
pub fn bclose_maybe_open(&mut self, span: rustc_span::Span, close_box: bool) {
self.maybe_print_comment(span.hi());
self.break_offset_if_not_bol(1, -(INDENT_UNIT as isize));
- self.s.word("}");
+ self.word("}");
if close_box {
self.end(); // close the outer-box
}
@@ -284,33 +254,6 @@ impl<'a> State<'a> {
self.bclose_maybe_open(span, true)
}
- pub fn space_if_not_bol(&mut self) {
- if !self.s.is_beginning_of_line() {
- self.s.space();
- }
- }
-
- pub fn break_offset_if_not_bol(&mut self, n: usize, off: isize) {
- if !self.s.is_beginning_of_line() {
- self.s.break_offset(n, off)
- } else if off != 0 && self.s.last_token().is_hardbreak_tok() {
- // We do something pretty sketchy here: tuck the nonzero
- // offset-adjustment we were going to deposit along with the
- // break into the previous hardbreak.
- self.s.replace_last_token(pp::Printer::hardbreak_tok_offset(off));
- }
- }
-
- // Synthesizes a comment that was not textually present in the original source
- // file.
- pub fn synth_comment(&mut self, text: String) {
- self.s.word("/*");
- self.s.space();
- self.s.word(text);
- self.s.space();
- self.s.word("*/")
- }
-
pub fn commasep_cmnt<T, F, G>(&mut self, b: Breaks, elts: &[T], mut op: F, mut get_span: G)
where
F: FnMut(&mut State<'_>, &T),
@@ -324,7 +267,7 @@ impl<'a> State<'a> {
op(self, elt);
i += 1;
if i < len {
- self.s.word(",");
+ self.word(",");
self.maybe_print_trailing_comment(get_span(elt), Some(get_span(&elts[i]).hi()));
self.space_if_not_bol();
}
@@ -355,27 +298,27 @@ impl<'a> State<'a> {
self.ibox(0);
match ty.kind {
hir::TyKind::Slice(ref ty) => {
- self.s.word("[");
+ self.word("[");
self.print_type(&ty);
- self.s.word("]");
+ self.word("]");
}
hir::TyKind::Ptr(ref mt) => {
- self.s.word("*");
+ self.word("*");
self.print_mt(mt, true);
}
hir::TyKind::Rptr(ref lifetime, ref mt) => {
- self.s.word("&");
+ self.word("&");
self.print_opt_lifetime(lifetime);
self.print_mt(mt, false);
}
hir::TyKind::Never => {
- self.s.word("!");
+ self.word("!");
}
hir::TyKind::Tup(ref elts) => {
self.popen();
- self.commasep(Inconsistent, &elts[..], |s, ty| s.print_type(&ty));
+ self.commasep(Inconsistent, &elts, |s, ty| s.print_type(&ty));
if elts.len() == 1 {
- self.s.word(",");
+ self.word(",");
}
self.pclose();
}
@@ -389,7 +332,7 @@ impl<'a> State<'a> {
f.param_names,
);
}
- hir::TyKind::OpaqueDef(..) => self.s.word("/*impl Trait*/"),
+ hir::TyKind::OpaqueDef(..) => self.word("/*impl Trait*/"),
hir::TyKind::Path(ref qpath) => self.print_qpath(qpath, false),
hir::TyKind::TraitObject(bounds, ref lifetime, syntax) => {
if syntax == ast::TraitObjectSyntax::Dyn {
@@ -412,24 +355,24 @@ impl<'a> State<'a> {
}
}
hir::TyKind::Array(ref ty, ref length) => {
- self.s.word("[");
+ self.word("[");
self.print_type(&ty);
- self.s.word("; ");
+ self.word("; ");
self.print_anon_const(length);
- self.s.word("]");
+ self.word("]");
}
hir::TyKind::Typeof(ref e) => {
- self.s.word("typeof(");
+ self.word("typeof(");
self.print_anon_const(e);
- self.s.word(")");
+ self.word(")");
}
hir::TyKind::Err => {
self.popen();
- self.s.word("/*ERROR*/");
+ self.word("/*ERROR*/");
self.pclose();
}
hir::TyKind::Infer => {
- self.s.word("_");
+ self.word("_");
}
}
self.end()
@@ -457,7 +400,7 @@ impl<'a> State<'a> {
None,
);
self.end(); // end head-ibox
- self.s.word(";");
+ self.word(";");
self.end() // end the outer fn box
}
hir::ForeignItemKind::Static(ref t, m) => {
@@ -468,14 +411,14 @@ impl<'a> State<'a> {
self.print_ident(item.ident);
self.word_space(":");
self.print_type(&t);
- self.s.word(";");
+ self.word(";");
self.end(); // end the head-ibox
self.end() // end the outer cbox
}
hir::ForeignItemKind::Type => {
self.head(visibility_qualified(&item.vis, "type"));
self.print_ident(item.ident);
- self.s.word(";");
+ self.word(";");
self.end(); // end the head-ibox
self.end() // end the outer cbox
}
@@ -489,17 +432,17 @@ impl<'a> State<'a> {
default: Option<hir::BodyId>,
vis: &hir::Visibility<'_>,
) {
- self.s.word(visibility_qualified(vis, ""));
+ self.word(visibility_qualified(vis, ""));
self.word_space("const");
self.print_ident(ident);
self.word_space(":");
self.print_type(ty);
if let Some(expr) = default {
- self.s.space();
+ self.space();
self.word_space("=");
self.ann.nested(self, Nested::Body(expr));
}
- self.s.word(";")
+ self.word(";")
}
fn print_associated_type(
@@ -517,11 +460,11 @@ impl<'a> State<'a> {
}
self.print_where_clause(&generics.where_clause);
if let Some(ty) = ty {
- self.s.space();
+ self.space();
self.word_space("=");
self.print_type(ty);
}
- self.s.word(";")
+ self.word(";")
}
fn print_item_type(
@@ -536,9 +479,9 @@ impl<'a> State<'a> {
self.end(); // end the inner ibox
self.print_where_clause(&generics.where_clause);
- self.s.space();
+ self.space();
inner(self);
- self.s.word(";");
+ self.word(";");
self.end(); // end the outer ibox
}
@@ -554,12 +497,12 @@ impl<'a> State<'a> {
self.head(visibility_qualified(&item.vis, "extern crate"));
if let Some(orig_name) = orig_name {
self.print_name(orig_name);
- self.s.space();
- self.s.word("as");
- self.s.space();
+ self.space();
+ self.word("as");
+ self.space();
}
self.print_ident(item.ident);
- self.s.word(";");
+ self.word(";");
self.end(); // end inner head-block
self.end(); // end outer head-block
}
@@ -570,14 +513,14 @@ impl<'a> State<'a> {
match kind {
hir::UseKind::Single => {
if path.segments.last().unwrap().ident != item.ident {
- self.s.space();
+ self.space();
self.word_space("as");
self.print_ident(item.ident);
}
- self.s.word(";");
+ self.word(";");
}
- hir::UseKind::Glob => self.s.word("::*;"),
- hir::UseKind::ListStem => self.s.word("::{};"),
+ hir::UseKind::Glob => self.word("::*;"),
+ hir::UseKind::ListStem => self.word("::{};"),
}
self.end(); // end inner head-block
self.end(); // end outer head-block
@@ -590,12 +533,12 @@ impl<'a> State<'a> {
self.print_ident(item.ident);
self.word_space(":");
self.print_type(&ty);
- self.s.space();
+ self.space();
self.end(); // end the head-ibox
self.word_space("=");
self.ann.nested(self, Nested::Body(expr));
- self.s.word(";");
+ self.word(";");
self.end(); // end the outer cbox
}
hir::ItemKind::Const(ref ty, expr) => {
@@ -603,12 +546,12 @@ impl<'a> State<'a> {
self.print_ident(item.ident);
self.word_space(":");
self.print_type(&ty);
- self.s.space();
+ self.space();
self.end(); // end the head-ibox
self.word_space("=");
self.ann.nested(self, Nested::Body(expr));
- self.s.word(";");
+ self.word(";");
self.end(); // end the outer cbox
}
hir::ItemKind::Fn(ref sig, ref param_names, body) => {
@@ -622,7 +565,7 @@ impl<'a> State<'a> {
&[],
Some(body),
);
- self.s.word(" ");
+ self.word(" ");
self.end(); // need to close a box
self.end(); // need to close a box
self.ann.nested(self, Nested::Body(body));
@@ -666,7 +609,7 @@ impl<'a> State<'a> {
let mut real_bounds = Vec::with_capacity(opaque_ty.bounds.len());
for b in opaque_ty.bounds.iter() {
if let GenericBound::Trait(ref ptr, hir::TraitBoundModifier::Maybe) = *b {
- state.s.space();
+ state.space();
state.word_space("for ?");
state.print_trait_ref(&ptr.trait_ref);
} else {
@@ -706,7 +649,7 @@ impl<'a> State<'a> {
if !generics.params.is_empty() {
self.print_generic_params(&generics.params);
- self.s.space();
+ self.space();
}
if constness == hir::Constness::Const {
@@ -714,19 +657,19 @@ impl<'a> State<'a> {
}
if let hir::ImplPolarity::Negative(_) = polarity {
- self.s.word("!");
+ self.word("!");
}
if let Some(ref t) = of_trait {
self.print_trait_ref(t);
- self.s.space();
+ self.space();
self.word_space("for");
}
self.print_type(&self_ty);
self.print_where_clause(&generics.where_clause);
- self.s.space();
+ self.space();
self.bopen();
self.print_inner_attributes(attrs);
for impl_item in items {
@@ -745,7 +688,7 @@ impl<'a> State<'a> {
let mut real_bounds = Vec::with_capacity(bounds.len());
for b in bounds.iter() {
if let GenericBound::Trait(ref ptr, hir::TraitBoundModifier::Maybe) = *b {
- self.s.space();
+ self.space();
self.word_space("for ?");
self.print_trait_ref(&ptr.trait_ref);
} else {
@@ -754,7 +697,7 @@ impl<'a> State<'a> {
}
self.print_bounds(":", real_bounds);
self.print_where_clause(&generics.where_clause);
- self.s.word(" ");
+ self.word(" ");
self.bopen();
for trait_item in trait_items {
self.ann.nested(self, Nested::TraitItem(trait_item.id));
@@ -771,7 +714,7 @@ impl<'a> State<'a> {
// FIXME(durka) this seems to be some quite outdated syntax
for b in bounds.iter() {
if let GenericBound::Trait(ref ptr, hir::TraitBoundModifier::Maybe) = *b {
- self.s.space();
+ self.space();
self.word_space("for ?");
self.print_trait_ref(&ptr.trait_ref);
} else {
@@ -781,7 +724,7 @@ impl<'a> State<'a> {
self.nbsp();
self.print_bounds("=", real_bounds);
self.print_where_clause(&generics.where_clause);
- self.s.word(";");
+ self.word(";");
}
}
self.ann.post(self, AnnNode::Item(item))
@@ -793,7 +736,7 @@ impl<'a> State<'a> {
fn print_formal_generic_params(&mut self, generic_params: &[hir::GenericParam<'_>]) {
if !generic_params.is_empty() {
- self.s.word("for");
+ self.word("for");
self.print_generic_params(generic_params);
self.nbsp();
}
@@ -816,7 +759,7 @@ impl<'a> State<'a> {
self.print_name(name);
self.print_generic_params(&generics.params);
self.print_where_clause(&generics.where_clause);
- self.s.space();
+ self.space();
self.print_variants(&enum_definition.variants, span)
}
@@ -828,7 +771,7 @@ impl<'a> State<'a> {
self.print_outer_attributes(self.attrs(v.id));
self.ibox(INDENT_UNIT);
self.print_variant(v);
- self.s.word(",");
+ self.word(",");
self.end();
self.maybe_print_trailing_comment(v.span, None);
}
@@ -841,10 +784,10 @@ impl<'a> State<'a> {
hir::VisibilityKind::Crate(ast::CrateSugar::JustCrate) => self.word_nbsp("crate"),
hir::VisibilityKind::Crate(ast::CrateSugar::PubCrate) => self.word_nbsp("pub(crate)"),
hir::VisibilityKind::Restricted { ref path, .. } => {
- self.s.word("pub(");
+ self.word("pub(");
if path.segments.len() == 1 && path.segments[0].ident.name == kw::Super {
// Special case: `super` can print like `pub(super)`.
- self.s.word("super");
+ self.word("super");
} else {
// Everything else requires `in` at present.
self.word_nbsp("in");
@@ -887,7 +830,7 @@ impl<'a> State<'a> {
}
self.print_where_clause(&generics.where_clause);
if print_finalizer {
- self.s.word(";");
+ self.word(";");
}
self.end();
self.end() // close the outer-box
@@ -906,7 +849,7 @@ impl<'a> State<'a> {
self.print_ident(field.ident);
self.word_nbsp(":");
self.print_type(&field.ty);
- self.s.word(",");
+ self.word(",");
}
self.bclose(span)
@@ -919,7 +862,7 @@ impl<'a> State<'a> {
let generics = hir::Generics::empty();
self.print_struct(&v.data, &generics, v.ident.name, v.span, false);
if let Some(ref d) = v.disr_expr {
- self.s.space();
+ self.space();
self.word_space("=");
self.print_anon_const(d);
}
@@ -951,7 +894,7 @@ impl<'a> State<'a> {
let vis =
Spanned { span: rustc_span::DUMMY_SP, node: hir::VisibilityKind::Inherited };
self.print_method_sig(ti.ident, sig, &ti.generics, &vis, arg_names, None);
- self.s.word(";");
+ self.word(";");
}
hir::TraitItemKind::Fn(ref sig, hir::TraitFn::Provided(body)) => {
let vis =
@@ -1032,11 +975,11 @@ impl<'a> State<'a> {
hir::StmtKind::Semi(ref expr) => {
self.space_if_not_bol();
self.print_expr(&expr);
- self.s.word(";");
+ self.word(";");
}
}
if stmt_ends_with_semi(&st.kind) {
- self.s.word(";");
+ self.word(";");
}
self.maybe_print_trailing_comment(st.span, None)
}
@@ -1088,9 +1031,9 @@ impl<'a> State<'a> {
hir::ExprKind::If(ref i, ref then, ref e) => {
self.cbox(INDENT_UNIT - 1);
self.ibox(0);
- self.s.word(" else if ");
+ self.word(" else if ");
self.print_expr_as_cond(&i);
- self.s.space();
+ self.space();
self.print_expr(&then);
self.print_else(e.as_ref().map(|e| &**e))
}
@@ -1098,7 +1041,7 @@ impl<'a> State<'a> {
hir::ExprKind::Block(ref b, _) => {
self.cbox(INDENT_UNIT - 1);
self.ibox(0);
- self.s.word(" else ");
+ self.word(" else ");
self.print_block(&b)
}
// Constraints would be great here!
@@ -1117,7 +1060,7 @@ impl<'a> State<'a> {
) {
self.head("if");
self.print_expr_as_cond(test);
- self.s.space();
+ self.space();
self.print_expr(blk);
self.print_else(elseopt)
}
@@ -1158,13 +1101,17 @@ impl<'a> State<'a> {
}
/// Print a `let pat = expr` expression.
- fn print_let(&mut self, pat: &hir::Pat<'_>, expr: &hir::Expr<'_>) {
- self.s.word("let ");
+ fn print_let(&mut self, pat: &hir::Pat<'_>, ty: Option<&hir::Ty<'_>>, init: &hir::Expr<'_>) {
+ self.word_space("let");
self.print_pat(pat);
- self.s.space();
+ if let Some(ty) = ty {
+ self.word_space(":");
+ self.print_type(ty);
+ }
+ self.space();
self.word_space("=");
- let npals = || parser::needs_par_as_let_scrutinee(expr.precedence().order());
- self.print_expr_cond_paren(expr, Self::cond_needs_par(expr) || npals())
+ let npals = || parser::needs_par_as_let_scrutinee(init.precedence().order());
+ self.print_expr_cond_paren(init, Self::cond_needs_par(init) || npals())
}
// Does `expr` need parentheses when printed in a condition position?
@@ -1180,26 +1127,26 @@ impl<'a> State<'a> {
fn print_expr_vec(&mut self, exprs: &[hir::Expr<'_>]) {
self.ibox(INDENT_UNIT);
- self.s.word("[");
+ self.word("[");
self.commasep_exprs(Inconsistent, exprs);
- self.s.word("]");
+ self.word("]");
self.end()
}
fn print_expr_anon_const(&mut self, anon_const: &hir::AnonConst) {
self.ibox(INDENT_UNIT);
- self.s.word_space("const");
+ self.word_space("const");
self.print_anon_const(anon_const);
self.end()
}
fn print_expr_repeat(&mut self, element: &hir::Expr<'_>, count: &hir::AnonConst) {
self.ibox(INDENT_UNIT);
- self.s.word("[");
+ self.word("[");
self.print_expr(element);
self.word_space(";");
self.print_anon_const(count);
- self.s.word("]");
+ self.word("]");
self.end()
}
@@ -1210,7 +1157,7 @@ impl<'a> State<'a> {
wth: &Option<&hir::Expr<'_>>,
) {
self.print_qpath(qpath, true);
- self.s.word("{");
+ self.word("{");
self.commasep_cmnt(
Consistent,
fields,
@@ -1229,27 +1176,27 @@ impl<'a> State<'a> {
Some(ref expr) => {
self.ibox(INDENT_UNIT);
if !fields.is_empty() {
- self.s.word(",");
- self.s.space();
+ self.word(",");
+ self.space();
}
- self.s.word("..");
+ self.word("..");
self.print_expr(&expr);
self.end();
}
_ => {
if !fields.is_empty() {
- self.s.word(",")
+ self.word(",")
}
}
}
- self.s.word("}");
+ self.word("}");
}
fn print_expr_tup(&mut self, exprs: &[hir::Expr<'_>]) {
self.popen();
self.commasep_exprs(Inconsistent, exprs);
if exprs.len() == 1 {
- self.s.word(",");
+ self.word(",");
}
self.pclose()
}
@@ -1267,7 +1214,7 @@ impl<'a> State<'a> {
fn print_expr_method_call(&mut self, segment: &hir::PathSegment<'_>, args: &[hir::Expr<'_>]) {
let base_args = &args[1..];
self.print_expr_maybe_paren(&args[0], parser::PREC_POSTFIX);
- self.s.word(".");
+ self.word(".");
self.print_ident(segment.ident);
let generic_args = segment.args();
@@ -1303,13 +1250,13 @@ impl<'a> State<'a> {
};
self.print_expr_maybe_paren(lhs, left_prec);
- self.s.space();
+ self.space();
self.word_space(op.node.as_str());
self.print_expr_maybe_paren(rhs, right_prec)
}
fn print_expr_unary(&mut self, op: hir::UnOp, expr: &hir::Expr<'_>) {
- self.s.word(op.as_str());
+ self.word(op.as_str());
self.print_expr_maybe_paren(expr, parser::PREC_PREFIX)
}
@@ -1319,7 +1266,7 @@ impl<'a> State<'a> {
mutability: hir::Mutability,
expr: &hir::Expr<'_>,
) {
- self.s.word("&");
+ self.word("&");
match kind {
hir::BorrowKind::Ref => self.print_mutability(mutability, false),
hir::BorrowKind::Raw => {
@@ -1433,6 +1380,9 @@ impl<'a> State<'a> {
if opts.contains(ast::InlineAsmOptions::RAW) {
options.push("raw");
}
+ if opts.contains(ast::InlineAsmOptions::MAY_UNWIND) {
+ options.push("may_unwind");
+ }
s.commasep(Inconsistent, &options, |s, &opt| {
s.word(opt);
});
@@ -1488,7 +1438,7 @@ impl<'a> State<'a> {
hir::ExprKind::Cast(ref expr, ref ty) => {
let prec = AssocOp::As.precedence() as i8;
self.print_expr_maybe_paren(&expr, prec);
- self.s.space();
+ self.space();
self.word_space("as");
self.print_type(&ty);
}
@@ -1507,7 +1457,7 @@ impl<'a> State<'a> {
// Print `let _t = $init;`:
let temp = Ident::from_str("_t");
self.print_local(Some(init), |this| this.print_ident(temp));
- self.s.word(";");
+ self.word(";");
// Print `_t`:
self.space_if_not_bol();
@@ -1516,8 +1466,8 @@ impl<'a> State<'a> {
// Print `}`:
self.bclose_maybe_open(expr.span, true);
}
- hir::ExprKind::Let(ref pat, ref scrutinee, _) => {
- self.print_let(pat, scrutinee);
+ hir::ExprKind::Let(hir::Let { pat, ty, init, .. }) => {
+ self.print_let(pat, *ty, init);
}
hir::ExprKind::If(ref test, ref blk, ref elseopt) => {
self.print_if(&test, &blk, elseopt.as_ref().map(|e| &**e));
@@ -1535,7 +1485,7 @@ impl<'a> State<'a> {
self.ibox(INDENT_UNIT);
self.word_nbsp("match");
self.print_expr_as_cond(&expr);
- self.s.space();
+ self.space();
self.bopen();
for arm in arms {
self.print_arm(arm);
@@ -1546,7 +1496,7 @@ impl<'a> State<'a> {
self.print_capture_clause(capture_clause);
self.print_closure_params(&decl, body);
- self.s.space();
+ self.space();
// This is a bare expression.
self.ann.nested(self, Nested::Body(body));
@@ -1571,54 +1521,52 @@ impl<'a> State<'a> {
hir::ExprKind::Assign(ref lhs, ref rhs, _) => {
let prec = AssocOp::Assign.precedence() as i8;
self.print_expr_maybe_paren(&lhs, prec + 1);
- self.s.space();
+ self.space();
self.word_space("=");
self.print_expr_maybe_paren(&rhs, prec);
}
hir::ExprKind::AssignOp(op, ref lhs, ref rhs) => {
let prec = AssocOp::Assign.precedence() as i8;
self.print_expr_maybe_paren(&lhs, prec + 1);
- self.s.space();
- self.s.word(op.node.as_str());
+ self.space();
+ self.word(op.node.as_str());
self.word_space("=");
self.print_expr_maybe_paren(&rhs, prec);
}
hir::ExprKind::Field(ref expr, ident) => {
self.print_expr_maybe_paren(expr, parser::PREC_POSTFIX);
- self.s.word(".");
+ self.word(".");
self.print_ident(ident);
}
hir::ExprKind::Index(ref expr, ref index) => {
self.print_expr_maybe_paren(&expr, parser::PREC_POSTFIX);
- self.s.word("[");
+ self.word("[");
self.print_expr(&index);
- self.s.word("]");
+ self.word("]");
}
hir::ExprKind::Path(ref qpath) => self.print_qpath(qpath, true),
hir::ExprKind::Break(destination, ref opt_expr) => {
- self.s.word("break");
- self.s.space();
+ self.word("break");
if let Some(label) = destination.label {
+ self.space();
self.print_ident(label.ident);
- self.s.space();
}
if let Some(ref expr) = *opt_expr {
+ self.space();
self.print_expr_maybe_paren(expr, parser::PREC_JUMP);
- self.s.space();
}
}
hir::ExprKind::Continue(destination) => {
- self.s.word("continue");
- self.s.space();
+ self.word("continue");
if let Some(label) = destination.label {
+ self.space();
self.print_ident(label.ident);
- self.s.space()
}
}
hir::ExprKind::Ret(ref result) => {
- self.s.word("return");
+ self.word("return");
if let Some(ref expr) = *result {
- self.s.word(" ");
+ self.word(" ");
self.print_expr_maybe_paren(&expr, parser::PREC_JUMP);
}
}
@@ -1628,7 +1576,7 @@ impl<'a> State<'a> {
}
hir::ExprKind::LlvmInlineAsm(ref a) => {
let i = &a.inner;
- self.s.word("llvm_asm!");
+ self.word("llvm_asm!");
self.popen();
self.print_symbol(i.asm, i.asm_str_style);
self.word_space(":");
@@ -1648,7 +1596,7 @@ impl<'a> State<'a> {
s.pclose();
out_idx += 1;
});
- self.s.space();
+ self.space();
self.word_space(":");
let mut in_idx = 0;
@@ -1659,7 +1607,7 @@ impl<'a> State<'a> {
s.pclose();
in_idx += 1;
});
- self.s.space();
+ self.space();
self.word_space(":");
self.commasep(Inconsistent, &i.clobbers, |s, &co| {
@@ -1678,7 +1626,7 @@ impl<'a> State<'a> {
}
if !options.is_empty() {
- self.s.space();
+ self.space();
self.word_space(":");
self.commasep(Inconsistent, &options, |s, &co| {
s.print_string(co, ast::StrStyle::Cooked);
@@ -1693,7 +1641,7 @@ impl<'a> State<'a> {
}
hir::ExprKind::Err => {
self.popen();
- self.s.word("/*ERROR*/");
+ self.word("/*ERROR*/");
self.pclose();
}
}
@@ -1718,7 +1666,7 @@ impl<'a> State<'a> {
for (i, segment) in path.segments.iter().enumerate() {
if i > 0 {
- self.s.word("::")
+ self.word("::")
}
if segment.ident.name != kw::PathRoot {
self.print_ident(segment.ident);
@@ -1738,14 +1686,14 @@ impl<'a> State<'a> {
match *qpath {
hir::QPath::Resolved(None, ref path) => self.print_path(path, colons_before_params),
hir::QPath::Resolved(Some(ref qself), ref path) => {
- self.s.word("<");
+ self.word("<");
self.print_type(qself);
- self.s.space();
+ self.space();
self.word_space("as");
for (i, segment) in path.segments[..path.segments.len() - 1].iter().enumerate() {
if i > 0 {
- self.s.word("::")
+ self.word("::")
}
if segment.ident.name != kw::PathRoot {
self.print_ident(segment.ident);
@@ -1757,8 +1705,8 @@ impl<'a> State<'a> {
}
}
- self.s.word(">");
- self.s.word("::");
+ self.word(">");
+ self.word("::");
let item_segment = path.segments.last().unwrap();
self.print_ident(item_segment.ident);
self.print_generic_args(
@@ -1774,12 +1722,12 @@ impl<'a> State<'a> {
if let hir::TyKind::Path(hir::QPath::Resolved(None, _)) = &qself.kind {
self.print_type(qself);
} else {
- self.s.word("<");
+ self.word("<");
self.print_type(qself);
- self.s.word(">");
+ self.word(">");
}
- self.s.word("::");
+ self.word("::");
self.print_ident(item_segment.ident);
self.print_generic_args(
item_segment.args(),
@@ -1787,10 +1735,10 @@ impl<'a> State<'a> {
colons_before_params,
)
}
- hir::QPath::LangItem(lang_item, span) => {
- self.s.word("#[lang = \"");
+ hir::QPath::LangItem(lang_item, span, _) => {
+ self.word("#[lang = \"");
self.print_ident(Ident::new(lang_item.name(), span));
- self.s.word("\"]");
+ self.word("\"]");
}
}
}
@@ -1802,9 +1750,9 @@ impl<'a> State<'a> {
colons_before_params: bool,
) {
if generic_args.parenthesized {
- self.s.word("(");
+ self.word("(");
self.commasep(Inconsistent, generic_args.inputs(), |s, ty| s.print_type(&ty));
- self.s.word(")");
+ self.word(")");
self.space_if_not_bol();
self.word_space("->");
@@ -1815,7 +1763,7 @@ impl<'a> State<'a> {
let start_or_comma = |this: &mut Self| {
if empty.get() {
empty.set(false);
- this.s.word(start)
+ this.word(start)
} else {
this.word_space(",")
}
@@ -1849,14 +1797,14 @@ impl<'a> State<'a> {
// "non-exhaustive patterns: `Some::<..>(_)` not covered").
if infer_args && false {
start_or_comma(self);
- self.s.word("..");
+ self.word("..");
}
for binding in generic_args.bindings.iter() {
start_or_comma(self);
self.print_ident(binding.ident);
self.print_generic_args(binding.gen_args, false, false);
- self.s.space();
+ self.space();
match generic_args.bindings[0].kind {
hir::TypeBindingKind::Equality { ref ty } => {
self.word_space("=");
@@ -1869,7 +1817,7 @@ impl<'a> State<'a> {
}
if !empty.get() {
- self.s.word(">")
+ self.word(">")
}
}
}
@@ -1880,7 +1828,7 @@ impl<'a> State<'a> {
// Pat isn't normalized, but the beauty of it
// is that it doesn't matter
match pat.kind {
- PatKind::Wild => self.s.word("_"),
+ PatKind::Wild => self.word("_"),
PatKind::Binding(binding_mode, _, ident, ref sub) => {
match binding_mode {
hir::BindingAnnotation::Ref => {
@@ -1898,7 +1846,7 @@ impl<'a> State<'a> {
}
self.print_ident(ident);
if let Some(ref p) = *sub {
- self.s.word("@");
+ self.word("@");
self.print_pat(&p);
}
}
@@ -1910,13 +1858,13 @@ impl<'a> State<'a> {
if ddpos != 0 {
self.word_space(",");
}
- self.s.word("..");
+ self.word("..");
if ddpos != elts.len() {
- self.s.word(",");
+ self.word(",");
self.commasep(Inconsistent, &elts[ddpos..], |s, p| s.print_pat(&p));
}
} else {
- self.commasep(Inconsistent, &elts[..], |s, p| s.print_pat(&p));
+ self.commasep(Inconsistent, &elts, |s, p| s.print_pat(&p));
}
self.pclose();
}
@@ -1929,7 +1877,7 @@ impl<'a> State<'a> {
self.word_space("{");
self.commasep_cmnt(
Consistent,
- &fields[..],
+ &fields,
|s, f| {
s.cbox(INDENT_UNIT);
if !f.is_shorthand {
@@ -1945,13 +1893,13 @@ impl<'a> State<'a> {
if !fields.is_empty() {
self.word_space(",");
}
- self.s.word("..");
+ self.word("..");
}
- self.s.space();
- self.s.word("}");
+ self.space();
+ self.word("}");
}
PatKind::Or(ref pats) => {
- self.strsep("|", true, Inconsistent, &pats[..], |s, p| s.print_pat(&p));
+ self.strsep("|", true, Inconsistent, &pats, |s, p| s.print_pat(&p));
}
PatKind::Tuple(ref elts, ddpos) => {
self.popen();
@@ -1960,22 +1908,22 @@ impl<'a> State<'a> {
if ddpos != 0 {
self.word_space(",");
}
- self.s.word("..");
+ self.word("..");
if ddpos != elts.len() {
- self.s.word(",");
+ self.word(",");
self.commasep(Inconsistent, &elts[ddpos..], |s, p| s.print_pat(&p));
}
} else {
self.commasep(Inconsistent, &elts[..], |s, p| s.print_pat(&p));
if elts.len() == 1 {
- self.s.word(",");
+ self.word(",");
}
}
self.pclose();
}
PatKind::Box(ref inner) => {
let is_range_inner = matches!(inner.kind, PatKind::Range(..));
- self.s.word("box ");
+ self.word("box ");
if is_range_inner {
self.popen();
}
@@ -1986,8 +1934,8 @@ impl<'a> State<'a> {
}
PatKind::Ref(ref inner, mutbl) => {
let is_range_inner = matches!(inner.kind, PatKind::Range(..));
- self.s.word("&");
- self.s.word(mutbl.prefix_str());
+ self.word("&");
+ self.word(mutbl.prefix_str());
if is_range_inner {
self.popen();
}
@@ -2000,19 +1948,19 @@ impl<'a> State<'a> {
PatKind::Range(ref begin, ref end, ref end_kind) => {
if let Some(expr) = begin {
self.print_expr(expr);
- self.s.space();
+ self.space();
}
match *end_kind {
- RangeEnd::Included => self.s.word("..."),
- RangeEnd::Excluded => self.s.word(".."),
+ RangeEnd::Included => self.word("..."),
+ RangeEnd::Excluded => self.word(".."),
}
if let Some(expr) = end {
self.print_expr(expr);
}
}
PatKind::Slice(ref before, ref slice, ref after) => {
- self.s.word("[");
- self.commasep(Inconsistent, &before[..], |s, p| s.print_pat(&p));
+ self.word("[");
+ self.commasep(Inconsistent, &before, |s, p| s.print_pat(&p));
if let Some(ref p) = *slice {
if !before.is_empty() {
self.word_space(",");
@@ -2022,13 +1970,13 @@ impl<'a> State<'a> {
} else {
self.print_pat(&p);
}
- self.s.word("..");
+ self.word("..");
if !after.is_empty() {
self.word_space(",");
}
}
- self.commasep(Inconsistent, &after[..], |s, p| s.print_pat(&p));
- self.s.word("]");
+ self.commasep(Inconsistent, &after, |s, p| s.print_pat(&p));
+ self.word("]");
}
}
self.ann.post(self, AnnNode::Pat(pat))
@@ -2043,29 +1991,29 @@ impl<'a> State<'a> {
// I have no idea why this check is necessary, but here it
// is :(
if self.attrs(arm.hir_id).is_empty() {
- self.s.space();
+ self.space();
}
self.cbox(INDENT_UNIT);
self.ann.pre(self, AnnNode::Arm(arm));
self.ibox(0);
self.print_outer_attributes(&self.attrs(arm.hir_id));
self.print_pat(&arm.pat);
- self.s.space();
+ self.space();
if let Some(ref g) = arm.guard {
match g {
hir::Guard::If(e) => {
self.word_space("if");
self.print_expr(&e);
- self.s.space();
+ self.space();
}
hir::Guard::IfLet(pat, e) => {
self.word_nbsp("if");
self.word_nbsp("let");
self.print_pat(&pat);
- self.s.space();
+ self.space();
self.word_space("=");
self.print_expr(&e);
- self.s.space();
+ self.space();
}
}
}
@@ -2083,13 +2031,13 @@ impl<'a> State<'a> {
// If it is a user-provided unsafe block, print a comma after it
if let hir::BlockCheckMode::UnsafeBlock(hir::UnsafeSource::UserProvided) = blk.rules
{
- self.s.word(",");
+ self.word(",");
}
}
_ => {
self.end(); // close the ibox for the pattern
self.print_expr(&arm.body);
- self.s.word(",");
+ self.word(",");
}
}
self.ann.post(self, AnnNode::Arm(arm));
@@ -2121,20 +2069,20 @@ impl<'a> State<'a> {
self.commasep(Inconsistent, &decl.inputs, |s, ty| {
s.ibox(INDENT_UNIT);
if let Some(arg_name) = arg_names.get(i) {
- s.s.word(arg_name.to_string());
- s.s.word(":");
- s.s.space();
+ s.word(arg_name.to_string());
+ s.word(":");
+ s.space();
} else if let Some(body_id) = body_id {
s.ann.nested(s, Nested::BodyParamPat(body_id, i));
- s.s.word(":");
- s.s.space();
+ s.word(":");
+ s.space();
}
i += 1;
s.print_type(ty);
s.end()
});
if decl.c_variadic {
- self.s.word(", ...");
+ self.word(", ...");
}
self.pclose();
@@ -2143,7 +2091,7 @@ impl<'a> State<'a> {
}
fn print_closure_params(&mut self, decl: &hir::FnDecl<'_>, body_id: hir::BodyId) {
- self.s.word("|");
+ self.word("|");
let mut i = 0;
self.commasep(Inconsistent, &decl.inputs, |s, ty| {
s.ibox(INDENT_UNIT);
@@ -2154,13 +2102,13 @@ impl<'a> State<'a> {
if let hir::TyKind::Infer = ty.kind {
// Print nothing.
} else {
- s.s.word(":");
- s.s.space();
+ s.word(":");
+ s.space();
s.print_type(ty);
}
s.end();
});
- self.s.word("|");
+ self.word("|");
if let hir::FnRetTy::DefaultReturn(..) = decl.output {
return;
@@ -2171,7 +2119,7 @@ impl<'a> State<'a> {
match decl.output {
hir::FnRetTy::Return(ref ty) => {
self.print_type(&ty);
- self.maybe_print_comment(ty.span.lo())
+ self.maybe_print_comment(ty.span.lo());
}
hir::FnRetTy::DefaultReturn(..) => unreachable!(),
}
@@ -2192,7 +2140,7 @@ impl<'a> State<'a> {
let mut first = true;
for bound in bounds {
if first {
- self.s.word(prefix);
+ self.word(prefix);
}
if !(first && prefix.is_empty()) {
self.nbsp();
@@ -2206,14 +2154,14 @@ impl<'a> State<'a> {
match bound {
GenericBound::Trait(tref, modifier) => {
if modifier == &TraitBoundModifier::Maybe {
- self.s.word("?");
+ self.word("?");
}
self.print_poly_trait_ref(tref);
}
GenericBound::LangItemTrait(lang_item, span, ..) => {
- self.s.word("#[lang = \"");
+ self.word("#[lang = \"");
self.print_ident(Ident::new(lang_item.name(), *span));
- self.s.word("\"]");
+ self.word("\"]");
}
GenericBound::Outlives(lt) => {
self.print_lifetime(lt);
@@ -2224,11 +2172,11 @@ impl<'a> State<'a> {
pub fn print_generic_params(&mut self, generic_params: &[GenericParam<'_>]) {
if !generic_params.is_empty() {
- self.s.word("<");
+ self.word("<");
self.commasep(Inconsistent, generic_params, |s, param| s.print_generic_param(param));
- self.s.word(">");
+ self.word(">");
}
}
@@ -2245,7 +2193,7 @@ impl<'a> State<'a> {
for bound in param.bounds {
match bound {
GenericBound::Outlives(ref lt) => {
- self.s.word(sep);
+ self.word(sep);
self.print_lifetime(lt);
sep = "+";
}
@@ -2256,7 +2204,7 @@ impl<'a> State<'a> {
GenericParamKind::Type { ref default, .. } => {
self.print_bounds(":", param.bounds);
if let Some(default) = default {
- self.s.space();
+ self.space();
self.word_space("=");
self.print_type(&default)
}
@@ -2265,7 +2213,7 @@ impl<'a> State<'a> {
self.word_space(":");
self.print_type(ty);
if let Some(ref default) = default {
- self.s.space();
+ self.space();
self.word_space("=");
self.print_anon_const(&default)
}
@@ -2282,7 +2230,7 @@ impl<'a> State<'a> {
return;
}
- self.s.space();
+ self.space();
self.word_space("where");
for (i, predicate) in where_clause.predicates.iter().enumerate() {
@@ -2307,7 +2255,7 @@ impl<'a> State<'a> {
..
}) => {
self.print_lifetime(lifetime);
- self.s.word(":");
+ self.word(":");
for (i, bound) in bounds.iter().enumerate() {
match bound {
@@ -2318,7 +2266,7 @@ impl<'a> State<'a> {
}
if i != 0 {
- self.s.word(":");
+ self.word(":");
}
}
}
@@ -2326,7 +2274,7 @@ impl<'a> State<'a> {
lhs_ty, rhs_ty, ..
}) => {
self.print_type(lhs_ty);
- self.s.space();
+ self.space();
self.word_space("=");
self.print_type(rhs_ty);
}
@@ -2365,7 +2313,7 @@ impl<'a> State<'a> {
self.end();
if let hir::FnRetTy::Return(ref output) = decl.output {
- self.maybe_print_comment(output.span.lo())
+ self.maybe_print_comment(output.span.lo());
}
}
@@ -2380,7 +2328,7 @@ impl<'a> State<'a> {
) {
self.ibox(INDENT_UNIT);
if !generic_params.is_empty() {
- self.s.word("for");
+ self.word("for");
self.print_generic_params(generic_params);
}
let generics = hir::Generics {
@@ -2405,31 +2353,8 @@ impl<'a> State<'a> {
self.end();
}
- pub fn maybe_print_trailing_comment(
- &mut self,
- span: rustc_span::Span,
- next_pos: Option<BytePos>,
- ) {
- if let Some(cmnts) = self.comments() {
- if let Some(cmnt) = cmnts.trailing_comment(span, next_pos) {
- self.print_comment(&cmnt);
- }
- }
- }
-
- pub fn print_remaining_comments(&mut self) {
- // If there aren't any remaining comments, then we need to manually
- // make sure there is a line break at the end.
- if self.next_comment().is_none() {
- self.s.hardbreak();
- }
- while let Some(ref cmnt) = self.next_comment() {
- self.print_comment(cmnt)
- }
- }
-
pub fn print_fn_header_info(&mut self, header: hir::FnHeader, vis: &hir::Visibility<'_>) {
- self.s.word(visibility_qualified(vis, ""));
+ self.word(visibility_qualified(vis, ""));
match header.constness {
hir::Constness::NotConst => {}
@@ -2448,7 +2373,7 @@ impl<'a> State<'a> {
self.word_nbsp(header.abi.to_string());
}
- self.s.word("fn")
+ self.word("fn")
}
pub fn print_unsafety(&mut self, s: hir::Unsafety) {
diff --git a/compiler/rustc_incremental/src/assert_dep_graph.rs b/compiler/rustc_incremental/src/assert_dep_graph.rs
index 571337a8dcb..4691cdd64c1 100644
--- a/compiler/rustc_incremental/src/assert_dep_graph.rs
+++ b/compiler/rustc_incremental/src/assert_dep_graph.rs
@@ -52,6 +52,7 @@ use std::env;
use std::fs::{self, File};
use std::io::{BufWriter, Write};
+#[allow(missing_docs)]
pub fn assert_dep_graph(tcx: TyCtxt<'_>) {
tcx.dep_graph.with_ignore(|| {
if tcx.sess.opts.debugging_opts.dump_dep_graph {
@@ -102,7 +103,7 @@ struct IfThisChanged<'tcx> {
then_this_would_need: Targets,
}
-impl IfThisChanged<'tcx> {
+impl<'tcx> IfThisChanged<'tcx> {
fn argument(&self, attr: &ast::Attribute) -> Option<Symbol> {
let mut value = None;
for list_item in attr.meta_item_list().unwrap_or_default() {
@@ -171,7 +172,7 @@ impl IfThisChanged<'tcx> {
}
}
-impl Visitor<'tcx> for IfThisChanged<'tcx> {
+impl<'tcx> Visitor<'tcx> for IfThisChanged<'tcx> {
type Map = Map<'tcx>;
fn nested_visit_map(&mut self) -> NestedVisitorMap<Self::Map> {
@@ -262,6 +263,7 @@ fn dump_graph(query: &DepGraphQuery) {
}
}
+#[allow(missing_docs)]
pub struct GraphvizDepGraph<'q>(FxHashSet<&'q DepNode>, Vec<(&'q DepNode, &'q DepNode)>);
impl<'a, 'q> dot::GraphWalk<'a> for GraphvizDepGraph<'q> {
diff --git a/compiler/rustc_incremental/src/assert_module_sources.rs b/compiler/rustc_incremental/src/assert_module_sources.rs
index a5f3e4553ce..b5974f8fb76 100644
--- a/compiler/rustc_incremental/src/assert_module_sources.rs
+++ b/compiler/rustc_incremental/src/assert_module_sources.rs
@@ -29,6 +29,7 @@ use rustc_session::cgu_reuse_tracker::*;
use rustc_span::symbol::{sym, Symbol};
use std::collections::BTreeSet;
+#[allow(missing_docs)]
pub fn assert_module_sources(tcx: TyCtxt<'_>) {
tcx.dep_graph.with_ignore(|| {
if tcx.sess.opts.incremental.is_none() {
@@ -55,7 +56,7 @@ struct AssertModuleSource<'tcx> {
available_cgus: BTreeSet<String>,
}
-impl AssertModuleSource<'tcx> {
+impl<'tcx> AssertModuleSource<'tcx> {
fn check_attr(&self, attr: &ast::Attribute) {
let (expected_reuse, comp_kind) = if attr.has_name(sym::rustc_partition_reused) {
(CguReuse::PreLto, ComparisonKind::AtLeast)
diff --git a/compiler/rustc_incremental/src/lib.rs b/compiler/rustc_incremental/src/lib.rs
index dd3f8c937f8..df64534ce54 100644
--- a/compiler/rustc_incremental/src/lib.rs
+++ b/compiler/rustc_incremental/src/lib.rs
@@ -1,7 +1,7 @@
//! Support for serializing the dep-graph and reloading it.
+#![deny(missing_docs)]
#![doc(html_root_url = "https://doc.rust-lang.org/nightly/nightly-rustc/")]
-#![feature(in_band_lifetimes)]
#![feature(let_else)]
#![feature(nll)]
#![recursion_limit = "256"]
diff --git a/compiler/rustc_incremental/src/persist/dirty_clean.rs b/compiler/rustc_incremental/src/persist/dirty_clean.rs
index b2eaf61b7d1..7ac00b4609a 100644
--- a/compiler/rustc_incremental/src/persist/dirty_clean.rs
+++ b/compiler/rustc_incremental/src/persist/dirty_clean.rs
@@ -155,7 +155,7 @@ pub struct DirtyCleanVisitor<'tcx> {
checked_attrs: FxHashSet<ast::AttrId>,
}
-impl DirtyCleanVisitor<'tcx> {
+impl<'tcx> DirtyCleanVisitor<'tcx> {
/// Possibly "deserialize" the attribute into a clean/dirty assertion
fn assertion_maybe(&mut self, item_id: LocalDefId, attr: &Attribute) -> Option<Assertion> {
if !attr.has_name(sym::rustc_clean) {
@@ -352,7 +352,7 @@ impl DirtyCleanVisitor<'tcx> {
}
}
-impl ItemLikeVisitor<'tcx> for DirtyCleanVisitor<'tcx> {
+impl<'tcx> ItemLikeVisitor<'tcx> for DirtyCleanVisitor<'tcx> {
fn visit_item(&mut self, item: &'tcx hir::Item<'tcx>) {
self.check_item(item.def_id, item.span);
}
@@ -415,7 +415,7 @@ pub struct FindAllAttrs<'tcx> {
found_attrs: Vec<&'tcx Attribute>,
}
-impl FindAllAttrs<'tcx> {
+impl<'tcx> FindAllAttrs<'tcx> {
fn is_active_attr(&mut self, attr: &Attribute) -> bool {
if attr.has_name(sym::rustc_clean) && check_config(self.tcx, attr) {
return true;
@@ -434,7 +434,7 @@ impl FindAllAttrs<'tcx> {
}
}
-impl intravisit::Visitor<'tcx> for FindAllAttrs<'tcx> {
+impl<'tcx> intravisit::Visitor<'tcx> for FindAllAttrs<'tcx> {
type Map = Map<'tcx>;
fn nested_visit_map(&mut self) -> intravisit::NestedVisitorMap<Self::Map> {
diff --git a/compiler/rustc_incremental/src/persist/fs.rs b/compiler/rustc_incremental/src/persist/fs.rs
index c0137fc7a5a..a49a1554d5b 100644
--- a/compiler/rustc_incremental/src/persist/fs.rs
+++ b/compiler/rustc_incremental/src/persist/fs.rs
@@ -133,21 +133,26 @@ const QUERY_CACHE_FILENAME: &str = "query-cache.bin";
// case-sensitive (as opposed to base64, for example).
const INT_ENCODE_BASE: usize = base_n::CASE_INSENSITIVE;
+/// Returns the path to a session's dependency graph.
pub fn dep_graph_path(sess: &Session) -> PathBuf {
in_incr_comp_dir_sess(sess, DEP_GRAPH_FILENAME)
}
+/// Returns the path to a session's staging dependency graph.
+///
+/// On the difference between dep-graph and staging dep-graph,
+/// see `build_dep_graph`.
pub fn staging_dep_graph_path(sess: &Session) -> PathBuf {
in_incr_comp_dir_sess(sess, STAGING_DEP_GRAPH_FILENAME)
}
-
pub fn work_products_path(sess: &Session) -> PathBuf {
in_incr_comp_dir_sess(sess, WORK_PRODUCTS_FILENAME)
}
-
+/// Returns the path to a session's query cache.
pub fn query_cache_path(sess: &Session) -> PathBuf {
in_incr_comp_dir_sess(sess, QUERY_CACHE_FILENAME)
}
+/// Locks a given session directory.
pub fn lock_file_path(session_dir: &Path) -> PathBuf {
let crate_dir = session_dir.parent().unwrap();
@@ -166,23 +171,35 @@ pub fn lock_file_path(session_dir: &Path) -> PathBuf {
crate_dir.join(&directory_name[0..dash_indices[2]]).with_extension(&LOCK_FILE_EXT[1..])
}
+/// Returns the path for a given filename within the incremental compilation directory
+/// in the current session.
pub fn in_incr_comp_dir_sess(sess: &Session, file_name: &str) -> PathBuf {
in_incr_comp_dir(&sess.incr_comp_session_dir(), file_name)
}
+/// Returns the path for a given filename within the incremental compilation directory,
+/// not necessarily from the current session.
+///
+/// To ensure the file is part of the current session, use [`in_incr_comp_dir_sess`].
pub fn in_incr_comp_dir(incr_comp_session_dir: &Path, file_name: &str) -> PathBuf {
incr_comp_session_dir.join(file_name)
}
-/// Allocates the private session directory. The boolean in the Ok() result
-/// indicates whether we should try loading a dep graph from the successfully
-/// initialized directory, or not.
-/// The post-condition of this fn is that we have a valid incremental
-/// compilation session directory, if the result is `Ok`. A valid session
+/// Allocates the private session directory.
+///
+/// If the result of this function is `Ok`, we have a valid incremental
+/// compilation session directory. A valid session
/// directory is one that contains a locked lock file. It may or may not contain
/// a dep-graph and work products from a previous session.
-/// If the call fails, the fn may leave behind an invalid session directory.
+///
+/// This always attempts to load a dep-graph from the directory.
+/// If loading fails for some reason, we fallback to a disabled `DepGraph`.
+/// See [`rustc_interface::queries::dep_graph`].
+///
+/// If this function returns an error, it may leave behind an invalid session directory.
/// The garbage collection will take care of it.
+///
+/// [`rustc_interface::queries::dep_graph`]: ../../rustc_interface/struct.Queries.html#structfield.dep_graph
pub fn prepare_session_directory(
sess: &Session,
crate_name: &str,
@@ -661,6 +678,7 @@ fn is_old_enough_to_be_collected(timestamp: SystemTime) -> bool {
timestamp < SystemTime::now() - Duration::from_secs(10)
}
+/// Runs garbage collection for the current session.
pub fn garbage_collect_session_directories(sess: &Session) -> io::Result<()> {
debug!("garbage_collect_session_directories() - begin");
diff --git a/compiler/rustc_incremental/src/persist/load.rs b/compiler/rustc_incremental/src/persist/load.rs
index 9c6e2aeb50a..d563a6ca478 100644
--- a/compiler/rustc_incremental/src/persist/load.rs
+++ b/compiler/rustc_incremental/src/persist/load.rs
@@ -18,13 +18,24 @@ use super::work_product;
type WorkProductMap = FxHashMap<WorkProductId, WorkProduct>;
#[derive(Debug)]
+/// Represents the result of an attempt to load incremental compilation data.
pub enum LoadResult<T> {
- Ok { data: T },
+ /// Loading was successful.
+ Ok {
+ #[allow(missing_docs)]
+ data: T,
+ },
+ /// The file either didn't exist or was produced by an incompatible compiler version.
DataOutOfDate,
- Error { message: String },
+ /// An error occured.
+ Error {
+ #[allow(missing_docs)]
+ message: String,
+ },
}
impl<T: Default> LoadResult<T> {
+ /// Accesses the data returned in [`LoadResult::Ok`].
pub fn open(self, sess: &Session) -> T {
// Check for errors when using `-Zassert-incremental-state`
match (sess.opts.assert_incr_state, &self) {
@@ -99,6 +110,7 @@ pub enum MaybeAsync<T> {
}
impl<T> MaybeAsync<LoadResult<T>> {
+ /// Accesses the data returned in [`LoadResult::Ok`] in an asynchronous way if possible.
pub fn open(self) -> LoadResult<T> {
match self {
MaybeAsync::Sync(result) => result,
@@ -109,6 +121,7 @@ impl<T> MaybeAsync<LoadResult<T>> {
}
}
+/// An asynchronous type for computing the dependency graph.
pub type DepGraphFuture = MaybeAsync<LoadResult<(SerializedDepGraph, WorkProductMap)>>;
/// Launch a thread and load the dependency graph in the background.
@@ -151,7 +164,7 @@ pub fn load_dep_graph(sess: &Session) -> DepGraphFuture {
compilation session directory: {}",
e
);
- sess.fatal(&msg[..])
+ sess.fatal(&msg)
});
for swp in work_products {
diff --git a/compiler/rustc_incremental/src/persist/save.rs b/compiler/rustc_incremental/src/persist/save.rs
index 6c683058b12..9601a49267f 100644
--- a/compiler/rustc_incremental/src/persist/save.rs
+++ b/compiler/rustc_incremental/src/persist/save.rs
@@ -13,9 +13,13 @@ use super::file_format;
use super::fs::*;
use super::work_product;
-/// Save and dump the DepGraph.
+/// Saves and writes the [`DepGraph`] to the file system.
///
-/// No query must be invoked after this function.
+/// This function saves both the dep-graph and the query result cache,
+/// and drops the result cache.
+///
+/// This function should only run after all queries have completed.
+/// Trying to execute a query afterwards would attempt to read the result cache we just dropped.
pub fn save_dep_graph(tcx: TyCtxt<'_>) {
debug!("save_dep_graph()");
tcx.dep_graph.with_ignore(|| {
@@ -75,6 +79,7 @@ pub fn save_dep_graph(tcx: TyCtxt<'_>) {
})
}
+/// Saves the work product index.
pub fn save_work_product_index(
sess: &Session,
dep_graph: &DepGraph,
@@ -139,6 +144,12 @@ fn encode_query_cache(tcx: TyCtxt<'_>, encoder: &mut FileEncoder) -> FileEncodeR
tcx.sess.time("incr_comp_serialize_result_cache", || tcx.serialize_query_result_cache(encoder))
}
+/// Builds the dependency graph.
+///
+/// This function breates the *staging dep-graph*. When the dep-graph is modified by a query
+/// execution, the new dependency information is not kept in memory but directly
+/// output to this file. `save_dep_graph` then finalizes the staging dep-graph
+/// and moves it to the permanent dep-graph path
pub fn build_dep_graph(
sess: &Session,
prev_graph: SerializedDepGraph,
diff --git a/compiler/rustc_incremental/src/persist/work_product.rs b/compiler/rustc_incremental/src/persist/work_product.rs
index 19d64bda56d..85b44ed7531 100644
--- a/compiler/rustc_incremental/src/persist/work_product.rs
+++ b/compiler/rustc_incremental/src/persist/work_product.rs
@@ -1,4 +1,6 @@
-//! This module contains files for saving intermediate work-products.
+//! Functions for saving and removing intermediate [work products].
+//!
+//! [work products]: WorkProduct
use crate::persist::fs::*;
use rustc_fs_util::link_or_copy;
@@ -7,6 +9,7 @@ use rustc_session::Session;
use std::fs as std_fs;
use std::path::PathBuf;
+/// Copies a CGU work product to the incremental compilation directory, so next compilation can find and reuse it.
pub fn copy_cgu_workproduct_to_incr_comp_cache_dir(
sess: &Session,
cgu_name: &str,
@@ -40,6 +43,7 @@ pub fn copy_cgu_workproduct_to_incr_comp_cache_dir(
Some((work_product_id, work_product))
}
+/// Removes files for a given work product.
pub fn delete_workproduct_files(sess: &Session, work_product: &WorkProduct) {
if let Some(ref file_name) = work_product.saved_file {
let path = in_incr_comp_dir_sess(sess, file_name);
diff --git a/compiler/rustc_index/src/bit_set.rs b/compiler/rustc_index/src/bit_set.rs
index 67b3cec0a3e..08f13d46ee1 100644
--- a/compiler/rustc_index/src/bit_set.rs
+++ b/compiler/rustc_index/src/bit_set.rs
@@ -4,7 +4,7 @@ use std::fmt;
use std::iter;
use std::marker::PhantomData;
use std::mem;
-use std::ops::{BitAnd, BitAndAssign, BitOrAssign, Not, Range, Shl};
+use std::ops::{BitAnd, BitAndAssign, BitOrAssign, Bound, Not, Range, RangeBounds, Shl};
use std::slice;
use rustc_macros::{Decodable, Encodable};
@@ -22,6 +22,29 @@ pub trait BitRelations<Rhs> {
fn intersect(&mut self, other: &Rhs) -> bool;
}
+#[inline]
+fn inclusive_start_end<T: Idx>(
+ range: impl RangeBounds<T>,
+ domain: usize,
+) -> Option<(usize, usize)> {
+ // Both start and end are inclusive.
+ let start = match range.start_bound().cloned() {
+ Bound::Included(start) => start.index(),
+ Bound::Excluded(start) => start.index() + 1,
+ Bound::Unbounded => 0,
+ };
+ let end = match range.end_bound().cloned() {
+ Bound::Included(end) => end.index(),
+ Bound::Excluded(end) => end.index().checked_sub(1)?,
+ Bound::Unbounded => domain - 1,
+ };
+ assert!(end < domain);
+ if start > end {
+ return None;
+ }
+ Some((start, end))
+}
+
macro_rules! bit_relations_inherent_impls {
() => {
/// Sets `self = self | other` and returns `true` if `self` changed
@@ -151,6 +174,33 @@ impl<T: Idx> BitSet<T> {
new_word != word
}
+ #[inline]
+ pub fn insert_range(&mut self, elems: impl RangeBounds<T>) {
+ let Some((start, end)) = inclusive_start_end(elems, self.domain_size) else {
+ return;
+ };
+
+ let (start_word_index, start_mask) = word_index_and_mask(start);
+ let (end_word_index, end_mask) = word_index_and_mask(end);
+
+ // Set all words in between start and end (exclusively of both).
+ for word_index in (start_word_index + 1)..end_word_index {
+ self.words[word_index] = !0;
+ }
+
+ if start_word_index != end_word_index {
+ // Start and end are in different words, so we handle each in turn.
+ //
+ // We set all leading bits. This includes the start_mask bit.
+ self.words[start_word_index] |= !(start_mask - 1);
+ // And all trailing bits (i.e. from 0..=end) in the end word,
+ // including the end.
+ self.words[end_word_index] |= end_mask | end_mask - 1;
+ } else {
+ self.words[start_word_index] |= end_mask | (end_mask - start_mask);
+ }
+ }
+
/// Sets all bits to true.
pub fn insert_all(&mut self) {
for word in &mut self.words {
@@ -227,6 +277,36 @@ impl<T: Idx> BitSet<T> {
not_already
}
+ fn last_set_in(&self, range: impl RangeBounds<T>) -> Option<T> {
+ let (start, end) = inclusive_start_end(range, self.domain_size)?;
+ let (start_word_index, _) = word_index_and_mask(start);
+ let (end_word_index, end_mask) = word_index_and_mask(end);
+
+ let end_word = self.words[end_word_index] & (end_mask | (end_mask - 1));
+ if end_word != 0 {
+ let pos = max_bit(end_word) + WORD_BITS * end_word_index;
+ if start <= pos {
+ return Some(T::new(pos));
+ }
+ }
+
+ // We exclude end_word_index from the range here, because we don't want
+ // to limit ourselves to *just* the last word: the bits set it in may be
+ // after `end`, so it may not work out.
+ if let Some(offset) =
+ self.words[start_word_index..end_word_index].iter().rposition(|&w| w != 0)
+ {
+ let word_idx = start_word_index + offset;
+ let start_word = self.words[word_idx];
+ let pos = max_bit(start_word) + WORD_BITS * word_idx;
+ if start <= pos {
+ return Some(T::new(pos));
+ }
+ }
+
+ None
+ }
+
bit_relations_inherent_impls! {}
}
@@ -635,6 +715,16 @@ impl<T: Idx> SparseBitSet<T> {
self.elems.iter()
}
+ fn last_set_in(&self, range: impl RangeBounds<T>) -> Option<T> {
+ let mut last_leq = None;
+ for e in self.iter() {
+ if range.contains(e) {
+ last_leq = Some(*e);
+ }
+ }
+ last_leq
+ }
+
bit_relations_inherent_impls! {}
}
@@ -709,6 +799,16 @@ impl<T: Idx> HybridBitSet<T> {
}
}
+ /// Returns the previous element present in the bitset from `elem`,
+ /// inclusively of elem. That is, will return `Some(elem)` if elem is in the
+ /// bitset.
+ pub fn last_set_in(&self, range: impl RangeBounds<T>) -> Option<T> {
+ match self {
+ HybridBitSet::Sparse(sparse) => sparse.last_set_in(range),
+ HybridBitSet::Dense(dense) => dense.last_set_in(range),
+ }
+ }
+
pub fn insert(&mut self, elem: T) -> bool {
// No need to check `elem` against `self.domain_size` here because all
// the match cases check it, one way or another.
@@ -734,6 +834,41 @@ impl<T: Idx> HybridBitSet<T> {
}
}
+ pub fn insert_range(&mut self, elems: impl RangeBounds<T>) {
+ // No need to check `elem` against `self.domain_size` here because all
+ // the match cases check it, one way or another.
+ let start = match elems.start_bound().cloned() {
+ Bound::Included(start) => start.index(),
+ Bound::Excluded(start) => start.index() + 1,
+ Bound::Unbounded => 0,
+ };
+ let end = match elems.end_bound().cloned() {
+ Bound::Included(end) => end.index() + 1,
+ Bound::Excluded(end) => end.index(),
+ Bound::Unbounded => self.domain_size() - 1,
+ };
+ let len = if let Some(l) = end.checked_sub(start) {
+ l
+ } else {
+ return;
+ };
+ match self {
+ HybridBitSet::Sparse(sparse) if sparse.len() + len < SPARSE_MAX => {
+ // The set is sparse and has space for `elems`.
+ for elem in start..end {
+ sparse.insert(T::new(elem));
+ }
+ }
+ HybridBitSet::Sparse(sparse) => {
+ // The set is sparse and full. Convert to a dense set.
+ let mut dense = sparse.to_dense();
+ dense.insert_range(elems);
+ *self = HybridBitSet::Dense(dense);
+ }
+ HybridBitSet::Dense(dense) => dense.insert_range(elems),
+ }
+ }
+
pub fn insert_all(&mut self) {
let domain_size = self.domain_size();
match self {
@@ -1205,6 +1340,11 @@ fn word_index_and_mask<T: Idx>(elem: T) -> (usize, Word) {
(word_index, mask)
}
+#[inline]
+fn max_bit(word: Word) -> usize {
+ WORD_BITS - 1 - word.leading_zeros() as usize
+}
+
/// Integral type used to represent the bit set.
pub trait FiniteBitSetTy:
BitAnd<Output = Self>
diff --git a/compiler/rustc_index/src/bit_set/tests.rs b/compiler/rustc_index/src/bit_set/tests.rs
index aebc6d0ddd8..e2b07305c96 100644
--- a/compiler/rustc_index/src/bit_set/tests.rs
+++ b/compiler/rustc_index/src/bit_set/tests.rs
@@ -370,6 +370,101 @@ fn sparse_matrix_operations() {
}
}
+#[test]
+fn dense_insert_range() {
+ #[track_caller]
+ fn check<R>(domain: usize, range: R)
+ where
+ R: RangeBounds<usize> + Clone + IntoIterator<Item = usize> + std::fmt::Debug,
+ {
+ let mut set = BitSet::new_empty(domain);
+ set.insert_range(range.clone());
+ for i in set.iter() {
+ assert!(range.contains(&i));
+ }
+ for i in range.clone() {
+ assert!(set.contains(i), "{} in {:?}, inserted {:?}", i, set, range);
+ }
+ }
+ check(300, 10..10);
+ check(300, WORD_BITS..WORD_BITS * 2);
+ check(300, WORD_BITS - 1..WORD_BITS * 2);
+ check(300, WORD_BITS - 1..WORD_BITS);
+ check(300, 10..100);
+ check(300, 10..30);
+ check(300, 0..5);
+ check(300, 0..250);
+ check(300, 200..250);
+
+ check(300, 10..=10);
+ check(300, WORD_BITS..=WORD_BITS * 2);
+ check(300, WORD_BITS - 1..=WORD_BITS * 2);
+ check(300, WORD_BITS - 1..=WORD_BITS);
+ check(300, 10..=100);
+ check(300, 10..=30);
+ check(300, 0..=5);
+ check(300, 0..=250);
+ check(300, 200..=250);
+
+ for i in 0..WORD_BITS * 2 {
+ for j in i..WORD_BITS * 2 {
+ check(WORD_BITS * 2, i..j);
+ check(WORD_BITS * 2, i..=j);
+ check(300, i..j);
+ check(300, i..=j);
+ }
+ }
+}
+
+#[test]
+fn dense_last_set_before() {
+ fn easy(set: &BitSet<usize>, needle: impl RangeBounds<usize>) -> Option<usize> {
+ let mut last_leq = None;
+ for e in set.iter() {
+ if needle.contains(&e) {
+ last_leq = Some(e);
+ }
+ }
+ last_leq
+ }
+
+ #[track_caller]
+ fn cmp(set: &BitSet<usize>, needle: impl RangeBounds<usize> + Clone + std::fmt::Debug) {
+ assert_eq!(
+ set.last_set_in(needle.clone()),
+ easy(set, needle.clone()),
+ "{:?} in {:?}",
+ needle,
+ set
+ );
+ }
+ let mut set = BitSet::new_empty(300);
+ cmp(&set, 50..=50);
+ set.insert(WORD_BITS);
+ cmp(&set, WORD_BITS..=WORD_BITS);
+ set.insert(WORD_BITS - 1);
+ cmp(&set, 0..=WORD_BITS - 1);
+ cmp(&set, 0..=5);
+ cmp(&set, 10..100);
+ set.insert(100);
+ cmp(&set, 100..110);
+ cmp(&set, 99..100);
+ cmp(&set, 99..=100);
+
+ for i in 0..=WORD_BITS * 2 {
+ for j in i..=WORD_BITS * 2 {
+ for k in 0..WORD_BITS * 2 {
+ let mut set = BitSet::new_empty(300);
+ cmp(&set, i..j);
+ cmp(&set, i..=j);
+ set.insert(k);
+ cmp(&set, i..j);
+ cmp(&set, i..=j);
+ }
+ }
+ }
+}
+
/// Merge dense hybrid set into empty sparse hybrid set.
#[bench]
fn union_hybrid_sparse_empty_to_dense(b: &mut Bencher) {
diff --git a/compiler/rustc_index/src/lib.rs b/compiler/rustc_index/src/lib.rs
index a72a27e07bd..a9efd6bb8bc 100644
--- a/compiler/rustc_index/src/lib.rs
+++ b/compiler/rustc_index/src/lib.rs
@@ -1,9 +1,10 @@
#![feature(allow_internal_unstable)]
#![feature(bench_black_box)]
#![feature(extend_one)]
-#![feature(iter_zip)]
#![feature(min_specialization)]
+#![feature(step_trait)]
#![feature(test)]
+#![feature(let_else)]
pub mod bit_set;
pub mod vec;
diff --git a/compiler/rustc_infer/src/infer/combine.rs b/compiler/rustc_infer/src/infer/combine.rs
index 09bfb3290f4..03596f7dfad 100644
--- a/compiler/rustc_infer/src/infer/combine.rs
+++ b/compiler/rustc_infer/src/infer/combine.rs
@@ -37,7 +37,7 @@ use crate::traits::{Obligation, PredicateObligations};
use rustc_data_structures::sso::SsoHashMap;
use rustc_hir::def_id::DefId;
use rustc_middle::traits::ObligationCause;
-use rustc_middle::ty::error::TypeError;
+use rustc_middle::ty::error::{ExpectedFound, TypeError};
use rustc_middle::ty::relate::{self, Relate, RelateResult, TypeRelation};
use rustc_middle::ty::subst::SubstsRef;
use rustc_middle::ty::{self, InferConst, ToPredicate, Ty, TyCtxt, TypeFoldable};
@@ -790,7 +790,7 @@ pub fn const_unification_error<'tcx>(
a_is_expected: bool,
(a, b): (&'tcx ty::Const<'tcx>, &'tcx ty::Const<'tcx>),
) -> TypeError<'tcx> {
- TypeError::ConstMismatch(ty::relate::expected_found_bool(a_is_expected, a, b))
+ TypeError::ConstMismatch(ExpectedFound::new(a_is_expected, a, b))
}
fn int_unification_error<'tcx>(
@@ -798,7 +798,7 @@ fn int_unification_error<'tcx>(
v: (ty::IntVarValue, ty::IntVarValue),
) -> TypeError<'tcx> {
let (a, b) = v;
- TypeError::IntMismatch(ty::relate::expected_found_bool(a_is_expected, a, b))
+ TypeError::IntMismatch(ExpectedFound::new(a_is_expected, a, b))
}
fn float_unification_error<'tcx>(
@@ -806,7 +806,7 @@ fn float_unification_error<'tcx>(
v: (ty::FloatVarValue, ty::FloatVarValue),
) -> TypeError<'tcx> {
let (ty::FloatVarValue(a), ty::FloatVarValue(b)) = v;
- TypeError::FloatMismatch(ty::relate::expected_found_bool(a_is_expected, a, b))
+ TypeError::FloatMismatch(ExpectedFound::new(a_is_expected, a, b))
}
struct ConstInferUnifier<'cx, 'tcx> {
diff --git a/compiler/rustc_infer/src/infer/error_reporting/mod.rs b/compiler/rustc_infer/src/infer/error_reporting/mod.rs
index 85226e60bdb..bf867db9ce6 100644
--- a/compiler/rustc_infer/src/infer/error_reporting/mod.rs
+++ b/compiler/rustc_infer/src/infer/error_reporting/mod.rs
@@ -275,7 +275,7 @@ pub fn unexpected_hidden_region_diagnostic(
fn_returns,
hidden_region.to_string(),
None,
- format!("captures {}", hidden_region),
+ format!("captures `{}`", hidden_region),
None,
)
}
@@ -384,6 +384,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
sub_r,
sup_origin,
sup_r,
+ _,
) => {
if sub_r.is_placeholder() {
self.report_placeholder_failure(sub_origin, sub_r, sup_r).emit();
@@ -464,7 +465,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
errors.sort_by_key(|u| match *u {
RegionResolutionError::ConcreteFailure(ref sro, _, _) => sro.span(),
RegionResolutionError::GenericBoundFailure(ref sro, _, _) => sro.span(),
- RegionResolutionError::SubSupConflict(_, ref rvo, _, _, _, _) => rvo.span(),
+ RegionResolutionError::SubSupConflict(_, ref rvo, _, _, _, _, _) => rvo.span(),
RegionResolutionError::UpperBoundUniverseConflict(_, ref rvo, _, _, _) => rvo.span(),
});
errors
@@ -1429,6 +1430,15 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
}
}
+ /// Extend a type error with extra labels pointing at "non-trivial" types, like closures and
+ /// the return type of `async fn`s.
+ ///
+ /// `secondary_span` gives the caller the opportunity to expand `diag` with a `span_label`.
+ ///
+ /// `swap_secondary_and_primary` is used to make projection errors in particular nicer by using
+ /// the message in `secondary_span` as the primary label, and apply the message that would
+ /// otherwise be used for the primary label on the `secondary_span` `Span`. This applies on
+ /// E0271, like `src/test/ui/issues/issue-39970.stderr`.
pub fn note_type_err(
&self,
diag: &mut DiagnosticBuilder<'tcx>,
@@ -1436,6 +1446,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
secondary_span: Option<(Span, String)>,
mut values: Option<ValuePairs<'tcx>>,
terr: &TypeError<'tcx>,
+ swap_secondary_and_primary: bool,
) {
let span = cause.span(self.tcx);
debug!("note_type_err cause={:?} values={:?}, terr={:?}", cause, values, terr);
@@ -1612,9 +1623,32 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
match terr {
TypeError::ObjectUnsafeCoercion(_) => {}
_ => {
- diag.span_label(span, terr.to_string());
+ let mut label_or_note = |span: Span, msg: &str| {
+ if &[span] == diag.span.primary_spans() {
+ diag.span_label(span, msg);
+ } else {
+ diag.span_note(span, msg);
+ }
+ };
if let Some((sp, msg)) = secondary_span {
- diag.span_label(sp, msg);
+ if swap_secondary_and_primary {
+ let terr = if let Some(infer::ValuePairs::Types(infer::ExpectedFound {
+ expected,
+ ..
+ })) = values
+ {
+ format!("expected this to be `{}`", expected)
+ } else {
+ terr.to_string()
+ };
+ label_or_note(sp, &terr);
+ label_or_note(span, &msg);
+ } else {
+ label_or_note(span, &terr.to_string());
+ label_or_note(sp, &msg);
+ }
+ } else {
+ label_or_note(span, &terr.to_string());
}
}
};
@@ -2048,7 +2082,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
struct_span_err!(self.tcx.sess, span, E0644, "{}", failure_str)
}
};
- self.note_type_err(&mut diag, &trace.cause, None, Some(trace.values), terr);
+ self.note_type_err(&mut diag, &trace.cause, None, Some(trace.values), terr, false);
diag
}
diff --git a/compiler/rustc_infer/src/infer/error_reporting/need_type_info.rs b/compiler/rustc_infer/src/infer/error_reporting/need_type_info.rs
index a7e019a53ee..9cf6cde2591 100644
--- a/compiler/rustc_infer/src/infer/error_reporting/need_type_info.rs
+++ b/compiler/rustc_infer/src/infer/error_reporting/need_type_info.rs
@@ -1,5 +1,5 @@
use crate::infer::type_variable::TypeVariableOriginKind;
-use crate::infer::InferCtxt;
+use crate::infer::{InferCtxt, Symbol};
use rustc_errors::{pluralize, struct_span_err, Applicability, DiagnosticBuilder};
use rustc_hir as hir;
use rustc_hir::def::{DefKind, Namespace};
@@ -10,7 +10,7 @@ use rustc_middle::hir::map::Map;
use rustc_middle::infer::unify_key::ConstVariableOriginKind;
use rustc_middle::ty::print::Print;
use rustc_middle::ty::subst::{GenericArg, GenericArgKind};
-use rustc_middle::ty::{self, DefIdTree, InferConst, Ty, TyCtxt};
+use rustc_middle::ty::{self, Const, DefIdTree, InferConst, Ty, TyCtxt, TypeFoldable, TypeFolder};
use rustc_span::symbol::kw;
use rustc_span::Span;
use std::borrow::Cow;
@@ -305,6 +305,15 @@ pub enum UnderspecifiedArgKind {
Const { is_parameter: bool },
}
+impl UnderspecifiedArgKind {
+ fn descr(&self) -> &'static str {
+ match self {
+ Self::Type { .. } => "type",
+ Self::Const { .. } => "const",
+ }
+ }
+}
+
impl InferenceDiagnosticsData {
/// Generate a label for a generic argument which can't be inferred. When not
/// much is known about the argument, `use_diag` may be used to describe the
@@ -400,36 +409,75 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
}
}
GenericArgKind::Const(ct) => {
- if let ty::ConstKind::Infer(InferConst::Var(vid)) = ct.val {
- let origin =
- self.inner.borrow_mut().const_unification_table().probe_value(vid).origin;
- if let ConstVariableOriginKind::ConstParameterDefinition(name, def_id) =
- origin.kind
- {
- return InferenceDiagnosticsData {
- name: name.to_string(),
+ match ct.val {
+ ty::ConstKind::Infer(InferConst::Var(vid)) => {
+ let origin = self
+ .inner
+ .borrow_mut()
+ .const_unification_table()
+ .probe_value(vid)
+ .origin;
+ if let ConstVariableOriginKind::ConstParameterDefinition(name, def_id) =
+ origin.kind
+ {
+ return InferenceDiagnosticsData {
+ name: name.to_string(),
+ span: Some(origin.span),
+ kind: UnderspecifiedArgKind::Const { is_parameter: true },
+ parent: InferenceDiagnosticsParentData::for_def_id(
+ self.tcx, def_id,
+ ),
+ };
+ }
+
+ debug_assert!(!origin.span.is_dummy());
+ let mut s = String::new();
+ let mut printer =
+ ty::print::FmtPrinter::new(self.tcx, &mut s, Namespace::ValueNS);
+ if let Some(highlight) = highlight {
+ printer.region_highlight_mode = highlight;
+ }
+ let _ = ct.print(printer);
+ InferenceDiagnosticsData {
+ name: s,
span: Some(origin.span),
- kind: UnderspecifiedArgKind::Const { is_parameter: true },
- parent: InferenceDiagnosticsParentData::for_def_id(self.tcx, def_id),
- };
+ kind: UnderspecifiedArgKind::Const { is_parameter: false },
+ parent: None,
+ }
}
+ ty::ConstKind::Unevaluated(ty::Unevaluated {
+ substs_: Some(substs), ..
+ }) => {
+ assert!(substs.has_infer_types_or_consts());
- debug_assert!(!origin.span.is_dummy());
- let mut s = String::new();
- let mut printer =
- ty::print::FmtPrinter::new(self.tcx, &mut s, Namespace::ValueNS);
- if let Some(highlight) = highlight {
- printer.region_highlight_mode = highlight;
+ // FIXME: We only use the first inference variable we encounter in
+ // `substs` here, this gives insufficiently informative diagnostics
+ // in case there are multiple inference variables
+ for s in substs.iter() {
+ match s.unpack() {
+ GenericArgKind::Type(t) => match t.kind() {
+ ty::Infer(_) => {
+ return self.extract_inference_diagnostics_data(s, None);
+ }
+ _ => {}
+ },
+ GenericArgKind::Const(c) => match c.val {
+ ty::ConstKind::Infer(InferConst::Var(_)) => {
+ return self.extract_inference_diagnostics_data(s, None);
+ }
+ _ => {}
+ },
+ _ => {}
+ }
+ }
+ bug!(
+ "expected an inference variable in substs of unevaluated const {:?}",
+ ct
+ );
}
- let _ = ct.print(printer);
- InferenceDiagnosticsData {
- name: s,
- span: Some(origin.span),
- kind: UnderspecifiedArgKind::Const { is_parameter: false },
- parent: None,
+ _ => {
+ bug!("unexpect const: {:?}", ct);
}
- } else {
- bug!("unexpect const: {:?}", ct);
}
}
GenericArgKind::Lifetime(_) => bug!("unexpected lifetime"),
@@ -548,6 +596,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
}
}
+ let param_type = arg_data.kind.descr();
let suffix = match local_visitor.found_node_ty {
Some(ty) if ty.is_closure() => {
let substs =
@@ -586,13 +635,15 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
}
Some(ty) if is_named_and_not_impl_trait(ty) && arg_data.name == "_" => {
let ty = ty_to_string(ty);
- format!("the explicit type `{}`, with the type parameters specified", ty)
+ format!("the explicit type `{}`, with the {} parameters specified", ty, param_type)
}
Some(ty) if is_named_and_not_impl_trait(ty) && ty.to_string() != arg_data.name => {
+ let ty = ResolvedTypeParamEraser::new(self.tcx).fold_ty(ty);
+ let ty = ErrTypeParamEraser(self.tcx).fold_ty(ty);
let ty = ty_to_string(ty);
format!(
- "the explicit type `{}`, where the type parameter `{}` is specified",
- ty, arg_data.name,
+ "the explicit type `{}`, where the {} parameter `{}` is specified",
+ ty, param_type, arg_data.name,
)
}
_ => "a type".to_string(),
@@ -868,3 +919,117 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
err
}
}
+
+/// Turn *resolved* type params into `[type error]` to signal we don't want to display them. After
+/// performing that replacement, we'll turn all remaining infer type params to use their name from
+/// their definition, and replace all the `[type error]`s back to being infer so they display in
+/// the output as `_`. If we didn't go through `[type error]`, we would either show all type params
+/// by their name *or* `_`, neither of which is desireable: we want to show all types that we could
+/// infer as `_` to reduce verbosity and avoid telling the user about unnecessary type annotations.
+struct ResolvedTypeParamEraser<'tcx> {
+ tcx: TyCtxt<'tcx>,
+ level: usize,
+}
+
+impl<'tcx> ResolvedTypeParamEraser<'tcx> {
+ fn new(tcx: TyCtxt<'tcx>) -> Self {
+ ResolvedTypeParamEraser { tcx, level: 0 }
+ }
+
+ /// Replace not yet inferred const params with their def name.
+ fn replace_infers(&self, c: &'tcx Const<'tcx>, index: u32, name: Symbol) -> &'tcx Const<'tcx> {
+ match c.val {
+ ty::ConstKind::Infer(..) => self.tcx().mk_const_param(index, name, c.ty),
+ _ => c,
+ }
+ }
+}
+
+impl<'tcx> TypeFolder<'tcx> for ResolvedTypeParamEraser<'tcx> {
+ fn tcx<'a>(&'a self) -> TyCtxt<'tcx> {
+ self.tcx
+ }
+ fn fold_ty(&mut self, t: Ty<'tcx>) -> Ty<'tcx> {
+ self.level += 1;
+ let t = match t.kind() {
+ // We'll hide this type only if all its type params are hidden as well.
+ ty::Adt(def, substs) => {
+ let generics = self.tcx().generics_of(def.did);
+ // Account for params with default values, like `Vec`, where we
+ // want to show `Vec<T>`, not `Vec<T, _>`. If we replaced that
+ // subst, then we'd get the incorrect output, so we passthrough.
+ let substs: Vec<_> = substs
+ .iter()
+ .zip(generics.params.iter())
+ .map(|(subst, param)| match &(subst.unpack(), &param.kind) {
+ (_, ty::GenericParamDefKind::Type { has_default: true, .. }) => subst,
+ (crate::infer::GenericArgKind::Const(c), _) => {
+ self.replace_infers(c, param.index, param.name).into()
+ }
+ _ => subst.super_fold_with(self),
+ })
+ .collect();
+ let should_keep = |subst: &GenericArg<'_>| match subst.unpack() {
+ ty::subst::GenericArgKind::Type(t) => match t.kind() {
+ ty::Error(_) => false,
+ _ => true,
+ },
+ // Account for `const` params here, otherwise `doesnt_infer.rs`
+ // shows `_` instead of `Foo<{ _: u32 }>`
+ ty::subst::GenericArgKind::Const(_) => true,
+ _ => false,
+ };
+ if self.level == 1 || substs.iter().any(should_keep) {
+ let substs = self.tcx().intern_substs(&substs[..]);
+ self.tcx().mk_ty(ty::Adt(def, substs))
+ } else {
+ self.tcx().ty_error()
+ }
+ }
+ ty::Ref(_, ty, _) => {
+ let ty = self.fold_ty(ty);
+ match ty.kind() {
+ // Avoid `&_`, these can be safely presented as `_`.
+ ty::Error(_) => self.tcx().ty_error(),
+ _ => t.super_fold_with(self),
+ }
+ }
+ // We could account for `()` if we wanted to replace it, but it's assured to be short.
+ ty::Tuple(_)
+ | ty::Slice(_)
+ | ty::RawPtr(_)
+ | ty::FnDef(..)
+ | ty::FnPtr(_)
+ | ty::Opaque(..)
+ | ty::Projection(_)
+ | ty::Never => t.super_fold_with(self),
+ ty::Array(ty, c) => self
+ .tcx()
+ .mk_ty(ty::Array(self.fold_ty(ty), self.replace_infers(c, 0, Symbol::intern("N")))),
+ // We don't want to hide type params that haven't been resolved yet.
+ // This would be the type that will be written out with the type param
+ // name in the output.
+ ty::Infer(_) => t,
+ // We don't want to hide the outermost type, only its type params.
+ _ if self.level == 1 => t.super_fold_with(self),
+ // Hide this type
+ _ => self.tcx().ty_error(),
+ };
+ self.level -= 1;
+ t
+ }
+}
+
+/// Replace `[type error]` with `ty::Infer(ty::Var)` to display `_`.
+struct ErrTypeParamEraser<'tcx>(TyCtxt<'tcx>);
+impl<'tcx> TypeFolder<'tcx> for ErrTypeParamEraser<'tcx> {
+ fn tcx<'a>(&'a self) -> TyCtxt<'tcx> {
+ self.0
+ }
+ fn fold_ty(&mut self, t: Ty<'tcx>) -> Ty<'tcx> {
+ match t.kind() {
+ ty::Error(_) => self.tcx().mk_ty_var(ty::TyVid::from_u32(0)),
+ _ => t.super_fold_with(self),
+ }
+ }
+}
diff --git a/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/mod.rs b/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/mod.rs
index 6a330977002..fd295b74342 100644
--- a/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/mod.rs
+++ b/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/mod.rs
@@ -67,7 +67,7 @@ impl<'cx, 'tcx> NiceRegionError<'cx, 'tcx> {
pub fn regions(&self) -> Option<(Span, ty::Region<'tcx>, ty::Region<'tcx>)> {
match (&self.error, self.regions) {
(Some(ConcreteFailure(origin, sub, sup)), None) => Some((origin.span(), sub, sup)),
- (Some(SubSupConflict(_, _, origin, sub, _, sup)), None) => {
+ (Some(SubSupConflict(_, _, origin, sub, _, sup, _)), None) => {
Some((origin.span(), sub, sup))
}
(None, Some((span, sub, sup))) => Some((span, sub, sup)),
diff --git a/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/placeholder_error.rs b/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/placeholder_error.rs
index 4aecc2f40b8..1a4a2803821 100644
--- a/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/placeholder_error.rs
+++ b/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/placeholder_error.rs
@@ -34,6 +34,7 @@ impl NiceRegionError<'me, 'tcx> {
sub_placeholder @ ty::RePlaceholder(_),
_,
sup_placeholder @ ty::RePlaceholder(_),
+ _,
)) => self.try_report_trait_placeholder_mismatch(
Some(self.tcx().mk_region(ty::ReVar(*vid))),
cause,
@@ -49,6 +50,7 @@ impl NiceRegionError<'me, 'tcx> {
sub_placeholder @ ty::RePlaceholder(_),
_,
_,
+ _,
)) => self.try_report_trait_placeholder_mismatch(
Some(self.tcx().mk_region(ty::ReVar(*vid))),
cause,
@@ -64,6 +66,7 @@ impl NiceRegionError<'me, 'tcx> {
_,
_,
sup_placeholder @ ty::RePlaceholder(_),
+ _,
)) => self.try_report_trait_placeholder_mismatch(
Some(self.tcx().mk_region(ty::ReVar(*vid))),
cause,
@@ -79,6 +82,7 @@ impl NiceRegionError<'me, 'tcx> {
_,
SubregionOrigin::Subtype(box TypeTrace { cause, values }),
sup_placeholder @ ty::RePlaceholder(_),
+ _,
)) => self.try_report_trait_placeholder_mismatch(
Some(self.tcx().mk_region(ty::ReVar(*vid))),
cause,
diff --git a/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/static_impl_trait.rs b/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/static_impl_trait.rs
index 2aaebed28ce..80d4a2e57da 100644
--- a/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/static_impl_trait.rs
+++ b/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/static_impl_trait.rs
@@ -10,7 +10,8 @@ use rustc_hir::def_id::DefId;
use rustc_hir::intravisit::{walk_ty, ErasedMap, NestedVisitorMap, Visitor};
use rustc_hir::{self as hir, GenericBound, Item, ItemKind, Lifetime, LifetimeName, Node, TyKind};
use rustc_middle::ty::{
- self, AssocItemContainer, RegionKind, Ty, TyCtxt, TypeFoldable, TypeVisitor,
+ self, AssocItemContainer, RegionKind, StaticLifetimeVisitor, Ty, TyCtxt, TypeFoldable,
+ TypeVisitor,
};
use rustc_span::symbol::Ident;
use rustc_span::{MultiSpan, Span};
@@ -23,7 +24,7 @@ impl<'a, 'tcx> NiceRegionError<'a, 'tcx> {
pub(super) fn try_report_static_impl_trait(&self) -> Option<ErrorReported> {
debug!("try_report_static_impl_trait(error={:?})", self.error);
let tcx = self.tcx();
- let (var_origin, sub_origin, sub_r, sup_origin, sup_r) = match self.error.as_ref()? {
+ let (var_origin, sub_origin, sub_r, sup_origin, sup_r, spans) = match self.error.as_ref()? {
RegionResolutionError::SubSupConflict(
_,
var_origin,
@@ -31,8 +32,9 @@ impl<'a, 'tcx> NiceRegionError<'a, 'tcx> {
sub_r,
sup_origin,
sup_r,
+ spans,
) if **sub_r == RegionKind::ReStatic => {
- (var_origin, sub_origin, sub_r, sup_origin, sup_r)
+ (var_origin, sub_origin, sub_r, sup_origin, sup_r, spans)
}
RegionResolutionError::ConcreteFailure(
SubregionOrigin::Subtype(box TypeTrace { cause, .. }),
@@ -74,7 +76,7 @@ impl<'a, 'tcx> NiceRegionError<'a, 'tcx> {
err.span_label(
cause.span,
&format!(
- "...is captured and required to live as long as `'static` here \
+ "...is used and required to live as long as `'static` here \
because of an implicit lifetime bound on the {}",
match ctxt.assoc_item.container {
AssocItemContainer::TraitContainer(id) =>
@@ -123,56 +125,101 @@ impl<'a, 'tcx> NiceRegionError<'a, 'tcx> {
param_name,
lifetime,
);
- err.span_label(param.param_ty_span, &format!("this data with {}...", lifetime));
- debug!("try_report_static_impl_trait: param_info={:?}", param);
- // We try to make the output have fewer overlapping spans if possible.
- if (sp == sup_origin.span() || !return_sp.overlaps(sup_origin.span()))
- && sup_origin.span() != return_sp
- {
- // FIXME: account for `async fn` like in `async-await/issues/issue-62097.rs`
-
- // Customize the spans and labels depending on their relative order so
- // that split sentences flow correctly.
- if sup_origin.span().overlaps(return_sp) && sp == sup_origin.span() {
- // Avoid the following:
- //
- // error: cannot infer an appropriate lifetime
- // --> $DIR/must_outlive_least_region_or_bound.rs:18:50
- // |
- // LL | fn foo(x: &i32) -> Box<dyn Debug> { Box::new(x) }
- // | ---- ---------^-
+ let (mention_influencer, influencer_point) =
+ if sup_origin.span().overlaps(param.param_ty_span) {
+ // Account for `async fn` like in `async-await/issues/issue-62097.rs`.
+ // The desugaring of `async `fn`s causes `sup_origin` and `param` to point at the same
+ // place (but with different `ctxt`, hence `overlaps` instead of `==` above).
//
- // and instead show:
+ // This avoids the following:
//
- // error: cannot infer an appropriate lifetime
- // --> $DIR/must_outlive_least_region_or_bound.rs:18:50
- // |
- // LL | fn foo(x: &i32) -> Box<dyn Debug> { Box::new(x) }
- // | ---- ^
- err.span_label(
- sup_origin.span(),
- "...is captured here, requiring it to live as long as `'static`",
- );
+ // LL | pub async fn run_dummy_fn(&self) {
+ // | ^^^^^
+ // | |
+ // | this data with an anonymous lifetime `'_`...
+ // | ...is captured here...
+ (false, sup_origin.span())
} else {
- err.span_label(sup_origin.span(), "...is captured here...");
- if return_sp < sup_origin.span() {
- err.span_note(
- return_sp,
- "...and is required to live as long as `'static` here",
+ (!sup_origin.span().overlaps(return_sp), param.param_ty_span)
+ };
+ err.span_label(influencer_point, &format!("this data with {}...", lifetime));
+
+ debug!("try_report_static_impl_trait: param_info={:?}", param);
+
+ let mut spans = spans.clone();
+
+ if mention_influencer {
+ spans.push(sup_origin.span());
+ }
+ // We dedup the spans *ignoring* expansion context.
+ spans.sort();
+ spans.dedup_by_key(|span| (span.lo(), span.hi()));
+
+ // We try to make the output have fewer overlapping spans if possible.
+ let require_msg = if spans.is_empty() {
+ "...is used and required to live as long as `'static` here"
+ } else {
+ "...and is required to live as long as `'static` here"
+ };
+ let require_span =
+ if sup_origin.span().overlaps(return_sp) { sup_origin.span() } else { return_sp };
+
+ for span in &spans {
+ err.span_label(*span, "...is used here...");
+ }
+
+ if spans.iter().any(|sp| sp.overlaps(return_sp) || *sp > return_sp) {
+ // If any of the "captured here" labels appears on the same line or after
+ // `require_span`, we put it on a note to ensure the text flows by appearing
+ // always at the end.
+ err.span_note(require_span, require_msg);
+ } else {
+ // We don't need a note, it's already at the end, it can be shown as a `span_label`.
+ err.span_label(require_span, require_msg);
+ }
+
+ if let SubregionOrigin::RelateParamBound(_, _, Some(bound)) = sub_origin {
+ err.span_note(*bound, "`'static` lifetime requirement introduced by this bound");
+ }
+ if let SubregionOrigin::Subtype(box TypeTrace { cause, .. }) = sub_origin {
+ if let ObligationCauseCode::ReturnValue(hir_id)
+ | ObligationCauseCode::BlockTailExpression(hir_id) = &cause.code
+ {
+ let parent_id = tcx.hir().get_parent_item(*hir_id);
+ if let Some(fn_decl) = tcx.hir().fn_decl_by_hir_id(parent_id) {
+ let mut span: MultiSpan = fn_decl.output.span().into();
+ let mut add_label = true;
+ if let hir::FnRetTy::Return(ty) = fn_decl.output {
+ let mut v = StaticLifetimeVisitor(vec![], tcx.hir());
+ v.visit_ty(ty);
+ if !v.0.is_empty() {
+ span = v.0.clone().into();
+ for sp in v.0 {
+ span.push_span_label(
+ sp,
+ "`'static` requirement introduced here".to_string(),
+ );
+ }
+ add_label = false;
+ }
+ }
+ if add_label {
+ span.push_span_label(
+ fn_decl.output.span(),
+ "requirement introduced by this return type".to_string(),
+ );
+ }
+ span.push_span_label(
+ cause.span,
+ "because of this returned expression".to_string(),
);
- } else {
- err.span_label(
- return_sp,
- "...and is required to live as long as `'static` here",
+ err.span_note(
+ span,
+ "`'static` lifetime requirement introduced by the return type",
);
}
}
- } else {
- err.span_label(
- return_sp,
- "...is captured and required to live as long as `'static` here",
- );
}
let fn_returns = tcx.return_type_impl_or_dyn_traits(anon_reg_sup.def_id);
diff --git a/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/trait_impl_difference.rs b/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/trait_impl_difference.rs
index cfa79213c80..452ca5eeabd 100644
--- a/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/trait_impl_difference.rs
+++ b/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/trait_impl_difference.rs
@@ -28,6 +28,7 @@ impl<'a, 'tcx> NiceRegionError<'a, 'tcx> {
_sub,
sup_origin,
_sup,
+ _,
) = error.clone()
{
if let (&Subtype(ref sup_trace), &Subtype(ref sub_trace)) = (&sup_origin, &sub_origin) {
diff --git a/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/util.rs b/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/util.rs
index 90bc5b3b2fe..04eceecc5f0 100644
--- a/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/util.rs
+++ b/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/util.rs
@@ -107,7 +107,7 @@ impl<'a, 'tcx> NiceRegionError<'a, 'tcx> {
kind:
hir::ItemKind::OpaqueTy(hir::OpaqueTy {
bounds,
- origin: hir::OpaqueTyOrigin::AsyncFn,
+ origin: hir::OpaqueTyOrigin::AsyncFn(..),
..
}),
..
diff --git a/compiler/rustc_infer/src/infer/free_regions.rs b/compiler/rustc_infer/src/infer/free_regions.rs
index 4814b65e320..e93cdf79421 100644
--- a/compiler/rustc_infer/src/infer/free_regions.rs
+++ b/compiler/rustc_infer/src/infer/free_regions.rs
@@ -11,7 +11,7 @@ use rustc_middle::ty::{self, Lift, Region, TyCtxt};
///
/// This stuff is a bit convoluted and should be refactored, but as we
/// transition to NLL, it'll all go away anyhow.
-pub struct RegionRelations<'a, 'tcx> {
+pub(crate) struct RegionRelations<'a, 'tcx> {
pub tcx: TyCtxt<'tcx>,
/// The context used for debug messages
diff --git a/compiler/rustc_infer/src/infer/lexical_region_resolve/mod.rs b/compiler/rustc_infer/src/infer/lexical_region_resolve/mod.rs
index 4c9dcab26b1..a5ec84a4f14 100644
--- a/compiler/rustc_infer/src/infer/lexical_region_resolve/mod.rs
+++ b/compiler/rustc_infer/src/infer/lexical_region_resolve/mod.rs
@@ -19,6 +19,7 @@ use rustc_middle::ty::{self, Ty, TyCtxt};
use rustc_middle::ty::{ReEarlyBound, ReEmpty, ReErased, ReFree, ReStatic};
use rustc_middle::ty::{ReLateBound, RePlaceholder, ReVar};
use rustc_middle::ty::{Region, RegionVid};
+use rustc_span::Span;
use std::fmt;
/// This function performs lexical region resolution given a complete
@@ -27,7 +28,7 @@ use std::fmt;
/// assuming such values can be found. It returns the final values of
/// all the variables as well as a set of errors that must be reported.
#[instrument(level = "debug", skip(region_rels, var_infos, data))]
-pub fn resolve<'tcx>(
+pub(crate) fn resolve<'tcx>(
region_rels: &RegionRelations<'_, 'tcx>,
var_infos: VarInfos,
data: RegionConstraintData<'tcx>,
@@ -96,6 +97,7 @@ pub enum RegionResolutionError<'tcx> {
Region<'tcx>,
SubregionOrigin<'tcx>,
Region<'tcx>,
+ Vec<Span>, // All the influences on a given value that didn't meet its constraints.
),
/// Indicates a `'b: 'a` constraint where `'a` is in a universe that
@@ -567,7 +569,30 @@ impl<'cx, 'tcx> LexicalResolver<'cx, 'tcx> {
// if this rule starts to create problems we'll
// have to revisit this portion of the code and
// think hard about it. =) -- nikomatsakis
- self.collect_error_for_expanding_node(graph, &mut dup_vec, node_vid, errors);
+
+ // Obtain the spans for all the places that can
+ // influence the constraints on this value for
+ // richer diagnostics in `static_impl_trait`.
+ let influences: Vec<Span> = self
+ .data
+ .constraints
+ .iter()
+ .filter_map(|(constraint, origin)| match (constraint, origin) {
+ (
+ Constraint::VarSubVar(_, sup),
+ SubregionOrigin::DataBorrowed(_, sp),
+ ) if sup == &node_vid => Some(*sp),
+ _ => None,
+ })
+ .collect();
+
+ self.collect_error_for_expanding_node(
+ graph,
+ &mut dup_vec,
+ node_vid,
+ errors,
+ influences,
+ );
}
}
}
@@ -621,6 +646,7 @@ impl<'cx, 'tcx> LexicalResolver<'cx, 'tcx> {
dup_vec: &mut IndexVec<RegionVid, Option<RegionVid>>,
node_idx: RegionVid,
errors: &mut Vec<RegionResolutionError<'tcx>>,
+ influences: Vec<Span>,
) {
// Errors in expanding nodes result from a lower-bound that is
// not contained by an upper-bound.
@@ -667,6 +693,7 @@ impl<'cx, 'tcx> LexicalResolver<'cx, 'tcx> {
sup: {:?}",
origin, node_idx, lower_bound.region, upper_bound.region
);
+
errors.push(RegionResolutionError::SubSupConflict(
node_idx,
origin,
@@ -674,6 +701,7 @@ impl<'cx, 'tcx> LexicalResolver<'cx, 'tcx> {
lower_bound.region,
upper_bound.origin.clone(),
upper_bound.region,
+ influences,
));
return;
}
diff --git a/compiler/rustc_infer/src/infer/mod.rs b/compiler/rustc_infer/src/infer/mod.rs
index b874947cc69..48dfa0b6342 100644
--- a/compiler/rustc_infer/src/infer/mod.rs
+++ b/compiler/rustc_infer/src/infer/mod.rs
@@ -21,6 +21,7 @@ use rustc_hir::def_id::{DefId, LocalDefId};
use rustc_middle::infer::canonical::{Canonical, CanonicalVarValues};
use rustc_middle::infer::unify_key::{ConstVarValue, ConstVariableValue};
use rustc_middle::infer::unify_key::{ConstVariableOrigin, ConstVariableOriginKind, ToType};
+use rustc_middle::mir::interpret::ErrorHandled;
use rustc_middle::mir::interpret::EvalToConstValueResult;
use rustc_middle::traits::select;
use rustc_middle::ty::error::{ExpectedFound, TypeError};
@@ -95,9 +96,10 @@ pub(crate) type UnificationTable<'a, 'tcx, T> = ut::UnificationTable<
/// This is used so that the region values inferred by HIR region solving are
/// not exposed, and so that we can avoid doing work in HIR typeck that MIR
/// typeck will also do.
-#[derive(Copy, Clone, Debug)]
+#[derive(Copy, Clone, Debug, Default)]
pub enum RegionckMode {
/// The default mode: report region errors, don't erase regions.
+ #[default]
Solve,
/// Erase the results of region after solving.
Erase {
@@ -108,12 +110,6 @@ pub enum RegionckMode {
},
}
-impl Default for RegionckMode {
- fn default() -> Self {
- RegionckMode::Solve
- }
-}
-
impl RegionckMode {
/// Indicates that the MIR borrowck will repeat these region
/// checks, so we should ignore errors if NLL is (unconditionally)
@@ -1589,13 +1585,27 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
unevaluated: ty::Unevaluated<'tcx>,
span: Option<Span>,
) -> EvalToConstValueResult<'tcx> {
- let mut original_values = OriginalQueryValues::default();
- let canonical = self.canonicalize_query((param_env, unevaluated), &mut original_values);
+ let mut substs = unevaluated.substs(self.tcx);
+ substs = self.resolve_vars_if_possible(substs);
+
+ // Postpone the evaluation of constants whose substs depend on inference
+ // variables
+ if substs.has_infer_types_or_consts() {
+ return Err(ErrorHandled::TooGeneric);
+ }
+
+ let param_env_erased = self.tcx.erase_regions(param_env);
+ let substs_erased = self.tcx.erase_regions(substs);
+
+ let unevaluated = ty::Unevaluated {
+ def: unevaluated.def,
+ substs_: Some(substs_erased),
+ promoted: unevaluated.promoted,
+ };
- let (param_env, unevaluated) = canonical.value;
// The return value is the evaluated value which doesn't contain any reference to inference
// variables, thus we don't need to substitute back the original values.
- self.tcx.const_eval_resolve(param_env, unevaluated, span)
+ self.tcx.const_eval_resolve(param_env_erased, unevaluated, span)
}
/// If `typ` is a type variable of some kind, resolve it one level
diff --git a/compiler/rustc_infer/src/infer/opaque_types.rs b/compiler/rustc_infer/src/infer/opaque_types.rs
index e2e07f2072e..c2ef0b41e27 100644
--- a/compiler/rustc_infer/src/infer/opaque_types.rs
+++ b/compiler/rustc_infer/src/infer/opaque_types.rs
@@ -276,7 +276,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
debug!(?concrete_ty);
let first_own_region = match opaque_defn.origin {
- hir::OpaqueTyOrigin::FnReturn | hir::OpaqueTyOrigin::AsyncFn => {
+ hir::OpaqueTyOrigin::FnReturn(..) | hir::OpaqueTyOrigin::AsyncFn(..) => {
// We lower
//
// fn foo<'l0..'ln>() -> impl Trait<'l0..'lm>
@@ -461,33 +461,29 @@ impl<'a, 'tcx> Instantiator<'a, 'tcx> {
if let Some(def_id) = def_id.as_local() {
let opaque_hir_id = tcx.hir().local_def_id_to_hir_id(def_id);
let parent_def_id = self.infcx.defining_use_anchor;
- let def_scope_default = || {
- let opaque_parent_hir_id = tcx.hir().get_parent_item(opaque_hir_id);
- parent_def_id == tcx.hir().local_def_id(opaque_parent_hir_id)
+ let item_kind = &tcx.hir().expect_item(def_id).kind;
+ let hir::ItemKind::OpaqueTy(hir::OpaqueTy { origin, .. }) = item_kind else {
+ span_bug!(
+ self.value_span,
+ "weird opaque type: {:#?}, {:#?}",
+ ty.kind(),
+ item_kind
+ )
+ };
+ let in_definition_scope = match *origin {
+ // Async `impl Trait`
+ hir::OpaqueTyOrigin::AsyncFn(parent) => parent == parent_def_id,
+ // Anonymous `impl Trait`
+ hir::OpaqueTyOrigin::FnReturn(parent) => parent == parent_def_id,
+ // Named `type Foo = impl Bar;`
+ hir::OpaqueTyOrigin::TyAlias => {
+ may_define_opaque_type(tcx, parent_def_id, opaque_hir_id)
+ }
};
- let (in_definition_scope, origin) =
- match tcx.hir().expect_item(opaque_hir_id).kind {
- // Anonymous `impl Trait`
- hir::ItemKind::OpaqueTy(hir::OpaqueTy {
- impl_trait_fn: Some(parent),
- origin,
- ..
- }) => (parent == parent_def_id.to_def_id(), origin),
- // Named `type Foo = impl Bar;`
- hir::ItemKind::OpaqueTy(hir::OpaqueTy {
- impl_trait_fn: None,
- origin,
- ..
- }) => (
- may_define_opaque_type(tcx, parent_def_id, opaque_hir_id),
- origin,
- ),
- _ => (def_scope_default(), hir::OpaqueTyOrigin::TyAlias),
- };
if in_definition_scope {
let opaque_type_key =
OpaqueTypeKey { def_id: def_id.to_def_id(), substs };
- return self.fold_opaque_ty(ty, opaque_type_key, origin);
+ return self.fold_opaque_ty(ty, opaque_type_key, *origin);
}
debug!(
diff --git a/compiler/rustc_infer/src/infer/resolve.rs b/compiler/rustc_infer/src/infer/resolve.rs
index 4b08c2eb9c1..f036e1214aa 100644
--- a/compiler/rustc_infer/src/infer/resolve.rs
+++ b/compiler/rustc_infer/src/infer/resolve.rs
@@ -1,7 +1,7 @@
use super::type_variable::{TypeVariableOrigin, TypeVariableOriginKind};
use super::{FixupError, FixupResult, InferCtxt, Span};
use rustc_middle::mir;
-use rustc_middle::ty::fold::{TypeFolder, TypeVisitor};
+use rustc_middle::ty::fold::{FallibleTypeFolder, TypeFolder, TypeVisitor};
use rustc_middle::ty::{self, Const, InferConst, Ty, TyCtxt, TypeFoldable};
use std::ops::ControlFlow;
@@ -175,81 +175,72 @@ pub fn fully_resolve<'a, 'tcx, T>(infcx: &InferCtxt<'a, 'tcx>, value: T) -> Fixu
where
T: TypeFoldable<'tcx>,
{
- let mut full_resolver = FullTypeResolver { infcx, err: None };
- let result = value.fold_with(&mut full_resolver);
- match full_resolver.err {
- None => Ok(result),
- Some(e) => Err(e),
- }
+ value.try_fold_with(&mut FullTypeResolver { infcx })
}
// N.B. This type is not public because the protocol around checking the
// `err` field is not enforceable otherwise.
struct FullTypeResolver<'a, 'tcx> {
infcx: &'a InferCtxt<'a, 'tcx>,
- err: Option<FixupError<'tcx>>,
}
impl<'a, 'tcx> TypeFolder<'tcx> for FullTypeResolver<'a, 'tcx> {
+ type Error = FixupError<'tcx>;
+
fn tcx<'b>(&'b self) -> TyCtxt<'tcx> {
self.infcx.tcx
}
+}
- fn fold_ty(&mut self, t: Ty<'tcx>) -> Ty<'tcx> {
+impl<'a, 'tcx> FallibleTypeFolder<'tcx> for FullTypeResolver<'a, 'tcx> {
+ fn try_fold_ty(&mut self, t: Ty<'tcx>) -> Result<Ty<'tcx>, Self::Error> {
if !t.needs_infer() {
- t // micro-optimize -- if there is nothing in this type that this fold affects...
+ Ok(t) // micro-optimize -- if there is nothing in this type that this fold affects...
} else {
let t = self.infcx.shallow_resolve(t);
match *t.kind() {
- ty::Infer(ty::TyVar(vid)) => {
- self.err = Some(FixupError::UnresolvedTy(vid));
- self.tcx().ty_error()
- }
- ty::Infer(ty::IntVar(vid)) => {
- self.err = Some(FixupError::UnresolvedIntTy(vid));
- self.tcx().ty_error()
- }
- ty::Infer(ty::FloatVar(vid)) => {
- self.err = Some(FixupError::UnresolvedFloatTy(vid));
- self.tcx().ty_error()
- }
+ ty::Infer(ty::TyVar(vid)) => Err(FixupError::UnresolvedTy(vid)),
+ ty::Infer(ty::IntVar(vid)) => Err(FixupError::UnresolvedIntTy(vid)),
+ ty::Infer(ty::FloatVar(vid)) => Err(FixupError::UnresolvedFloatTy(vid)),
ty::Infer(_) => {
bug!("Unexpected type in full type resolver: {:?}", t);
}
- _ => t.super_fold_with(self),
+ _ => t.try_super_fold_with(self),
}
}
}
- fn fold_region(&mut self, r: ty::Region<'tcx>) -> ty::Region<'tcx> {
+ fn try_fold_region(&mut self, r: ty::Region<'tcx>) -> Result<ty::Region<'tcx>, Self::Error> {
match *r {
- ty::ReVar(rid) => self
+ ty::ReVar(rid) => Ok(self
.infcx
.lexical_region_resolutions
.borrow()
.as_ref()
.expect("region resolution not performed")
- .resolve_var(rid),
- _ => r,
+ .resolve_var(rid)),
+ _ => Ok(r),
}
}
- fn fold_const(&mut self, c: &'tcx ty::Const<'tcx>) -> &'tcx ty::Const<'tcx> {
+ fn try_fold_const(
+ &mut self,
+ c: &'tcx ty::Const<'tcx>,
+ ) -> Result<&'tcx ty::Const<'tcx>, Self::Error> {
if !c.needs_infer() {
- c // micro-optimize -- if there is nothing in this const that this fold affects...
+ Ok(c) // micro-optimize -- if there is nothing in this const that this fold affects...
} else {
let c = self.infcx.shallow_resolve(c);
match c.val {
ty::ConstKind::Infer(InferConst::Var(vid)) => {
- self.err = Some(FixupError::UnresolvedConst(vid));
- return self.tcx().const_error(c.ty);
+ return Err(FixupError::UnresolvedConst(vid));
}
ty::ConstKind::Infer(InferConst::Fresh(_)) => {
bug!("Unexpected const in full const resolver: {:?}", c);
}
_ => {}
}
- c.super_fold_with(self)
+ c.try_super_fold_with(self)
}
}
}
diff --git a/compiler/rustc_infer/src/lib.rs b/compiler/rustc_infer/src/lib.rs
index d0f1ff649d0..ba77e363761 100644
--- a/compiler/rustc_infer/src/lib.rs
+++ b/compiler/rustc_infer/src/lib.rs
@@ -15,8 +15,8 @@
#![doc(html_root_url = "https://doc.rust-lang.org/nightly/nightly-rustc/")]
#![feature(bool_to_option)]
#![feature(box_patterns)]
+#![feature(derive_default_enum)]
#![feature(extend_one)]
-#![feature(iter_zip)]
#![feature(let_else)]
#![feature(never_type)]
#![feature(in_band_lifetimes)]
diff --git a/compiler/rustc_infer/src/traits/engine.rs b/compiler/rustc_infer/src/traits/engine.rs
index 152a395c871..822f2365e02 100644
--- a/compiler/rustc_infer/src/traits/engine.rs
+++ b/compiler/rustc_infer/src/traits/engine.rs
@@ -1,9 +1,8 @@
use crate::infer::InferCtxt;
use crate::traits::Obligation;
use rustc_data_structures::fx::FxHashMap;
-use rustc_hir as hir;
use rustc_hir::def_id::DefId;
-use rustc_middle::ty::{self, ToPredicate, Ty, WithConstness};
+use rustc_middle::ty::{self, ToPredicate, Ty};
use super::FulfillmentError;
use super::{ObligationCause, PredicateObligation};
@@ -48,26 +47,9 @@ pub trait TraitEngine<'tcx>: 'tcx {
fn select_all_or_error(&mut self, infcx: &InferCtxt<'_, 'tcx>) -> Vec<FulfillmentError<'tcx>>;
- fn select_all_with_constness_or_error(
- &mut self,
- infcx: &InferCtxt<'_, 'tcx>,
- _constness: hir::Constness,
- ) -> Vec<FulfillmentError<'tcx>> {
- self.select_all_or_error(infcx)
- }
-
fn select_where_possible(&mut self, infcx: &InferCtxt<'_, 'tcx>)
-> Vec<FulfillmentError<'tcx>>;
- // FIXME(fee1-dead) this should not provide a default body for chalk as chalk should be updated
- fn select_with_constness_where_possible(
- &mut self,
- infcx: &InferCtxt<'_, 'tcx>,
- _constness: hir::Constness,
- ) -> Vec<FulfillmentError<'tcx>> {
- self.select_where_possible(infcx)
- }
-
fn pending_obligations(&self) -> Vec<PredicateObligation<'tcx>>;
fn relationships(&mut self) -> &mut FxHashMap<ty::TyVid, ty::FoundRelationships>;
diff --git a/compiler/rustc_infer/src/traits/mod.rs b/compiler/rustc_infer/src/traits/mod.rs
index e8622b3c819..7e30f859dae 100644
--- a/compiler/rustc_infer/src/traits/mod.rs
+++ b/compiler/rustc_infer/src/traits/mod.rs
@@ -69,6 +69,16 @@ impl PredicateObligation<'tcx> {
}
}
+impl TraitObligation<'tcx> {
+ /// Returns `true` if the trait predicate is considered `const` in its ParamEnv.
+ pub fn is_const(&self) -> bool {
+ match (self.predicate.skip_binder().constness, self.param_env.constness()) {
+ (ty::BoundConstness::ConstIfConst, hir::Constness::Const) => true,
+ _ => false,
+ }
+ }
+}
+
// `PredicateObligation` is used a lot. Make sure it doesn't unintentionally get bigger.
#[cfg(all(target_arch = "x86_64", target_pointer_width = "64"))]
static_assert_size!(PredicateObligation<'_>, 32);
diff --git a/compiler/rustc_infer/src/traits/project.rs b/compiler/rustc_infer/src/traits/project.rs
index e2c13d20a9a..9fc0b978c73 100644
--- a/compiler/rustc_infer/src/traits/project.rs
+++ b/compiler/rustc_infer/src/traits/project.rs
@@ -10,7 +10,7 @@ use rustc_data_structures::{
};
use rustc_middle::ty::{self, Ty};
-pub use rustc_middle::traits::Reveal;
+pub use rustc_middle::traits::{EvaluationResult, Reveal};
pub(crate) type UndoLog<'tcx> =
snapshot_map::UndoLog<ProjectionCacheKey<'tcx>, ProjectionCacheEntry<'tcx>>;
@@ -92,7 +92,42 @@ pub enum ProjectionCacheEntry<'tcx> {
Ambiguous,
Recur,
Error,
- NormalizedTy(NormalizedTy<'tcx>),
+ NormalizedTy {
+ ty: NormalizedTy<'tcx>,
+ /// If we were able to successfully evaluate the
+ /// corresponding cache entry key during predicate
+ /// evaluation, then this field stores the final
+ /// result obtained from evaluating all of the projection
+ /// sub-obligations. During evaluation, we will skip
+ /// evaluating the cached sub-obligations in `ty`
+ /// if this field is set. Evaluation only
+ /// cares about the final result, so we don't
+ /// care about any region constraint side-effects
+ /// produced by evaluating the sub-boligations.
+ ///
+ /// Additionally, we will clear out the sub-obligations
+ /// entirely if we ever evaluate the cache entry (along
+ /// with all its sub obligations) to `EvaluatedToOk`.
+ /// This affects all users of the cache, not just evaluation.
+ /// Since a result of `EvaluatedToOk` means that there were
+ /// no region obligations that need to be tracked, it's
+ /// fine to forget about the sub-obligations - they
+ /// don't provide any additional information. However,
+ /// we do *not* discard any obligations when we see
+ /// `EvaluatedToOkModuloRegions` - we don't know
+ /// which sub-obligations may introduce region constraints,
+ /// so we keep them all to be safe.
+ ///
+ /// When we are not performing evaluation
+ /// (e.g. in `FulfillmentContext`), we ignore this field,
+ /// and always re-process the cached sub-obligations
+ /// (which may have been cleared out - see the above
+ /// paragraph).
+ /// This ensures that we do not lose any regions
+ /// constraints that arise from processing the
+ /// sub-obligations.
+ complete: Option<EvaluationResult>,
+ },
}
impl<'tcx> ProjectionCacheStorage<'tcx> {
@@ -149,10 +184,41 @@ impl<'tcx> ProjectionCache<'_, 'tcx> {
debug!("Not overwriting Recur");
return;
}
- let fresh_key = map.insert(key, ProjectionCacheEntry::NormalizedTy(value));
+ let fresh_key =
+ map.insert(key, ProjectionCacheEntry::NormalizedTy { ty: value, complete: None });
assert!(!fresh_key, "never started projecting `{:?}`", key);
}
+ /// Mark the relevant projection cache key as having its derived obligations
+ /// complete, so they won't have to be re-computed (this is OK to do in a
+ /// snapshot - if the snapshot is rolled back, the obligations will be
+ /// marked as incomplete again).
+ pub fn complete(&mut self, key: ProjectionCacheKey<'tcx>, result: EvaluationResult) {
+ let mut map = self.map();
+ match map.get(&key) {
+ Some(&ProjectionCacheEntry::NormalizedTy { ref ty, complete: _ }) => {
+ info!("ProjectionCacheEntry::complete({:?}) - completing {:?}", key, ty);
+ let mut ty = ty.clone();
+ if result == EvaluationResult::EvaluatedToOk {
+ ty.obligations = vec![];
+ }
+ map.insert(key, ProjectionCacheEntry::NormalizedTy { ty, complete: Some(result) });
+ }
+ ref value => {
+ // Type inference could "strand behind" old cache entries. Leave
+ // them alone for now.
+ info!("ProjectionCacheEntry::complete({:?}) - ignoring {:?}", key, value);
+ }
+ };
+ }
+
+ pub fn is_complete(&mut self, key: ProjectionCacheKey<'tcx>) -> Option<EvaluationResult> {
+ self.map().get(&key).and_then(|res| match res {
+ ProjectionCacheEntry::NormalizedTy { ty: _, complete } => *complete,
+ _ => None,
+ })
+ }
+
/// Indicates that trying to normalize `key` resulted in
/// ambiguity. No point in trying it again then until we gain more
/// type information (in which case, the "fully resolved" key will
diff --git a/compiler/rustc_infer/src/traits/structural_impls.rs b/compiler/rustc_infer/src/traits/structural_impls.rs
index c4a2ecee096..20453eeb147 100644
--- a/compiler/rustc_infer/src/traits/structural_impls.rs
+++ b/compiler/rustc_infer/src/traits/structural_impls.rs
@@ -1,7 +1,7 @@
use crate::traits;
use crate::traits::project::Normalized;
use rustc_middle::ty;
-use rustc_middle::ty::fold::{TypeFoldable, TypeFolder, TypeVisitor};
+use rustc_middle::ty::fold::{FallibleTypeFolder, TypeFoldable, TypeVisitor};
use std::fmt;
use std::ops::ControlFlow;
@@ -60,16 +60,20 @@ impl<'tcx> fmt::Debug for traits::MismatchedProjectionTypes<'tcx> {
// TypeFoldable implementations.
impl<'tcx, O: TypeFoldable<'tcx>> TypeFoldable<'tcx> for traits::Obligation<'tcx, O> {
- fn super_fold_with<F: TypeFolder<'tcx>>(self, folder: &mut F) -> Self {
- traits::Obligation {
+ fn try_super_fold_with<F: FallibleTypeFolder<'tcx>>(
+ self,
+ folder: &mut F,
+ ) -> Result<Self, F::Error> {
+ Ok(traits::Obligation {
cause: self.cause,
recursion_depth: self.recursion_depth,
- predicate: self.predicate.fold_with(folder),
- param_env: self.param_env.fold_with(folder),
- }
+ predicate: self.predicate.try_fold_with(folder)?,
+ param_env: self.param_env.try_fold_with(folder)?,
+ })
}
fn super_visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> ControlFlow<V::BreakTy> {
- self.predicate.visit_with(visitor)
+ self.predicate.visit_with(visitor)?;
+ self.param_env.visit_with(visitor)
}
}
diff --git a/compiler/rustc_infer/src/traits/util.rs b/compiler/rustc_infer/src/traits/util.rs
index 92f74af4eb3..61588147364 100644
--- a/compiler/rustc_infer/src/traits/util.rs
+++ b/compiler/rustc_infer/src/traits/util.rs
@@ -3,7 +3,7 @@ use smallvec::smallvec;
use crate::infer::outlives::components::{push_outlives_components, Component};
use crate::traits::{Obligation, ObligationCause, PredicateObligation};
use rustc_data_structures::fx::{FxHashSet, FxIndexSet};
-use rustc_middle::ty::{self, ToPredicate, TyCtxt, WithConstness};
+use rustc_middle::ty::{self, ToPredicate, TyCtxt};
use rustc_span::symbol::Ident;
use rustc_span::Span;
@@ -328,8 +328,8 @@ pub fn transitive_bounds_that_define_assoc_type<'tcx>(
));
for (super_predicate, _) in super_predicates.predicates {
let subst_predicate = super_predicate.subst_supertrait(tcx, &trait_ref);
- if let Some(binder) = subst_predicate.to_opt_poly_trait_ref() {
- stack.push(binder.value);
+ if let Some(binder) = subst_predicate.to_opt_poly_trait_pred() {
+ stack.push(binder.map_bound(|t| t.trait_ref));
}
}
@@ -362,8 +362,8 @@ impl<'tcx, I: Iterator<Item = PredicateObligation<'tcx>>> Iterator for FilterToT
fn next(&mut self) -> Option<ty::PolyTraitRef<'tcx>> {
while let Some(obligation) = self.base_iterator.next() {
- if let Some(data) = obligation.predicate.to_opt_poly_trait_ref() {
- return Some(data.value);
+ if let Some(data) = obligation.predicate.to_opt_poly_trait_pred() {
+ return Some(data.map_bound(|t| t.trait_ref));
}
}
None
diff --git a/compiler/rustc_interface/Cargo.toml b/compiler/rustc_interface/Cargo.toml
index 07af2201f5f..f5823e521b9 100644
--- a/compiler/rustc_interface/Cargo.toml
+++ b/compiler/rustc_interface/Cargo.toml
@@ -8,6 +8,7 @@ doctest = false
[dependencies]
libc = "0.2"
+libloading = "0.7.1"
tracing = "0.1"
rustc-rayon-core = "0.3.1"
rayon = { version = "0.3.1", package = "rustc-rayon" }
diff --git a/compiler/rustc_interface/src/passes.rs b/compiler/rustc_interface/src/passes.rs
index b073ee9682f..34865900495 100644
--- a/compiler/rustc_interface/src/passes.rs
+++ b/compiler/rustc_interface/src/passes.rs
@@ -10,7 +10,7 @@ use rustc_codegen_ssa::traits::CodegenBackend;
use rustc_data_structures::parallel;
use rustc_data_structures::sync::{Lrc, OnceCell, WorkerLocal};
use rustc_data_structures::temp_dir::MaybeTempDir;
-use rustc_errors::{ErrorReported, PResult};
+use rustc_errors::{Applicability, ErrorReported, PResult};
use rustc_expand::base::ExtCtxt;
use rustc_hir::def_id::{StableCrateId, LOCAL_CRATE};
use rustc_hir::Crate;
@@ -35,7 +35,7 @@ use rustc_session::output::{filename_for_input, filename_for_metadata};
use rustc_session::search_paths::PathKind;
use rustc_session::{Limit, Session};
use rustc_span::symbol::{sym, Ident, Symbol};
-use rustc_span::FileName;
+use rustc_span::{FileName, MultiSpan};
use rustc_trait_selection::traits;
use rustc_typeck as typeck;
use tempfile::Builder as TempFileBuilder;
@@ -323,7 +323,7 @@ pub fn configure_and_expand(
let crate_attrs = krate.attrs.clone();
let extern_mod_loaded = |ident: Ident, attrs, items, span| {
- let krate = ast::Crate { attrs, items, span };
+ let krate = ast::Crate { attrs, items, span, is_placeholder: None };
pre_expansion_lint(sess, lint_store, &krate, &crate_attrs, &ident.name.as_str());
(krate.attrs, krate.items)
};
@@ -450,6 +450,35 @@ pub fn configure_and_expand(
});
}
+ // Gate identifiers containing invalid Unicode codepoints that were recovered during lexing.
+ sess.parse_sess.bad_unicode_identifiers.with_lock(|identifiers| {
+ let mut identifiers: Vec<_> = identifiers.drain().collect();
+ identifiers.sort_by_key(|&(key, _)| key);
+ for (ident, mut spans) in identifiers.into_iter() {
+ spans.sort();
+ if ident == sym::ferris {
+ let first_span = spans[0];
+ sess.diagnostic()
+ .struct_span_err(
+ MultiSpan::from(spans),
+ "Ferris cannot be used as an identifier",
+ )
+ .span_suggestion(
+ first_span,
+ "try using their name instead",
+ "ferris".to_string(),
+ Applicability::MaybeIncorrect,
+ )
+ .emit();
+ } else {
+ sess.diagnostic().span_err(
+ MultiSpan::from(spans),
+ &format!("identifiers cannot contain emoji: `{}`", ident),
+ );
+ }
+ }
+ });
+
Ok(krate)
}
@@ -555,7 +584,7 @@ fn output_conflicts_with_dir(output_paths: &[PathBuf]) -> Option<PathBuf> {
fn escape_dep_filename(filename: &str) -> String {
// Apparently clang and gcc *only* escape spaces:
// https://llvm.org/klaus/clang/commit/9d50634cfc268ecc9a7250226dd5ca0e945240d4
- filename.replace(" ", "\\ ")
+ filename.replace(' ', "\\ ")
}
// Makefile comments only need escaping newlines and `\`.
diff --git a/compiler/rustc_interface/src/queries.rs b/compiler/rustc_interface/src/queries.rs
index f188ad35605..e635ee1e0ec 100644
--- a/compiler/rustc_interface/src/queries.rs
+++ b/compiler/rustc_interface/src/queries.rs
@@ -335,8 +335,11 @@ pub struct Linker {
impl Linker {
pub fn link(self) -> Result<()> {
- let (codegen_results, work_products) =
- self.codegen_backend.join_codegen(self.ongoing_codegen, &self.sess)?;
+ let (codegen_results, work_products) = self.codegen_backend.join_codegen(
+ self.ongoing_codegen,
+ &self.sess,
+ &self.prepare_outputs,
+ )?;
self.sess.compile_status()?;
diff --git a/compiler/rustc_interface/src/tests.rs b/compiler/rustc_interface/src/tests.rs
index ab12c936710..c651feaaa66 100644
--- a/compiler/rustc_interface/src/tests.rs
+++ b/compiler/rustc_interface/src/tests.rs
@@ -20,7 +20,9 @@ use rustc_span::edition::{Edition, DEFAULT_EDITION};
use rustc_span::symbol::sym;
use rustc_span::SourceFileHashAlgorithm;
use rustc_target::spec::{CodeModel, LinkerFlavor, MergeFunctions, PanicStrategy};
-use rustc_target::spec::{RelocModel, RelroLevel, SanitizerSet, SplitDebuginfo, TlsModel};
+use rustc_target::spec::{
+ RelocModel, RelroLevel, SanitizerSet, SplitDebuginfo, StackProtector, TlsModel,
+};
use std::collections::{BTreeMap, BTreeSet};
use std::iter::FromIterator;
@@ -649,7 +651,6 @@ fn test_debugging_options_tracking_hash() {
untracked!(dump_mir_dir, String::from("abc"));
untracked!(dump_mir_exclude_pass_number, true);
untracked!(dump_mir_graphviz, true);
- untracked!(emit_future_incompat_report, true);
untracked!(emit_stack_sizes, true);
untracked!(future_incompat_test, true);
untracked!(hir_stats, true);
@@ -713,8 +714,8 @@ fn test_debugging_options_tracking_hash() {
// This list is in alphabetical order.
tracked!(allow_features, Some(vec![String::from("lang_items")]));
tracked!(always_encode_mir, true);
- tracked!(assume_incomplete_release, true);
tracked!(asm_comments, true);
+ tracked!(assume_incomplete_release, true);
tracked!(binary_dep_depinfo, true);
tracked!(chalk, true);
tracked!(codegen_backend, Some("abc".to_string()));
@@ -724,15 +725,14 @@ fn test_debugging_options_tracking_hash() {
tracked!(dep_info_omit_d_target, true);
tracked!(dual_proc_macros, true);
tracked!(fewer_names, Some(true));
- tracked!(force_overflow_checks, Some(true));
tracked!(force_unstable_if_unmarked, true);
tracked!(fuel, Some(("abc".to_string(), 99)));
tracked!(function_sections, Some(false));
tracked!(human_readable_cgu_names, true);
tracked!(inline_in_all_cgus, Some(true));
tracked!(inline_mir, Some(true));
- tracked!(inline_mir_threshold, Some(123));
tracked!(inline_mir_hint_threshold, Some(123));
+ tracked!(inline_mir_threshold, Some(123));
tracked!(instrument_coverage, Some(InstrumentCoverage::All));
tracked!(instrument_mcount, true);
tracked!(link_only, true);
@@ -764,7 +764,6 @@ fn test_debugging_options_tracking_hash() {
tracked!(relax_elf_relocations, Some(true));
tracked!(relro_level, Some(RelroLevel::Full));
tracked!(remap_cwd_prefix, Some(PathBuf::from("abc")));
- tracked!(simulate_remapped_rust_src_base, Some(PathBuf::from("/rustc/abc")));
tracked!(report_delayed_bugs, true);
tracked!(sanitizer, SanitizerSet::ADDRESS);
tracked!(sanitizer_memory_track_origins, 2);
@@ -772,15 +771,17 @@ fn test_debugging_options_tracking_hash() {
tracked!(saturating_float_casts, Some(true));
tracked!(share_generics, Some(true));
tracked!(show_span, Some(String::from("abc")));
+ tracked!(simulate_remapped_rust_src_base, Some(PathBuf::from("/rustc/abc")));
tracked!(src_hash_algorithm, Some(SourceFileHashAlgorithm::Sha1));
+ tracked!(stack_protector, StackProtector::All);
tracked!(symbol_mangling_version, Some(SymbolManglingVersion::V0));
tracked!(teach, true);
tracked!(thinlto, Some(true));
tracked!(thir_unsafeck, true);
- tracked!(tune_cpu, Some(String::from("abc")));
tracked!(tls_model, Some(TlsModel::GeneralDynamic));
tracked!(trap_unreachable, Some(false));
tracked!(treat_err_as_bug, NonZeroUsize::new(1));
+ tracked!(tune_cpu, Some(String::from("abc")));
tracked!(unleash_the_miri_inside_of_you, true);
tracked!(use_ctors_section, Some(true));
tracked!(verify_llvm_ir, true);
diff --git a/compiler/rustc_interface/src/util.rs b/compiler/rustc_interface/src/util.rs
index 04e183a9ba5..b04f91634cc 100644
--- a/compiler/rustc_interface/src/util.rs
+++ b/compiler/rustc_interface/src/util.rs
@@ -1,3 +1,4 @@
+use libloading::Library;
use rustc_ast::mut_visit::{visit_clobber, MutVisitor, *};
use rustc_ast::ptr::P;
use rustc_ast::{self as ast, AttrVec, BlockCheckMode};
@@ -7,7 +8,6 @@ use rustc_data_structures::fx::{FxHashMap, FxHashSet};
use rustc_data_structures::jobserver;
use rustc_data_structures::sync::Lrc;
use rustc_errors::registry::Registry;
-use rustc_metadata::dynamic_lib::DynamicLibrary;
#[cfg(parallel_compiler)]
use rustc_middle::ty::tls;
use rustc_parse::validate_attr;
@@ -39,6 +39,9 @@ use std::sync::{Arc, Mutex};
use std::thread;
use tracing::info;
+/// Function pointer type that constructs a new CodegenBackend.
+pub type MakeBackendFn = fn() -> Box<dyn CodegenBackend>;
+
/// Adds `target_feature = "..."` cfgs for a variety of platform
/// specific features (SSE, NEON etc.).
///
@@ -211,28 +214,24 @@ pub fn setup_callbacks_and_run_in_thread_pool_with_globals<F: FnOnce() -> R + Se
})
}
-fn load_backend_from_dylib(path: &Path) -> fn() -> Box<dyn CodegenBackend> {
- let lib = DynamicLibrary::open(path).unwrap_or_else(|err| {
- let err = format!("couldn't load codegen backend {:?}: {:?}", path, err);
+fn load_backend_from_dylib(path: &Path) -> MakeBackendFn {
+ let lib = unsafe { Library::new(path) }.unwrap_or_else(|err| {
+ let err = format!("couldn't load codegen backend {:?}: {}", path, err);
early_error(ErrorOutputType::default(), &err);
});
- unsafe {
- match lib.symbol("__rustc_codegen_backend") {
- Ok(f) => {
- mem::forget(lib);
- mem::transmute::<*mut u8, _>(f)
- }
- Err(e) => {
- let err = format!(
- "couldn't load codegen backend as it \
- doesn't export the `__rustc_codegen_backend` \
- symbol: {:?}",
- e
- );
- early_error(ErrorOutputType::default(), &err);
- }
- }
- }
+
+ let backend_sym = unsafe { lib.get::<MakeBackendFn>(b"__rustc_codegen_backend") }
+ .unwrap_or_else(|e| {
+ let err = format!("couldn't load codegen backend: {}", e);
+ early_error(ErrorOutputType::default(), &err);
+ });
+
+ // Intentionally leak the dynamic library. We can't ever unload it
+ // since the library can make things that will live arbitrarily long.
+ let backend_sym = unsafe { backend_sym.into_raw() };
+ mem::forget(lib);
+
+ *backend_sym
}
/// Get the codegen backend based on the name and specified sysroot.
@@ -380,10 +379,7 @@ fn sysroot_candidates() -> Vec<PathBuf> {
}
}
-pub fn get_codegen_sysroot(
- maybe_sysroot: &Option<PathBuf>,
- backend_name: &str,
-) -> fn() -> Box<dyn CodegenBackend> {
+pub fn get_codegen_sysroot(maybe_sysroot: &Option<PathBuf>, backend_name: &str) -> MakeBackendFn {
// For now we only allow this function to be called once as it'll dlopen a
// few things, which seems to work best if we only do that once. In
// general this assertion never trips due to the once guard in `get_codegen_backend`,
diff --git a/compiler/rustc_lexer/Cargo.toml b/compiler/rustc_lexer/Cargo.toml
index 60c146f457b..35af110537d 100644
--- a/compiler/rustc_lexer/Cargo.toml
+++ b/compiler/rustc_lexer/Cargo.toml
@@ -17,6 +17,7 @@ doctest = false
# Note that this crate purposefully does not depend on other rustc crates
[dependencies]
unicode-xid = "0.2.0"
+unic-emoji-char = "0.9.0"
[dev-dependencies]
expect-test = "1.0"
diff --git a/compiler/rustc_lexer/src/cursor.rs b/compiler/rustc_lexer/src/cursor.rs
index 297f3d19ca1..0ba6c56dbb5 100644
--- a/compiler/rustc_lexer/src/cursor.rs
+++ b/compiler/rustc_lexer/src/cursor.rs
@@ -2,10 +2,11 @@ use std::str::Chars;
/// Peekable iterator over a char sequence.
///
-/// Next characters can be peeked via `nth_char` method,
+/// Next characters can be peeked via `first` method,
/// and position can be shifted forward via `bump` method.
pub(crate) struct Cursor<'a> {
initial_len: usize,
+ /// Iterator over chars. Slightly faster than a &str.
chars: Chars<'a>,
#[cfg(debug_assertions)]
prev: char,
@@ -37,22 +38,21 @@ impl<'a> Cursor<'a> {
}
}
- /// Returns nth character relative to the current cursor position.
+ /// Peeks the next symbol from the input stream without consuming it.
/// If requested position doesn't exist, `EOF_CHAR` is returned.
/// However, getting `EOF_CHAR` doesn't always mean actual end of file,
/// it should be checked with `is_eof` method.
- fn nth_char(&self, n: usize) -> char {
- self.chars().nth(n).unwrap_or(EOF_CHAR)
- }
-
- /// Peeks the next symbol from the input stream without consuming it.
pub(crate) fn first(&self) -> char {
- self.nth_char(0)
+ // `.next()` optimizes better than `.nth(0)`
+ self.chars.clone().next().unwrap_or(EOF_CHAR)
}
/// Peeks the second symbol from the input stream without consuming it.
pub(crate) fn second(&self) -> char {
- self.nth_char(1)
+ // `.next()` optimizes better than `.nth(1)`
+ let mut iter = self.chars.clone();
+ iter.next();
+ iter.next().unwrap_or(EOF_CHAR)
}
/// Checks if there is nothing more to consume.
@@ -65,9 +65,9 @@ impl<'a> Cursor<'a> {
self.initial_len - self.chars.as_str().len()
}
- /// Returns a `Chars` iterator over the remaining characters.
- fn chars(&self) -> Chars<'a> {
- self.chars.clone()
+ /// Resets the number of bytes consumed to 0.
+ pub(crate) fn reset_len_consumed(&mut self) {
+ self.initial_len = self.chars.as_str().len();
}
/// Moves to the next character.
@@ -81,4 +81,13 @@ impl<'a> Cursor<'a> {
Some(c)
}
+
+ /// Eats symbols while predicate returns true or until the end of file is reached.
+ pub(crate) fn eat_while(&mut self, mut predicate: impl FnMut(char) -> bool) {
+ // It was tried making optimized version of this for eg. line comments, but
+ // LLVM can inline all of this and compile it down to fast iteration over bytes.
+ while predicate(self.first()) && !self.is_eof() {
+ self.bump();
+ }
+ }
}
diff --git a/compiler/rustc_lexer/src/lib.rs b/compiler/rustc_lexer/src/lib.rs
index b64a891cb25..5b8300ab530 100644
--- a/compiler/rustc_lexer/src/lib.rs
+++ b/compiler/rustc_lexer/src/lib.rs
@@ -64,6 +64,8 @@ pub enum TokenKind {
/// "ident" or "continue"
/// At this step keywords are also considered identifiers.
Ident,
+ /// Like the above, but containing invalid unicode codepoints.
+ InvalidIdent,
/// "r#ident"
RawIdent,
/// An unknown prefix like `foo#`, `foo'`, `foo"`. Note that only the
@@ -225,14 +227,15 @@ pub fn first_token(input: &str) -> Token {
}
/// Creates an iterator that produces tokens from the input string.
-pub fn tokenize(mut input: &str) -> impl Iterator<Item = Token> + '_ {
+pub fn tokenize(input: &str) -> impl Iterator<Item = Token> + '_ {
+ let mut cursor = Cursor::new(input);
std::iter::from_fn(move || {
- if input.is_empty() {
- return None;
+ if cursor.is_eof() {
+ None
+ } else {
+ cursor.reset_len_consumed();
+ Some(cursor.advance_token())
}
- let token = first_token(input);
- input = &input[token.len..];
- Some(token)
})
}
@@ -411,6 +414,10 @@ impl Cursor<'_> {
let kind = Str { terminated };
Literal { kind, suffix_start }
}
+ // Identifier starting with an emoji. Only lexed for graceful error recovery.
+ c if !c.is_ascii() && unic_emoji_char::is_emoji(c) => {
+ self.fake_ident_or_unknown_prefix()
+ }
_ => Unknown,
};
Token::new(token_kind, self.len_consumed())
@@ -492,10 +499,28 @@ impl Cursor<'_> {
// we see a prefix here, it is definitely an unknown prefix.
match self.first() {
'#' | '"' | '\'' => UnknownPrefix,
+ c if !c.is_ascii() && unic_emoji_char::is_emoji(c) => {
+ self.fake_ident_or_unknown_prefix()
+ }
_ => Ident,
}
}
+ fn fake_ident_or_unknown_prefix(&mut self) -> TokenKind {
+ // Start is already eaten, eat the rest of identifier.
+ self.eat_while(|c| {
+ unicode_xid::UnicodeXID::is_xid_continue(c)
+ || (!c.is_ascii() && unic_emoji_char::is_emoji(c))
+ || c == '\u{200d}'
+ });
+ // Known prefixes must have been handled earlier. So if
+ // we see a prefix here, it is definitely an unknown prefix.
+ match self.first() {
+ '#' | '"' | '\'' => UnknownPrefix,
+ _ => InvalidIdent,
+ }
+ }
+
fn number(&mut self, first_digit: char) -> LiteralKind {
debug_assert!('0' <= self.prev() && self.prev() <= '9');
let mut base = Base::Decimal;
@@ -808,11 +833,4 @@ impl Cursor<'_> {
self.eat_while(is_id_continue);
}
-
- /// Eats symbols while predicate returns true or until the end of file is reached.
- fn eat_while(&mut self, mut predicate: impl FnMut(char) -> bool) {
- while predicate(self.first()) && !self.is_eof() {
- self.bump();
- }
- }
}
diff --git a/compiler/rustc_lint/src/array_into_iter.rs b/compiler/rustc_lint/src/array_into_iter.rs
index d8883b0e66d..b6151757588 100644
--- a/compiler/rustc_lint/src/array_into_iter.rs
+++ b/compiler/rustc_lint/src/array_into_iter.rs
@@ -52,7 +52,7 @@ impl<'tcx> LateLintPass<'tcx> for ArrayIntoIter {
if let hir::ExprKind::Call(path, [arg]) = &arg.kind {
if let hir::ExprKind::Path(hir::QPath::LangItem(
hir::LangItem::IntoIterIntoIter,
- _,
+ ..,
)) = &path.kind
{
self.for_expr_span = arg.span;
@@ -79,9 +79,8 @@ impl<'tcx> LateLintPass<'tcx> for ArrayIntoIter {
let receiver_ty = cx.typeck_results().expr_ty(receiver_arg);
let adjustments = cx.typeck_results().expr_adjustments(receiver_arg);
- let target = match adjustments.last() {
- Some(Adjustment { kind: Adjust::Borrow(_), target }) => target,
- _ => return,
+ let Some(Adjustment { kind: Adjust::Borrow(_), target }) = adjustments.last() else {
+ return
};
let types =
diff --git a/compiler/rustc_lint/src/builtin.rs b/compiler/rustc_lint/src/builtin.rs
index f2e4e70a197..61695109a89 100644
--- a/compiler/rustc_lint/src/builtin.rs
+++ b/compiler/rustc_lint/src/builtin.rs
@@ -609,14 +609,12 @@ impl<'tcx> LateLintPass<'tcx> for MissingDoc {
// If the trait is private, add the impl items to `private_traits` so they don't get
// reported for missing docs.
let real_trait = trait_ref.path.res.def_id();
- if let Some(def_id) = real_trait.as_local() {
- let hir_id = cx.tcx.hir().local_def_id_to_hir_id(def_id);
- if let Some(Node::Item(item)) = cx.tcx.hir().find(hir_id) {
- if let hir::VisibilityKind::Inherited = item.vis.node {
- for impl_item_ref in items {
- self.private_traits.insert(impl_item_ref.id.hir_id());
- }
- }
+ let Some(def_id) = real_trait.as_local() else { return };
+ let hir_id = cx.tcx.hir().local_def_id_to_hir_id(def_id);
+ let Some(Node::Item(item)) = cx.tcx.hir().find(hir_id) else { return };
+ if let hir::VisibilityKind::Inherited = item.vis.node {
+ for impl_item_ref in items {
+ self.private_traits.insert(impl_item_ref.id.hir_id());
}
}
return;
@@ -829,9 +827,8 @@ impl<'tcx> LateLintPass<'tcx> for MissingDebugImplementations {
_ => return,
}
- let debug = match cx.tcx.get_diagnostic_item(sym::Debug) {
- Some(debug) => debug,
- None => return,
+ let Some(debug) = cx.tcx.get_diagnostic_item(sym::Debug) else {
+ return
};
if self.impling_types.is_none() {
@@ -1079,6 +1076,10 @@ impl EarlyLintPass for UnusedDocComment {
fn check_expr(&mut self, cx: &EarlyContext<'_>, expr: &ast::Expr) {
warn_if_doc(cx, expr.span, "expressions", &expr.attrs);
}
+
+ fn check_generic_param(&mut self, cx: &EarlyContext<'_>, param: &ast::GenericParam) {
+ warn_if_doc(cx, param.ident.span, "generic parameters", &param.attrs);
+ }
}
declare_lint! {
@@ -1505,9 +1506,8 @@ impl TypeAliasBounds {
impl<'tcx> LateLintPass<'tcx> for TypeAliasBounds {
fn check_item(&mut self, cx: &LateContext<'_>, item: &hir::Item<'_>) {
- let (ty, type_alias_generics) = match item.kind {
- hir::ItemKind::TyAlias(ref ty, ref generics) => (&*ty, generics),
- _ => return,
+ let hir::ItemKind::TyAlias(ty, type_alias_generics) = &item.kind else {
+ return
};
if let hir::TyKind::OpaqueDef(..) = ty.kind {
// Bounds are respected for `type X = impl Trait`
@@ -2262,16 +2262,15 @@ impl<'tcx> LateLintPass<'tcx> for ExplicitOutlivesRequirements {
// and should check for them here.
match predicate.bounded_ty.kind {
hir::TyKind::Path(hir::QPath::Resolved(None, ref path)) => {
- if let Res::Def(DefKind::TyParam, def_id) = path.res {
- let index = ty_generics.param_def_id_to_index[&def_id];
- (
- Self::lifetimes_outliving_type(inferred_outlives, index),
- &predicate.bounds,
- predicate.span,
- )
- } else {
- continue;
- }
+ let Res::Def(DefKind::TyParam, def_id) = path.res else {
+ continue
+ };
+ let index = ty_generics.param_def_id_to_index[&def_id];
+ (
+ Self::lifetimes_outliving_type(inferred_outlives, index),
+ &predicate.bounds,
+ predicate.span,
+ )
}
_ => {
continue;
@@ -3011,7 +3010,7 @@ impl<'tcx> LateLintPass<'tcx> for ClashingExternDeclarations {
this_decl_ty,
CItemKind::Declaration,
) {
- let orig_fi = tcx.hir().expect_foreign_item(existing_hid);
+ let orig_fi = tcx.hir().expect_foreign_item(existing_hid.expect_owner());
let orig = Self::name_of_extern_decl(tcx, orig_fi);
// We want to ensure that we use spans for both decls that include where the
@@ -3148,7 +3147,8 @@ declare_lint! {
/// ### Example
///
/// ```rust,compile_fail
- /// #![feature(asm)]
+ /// use std::arch::asm;
+ ///
/// fn main() {
/// unsafe {
/// asm!("foo: bar");
@@ -3165,10 +3165,7 @@ declare_lint! {
/// of this, GNU assembler [local labels] *must* be used instead of labels
/// with a name. Using named labels might cause assembler or linker errors.
///
- /// See the [unstable book] for more details.
- ///
/// [local labels]: https://sourceware.org/binutils/docs/as/Symbol-Names.html#Local-Labels
- /// [unstable book]: https://doc.rust-lang.org/nightly/unstable-book/library-features/asm.html#labels
pub NAMED_ASM_LABELS,
Deny,
"named labels in inline assembly",
@@ -3212,18 +3209,17 @@ impl<'tcx> LateLintPass<'tcx> for NamedAsmLabels {
for (idx, _) in statement.match_indices(':') {
let possible_label = statement[start_idx..idx].trim();
let mut chars = possible_label.chars();
- if let Some(c) = chars.next() {
- // A label starts with an alphabetic character or . or _ and continues with alphanumeric characters, _, or $
- if (c.is_alphabetic() || matches!(c, '.' | '_'))
- && chars.all(|c| c.is_alphanumeric() || matches!(c, '_' | '$'))
- {
- found_labels.push(possible_label);
- } else {
- // If we encounter a non-label, there cannot be any further labels, so stop checking
- break;
- }
- } else {
+ let Some(c) = chars.next() else {
// Empty string means a leading ':' in this section, which is not a label
+ break
+ };
+ // A label starts with an alphabetic character or . or _ and continues with alphanumeric characters, _, or $
+ if (c.is_alphabetic() || matches!(c, '.' | '_'))
+ && chars.all(|c| c.is_alphanumeric() || matches!(c, '_' | '$'))
+ {
+ found_labels.push(possible_label);
+ } else {
+ // If we encounter a non-label, there cannot be any further labels, so stop checking
break;
}
diff --git a/compiler/rustc_lint/src/context.rs b/compiler/rustc_lint/src/context.rs
index 4c936dec6f2..c065ff37722 100644
--- a/compiler/rustc_lint/src/context.rs
+++ b/compiler/rustc_lint/src/context.rs
@@ -22,9 +22,7 @@ use ast::util::unicode::TEXT_FLOW_CONTROL_CHARS;
use rustc_ast as ast;
use rustc_data_structures::fx::FxHashMap;
use rustc_data_structures::sync;
-use rustc_errors::{
- add_elided_lifetime_in_path_suggestion, struct_span_err, Applicability, SuggestionStyle,
-};
+use rustc_errors::{struct_span_err, Applicability, SuggestionStyle};
use rustc_hir as hir;
use rustc_hir::def::Res;
use rustc_hir::def_id::{CrateNum, DefId};
@@ -635,16 +633,6 @@ pub trait LintContext: Sized {
}
},
BuiltinLintDiagnostics::Normal => (),
- BuiltinLintDiagnostics::BareTraitObject(span, is_global) => {
- let (sugg, app) = match sess.source_map().span_to_snippet(span) {
- Ok(s) if is_global => {
- (format!("dyn ({})", s), Applicability::MachineApplicable)
- }
- Ok(s) => (format!("dyn {}", s), Applicability::MachineApplicable),
- Err(_) => ("dyn <type>".to_string(), Applicability::HasPlaceholders),
- };
- db.span_suggestion(span, "use `dyn`", sugg, app);
- }
BuiltinLintDiagnostics::AbsPathWithModule(span) => {
let (sugg, app) = match sess.source_map().span_to_snippet(span) {
Ok(ref s) => {
@@ -670,23 +658,6 @@ pub trait LintContext: Sized {
) => {
db.span_note(span_def, "the macro is defined here");
}
- BuiltinLintDiagnostics::ElidedLifetimesInPaths(
- n,
- path_span,
- incl_angl_brckt,
- insertion_span,
- anon_lts,
- ) => {
- add_elided_lifetime_in_path_suggestion(
- sess.source_map(),
- &mut db,
- n,
- path_span,
- incl_angl_brckt,
- insertion_span,
- anon_lts,
- );
- }
BuiltinLintDiagnostics::UnknownCrateTypes(span, note, sugg) => {
db.span_suggestion(span, &note, sugg, Applicability::MaybeIncorrect);
}
@@ -791,7 +762,6 @@ pub trait LintContext: Sized {
}
BuiltinLintDiagnostics::NamedAsmLabel(help) => {
db.help(&help);
- db.note("see the asm section of the unstable book <https://doc.rust-lang.org/nightly/unstable-book/library-features/asm.html#labels> for more information");
}
}
// Rewrap `db`, and pass control to the user.
@@ -1060,8 +1030,8 @@ impl<'tcx> LateContext<'tcx> {
) -> Result<Self::Path, Self::Error> {
let mut path = print_prefix(self)?;
- // Skip `::{{constructor}}` on tuple/unit structs.
- if let DefPathData::Ctor = disambiguated_data.data {
+ // Skip `::{{extern}}` blocks and `::{{constructor}}` on tuple/unit structs.
+ if let DefPathData::ForeignMod | DefPathData::Ctor = disambiguated_data.data {
return Ok(path);
}
diff --git a/compiler/rustc_lint/src/enum_intrinsics_non_enums.rs b/compiler/rustc_lint/src/enum_intrinsics_non_enums.rs
index 876245747f6..65772d02376 100644
--- a/compiler/rustc_lint/src/enum_intrinsics_non_enums.rs
+++ b/compiler/rustc_lint/src/enum_intrinsics_non_enums.rs
@@ -91,16 +91,14 @@ fn enforce_mem_variant_count(cx: &LateContext<'_>, func_expr: &hir::Expr<'_>, sp
impl<'tcx> LateLintPass<'tcx> for EnumIntrinsicsNonEnums {
fn check_expr(&mut self, cx: &LateContext<'_>, expr: &hir::Expr<'_>) {
- if let hir::ExprKind::Call(ref func, ref args) = expr.kind {
- if let hir::ExprKind::Path(ref qpath) = func.kind {
- if let Some(def_id) = cx.qpath_res(qpath, func.hir_id).opt_def_id() {
- if cx.tcx.is_diagnostic_item(sym::mem_discriminant, def_id) {
- enforce_mem_discriminant(cx, func, expr.span, args[0].span);
- } else if cx.tcx.is_diagnostic_item(sym::mem_variant_count, def_id) {
- enforce_mem_variant_count(cx, func, expr.span);
- }
- }
- }
+ let hir::ExprKind::Call(func, args) = &expr.kind else { return };
+ let hir::ExprKind::Path(qpath) = &func.kind else { return };
+ let Some(def_id) = cx.qpath_res(qpath, func.hir_id).opt_def_id() else { return };
+ let Some(name) = cx.tcx.get_diagnostic_name(def_id) else { return };
+ match name {
+ sym::mem_discriminant => enforce_mem_discriminant(cx, func, expr.span, args[0].span),
+ sym::mem_variant_count => enforce_mem_variant_count(cx, func, expr.span),
+ _ => {}
}
}
}
diff --git a/compiler/rustc_lint/src/levels.rs b/compiler/rustc_lint/src/levels.rs
index b6d66eb12d0..485728cbfd3 100644
--- a/compiler/rustc_lint/src/levels.rs
+++ b/compiler/rustc_lint/src/levels.rs
@@ -227,14 +227,12 @@ impl<'s> LintLevelsBuilder<'s> {
let sess = self.sess;
let bad_attr = |span| struct_span_err!(sess, span, E0452, "malformed lint attribute input");
for attr in attrs {
- let level = match Level::from_symbol(attr.name_or_empty()) {
- None => continue,
- Some(lvl) => lvl,
+ let Some(level) = Level::from_symbol(attr.name_or_empty()) else {
+ continue
};
- let mut metas = match attr.meta_item_list() {
- Some(x) => x,
- None => continue,
+ let Some(mut metas) = attr.meta_item_list() else {
+ continue
};
if metas.is_empty() {
@@ -481,9 +479,8 @@ impl<'s> LintLevelsBuilder<'s> {
continue;
}
- let (lint_attr_name, lint_attr_span) = match *src {
- LintLevelSource::Node(name, span, _) => (name, span),
- _ => continue,
+ let LintLevelSource::Node(lint_attr_name, lint_attr_span, _) = *src else {
+ continue
};
let lint = builtin::UNUSED_ATTRIBUTES;
diff --git a/compiler/rustc_lint/src/lib.rs b/compiler/rustc_lint/src/lib.rs
index 507b4421fa1..c7823032b0c 100644
--- a/compiler/rustc_lint/src/lib.rs
+++ b/compiler/rustc_lint/src/lib.rs
@@ -30,9 +30,8 @@
#![feature(bool_to_option)]
#![feature(box_patterns)]
#![feature(crate_visibility_modifier)]
-#![cfg_attr(bootstrap, feature(format_args_capture))]
#![feature(iter_order_by)]
-#![feature(iter_zip)]
+#![feature(let_else)]
#![feature(never_type)]
#![feature(nll)]
#![feature(control_flow_enum)]
diff --git a/compiler/rustc_lint/src/non_fmt_panic.rs b/compiler/rustc_lint/src/non_fmt_panic.rs
index f2ad72f97ec..30506445ebb 100644
--- a/compiler/rustc_lint/src/non_fmt_panic.rs
+++ b/compiler/rustc_lint/src/non_fmt_panic.rs
@@ -207,7 +207,7 @@ fn check_panic_str<'tcx>(
arg: &'tcx hir::Expr<'tcx>,
fmt: &str,
) {
- if !fmt.contains(&['{', '}'][..]) {
+ if !fmt.contains(&['{', '}']) {
// No brace, no problem.
return;
}
@@ -309,14 +309,21 @@ fn panic_call<'tcx>(cx: &LateContext<'tcx>, f: &'tcx hir::Expr<'tcx>) -> (Span,
// Unwrap more levels of macro expansion, as panic_2015!()
// was likely expanded from panic!() and possibly from
// [debug_]assert!().
- for &i in
- &[sym::std_panic_macro, sym::core_panic_macro, sym::assert_macro, sym::debug_assert_macro]
- {
+ loop {
let parent = expn.call_site.ctxt().outer_expn_data();
- if parent.macro_def_id.map_or(false, |id| cx.tcx.is_diagnostic_item(i, id)) {
- expn = parent;
- panic_macro = i;
+ let Some(id) = parent.macro_def_id else { break };
+ let Some(name) = cx.tcx.get_diagnostic_name(id) else { break };
+ if !matches!(
+ name,
+ sym::core_panic_macro
+ | sym::std_panic_macro
+ | sym::assert_macro
+ | sym::debug_assert_macro
+ ) {
+ break;
}
+ expn = parent;
+ panic_macro = name;
}
let macro_symbol =
diff --git a/compiler/rustc_lint/src/noop_method_call.rs b/compiler/rustc_lint/src/noop_method_call.rs
index d2c970468ab..600504f7c12 100644
--- a/compiler/rustc_lint/src/noop_method_call.rs
+++ b/compiler/rustc_lint/src/noop_method_call.rs
@@ -40,9 +40,8 @@ declare_lint_pass!(NoopMethodCall => [NOOP_METHOD_CALL]);
impl<'tcx> LateLintPass<'tcx> for NoopMethodCall {
fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
// We only care about method calls.
- let (call, elements) = match expr.kind {
- ExprKind::MethodCall(call, _, elements, _) => (call, elements),
- _ => return,
+ let ExprKind::MethodCall(call, _, elements, _) = &expr.kind else {
+ return
};
// We only care about method calls corresponding to the `Clone`, `Deref` and `Borrow`
// traits and ignore any other method call.
@@ -70,43 +69,40 @@ impl<'tcx> LateLintPass<'tcx> for NoopMethodCall {
}
let param_env = cx.tcx.param_env(trait_id);
// Resolve the trait method instance.
- let i = match ty::Instance::resolve(cx.tcx, param_env, did, substs) {
- Ok(Some(i)) => i,
- _ => return,
+ let Ok(Some(i)) = ty::Instance::resolve(cx.tcx, param_env, did, substs) else {
+ return
};
// (Re)check that it implements the noop diagnostic.
- for s in [sym::noop_method_clone, sym::noop_method_deref, sym::noop_method_borrow].iter() {
- if cx.tcx.is_diagnostic_item(*s, i.def_id()) {
- let method = &call.ident.name;
- let receiver = &elements[0];
- let receiver_ty = cx.typeck_results().expr_ty(receiver);
- let expr_ty = cx.typeck_results().expr_ty_adjusted(expr);
- if receiver_ty != expr_ty {
- // This lint will only trigger if the receiver type and resulting expression \
- // type are the same, implying that the method call is unnecessary.
- return;
- }
- let expr_span = expr.span;
- let note = format!(
- "the type `{:?}` which `{}` is being called on is the same as \
- the type returned from `{}`, so the method call does not do \
- anything and can be removed",
- receiver_ty, method, method,
- );
-
- let span = expr_span.with_lo(receiver.span.hi());
- cx.struct_span_lint(NOOP_METHOD_CALL, span, |lint| {
- let method = &call.ident.name;
- let message = format!(
- "call to `.{}()` on a reference in this situation does nothing",
- &method,
- );
- lint.build(&message)
- .span_label(span, "unnecessary method call")
- .note(&note)
- .emit()
- });
- }
+ let Some(name) = cx.tcx.get_diagnostic_name(i.def_id()) else { return };
+ if !matches!(
+ name,
+ sym::noop_method_borrow | sym::noop_method_clone | sym::noop_method_deref
+ ) {
+ return;
+ }
+ let method = &call.ident.name;
+ let receiver = &elements[0];
+ let receiver_ty = cx.typeck_results().expr_ty(receiver);
+ let expr_ty = cx.typeck_results().expr_ty_adjusted(expr);
+ if receiver_ty != expr_ty {
+ // This lint will only trigger if the receiver type and resulting expression \
+ // type are the same, implying that the method call is unnecessary.
+ return;
}
+ let expr_span = expr.span;
+ let note = format!(
+ "the type `{:?}` which `{}` is being called on is the same as \
+ the type returned from `{}`, so the method call does not do \
+ anything and can be removed",
+ receiver_ty, method, method,
+ );
+
+ let span = expr_span.with_lo(receiver.span.hi());
+ cx.struct_span_lint(NOOP_METHOD_CALL, span, |lint| {
+ let method = &call.ident.name;
+ let message =
+ format!("call to `.{}()` on a reference in this situation does nothing", &method,);
+ lint.build(&message).span_label(span, "unnecessary method call").note(&note).emit()
+ });
}
}
diff --git a/compiler/rustc_lint/src/traits.rs b/compiler/rustc_lint/src/traits.rs
index 5435ff1396d..dafff640b36 100644
--- a/compiler/rustc_lint/src/traits.rs
+++ b/compiler/rustc_lint/src/traits.rs
@@ -91,9 +91,8 @@ impl<'tcx> LateLintPass<'tcx> for DropTraitConstraints {
let predicates = cx.tcx.explicit_predicates_of(item.def_id);
for &(predicate, span) in predicates.predicates {
- let trait_predicate = match predicate.kind().skip_binder() {
- Trait(trait_predicate) => trait_predicate,
- _ => continue,
+ let Trait(trait_predicate) = predicate.kind().skip_binder() else {
+ continue
};
if trait_predicate.constness == ty::BoundConstness::ConstIfConst {
// `~const Drop` definitely have meanings so avoid linting here.
@@ -106,9 +105,8 @@ impl<'tcx> LateLintPass<'tcx> for DropTraitConstraints {
continue;
}
cx.struct_span_lint(DROP_BOUNDS, span, |lint| {
- let needs_drop = match cx.tcx.get_diagnostic_item(sym::needs_drop) {
- Some(needs_drop) => needs_drop,
- None => return,
+ let Some(needs_drop) = cx.tcx.get_diagnostic_item(sym::needs_drop) else {
+ return
};
let msg = format!(
"bounds on `{}` are most likely incorrect, consider instead \
@@ -123,17 +121,15 @@ impl<'tcx> LateLintPass<'tcx> for DropTraitConstraints {
}
fn check_ty(&mut self, cx: &LateContext<'_>, ty: &'tcx hir::Ty<'tcx>) {
- let bounds = match &ty.kind {
- hir::TyKind::TraitObject(bounds, _lifetime, _syntax) => bounds,
- _ => return,
+ let hir::TyKind::TraitObject(bounds, _lifetime, _syntax) = &ty.kind else {
+ return
};
for bound in &bounds[..] {
let def_id = bound.trait_ref.trait_def_id();
if cx.tcx.lang_items().drop_trait() == def_id {
cx.struct_span_lint(DYN_DROP, bound.span, |lint| {
- let needs_drop = match cx.tcx.get_diagnostic_item(sym::needs_drop) {
- Some(needs_drop) => needs_drop,
- None => return,
+ let Some(needs_drop) = cx.tcx.get_diagnostic_item(sym::needs_drop) else {
+ return
};
let msg = format!(
"types that do not implement `Drop` can still have drop glue, consider \
diff --git a/compiler/rustc_lint/src/types.rs b/compiler/rustc_lint/src/types.rs
index 708cd56e068..32ed6dad7f8 100644
--- a/compiler/rustc_lint/src/types.rs
+++ b/compiler/rustc_lint/src/types.rs
@@ -1337,14 +1337,15 @@ impl<'tcx> LateLintPass<'tcx> for VariantSizeDifferences {
let layout = match cx.layout_of(ty) {
Ok(layout) => layout,
Err(
- ty::layout::LayoutError::Unknown(_) | ty::layout::LayoutError::SizeOverflow(_),
+ ty::layout::LayoutError::Unknown(_)
+ | ty::layout::LayoutError::SizeOverflow(_)
+ | ty::layout::LayoutError::NormalizationFailure(_, _),
) => return,
};
- let (variants, tag) = match layout.variants {
- Variants::Multiple {
+ let Variants::Multiple {
tag_encoding: TagEncoding::Direct, tag, ref variants, ..
- } => (variants, tag),
- _ => return,
+ } = &layout.variants else {
+ return
};
let tag_size = tag.value.size(&cx.tcx).bytes();
diff --git a/compiler/rustc_lint/src/unused.rs b/compiler/rustc_lint/src/unused.rs
index da1edcf6fe3..8e1c9b6394a 100644
--- a/compiler/rustc_lint/src/unused.rs
+++ b/compiler/rustc_lint/src/unused.rs
@@ -169,7 +169,9 @@ impl<'tcx> LateLintPass<'tcx> for UnusedResults {
}
if !(type_permits_lack_of_use || fn_warned || op_warned) {
- cx.struct_span_lint(UNUSED_RESULTS, s.span, |lint| lint.build("unused result").emit());
+ cx.struct_span_lint(UNUSED_RESULTS, s.span, |lint| {
+ lint.build(&format!("unused result of type `{}`", ty)).emit()
+ });
}
// Returns whether an error has been emitted (and thus another does not need to be later).
@@ -476,8 +478,11 @@ trait UnusedDelimLint {
lhs_needs_parens
|| (followed_by_block
- && match inner.kind {
+ && match &inner.kind {
ExprKind::Ret(_) | ExprKind::Break(..) | ExprKind::Yield(..) => true,
+ ExprKind::Range(_lhs, Some(rhs), _limits) => {
+ matches!(rhs.kind, ExprKind::Block(..))
+ }
_ => parser::contains_exterior_struct_lit(&inner),
})
}
diff --git a/compiler/rustc_lint_defs/src/builtin.rs b/compiler/rustc_lint_defs/src/builtin.rs
index c1a53c34b7a..27a06943cbc 100644
--- a/compiler/rustc_lint_defs/src/builtin.rs
+++ b/compiler/rustc_lint_defs/src/builtin.rs
@@ -2419,8 +2419,9 @@ declare_lint! {
///
/// ### Example
///
- /// ```rust,ignore (fails on system llvm)
- /// #![feature(asm)]
+ /// ```rust,ignore (fails on non-x86_64)
+ /// #[cfg(target_arch="x86_64")]
+ /// use std::arch::asm;
///
/// fn main() {
/// #[cfg(target_arch="x86_64")]
@@ -2430,19 +2431,7 @@ declare_lint! {
/// }
/// ```
///
- /// This will produce:
- ///
- /// ```text
- /// warning: formatting may not be suitable for sub-register argument
- /// --> src/main.rs:6:19
- /// |
- /// 6 | asm!("mov {0}, {0}", in(reg) 0i16);
- /// | ^^^ ^^^ ---- for this argument
- /// |
- /// = note: `#[warn(asm_sub_register)]` on by default
- /// = help: use the `x` modifier to have the register formatted as `ax`
- /// = help: or use the `r` modifier to keep the default formatting of `rax`
- /// ```
+ /// {{produces}}
///
/// ### Explanation
///
@@ -2455,10 +2444,6 @@ declare_lint! {
/// register size, to alert you of possibly using the incorrect width. To
/// fix this, add the suggested modifier to the template, or cast the
/// value to the correct size.
- ///
- /// See [register template modifiers] for more details.
- ///
- /// [register template modifiers]: https://doc.rust-lang.org/nightly/unstable-book/library-features/asm.html#register-template-modifiers
pub ASM_SUB_REGISTER,
Warn,
"using only a subset of a register for inline asm inputs",
@@ -2470,34 +2455,22 @@ declare_lint! {
///
/// ### Example
///
- /// ```rust,ignore (fails on system llvm)
- /// #![feature(asm)]
+ /// ```rust,ignore (fails on non-x86_64)
+ /// #[cfg(target_arch="x86_64")]
+ /// use std::arch::asm;
///
/// fn main() {
/// #[cfg(target_arch="x86_64")]
/// unsafe {
/// asm!(
/// ".att_syntax",
- /// "movl {0}, {0}", in(reg) 0usize
+ /// "movq %{0}, %{0}", in(reg) 0usize
/// );
/// }
/// }
/// ```
///
- /// This will produce:
- ///
- /// ```text
- /// warning: avoid using `.att_syntax`, prefer using `options(att_syntax)` instead
- /// --> test.rs:7:14
- /// |
- /// 7 | ".att_syntax",
- /// | ^^^^^^^^^^^
- /// 8 | "movq {0}, {0}", out(reg) _,
- /// 9 | );
- /// | - help: add option: `, options(att_syntax)`
- /// |
- /// = note: `#[warn(bad_asm_style)]` on by default
- /// ```
+ /// {{produces}}
///
/// ### Explanation
///
@@ -2739,7 +2712,8 @@ declare_lint! {
///
/// ```rust
/// #![feature(naked_functions)]
- /// #![feature(asm)]
+ ///
+ /// use std::arch::asm;
///
/// #[naked]
/// pub fn default_abi() -> u32 {
@@ -2960,6 +2934,41 @@ declare_lint! {
"detects large moves or copies",
}
+declare_lint! {
+ /// The `deprecated_cfg_attr_crate_type_name` lint detects uses of the
+ /// `#![cfg_attr(..., crate_type = "...")]` and
+ /// `#![cfg_attr(..., crate_name = "...")]` attributes to conditionally
+ /// specify the crate type and name in the source code.
+ ///
+ /// ### Example
+ ///
+ /// ```rust
+ /// #![cfg_attr(debug_assertions, crate_type = "lib")]
+ /// ```
+ ///
+ /// {{produces}}
+ ///
+ ///
+ /// ### Explanation
+ ///
+ /// The `#![crate_type]` and `#![crate_name]` attributes require a hack in
+ /// the compiler to be able to change the used crate type and crate name
+ /// after macros have been expanded. Neither attribute works in combination
+ /// with Cargo as it explicitly passes `--crate-type` and `--crate-name` on
+ /// the commandline. These values must match the value used in the source
+ /// code to prevent an error.
+ ///
+ /// To fix the warning use `--crate-type` on the commandline when running
+ /// rustc instead of `#![cfg_attr(..., crate_type = "...")]` and
+ /// `--crate-name` instead of `#![cfg_attr(..., crate_name = "...")]`.
+ pub DEPRECATED_CFG_ATTR_CRATE_TYPE_NAME,
+ Warn,
+ "detects usage of `#![cfg_attr(..., crate_type/crate_name = \"...\")]`",
+ @future_incompatible = FutureIncompatibleInfo {
+ reference: "issue #91632 <https://github.com/rust-lang/rust/issues/91632>",
+ };
+}
+
declare_lint_pass! {
/// Does nothing as a lint pass, but registers some `Lint`s
/// that are used by other parts of the compiler.
@@ -3056,6 +3065,8 @@ declare_lint_pass! {
NON_EXHAUSTIVE_OMITTED_PATTERNS,
TEXT_DIRECTION_CODEPOINT_IN_COMMENT,
DEREF_INTO_DYN_SUPERTRAIT,
+ DEPRECATED_CFG_ATTR_CRATE_TYPE_NAME,
+ DUPLICATE_MACRO_ATTRIBUTES,
]
}
@@ -3593,3 +3604,32 @@ declare_lint! {
reference: "issue #89460 <https://github.com/rust-lang/rust/issues/89460>",
};
}
+
+declare_lint! {
+ /// The `duplicate_macro_attributes` lint detects when a `#[test]`-like built-in macro
+ /// attribute is duplicated on an item. This lint may trigger on `bench`, `cfg_eval`, `test`
+ /// and `test_case`.
+ ///
+ /// ### Example
+ ///
+ /// ```rust,ignore (needs --test)
+ /// #[test]
+ /// #[test]
+ /// fn foo() {}
+ /// ```
+ ///
+ /// {{produces}}
+ ///
+ /// ### Explanation
+ ///
+ /// A duplicated attribute may erroneously originate from a copy-paste and the effect of it
+ /// being duplicated may not be obvious or desireable.
+ ///
+ /// For instance, doubling the `#[test]` attributes registers the test to be run twice with no
+ /// change to its environment.
+ ///
+ /// [issue #90979]: https://github.com/rust-lang/rust/issues/90979
+ pub DUPLICATE_MACRO_ATTRIBUTES,
+ Warn,
+ "duplicated attribute"
+}
diff --git a/compiler/rustc_lint_defs/src/lib.rs b/compiler/rustc_lint_defs/src/lib.rs
index feac2a7cfa4..e22c9c68de6 100644
--- a/compiler/rustc_lint_defs/src/lib.rs
+++ b/compiler/rustc_lint_defs/src/lib.rs
@@ -285,11 +285,9 @@ pub enum ExternDepSpec {
#[derive(PartialEq, Debug)]
pub enum BuiltinLintDiagnostics {
Normal,
- BareTraitObject(Span, /* is_global */ bool),
AbsPathWithModule(Span),
ProcMacroDeriveResolutionFallback(Span),
MacroExpandedMacroExportsAccessedByAbsolutePaths(Span),
- ElidedLifetimesInPaths(usize, Span, bool, Span, String),
UnknownCrateTypes(Span, String, String),
UnusedImports(String, Vec<(Span, String)>),
RedundantImport(Vec<(Span, bool)>, Ident),
diff --git a/compiler/rustc_llvm/build.rs b/compiler/rustc_llvm/build.rs
index 943ce589c4f..3b6808d693f 100644
--- a/compiler/rustc_llvm/build.rs
+++ b/compiler/rustc_llvm/build.rs
@@ -276,8 +276,11 @@ fn main() {
"stdc++"
};
- // RISC-V requires libatomic for sub-word atomic operations
- if target.starts_with("riscv") {
+ // RISC-V GCC erroneously requires libatomic for sub-word
+ // atomic operations. FreeBSD uses Clang as its system
+ // compiler and provides no libatomic in its base system so
+ // does not want this.
+ if !target.contains("freebsd") && target.starts_with("riscv") {
println!("cargo:rustc-link-lib=atomic");
}
diff --git a/compiler/rustc_llvm/llvm-wrapper/CoverageMappingWrapper.cpp b/compiler/rustc_llvm/llvm-wrapper/CoverageMappingWrapper.cpp
index 8cd2bd12450..154f554d607 100644
--- a/compiler/rustc_llvm/llvm-wrapper/CoverageMappingWrapper.cpp
+++ b/compiler/rustc_llvm/llvm-wrapper/CoverageMappingWrapper.cpp
@@ -10,6 +10,7 @@ using namespace llvm;
struct LLVMRustCounterMappingRegion {
coverage::Counter Count;
+ coverage::Counter FalseCount;
uint32_t FileID;
uint32_t ExpandedFileID;
uint32_t LineStart;
@@ -53,7 +54,7 @@ extern "C" void LLVMRustCoverageWriteMappingToBuffer(
MappingRegions.reserve(NumMappingRegions);
for (const auto &Region : makeArrayRef(RustMappingRegions, NumMappingRegions)) {
MappingRegions.emplace_back(
- Region.Count, Region.FileID, Region.ExpandedFileID,
+ Region.Count, Region.FalseCount, Region.FileID, Region.ExpandedFileID,
Region.LineStart, Region.ColumnStart, Region.LineEnd, Region.ColumnEnd,
Region.Kind);
}
@@ -108,5 +109,9 @@ extern "C" void LLVMRustCoverageWriteMappingVarNameToString(RustStringRef Str) {
}
extern "C" uint32_t LLVMRustCoverageMappingVersion() {
- return coverage::CovMapVersion::Version4;
+#if LLVM_VERSION_GE(13, 0)
+ return coverage::CovMapVersion::Version6;
+#else
+ return coverage::CovMapVersion::Version5;
+#endif
}
diff --git a/compiler/rustc_llvm/llvm-wrapper/LLVMWrapper.h b/compiler/rustc_llvm/llvm-wrapper/LLVMWrapper.h
index ebe495872c4..e2ce7da0e84 100644
--- a/compiler/rustc_llvm/llvm-wrapper/LLVMWrapper.h
+++ b/compiler/rustc_llvm/llvm-wrapper/LLVMWrapper.h
@@ -79,6 +79,9 @@ enum LLVMRustAttribute {
InaccessibleMemOnly = 27,
SanitizeHWAddress = 28,
WillReturn = 29,
+ StackProtectReq = 30,
+ StackProtectStrong = 31,
+ StackProtect = 32,
};
typedef struct OpaqueRustString *RustStringRef;
diff --git a/compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp b/compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp
index f3d8eb2602a..3fbf020c552 100644
--- a/compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp
+++ b/compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp
@@ -1,5 +1,6 @@
#include "LLVMWrapper.h"
#include "llvm/IR/DebugInfoMetadata.h"
+#include "llvm/IR/DiagnosticHandler.h"
#include "llvm/IR/DiagnosticInfo.h"
#include "llvm/IR/DiagnosticPrinter.h"
#include "llvm/IR/GlobalVariable.h"
@@ -213,6 +214,12 @@ static Attribute::AttrKind fromRust(LLVMRustAttribute Kind) {
return Attribute::SanitizeHWAddress;
case WillReturn:
return Attribute::WillReturn;
+ case StackProtectReq:
+ return Attribute::StackProtectReq;
+ case StackProtectStrong:
+ return Attribute::StackProtectStrong;
+ case StackProtect:
+ return Attribute::StackProtect;
}
report_fatal_error("bad AttributeKind");
}
@@ -438,11 +445,20 @@ extern "C" LLVMValueRef
LLVMRustInlineAsm(LLVMTypeRef Ty, char *AsmString, size_t AsmStringLen,
char *Constraints, size_t ConstraintsLen,
LLVMBool HasSideEffects, LLVMBool IsAlignStack,
- LLVMRustAsmDialect Dialect) {
+ LLVMRustAsmDialect Dialect, LLVMBool CanThrow) {
+#if LLVM_VERSION_GE(13, 0)
+ return wrap(InlineAsm::get(unwrap<FunctionType>(Ty),
+ StringRef(AsmString, AsmStringLen),
+ StringRef(Constraints, ConstraintsLen),
+ HasSideEffects, IsAlignStack,
+ fromRust(Dialect), CanThrow));
+#else
return wrap(InlineAsm::get(unwrap<FunctionType>(Ty),
StringRef(AsmString, AsmStringLen),
StringRef(Constraints, ConstraintsLen),
- HasSideEffects, IsAlignStack, fromRust(Dialect)));
+ HasSideEffects, IsAlignStack,
+ fromRust(Dialect)));
+#endif
}
extern "C" bool LLVMRustInlineAsmVerify(LLVMTypeRef Ty, char *Constraints,
@@ -1171,10 +1187,13 @@ static LLVMRustDiagnosticKind toRust(DiagnosticKind Kind) {
case DK_SampleProfile:
return LLVMRustDiagnosticKind::SampleProfile;
case DK_OptimizationRemark:
+ case DK_MachineOptimizationRemark:
return LLVMRustDiagnosticKind::OptimizationRemark;
case DK_OptimizationRemarkMissed:
+ case DK_MachineOptimizationRemarkMissed:
return LLVMRustDiagnosticKind::OptimizationRemarkMissed;
case DK_OptimizationRemarkAnalysis:
+ case DK_MachineOptimizationRemarkAnalysis:
return LLVMRustDiagnosticKind::OptimizationRemarkAnalysis;
case DK_OptimizationRemarkAnalysisFPCommute:
return LLVMRustDiagnosticKind::OptimizationRemarkAnalysisFPCommute;
@@ -1777,3 +1796,92 @@ extern "C" LLVMRustResult LLVMRustWriteImportLibrary(
return LLVMRustResult::Success;
}
}
+
+// Transfers ownership of DiagnosticHandler unique_ptr to the caller.
+extern "C" DiagnosticHandler *
+LLVMRustContextGetDiagnosticHandler(LLVMContextRef C) {
+ std::unique_ptr<DiagnosticHandler> DH = unwrap(C)->getDiagnosticHandler();
+ return DH.release();
+}
+
+// Sets unique_ptr to object of DiagnosticHandler to provide custom diagnostic
+// handling. Ownership of the handler is moved to the LLVMContext.
+extern "C" void LLVMRustContextSetDiagnosticHandler(LLVMContextRef C,
+ DiagnosticHandler *DH) {
+ unwrap(C)->setDiagnosticHandler(std::unique_ptr<DiagnosticHandler>(DH));
+}
+
+using LLVMDiagnosticHandlerTy = DiagnosticHandler::DiagnosticHandlerTy;
+
+// Configures a diagnostic handler that invokes provided callback when a
+// backend needs to emit a diagnostic.
+//
+// When RemarkAllPasses is true, remarks are enabled for all passes. Otherwise
+// the RemarkPasses array specifies individual passes for which remarks will be
+// enabled.
+extern "C" void LLVMRustContextConfigureDiagnosticHandler(
+ LLVMContextRef C, LLVMDiagnosticHandlerTy DiagnosticHandlerCallback,
+ void *DiagnosticHandlerContext, bool RemarkAllPasses,
+ const char * const * RemarkPasses, size_t RemarkPassesLen) {
+
+ class RustDiagnosticHandler final : public DiagnosticHandler {
+ public:
+ RustDiagnosticHandler(LLVMDiagnosticHandlerTy DiagnosticHandlerCallback,
+ void *DiagnosticHandlerContext,
+ bool RemarkAllPasses,
+ std::vector<std::string> RemarkPasses)
+ : DiagnosticHandlerCallback(DiagnosticHandlerCallback),
+ DiagnosticHandlerContext(DiagnosticHandlerContext),
+ RemarkAllPasses(RemarkAllPasses),
+ RemarkPasses(RemarkPasses) {}
+
+ virtual bool handleDiagnostics(const DiagnosticInfo &DI) override {
+ if (DiagnosticHandlerCallback) {
+ DiagnosticHandlerCallback(DI, DiagnosticHandlerContext);
+ return true;
+ }
+ return false;
+ }
+
+ bool isAnalysisRemarkEnabled(StringRef PassName) const override {
+ return isRemarkEnabled(PassName);
+ }
+
+ bool isMissedOptRemarkEnabled(StringRef PassName) const override {
+ return isRemarkEnabled(PassName);
+ }
+
+ bool isPassedOptRemarkEnabled(StringRef PassName) const override {
+ return isRemarkEnabled(PassName);
+ }
+
+ bool isAnyRemarkEnabled() const override {
+ return RemarkAllPasses || !RemarkPasses.empty();
+ }
+
+ private:
+ bool isRemarkEnabled(StringRef PassName) const {
+ if (RemarkAllPasses)
+ return true;
+
+ for (auto &Pass : RemarkPasses)
+ if (Pass == PassName)
+ return true;
+
+ return false;
+ }
+
+ LLVMDiagnosticHandlerTy DiagnosticHandlerCallback = nullptr;
+ void *DiagnosticHandlerContext = nullptr;
+
+ bool RemarkAllPasses = false;
+ std::vector<std::string> RemarkPasses;
+ };
+
+ std::vector<std::string> Passes;
+ for (size_t I = 0; I != RemarkPassesLen; ++I)
+ Passes.push_back(RemarkPasses[I]);
+
+ unwrap(C)->setDiagnosticHandler(std::make_unique<RustDiagnosticHandler>(
+ DiagnosticHandlerCallback, DiagnosticHandlerContext, RemarkAllPasses, Passes));
+}
diff --git a/compiler/rustc_macros/src/query.rs b/compiler/rustc_macros/src/query.rs
index 6dbba274360..478159147ac 100644
--- a/compiler/rustc_macros/src/query.rs
+++ b/compiler/rustc_macros/src/query.rs
@@ -58,6 +58,9 @@ enum QueryModifier {
/// Use a separate query provider for local and extern crates
SeparateProvideExtern(Ident),
+
+ /// Always remap the ParamEnv's constness before hashing and passing to the query provider
+ RemapEnvConstness(Ident),
}
impl Parse for QueryModifier {
@@ -123,6 +126,8 @@ impl Parse for QueryModifier {
Ok(QueryModifier::EvalAlways(modifier))
} else if modifier == "separate_provide_extern" {
Ok(QueryModifier::SeparateProvideExtern(modifier))
+ } else if modifier == "remap_env_constness" {
+ Ok(QueryModifier::RemapEnvConstness(modifier))
} else {
Err(Error::new(modifier.span(), "unknown query modifier"))
}
@@ -222,6 +227,9 @@ struct QueryModifiers {
/// Use a separate query provider for local and extern crates
separate_provide_extern: Option<Ident>,
+
+ /// Always remap the ParamEnv's constness before hashing.
+ remap_env_constness: Option<Ident>,
}
/// Process query modifiers into a struct, erroring on duplicates
@@ -236,6 +244,7 @@ fn process_modifiers(query: &mut Query) -> QueryModifiers {
let mut anon = None;
let mut eval_always = None;
let mut separate_provide_extern = None;
+ let mut remap_env_constness = None;
for modifier in query.modifiers.0.drain(..) {
match modifier {
QueryModifier::LoadCached(tcx, id, block) => {
@@ -335,6 +344,12 @@ fn process_modifiers(query: &mut Query) -> QueryModifiers {
}
separate_provide_extern = Some(ident);
}
+ QueryModifier::RemapEnvConstness(ident) => {
+ if remap_env_constness.is_some() {
+ panic!("duplicate modifier `remap_env_constness` for query `{}`", query.name);
+ }
+ remap_env_constness = Some(ident)
+ }
}
}
let desc = desc.unwrap_or_else(|| {
@@ -351,6 +366,7 @@ fn process_modifiers(query: &mut Query) -> QueryModifiers {
anon,
eval_always,
separate_provide_extern,
+ remap_env_constness,
}
}
@@ -485,6 +501,10 @@ pub fn rustc_queries(input: TokenStream) -> TokenStream {
if let Some(separate_provide_extern) = &modifiers.separate_provide_extern {
attributes.push(quote! { (#separate_provide_extern) });
}
+ // Pass on the remap_env_constness modifier
+ if let Some(remap_env_constness) = &modifiers.remap_env_constness {
+ attributes.push(quote! { (#remap_env_constness) });
+ }
// This uses the span of the query definition for the commas,
// which can be important if we later encounter any ambiguity
diff --git a/compiler/rustc_macros/src/serialize.rs b/compiler/rustc_macros/src/serialize.rs
index 7bc669f2b00..66e6b571beb 100644
--- a/compiler/rustc_macros/src/serialize.rs
+++ b/compiler/rustc_macros/src/serialize.rs
@@ -247,13 +247,24 @@ fn encodable_body(
})
.collect();
- let result = quote! { ::rustc_serialize::Encoder::emit_enum_variant(
- __encoder,
- #variant_name,
- #variant_idx,
- #field_idx,
- |__encoder| { ::std::result::Result::Ok({ #encode_fields }) }
- ) };
+ let result = if field_idx != 0 {
+ quote! {
+ ::rustc_serialize::Encoder::emit_enum_variant(
+ __encoder,
+ #variant_name,
+ #variant_idx,
+ #field_idx,
+ |__encoder| { ::std::result::Result::Ok({ #encode_fields }) }
+ )
+ }
+ } else {
+ quote! {
+ ::rustc_serialize::Encoder::emit_fieldless_enum_variant::<#variant_idx>(
+ __encoder,
+ #variant_name,
+ )
+ }
+ };
variant_idx += 1;
result
});
diff --git a/compiler/rustc_macros/src/type_foldable.rs b/compiler/rustc_macros/src/type_foldable.rs
index 082af087bf4..9f448a593da 100644
--- a/compiler/rustc_macros/src/type_foldable.rs
+++ b/compiler/rustc_macros/src/type_foldable.rs
@@ -17,7 +17,7 @@ pub fn type_foldable_derive(mut s: synstructure::Structure<'_>) -> proc_macro2::
vi.construct(|_, index| {
let bind = &bindings[index];
quote! {
- ::rustc_middle::ty::fold::TypeFoldable::fold_with(#bind, __folder)
+ ::rustc_middle::ty::fold::TypeFoldable::try_fold_with(#bind, __folder)?
}
})
});
@@ -25,11 +25,11 @@ pub fn type_foldable_derive(mut s: synstructure::Structure<'_>) -> proc_macro2::
s.bound_impl(
quote!(::rustc_middle::ty::fold::TypeFoldable<'tcx>),
quote! {
- fn super_fold_with<__F: ::rustc_middle::ty::fold::TypeFolder<'tcx>>(
+ fn try_super_fold_with<__F: ::rustc_middle::ty::fold::FallibleTypeFolder<'tcx>>(
self,
__folder: &mut __F
- ) -> Self {
- match self { #body_fold }
+ ) -> Result<Self, __F::Error> {
+ Ok(match self { #body_fold })
}
fn super_visit_with<__F: ::rustc_middle::ty::fold::TypeVisitor<'tcx>>(
diff --git a/compiler/rustc_metadata/Cargo.toml b/compiler/rustc_metadata/Cargo.toml
index dec77d996f3..59796dd6529 100644
--- a/compiler/rustc_metadata/Cargo.toml
+++ b/compiler/rustc_metadata/Cargo.toml
@@ -7,7 +7,7 @@ edition = "2021"
doctest = false
[dependencies]
-libc = "0.2"
+libloading = "0.7.1"
odht = { version = "0.3.1", features = ["nightly"] }
snap = "1"
tracing = "0.1"
@@ -27,6 +27,3 @@ rustc_ast = { path = "../rustc_ast" }
rustc_expand = { path = "../rustc_expand" }
rustc_span = { path = "../rustc_span" }
rustc_session = { path = "../rustc_session" }
-
-[target.'cfg(windows)'.dependencies]
-winapi = { version = "0.3", features = ["errhandlingapi", "libloaderapi"] }
diff --git a/compiler/rustc_metadata/src/creader.rs b/compiler/rustc_metadata/src/creader.rs
index eb0a693226c..e304682a2d4 100644
--- a/compiler/rustc_metadata/src/creader.rs
+++ b/compiler/rustc_metadata/src/creader.rs
@@ -1,6 +1,5 @@
//! Validates all used crates and extern libraries and loads their metadata
-use crate::dynamic_lib::DynamicLibrary;
use crate::locator::{CrateError, CrateLocator, CratePaths};
use crate::rmeta::{CrateDep, CrateMetadata, CrateNumMap, CrateRoot, MetadataBlob};
@@ -512,13 +511,17 @@ impl<'a> CrateLoader<'a> {
name: Symbol,
span: Span,
dep_kind: CrateDepKind,
- ) -> CrateNum {
+ ) -> Option<CrateNum> {
self.used_extern_options.insert(name);
- self.maybe_resolve_crate(name, dep_kind, None).unwrap_or_else(|err| {
- let missing_core =
- self.maybe_resolve_crate(sym::core, CrateDepKind::Explicit, None).is_err();
- err.report(&self.sess, span, missing_core)
- })
+ match self.maybe_resolve_crate(name, dep_kind, None) {
+ Ok(cnum) => Some(cnum),
+ Err(err) => {
+ let missing_core =
+ self.maybe_resolve_crate(sym::core, CrateDepKind::Explicit, None).is_err();
+ err.report(&self.sess, span, missing_core);
+ None
+ }
+ }
}
fn maybe_resolve_crate<'b>(
@@ -672,25 +675,19 @@ impl<'a> CrateLoader<'a> {
) -> Result<&'static [ProcMacro], CrateError> {
// Make sure the path contains a / or the linker will search for it.
let path = env::current_dir().unwrap().join(path);
- let lib = match DynamicLibrary::open(&path) {
- Ok(lib) => lib,
- Err(s) => return Err(CrateError::DlOpen(s)),
- };
+ let lib = unsafe { libloading::Library::new(path) }
+ .map_err(|err| CrateError::DlOpen(err.to_string()))?;
- let sym = self.sess.generate_proc_macro_decls_symbol(stable_crate_id);
- let decls = unsafe {
- let sym = match lib.symbol(&sym) {
- Ok(f) => f,
- Err(s) => return Err(CrateError::DlSym(s)),
- };
- *(sym as *const &[ProcMacro])
- };
+ let sym_name = self.sess.generate_proc_macro_decls_symbol(stable_crate_id);
+ let sym = unsafe { lib.get::<*const &[ProcMacro]>(sym_name.as_bytes()) }
+ .map_err(|err| CrateError::DlSym(err.to_string()))?;
// Intentionally leak the dynamic library. We can't ever unload it
// since the library can make things that will live arbitrarily long.
+ let sym = unsafe { sym.into_raw() };
std::mem::forget(lib);
- Ok(decls)
+ Ok(unsafe { **sym })
}
fn inject_panic_runtime(&mut self, krate: &ast::Crate) {
@@ -751,7 +748,7 @@ impl<'a> CrateLoader<'a> {
};
info!("panic runtime not found -- loading {}", name);
- let cnum = self.resolve_crate(name, DUMMY_SP, CrateDepKind::Implicit);
+ let Some(cnum) = self.resolve_crate(name, DUMMY_SP, CrateDepKind::Implicit) else { return; };
let data = self.cstore.get_crate_data(cnum);
// Sanity check the loaded crate to ensure it is indeed a panic runtime
@@ -791,7 +788,7 @@ impl<'a> CrateLoader<'a> {
);
}
- let cnum = self.resolve_crate(name, DUMMY_SP, CrateDepKind::Implicit);
+ let Some(cnum) = self.resolve_crate(name, DUMMY_SP, CrateDepKind::Implicit) else { return; };
let data = self.cstore.get_crate_data(cnum);
// Sanity check the loaded crate to ensure it is indeed a profiler runtime
@@ -991,7 +988,7 @@ impl<'a> CrateLoader<'a> {
item: &ast::Item,
definitions: &Definitions,
def_id: LocalDefId,
- ) -> CrateNum {
+ ) -> Option<CrateNum> {
match item.kind {
ast::ItemKind::ExternCrate(orig_name) => {
debug!(
@@ -1011,7 +1008,7 @@ impl<'a> CrateLoader<'a> {
CrateDepKind::Explicit
};
- let cnum = self.resolve_crate(name, item.span, dep_kind);
+ let cnum = self.resolve_crate(name, item.span, dep_kind)?;
let path_len = definitions.def_path(def_id).data.len();
self.update_extern_crate(
@@ -1023,14 +1020,14 @@ impl<'a> CrateLoader<'a> {
dependency_of: LOCAL_CRATE,
},
);
- cnum
+ Some(cnum)
}
_ => bug!(),
}
}
- pub fn process_path_extern(&mut self, name: Symbol, span: Span) -> CrateNum {
- let cnum = self.resolve_crate(name, span, CrateDepKind::Explicit);
+ pub fn process_path_extern(&mut self, name: Symbol, span: Span) -> Option<CrateNum> {
+ let cnum = self.resolve_crate(name, span, CrateDepKind::Explicit)?;
self.update_extern_crate(
cnum,
@@ -1043,7 +1040,7 @@ impl<'a> CrateLoader<'a> {
},
);
- cnum
+ Some(cnum)
}
pub fn maybe_process_path_extern(&mut self, name: Symbol) -> Option<CrateNum> {
diff --git a/compiler/rustc_metadata/src/dynamic_lib.rs b/compiler/rustc_metadata/src/dynamic_lib.rs
deleted file mode 100644
index e8929cd5c02..00000000000
--- a/compiler/rustc_metadata/src/dynamic_lib.rs
+++ /dev/null
@@ -1,194 +0,0 @@
-//! Dynamic library facilities.
-//!
-//! A simple wrapper over the platform's dynamic library facilities
-
-use std::ffi::CString;
-use std::path::Path;
-
-pub struct DynamicLibrary {
- handle: *mut u8,
-}
-
-impl Drop for DynamicLibrary {
- fn drop(&mut self) {
- unsafe { dl::close(self.handle) }
- }
-}
-
-impl DynamicLibrary {
- /// Lazily open a dynamic library.
- pub fn open(filename: &Path) -> Result<DynamicLibrary, String> {
- let maybe_library = dl::open(filename.as_os_str());
-
- // The dynamic library must not be constructed if there is
- // an error opening the library so the destructor does not
- // run.
- match maybe_library {
- Err(err) => Err(err),
- Ok(handle) => Ok(DynamicLibrary { handle }),
- }
- }
-
- /// Accesses the value at the symbol of the dynamic library.
- pub unsafe fn symbol<T>(&self, symbol: &str) -> Result<*mut T, String> {
- // This function should have a lifetime constraint of 'a on
- // T but that feature is still unimplemented
-
- let raw_string = CString::new(symbol).unwrap();
- let maybe_symbol_value = dl::symbol(self.handle, raw_string.as_ptr());
-
- // The value must not be constructed if there is an error so
- // the destructor does not run.
- match maybe_symbol_value {
- Err(err) => Err(err),
- Ok(symbol_value) => Ok(symbol_value as *mut T),
- }
- }
-}
-
-#[cfg(test)]
-mod tests;
-
-#[cfg(unix)]
-mod dl {
- use std::ffi::{CString, OsStr};
- use std::os::unix::prelude::*;
-
- // As of the 2017 revision of the POSIX standard (IEEE 1003.1-2017), it is
- // implementation-defined whether `dlerror` is thread-safe (in which case it returns the most
- // recent error in the calling thread) or not thread-safe (in which case it returns the most
- // recent error in *any* thread).
- //
- // There's no easy way to tell what strategy is used by a given POSIX implementation, so we
- // lock around all calls that can modify `dlerror` in this module lest we accidentally read an
- // error from a different thread. This is bulletproof when we are the *only* code using the
- // dynamic library APIs at a given point in time. However, it's still possible for us to race
- // with other code (see #74469) on platforms where `dlerror` is not thread-safe.
- mod error {
- use std::ffi::CStr;
- use std::lazy::SyncLazy;
- use std::sync::{Mutex, MutexGuard};
-
- pub fn lock() -> MutexGuard<'static, Guard> {
- static LOCK: SyncLazy<Mutex<Guard>> = SyncLazy::new(|| Mutex::new(Guard));
- LOCK.lock().unwrap()
- }
-
- #[non_exhaustive]
- pub struct Guard;
-
- impl Guard {
- pub fn get(&mut self) -> Result<(), String> {
- let msg = unsafe { libc::dlerror() };
- if msg.is_null() {
- Ok(())
- } else {
- let msg = unsafe { CStr::from_ptr(msg as *const _) };
- Err(msg.to_string_lossy().into_owned())
- }
- }
-
- pub fn clear(&mut self) {
- let _ = unsafe { libc::dlerror() };
- }
- }
- }
-
- pub(super) fn open(filename: &OsStr) -> Result<*mut u8, String> {
- let s = CString::new(filename.as_bytes()).unwrap();
-
- let mut dlerror = error::lock();
- let ret = unsafe { libc::dlopen(s.as_ptr(), libc::RTLD_LAZY | libc::RTLD_LOCAL) };
-
- if !ret.is_null() {
- return Ok(ret.cast());
- }
-
- // A null return from `dlopen` indicates that an error has definitely occurred, so if
- // nothing is in `dlerror`, we are racing with another thread that has stolen our error
- // message. See the explanation on the `dl::error` module for more information.
- dlerror.get().and_then(|()| Err("Unknown error".to_string()))
- }
-
- pub(super) unsafe fn symbol(
- handle: *mut u8,
- symbol: *const libc::c_char,
- ) -> Result<*mut u8, String> {
- let mut dlerror = error::lock();
-
- // Unlike `dlopen`, it's possible for `dlsym` to return null without overwriting `dlerror`.
- // Because of this, we clear `dlerror` before calling `dlsym` to avoid picking up a stale
- // error message by accident.
- dlerror.clear();
-
- let ret = libc::dlsym(handle as *mut libc::c_void, symbol);
-
- if !ret.is_null() {
- return Ok(ret.cast());
- }
-
- // If `dlsym` returns null but there is nothing in `dlerror` it means one of two things:
- // - We tried to load a symbol mapped to address 0. This is not technically an error but is
- // unlikely to occur in practice and equally unlikely to be handled correctly by calling
- // code. Therefore we treat it as an error anyway.
- // - An error has occurred, but we are racing with another thread that has stolen our error
- // message. See the explanation on the `dl::error` module for more information.
- dlerror.get().and_then(|()| Err("Tried to load symbol mapped to address 0".to_string()))
- }
-
- pub(super) unsafe fn close(handle: *mut u8) {
- libc::dlclose(handle as *mut libc::c_void);
- }
-}
-
-#[cfg(windows)]
-mod dl {
- use std::ffi::OsStr;
- use std::io;
- use std::os::windows::prelude::*;
- use std::ptr;
-
- use winapi::shared::minwindef::HMODULE;
- use winapi::um::errhandlingapi::SetThreadErrorMode;
- use winapi::um::libloaderapi::{FreeLibrary, GetProcAddress, LoadLibraryW};
- use winapi::um::winbase::SEM_FAILCRITICALERRORS;
-
- pub(super) fn open(filename: &OsStr) -> Result<*mut u8, String> {
- // disable "dll load failed" error dialog.
- let prev_error_mode = unsafe {
- let new_error_mode = SEM_FAILCRITICALERRORS;
- let mut prev_error_mode = 0;
- let result = SetThreadErrorMode(new_error_mode, &mut prev_error_mode);
- if result == 0 {
- return Err(io::Error::last_os_error().to_string());
- }
- prev_error_mode
- };
-
- let filename_str: Vec<_> = filename.encode_wide().chain(Some(0)).collect();
- let result = unsafe { LoadLibraryW(filename_str.as_ptr()) } as *mut u8;
- let result = ptr_result(result);
-
- unsafe {
- SetThreadErrorMode(prev_error_mode, ptr::null_mut());
- }
-
- result
- }
-
- pub(super) unsafe fn symbol(
- handle: *mut u8,
- symbol: *const libc::c_char,
- ) -> Result<*mut u8, String> {
- let ptr = GetProcAddress(handle as HMODULE, symbol) as *mut u8;
- ptr_result(ptr)
- }
-
- pub(super) unsafe fn close(handle: *mut u8) {
- FreeLibrary(handle as HMODULE);
- }
-
- fn ptr_result<T>(ptr: *mut T) -> Result<*mut T, String> {
- if ptr.is_null() { Err(io::Error::last_os_error().to_string()) } else { Ok(ptr) }
- }
-}
diff --git a/compiler/rustc_metadata/src/dynamic_lib/tests.rs b/compiler/rustc_metadata/src/dynamic_lib/tests.rs
deleted file mode 100644
index 7090bbf61c7..00000000000
--- a/compiler/rustc_metadata/src/dynamic_lib/tests.rs
+++ /dev/null
@@ -1,18 +0,0 @@
-use super::*;
-
-#[test]
-fn test_errors_do_not_crash() {
- use std::path::Path;
-
- if !cfg!(unix) {
- return;
- }
-
- // Open /dev/null as a library to get an error, and make sure
- // that only causes an error, and not a crash.
- let path = Path::new("/dev/null");
- match DynamicLibrary::open(&path) {
- Err(_) => {}
- Ok(_) => panic!("Successfully opened the empty library."),
- }
-}
diff --git a/compiler/rustc_metadata/src/foreign_modules.rs b/compiler/rustc_metadata/src/foreign_modules.rs
index 5b42f48a7d4..c70a6914520 100644
--- a/compiler/rustc_metadata/src/foreign_modules.rs
+++ b/compiler/rustc_metadata/src/foreign_modules.rs
@@ -13,7 +13,7 @@ struct Collector {
modules: Vec<ForeignModule>,
}
-impl ItemLikeVisitor<'tcx> for Collector {
+impl<'tcx> ItemLikeVisitor<'tcx> for Collector {
fn visit_item(&mut self, it: &'tcx hir::Item<'tcx>) {
let items = match it.kind {
hir::ItemKind::ForeignMod { items, .. } => items,
diff --git a/compiler/rustc_metadata/src/lib.rs b/compiler/rustc_metadata/src/lib.rs
index 6cf0dd8b1ad..918c3b9daf1 100644
--- a/compiler/rustc_metadata/src/lib.rs
+++ b/compiler/rustc_metadata/src/lib.rs
@@ -1,7 +1,6 @@
#![doc(html_root_url = "https://doc.rust-lang.org/nightly/nightly-rustc/")]
#![feature(crate_visibility_modifier)]
#![feature(drain_filter)]
-#![feature(in_band_lifetimes)]
#![feature(let_else)]
#![feature(nll)]
#![feature(once_cell)]
@@ -28,7 +27,6 @@ mod native_libs;
mod rmeta;
pub mod creader;
-pub mod dynamic_lib;
pub mod locator;
pub use rmeta::{encode_metadata, EncodedMetadata, METADATA_HEADER};
diff --git a/compiler/rustc_metadata/src/locator.rs b/compiler/rustc_metadata/src/locator.rs
index 7cba16e0a9a..2893ceb5bf5 100644
--- a/compiler/rustc_metadata/src/locator.rs
+++ b/compiler/rustc_metadata/src/locator.rs
@@ -220,7 +220,7 @@ use rustc_data_structures::memmap::Mmap;
use rustc_data_structures::owning_ref::OwningRef;
use rustc_data_structures::svh::Svh;
use rustc_data_structures::sync::MetadataRef;
-use rustc_errors::struct_span_err;
+use rustc_errors::{struct_span_err, FatalError};
use rustc_session::config::{self, CrateType};
use rustc_session::cstore::{CrateSource, MetadataLoader};
use rustc_session::filesearch::{FileDoesntMatch, FileMatches, FileSearch};
@@ -734,7 +734,7 @@ impl<'a> CrateLocator<'a> {
}
}
-fn get_metadata_section(
+fn get_metadata_section<'p>(
target: &Target,
flavor: CrateFlavor,
filename: &'p Path,
@@ -814,11 +814,11 @@ pub fn find_plugin_registrar(
span: Span,
name: Symbol,
) -> PathBuf {
- match find_plugin_registrar_impl(sess, metadata_loader, name) {
- Ok(res) => res,
+ find_plugin_registrar_impl(sess, metadata_loader, name).unwrap_or_else(|err| {
// `core` is always available if we got as far as loading plugins.
- Err(err) => err.report(sess, span, false),
- }
+ err.report(sess, span, false);
+ FatalError.raise()
+ })
}
fn find_plugin_registrar_impl<'a>(
@@ -931,8 +931,8 @@ impl fmt::Display for MetadataError<'_> {
}
impl CrateError {
- crate fn report(self, sess: &Session, span: Span, missing_core: bool) -> ! {
- let mut err = match self {
+ crate fn report(self, sess: &Session, span: Span, missing_core: bool) {
+ let mut diag = match self {
CrateError::NonAsciiName(crate_name) => sess.struct_span_err(
span,
&format!("cannot load a crate with a non-ascii name `{}`", crate_name),
@@ -1210,8 +1210,6 @@ impl CrateError {
),
};
- err.emit();
- sess.abort_if_errors();
- unreachable!();
+ diag.emit();
}
}
diff --git a/compiler/rustc_metadata/src/native_libs.rs b/compiler/rustc_metadata/src/native_libs.rs
index bd5cda15b91..808151089df 100644
--- a/compiler/rustc_metadata/src/native_libs.rs
+++ b/compiler/rustc_metadata/src/native_libs.rs
@@ -31,7 +31,7 @@ struct Collector<'tcx> {
libs: Vec<NativeLib>,
}
-impl ItemLikeVisitor<'tcx> for Collector<'tcx> {
+impl<'tcx> ItemLikeVisitor<'tcx> for Collector<'tcx> {
fn visit_item(&mut self, it: &'tcx hir::Item<'tcx>) {
let (abi, foreign_mod_items) = match it.kind {
hir::ItemKind::ForeignMod { abi, items } => (abi, items),
@@ -132,7 +132,7 @@ impl ItemLikeVisitor<'tcx> for Collector<'tcx> {
if let Some(modifiers) = item.value_str() {
let span = item.name_value_literal_span().unwrap();
for modifier in modifiers.as_str().split(',') {
- let (modifier, value) = match modifier.strip_prefix(&['+', '-'][..]) {
+ let (modifier, value) = match modifier.strip_prefix(&['+', '-']) {
Some(m) => (m, modifier.starts_with('+')),
None => {
sess.span_err(
@@ -223,7 +223,7 @@ impl ItemLikeVisitor<'tcx> for Collector<'tcx> {
fn visit_foreign_item(&mut self, _it: &'tcx hir::ForeignItem<'tcx>) {}
}
-impl Collector<'tcx> {
+impl Collector<'_> {
fn register_native_lib(&mut self, span: Option<Span>, lib: NativeLib) {
if lib.name.as_ref().map_or(false, |&s| s == kw::Empty) {
match span {
diff --git a/compiler/rustc_metadata/src/rmeta/decoder.rs b/compiler/rustc_metadata/src/rmeta/decoder.rs
index b2c7818a542..09c6cb010b0 100644
--- a/compiler/rustc_metadata/src/rmeta/decoder.rs
+++ b/compiler/rustc_metadata/src/rmeta/decoder.rs
@@ -628,7 +628,7 @@ where
implement_ty_decoder!(DecodeContext<'a, 'tcx>);
-impl MetadataBlob {
+impl<'tcx> MetadataBlob {
crate fn new(metadata_ref: MetadataRef) -> MetadataBlob {
MetadataBlob(Lrc::new(metadata_ref))
}
@@ -697,7 +697,7 @@ impl CrateRoot<'_> {
&self.triple
}
- crate fn decode_crate_deps(
+ crate fn decode_crate_deps<'a>(
&self,
metadata: &'a MetadataBlob,
) -> impl ExactSizeIterator<Item = CrateDep> + Captures<'a> {
diff --git a/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs b/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs
index eeb0a77adc0..5ba7efc37f8 100644
--- a/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs
+++ b/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs
@@ -83,7 +83,7 @@ impl IntoArgs for (CrateNum, DefId) {
}
}
-impl IntoArgs for ty::InstanceDef<'tcx> {
+impl<'tcx> IntoArgs for ty::InstanceDef<'tcx> {
fn into_args(self) -> (DefId, DefId) {
(self.def_id(), self.def_id())
}
diff --git a/compiler/rustc_metadata/src/rmeta/def_path_hash_map.rs b/compiler/rustc_metadata/src/rmeta/def_path_hash_map.rs
index d6435bb649d..054431169a2 100644
--- a/compiler/rustc_metadata/src/rmeta/def_path_hash_map.rs
+++ b/compiler/rustc_metadata/src/rmeta/def_path_hash_map.rs
@@ -11,7 +11,7 @@ crate enum DefPathHashMapRef<'tcx> {
BorrowedFromTcx(&'tcx DefPathHashMap),
}
-impl DefPathHashMapRef<'tcx> {
+impl DefPathHashMapRef<'_> {
#[inline]
pub fn def_path_hash_to_def_index(&self, def_path_hash: &DefPathHash) -> DefIndex {
match *self {
diff --git a/compiler/rustc_metadata/src/rmeta/encoder.rs b/compiler/rustc_metadata/src/rmeta/encoder.rs
index d46829c2cee..a6828e103dc 100644
--- a/compiler/rustc_metadata/src/rmeta/encoder.rs
+++ b/compiler/rustc_metadata/src/rmeta/encoder.rs
@@ -26,6 +26,7 @@ use rustc_middle::mir::interpret;
use rustc_middle::thir;
use rustc_middle::traits::specialization_graph;
use rustc_middle::ty::codec::TyEncoder;
+use rustc_middle::ty::fast_reject::{self, SimplifyParams, StripReferences};
use rustc_middle::ty::{self, SymbolName, Ty, TyCtxt};
use rustc_serialize::{opaque, Encodable, Encoder};
use rustc_session::config::CrateType;
@@ -869,8 +870,9 @@ fn should_encode_mir(tcx: TyCtxt<'_>, def_id: LocalDefId) -> (bool, bool) {
let needs_inline = (generics.requires_monomorphization(tcx)
|| tcx.codegen_fn_attrs(def_id).requests_inline())
&& tcx.sess.opts.output_types.should_codegen();
- // Only check the presence of the `const` modifier.
- let is_const_fn = tcx.is_const_fn_raw(def_id.to_def_id());
+ // The function has a `const` modifier or is annotated with `default_method_body_is_const`.
+ let is_const_fn = tcx.is_const_fn_raw(def_id.to_def_id())
+ || tcx.has_attr(def_id.to_def_id(), sym::default_method_body_is_const);
let always_encode_mir = tcx.sess.opts.debugging_opts.always_encode_mir;
(is_const_fn, needs_inline || always_encode_mir)
}
@@ -962,7 +964,7 @@ fn should_encode_generics(def_kind: DefKind) -> bool {
}
}
-impl EncodeContext<'a, 'tcx> {
+impl<'a, 'tcx> EncodeContext<'a, 'tcx> {
fn encode_def_ids(&mut self) {
if self.is_proc_macro {
return;
@@ -1152,8 +1154,7 @@ impl EncodeContext<'a, 'tcx> {
debug!("EncodeContext::encode_info_for_trait_item({:?})", def_id);
let tcx = self.tcx;
- let hir_id = tcx.hir().local_def_id_to_hir_id(def_id.expect_local());
- let ast_item = tcx.hir().expect_trait_item(hir_id);
+ let ast_item = tcx.hir().expect_trait_item(def_id.expect_local());
let trait_item = tcx.associated_item(def_id);
let container = match trait_item.defaultness {
@@ -1221,8 +1222,7 @@ impl EncodeContext<'a, 'tcx> {
debug!("EncodeContext::encode_info_for_impl_item({:?})", def_id);
let tcx = self.tcx;
- let hir_id = self.tcx.hir().local_def_id_to_hir_id(def_id.expect_local());
- let ast_item = self.tcx.hir().expect_impl_item(hir_id);
+ let ast_item = self.tcx.hir().expect_impl_item(def_id.expect_local());
let impl_item = self.tcx.associated_item(def_id);
let container = match impl_item.defaultness {
@@ -1751,7 +1751,7 @@ impl EncodeContext<'a, 'tcx> {
fn encode_lib_features(&mut self) -> Lazy<[(Symbol, Option<Symbol>)]> {
empty_proc_macro!(self);
let tcx = self.tcx;
- let lib_features = tcx.lib_features();
+ let lib_features = tcx.lib_features(());
self.lazy(lib_features.to_vec())
}
@@ -1894,7 +1894,7 @@ impl EncodeContext<'a, 'tcx> {
}
// FIXME(eddyb) make metadata encoding walk over all definitions, instead of HIR.
-impl Visitor<'tcx> for EncodeContext<'a, 'tcx> {
+impl<'a, 'tcx> Visitor<'tcx> for EncodeContext<'a, 'tcx> {
type Map = Map<'tcx>;
fn nested_visit_map(&mut self) -> NestedVisitorMap<Self::Map> {
@@ -1927,7 +1927,7 @@ impl Visitor<'tcx> for EncodeContext<'a, 'tcx> {
}
}
-impl EncodeContext<'a, 'tcx> {
+impl<'a, 'tcx> EncodeContext<'a, 'tcx> {
fn encode_fields(&mut self, adt_def: &ty::AdtDef) {
for (variant_index, variant) in adt_def.variants.iter_enumerated() {
for (field_index, _field) in variant.fields.iter().enumerate() {
@@ -2035,15 +2035,19 @@ impl EncodeContext<'a, 'tcx> {
struct ImplVisitor<'tcx> {
tcx: TyCtxt<'tcx>,
- impls: FxHashMap<DefId, Vec<(DefIndex, Option<ty::fast_reject::SimplifiedType>)>>,
+ impls: FxHashMap<DefId, Vec<(DefIndex, Option<fast_reject::SimplifiedType>)>>,
}
impl<'tcx, 'v> ItemLikeVisitor<'v> for ImplVisitor<'tcx> {
fn visit_item(&mut self, item: &hir::Item<'_>) {
if let hir::ItemKind::Impl { .. } = item.kind {
if let Some(trait_ref) = self.tcx.impl_trait_ref(item.def_id.to_def_id()) {
- let simplified_self_ty =
- ty::fast_reject::simplify_type(self.tcx, trait_ref.self_ty(), false);
+ let simplified_self_ty = fast_reject::simplify_type(
+ self.tcx,
+ trait_ref.self_ty(),
+ SimplifyParams::No,
+ StripReferences::No,
+ );
self.impls
.entry(trait_ref.def_id)
@@ -2121,7 +2125,7 @@ impl EncodedMetadata {
#[inline]
pub fn raw_data(&self) -> &[u8] {
- &self.raw_data[..]
+ &self.raw_data
}
}
diff --git a/compiler/rustc_metadata/src/rmeta/mod.rs b/compiler/rustc_metadata/src/rmeta/mod.rs
index 4e09d23169a..5ce239ac704 100644
--- a/compiler/rustc_metadata/src/rmeta/mod.rs
+++ b/compiler/rustc_metadata/src/rmeta/mod.rs
@@ -48,7 +48,7 @@ crate fn rustc_version() -> String {
/// Metadata encoding version.
/// N.B., increment this if you change the format of metadata such that
/// the rustc version can't be found to compare with `rustc_version()`.
-const METADATA_VERSION: u8 = 5;
+const METADATA_VERSION: u8 = 6;
/// Metadata header which includes `METADATA_VERSION`.
///
@@ -275,7 +275,7 @@ macro_rules! define_tables {
$($name: TableBuilder<$IDX, $T>),+
}
- impl TableBuilders<'tcx> {
+ impl<'tcx> TableBuilders<'tcx> {
fn encode(&self, buf: &mut Encoder) -> LazyTables<'tcx> {
LazyTables {
$($name: self.$name.encode(buf)),+
diff --git a/compiler/rustc_middle/src/hir/map/mod.rs b/compiler/rustc_middle/src/hir/map/mod.rs
index d9d0781b37a..394a1fc2270 100644
--- a/compiler/rustc_middle/src/hir/map/mod.rs
+++ b/compiler/rustc_middle/src/hir/map/mod.rs
@@ -474,7 +474,8 @@ impl<'hir> Map<'hir> {
/// Panics if `LocalDefId` does not have an associated body.
///
/// This should only be used for determining the context of a body, a return
- /// value of `Some` does not always suggest that the owner of the body is `const`.
+ /// value of `Some` does not always suggest that the owner of the body is `const`,
+ /// just that it has to be checked as if it were.
pub fn body_const_context(&self, did: LocalDefId) -> Option<ConstContext> {
let hir_id = self.local_def_id_to_hir_id(did);
let ccx = match self.body_owner_kind(hir_id) {
@@ -869,24 +870,24 @@ impl<'hir> Map<'hir> {
bug!("expected foreign mod or inlined parent, found {}", self.node_to_string(parent))
}
- pub fn expect_item(&self, id: HirId) -> &'hir Item<'hir> {
- match self.tcx.hir_owner(id.expect_owner()) {
+ pub fn expect_item(&self, id: LocalDefId) -> &'hir Item<'hir> {
+ match self.tcx.hir_owner(id) {
Some(Owner { node: OwnerNode::Item(item), .. }) => item,
- _ => bug!("expected item, found {}", self.node_to_string(id)),
+ _ => bug!("expected item, found {}", self.node_to_string(HirId::make_owner(id))),
}
}
- pub fn expect_impl_item(&self, id: HirId) -> &'hir ImplItem<'hir> {
- match self.tcx.hir_owner(id.expect_owner()) {
+ pub fn expect_impl_item(&self, id: LocalDefId) -> &'hir ImplItem<'hir> {
+ match self.tcx.hir_owner(id) {
Some(Owner { node: OwnerNode::ImplItem(item), .. }) => item,
- _ => bug!("expected impl item, found {}", self.node_to_string(id)),
+ _ => bug!("expected impl item, found {}", self.node_to_string(HirId::make_owner(id))),
}
}
- pub fn expect_trait_item(&self, id: HirId) -> &'hir TraitItem<'hir> {
- match self.tcx.hir_owner(id.expect_owner()) {
+ pub fn expect_trait_item(&self, id: LocalDefId) -> &'hir TraitItem<'hir> {
+ match self.tcx.hir_owner(id) {
Some(Owner { node: OwnerNode::TraitItem(item), .. }) => item,
- _ => bug!("expected trait item, found {}", self.node_to_string(id)),
+ _ => bug!("expected trait item, found {}", self.node_to_string(HirId::make_owner(id))),
}
}
@@ -897,10 +898,12 @@ impl<'hir> Map<'hir> {
}
}
- pub fn expect_foreign_item(&self, id: HirId) -> &'hir ForeignItem<'hir> {
- match self.tcx.hir_owner(id.expect_owner()) {
+ pub fn expect_foreign_item(&self, id: LocalDefId) -> &'hir ForeignItem<'hir> {
+ match self.tcx.hir_owner(id) {
Some(Owner { node: OwnerNode::ForeignItem(item), .. }) => item,
- _ => bug!("expected foreign item, found {}", self.node_to_string(id)),
+ _ => {
+ bug!("expected foreign item, found {}", self.node_to_string(HirId::make_owner(id)))
+ }
}
}
diff --git a/compiler/rustc_middle/src/infer/canonical.rs b/compiler/rustc_middle/src/infer/canonical.rs
index d764d45ba7e..14cff60475a 100644
--- a/compiler/rustc_middle/src/infer/canonical.rs
+++ b/compiler/rustc_middle/src/infer/canonical.rs
@@ -246,6 +246,14 @@ impl<'tcx, R> Canonical<'tcx, QueryResponse<'tcx, R>> {
}
}
+impl<'tcx, R> Canonical<'tcx, ty::ParamEnvAnd<'tcx, R>> {
+ #[inline]
+ pub fn without_const(mut self) -> Self {
+ self.value = self.value.without_const();
+ self
+ }
+}
+
impl<'tcx, V> Canonical<'tcx, V> {
/// Allows you to map the `value` of a canonical while keeping the
/// same set of bound variables.
diff --git a/compiler/rustc_middle/src/lib.rs b/compiler/rustc_middle/src/lib.rs
index 0894b805075..8590a5c2e2d 100644
--- a/compiler/rustc_middle/src/lib.rs
+++ b/compiler/rustc_middle/src/lib.rs
@@ -30,8 +30,10 @@
#![feature(bool_to_option)]
#![feature(box_patterns)]
#![feature(core_intrinsics)]
+#![feature(derive_default_enum)]
#![feature(discriminant_kind)]
#![feature(exhaustive_patterns)]
+#![feature(get_mut_unchecked)]
#![feature(if_let_guard)]
#![feature(map_first_last)]
#![feature(never_type)]
@@ -49,12 +51,11 @@
#![feature(half_open_range_patterns)]
#![feature(control_flow_enum)]
#![feature(associated_type_defaults)]
-#![feature(iter_zip)]
-#![feature(thread_local_const_init)]
#![feature(trusted_step)]
#![feature(try_blocks)]
#![feature(try_reserve_kind)]
#![feature(nonzero_ops)]
+#![feature(unwrap_infallible)]
#![recursion_limit = "512"]
#[macro_use]
diff --git a/compiler/rustc_middle/src/lint.rs b/compiler/rustc_middle/src/lint.rs
index 881b14278e9..a6432b30174 100644
--- a/compiler/rustc_middle/src/lint.rs
+++ b/compiler/rustc_middle/src/lint.rs
@@ -295,7 +295,7 @@ pub fn struct_lint_level<'s, 'd>(
Level::Allow => "-A",
Level::ForceWarn => "--force-warn",
};
- let hyphen_case_lint_name = name.replace("_", "-");
+ let hyphen_case_lint_name = name.replace('_', "-");
if lint_flag_val.as_str() == name {
sess.diag_note_once(
&mut err,
@@ -306,7 +306,7 @@ pub fn struct_lint_level<'s, 'd>(
),
);
} else {
- let hyphen_case_flag_val = lint_flag_val.as_str().replace("_", "-");
+ let hyphen_case_flag_val = lint_flag_val.as_str().replace('_', "-");
sess.diag_note_once(
&mut err,
DiagnosticMessageId::from(lint),
diff --git a/compiler/rustc_middle/src/macros.rs b/compiler/rustc_middle/src/macros.rs
index c0f2a76c19d..4e927f00acd 100644
--- a/compiler/rustc_middle/src/macros.rs
+++ b/compiler/rustc_middle/src/macros.rs
@@ -52,11 +52,11 @@ macro_rules! TrivialTypeFoldableImpls {
(for <$tcx:lifetime> { $($ty:ty,)+ }) => {
$(
impl<$tcx> $crate::ty::fold::TypeFoldable<$tcx> for $ty {
- fn super_fold_with<F: $crate::ty::fold::TypeFolder<$tcx>>(
+ fn try_super_fold_with<F: $crate::ty::fold::FallibleTypeFolder<$tcx>>(
self,
_: &mut F
- ) -> $ty {
- self
+ ) -> ::std::result::Result<$ty, F::Error> {
+ Ok(self)
}
fn super_visit_with<F: $crate::ty::fold::TypeVisitor<$tcx>>(
@@ -95,10 +95,10 @@ macro_rules! EnumTypeFoldableImpl {
impl<$($p),*> $crate::ty::fold::TypeFoldable<$tcx> for $s
$(where $($wc)*)*
{
- fn super_fold_with<V: $crate::ty::fold::TypeFolder<$tcx>>(
+ fn try_super_fold_with<V: $crate::ty::fold::FallibleTypeFolder<$tcx>>(
self,
folder: &mut V,
- ) -> Self {
+ ) -> ::std::result::Result<Self, V::Error> {
EnumTypeFoldableImpl!(@FoldVariants(self, folder) input($($variants)*) output())
}
@@ -112,9 +112,9 @@ macro_rules! EnumTypeFoldableImpl {
};
(@FoldVariants($this:expr, $folder:expr) input() output($($output:tt)*)) => {
- match $this {
+ Ok(match $this {
$($output)*
- }
+ })
};
(@FoldVariants($this:expr, $folder:expr)
@@ -126,7 +126,7 @@ macro_rules! EnumTypeFoldableImpl {
output(
$variant ( $($variant_arg),* ) => {
$variant (
- $($crate::ty::fold::TypeFoldable::fold_with($variant_arg, $folder)),*
+ $($crate::ty::fold::TypeFoldable::try_fold_with($variant_arg, $folder)?),*
)
}
$($output)*
@@ -145,7 +145,7 @@ macro_rules! EnumTypeFoldableImpl {
$variant {
$($variant_arg: $crate::ty::fold::TypeFoldable::fold_with(
$variant_arg, $folder
- )),* }
+ )?),* }
}
$($output)*
)
diff --git a/compiler/rustc_middle/src/middle/region.rs b/compiler/rustc_middle/src/middle/region.rs
index 605e0bc2e63..39ca41c92ff 100644
--- a/compiler/rustc_middle/src/middle/region.rs
+++ b/compiler/rustc_middle/src/middle/region.rs
@@ -7,13 +7,12 @@
//! [rustc dev guide]: https://rustc-dev-guide.rust-lang.org/borrow_check.html
use crate::ty::TyCtxt;
-use rustc_hir as hir;
-use rustc_hir::Node;
-use rustc_query_system::ich::{NodeIdHashingMode, StableHashingContext};
-
use rustc_data_structures::fx::FxHashMap;
use rustc_data_structures::stable_hasher::{HashStable, StableHasher};
+use rustc_hir as hir;
+use rustc_hir::Node;
use rustc_macros::HashStable;
+use rustc_query_system::ich::{NodeIdHashingMode, StableHashingContext};
use rustc_span::{Span, DUMMY_SP};
use std::fmt;
@@ -210,11 +209,6 @@ pub struct ScopeTree {
/// If not empty, this body is the root of this region hierarchy.
pub root_body: Option<hir::HirId>,
- /// The parent of the root body owner, if the latter is an
- /// an associated const or method, as impls/traits can also
- /// have lifetime parameters free in this body.
- pub root_parent: Option<hir::HirId>,
-
/// Maps from a scope ID to the enclosing scope id;
/// this is usually corresponding to the lexical nesting, though
/// in the case of closures the parent scope is the innermost
@@ -445,7 +439,6 @@ impl<'a> HashStable<StableHashingContext<'a>> for ScopeTree {
fn hash_stable(&self, hcx: &mut StableHashingContext<'a>, hasher: &mut StableHasher) {
let ScopeTree {
root_body,
- root_parent,
ref body_expr_count,
ref parent_map,
ref var_map,
@@ -455,8 +448,7 @@ impl<'a> HashStable<StableHashingContext<'a>> for ScopeTree {
} = *self;
hcx.with_node_id_hashing_mode(NodeIdHashingMode::HashDefPath, |hcx| {
- root_body.hash_stable(hcx, hasher);
- root_parent.hash_stable(hcx, hasher);
+ root_body.hash_stable(hcx, hasher)
});
body_expr_count.hash_stable(hcx, hasher);
diff --git a/compiler/rustc_middle/src/middle/stability.rs b/compiler/rustc_middle/src/middle/stability.rs
index 597622b2ebf..8a5fc5feeb7 100644
--- a/compiler/rustc_middle/src/middle/stability.rs
+++ b/compiler/rustc_middle/src/middle/stability.rs
@@ -3,7 +3,7 @@
pub use self::StabilityLevel::*;
-use crate::ty::{self, TyCtxt};
+use crate::ty::{self, DefIdTree, TyCtxt};
use rustc_ast::NodeId;
use rustc_attr::{self as attr, ConstStability, Deprecation, Stability};
use rustc_data_structures::fx::{FxHashMap, FxHashSet};
@@ -90,6 +90,7 @@ pub fn report_unstable(
feature: Symbol,
reason: Option<Symbol>,
issue: Option<NonZeroU32>,
+ suggestion: Option<(Span, String, String, Applicability)>,
is_soft: bool,
span: Span,
soft_handler: impl FnOnce(&'static Lint, Span, &str),
@@ -116,8 +117,12 @@ pub fn report_unstable(
if is_soft {
soft_handler(SOFT_UNSTABLE, span, &msg)
} else {
- feature_err_issue(&sess.parse_sess, feature, span, GateIssue::Library(issue), &msg)
- .emit();
+ let mut err =
+ feature_err_issue(&sess.parse_sess, feature, span, GateIssue::Library(issue), &msg);
+ if let Some((inner_types, ref msg, sugg, applicability)) = suggestion {
+ err.span_suggestion(inner_types, msg, sugg, applicability);
+ }
+ err.emit();
}
}
}
@@ -271,7 +276,13 @@ pub enum EvalResult {
Allow,
/// We cannot use the item because it is unstable and we did not provide the
/// corresponding feature gate.
- Deny { feature: Symbol, reason: Option<Symbol>, issue: Option<NonZeroU32>, is_soft: bool },
+ Deny {
+ feature: Symbol,
+ reason: Option<Symbol>,
+ issue: Option<NonZeroU32>,
+ suggestion: Option<(Span, String, String, Applicability)>,
+ is_soft: bool,
+ },
/// The item does not have the `#[stable]` or `#[unstable]` marker assigned.
Unmarked,
}
@@ -292,6 +303,32 @@ fn skip_stability_check_due_to_privacy(tcx: TyCtxt<'_>, def_id: DefId) -> bool {
}
}
+// See issue #83250.
+fn suggestion_for_allocator_api(
+ tcx: TyCtxt<'_>,
+ def_id: DefId,
+ span: Span,
+ feature: Symbol,
+) -> Option<(Span, String, String, Applicability)> {
+ if feature == sym::allocator_api {
+ if let Some(trait_) = tcx.parent(def_id) {
+ if tcx.is_diagnostic_item(sym::Vec, trait_) {
+ let sm = tcx.sess.parse_sess.source_map();
+ let inner_types = sm.span_extend_to_prev_char(span, '<', true);
+ if let Ok(snippet) = sm.span_to_snippet(inner_types) {
+ return Some((
+ inner_types,
+ "consider wrapping the inner types in tuple".to_string(),
+ format!("({})", snippet),
+ Applicability::MaybeIncorrect,
+ ));
+ }
+ }
+ }
+ }
+ None
+}
+
impl<'tcx> TyCtxt<'tcx> {
/// Evaluates the stability of an item.
///
@@ -406,7 +443,8 @@ impl<'tcx> TyCtxt<'tcx> {
}
}
- EvalResult::Deny { feature, reason, issue, is_soft }
+ let suggestion = suggestion_for_allocator_api(self, def_id, span, feature);
+ EvalResult::Deny { feature, reason, issue, suggestion, is_soft }
}
Some(_) => {
// Stable APIs are always ok to call and deprecated APIs are
@@ -457,9 +495,16 @@ impl<'tcx> TyCtxt<'tcx> {
};
match self.eval_stability(def_id, id, span, method_span) {
EvalResult::Allow => {}
- EvalResult::Deny { feature, reason, issue, is_soft } => {
- report_unstable(self.sess, feature, reason, issue, is_soft, span, soft_handler)
- }
+ EvalResult::Deny { feature, reason, issue, suggestion, is_soft } => report_unstable(
+ self.sess,
+ feature,
+ reason,
+ issue,
+ suggestion,
+ is_soft,
+ span,
+ soft_handler,
+ ),
EvalResult::Unmarked => unmarked(span, def_id),
}
}
diff --git a/compiler/rustc_middle/src/mir/coverage.rs b/compiler/rustc_middle/src/mir/coverage.rs
index ddb1a84fe7b..640d3a5a02b 100644
--- a/compiler/rustc_middle/src/mir/coverage.rs
+++ b/compiler/rustc_middle/src/mir/coverage.rs
@@ -21,9 +21,9 @@ rustc_index::newtype_index! {
impl ExpressionOperandId {
/// An expression operand for a "zero counter", as described in the following references:
///
- /// * <https://github.com/rust-lang/llvm-project/blob/rustc/11.0-2020-10-12/llvm/docs/CoverageMappingFormat.rst#counter>
- /// * <https://github.com/rust-lang/llvm-project/blob/rustc/11.0-2020-10-12/llvm/docs/CoverageMappingFormat.rst#tag>
- /// * <https://github.com/rust-lang/llvm-project/blob/rustc/11.0-2020-10-12/llvm/docs/CoverageMappingFormat.rst#counter-expressions>
+ /// * <https://github.com/rust-lang/llvm-project/blob/rustc/13.0-2021-09-30/llvm/docs/CoverageMappingFormat.rst#counter>
+ /// * <https://github.com/rust-lang/llvm-project/blob/rustc/13.0-2021-09-30/llvm/docs/CoverageMappingFormat.rst#tag>
+ /// * <https://github.com/rust-lang/llvm-project/blob/rustc/13.0-2021-09-30/llvm/docs/CoverageMappingFormat.rst#counter-expressions>
///
/// This operand can be used to count two or more separate code regions with a single counter,
/// if they run sequentially with no branches, by injecting the `Counter` in a `BasicBlock` for
diff --git a/compiler/rustc_middle/src/mir/generic_graphviz.rs b/compiler/rustc_middle/src/mir/generic_graphviz.rs
index 21c18b28e25..c907680bda1 100644
--- a/compiler/rustc_middle/src/mir/generic_graphviz.rs
+++ b/compiler/rustc_middle/src/mir/generic_graphviz.rs
@@ -126,7 +126,7 @@ impl<
write!(
w,
r#"<tr><td align="left" balign="left">{}</td></tr>"#,
- dot::escape_html(&section).replace("\n", "<br/>")
+ dot::escape_html(&section).replace('\n', "<br/>")
)?;
}
@@ -147,7 +147,7 @@ impl<
let src = self.node(source);
let trg = self.node(target);
let escaped_edge_label = if let Some(edge_label) = edge_labels.get(index) {
- dot::escape_html(edge_label).replace("\n", r#"<br align="left"/>"#)
+ dot::escape_html(edge_label).replace('\n', r#"<br align="left"/>"#)
} else {
"".to_owned()
};
diff --git a/compiler/rustc_middle/src/mir/interpret/error.rs b/compiler/rustc_middle/src/mir/interpret/error.rs
index 7a51bb4a1f3..8e4a17bfa65 100644
--- a/compiler/rustc_middle/src/mir/interpret/error.rs
+++ b/compiler/rustc_middle/src/mir/interpret/error.rs
@@ -492,9 +492,6 @@ impl dyn MachineStopType {
}
}
-#[cfg(all(target_arch = "x86_64", target_pointer_width = "64"))]
-static_assert_size!(InterpError<'_>, 64);
-
pub enum InterpError<'tcx> {
/// The program caused undefined behavior.
UndefinedBehavior(UndefinedBehaviorInfo<'tcx>),
diff --git a/compiler/rustc_middle/src/mir/interpret/queries.rs b/compiler/rustc_middle/src/mir/interpret/queries.rs
index c63613ae3af..f9831855633 100644
--- a/compiler/rustc_middle/src/mir/interpret/queries.rs
+++ b/compiler/rustc_middle/src/mir/interpret/queries.rs
@@ -64,6 +64,7 @@ impl<'tcx> TyCtxt<'tcx> {
cid: GlobalId<'tcx>,
span: Option<Span>,
) -> EvalToConstValueResult<'tcx> {
+ let param_env = param_env.with_const();
// Const-eval shouldn't depend on lifetimes at all, so we can erase them, which should
// improve caching of queries.
let inputs = self.erase_regions(param_env.and(cid));
@@ -92,6 +93,7 @@ impl<'tcx> TyCtxt<'tcx> {
gid: GlobalId<'tcx>,
param_env: ty::ParamEnv<'tcx>,
) -> Result<&'tcx mir::Allocation, ErrorHandled> {
+ let param_env = param_env.with_const();
trace!("eval_to_allocation: Need to compute {:?}", gid);
let raw_const = self.eval_to_allocation_raw(param_env.and(gid))?;
Ok(self.global_alloc(raw_const.alloc_id).unwrap_memory())
diff --git a/compiler/rustc_middle/src/mir/mod.rs b/compiler/rustc_middle/src/mir/mod.rs
index 253ac266bed..afd8083dfe4 100644
--- a/compiler/rustc_middle/src/mir/mod.rs
+++ b/compiler/rustc_middle/src/mir/mod.rs
@@ -7,15 +7,17 @@ use crate::mir::interpret::{Allocation, ConstValue, GlobalAlloc, Scalar};
use crate::mir::visit::MirVisitable;
use crate::ty::adjustment::PointerCast;
use crate::ty::codec::{TyDecoder, TyEncoder};
-use crate::ty::fold::{TypeFoldable, TypeFolder, TypeVisitor};
+use crate::ty::fold::{FallibleTypeFolder, TypeFoldable, TypeVisitor};
use crate::ty::print::{FmtPrinter, Printer};
use crate::ty::subst::{Subst, SubstsRef};
use crate::ty::{self, List, Ty, TyCtxt};
use crate::ty::{AdtDef, InstanceDef, Region, ScalarInt, UserTypeAnnotationIndex};
+
use rustc_hir::def::{CtorKind, Namespace};
use rustc_hir::def_id::{DefId, CRATE_DEF_INDEX};
use rustc_hir::{self, GeneratorKind};
use rustc_hir::{self as hir, HirId};
+use rustc_session::Session;
use rustc_target::abi::{Size, VariantIdx};
use polonius_engine::Atom;
@@ -29,6 +31,9 @@ use rustc_serialize::{Decodable, Encodable};
use rustc_span::symbol::Symbol;
use rustc_span::{Span, DUMMY_SP};
use rustc_target::asm::InlineAsmRegOrRegClass;
+
+use either::Either;
+
use std::borrow::Cow;
use std::convert::TryInto;
use std::fmt::{self, Debug, Display, Formatter, Write};
@@ -99,7 +104,21 @@ pub trait MirPass<'tcx> {
}
}
+ /// Returns `true` if this pass is enabled with the current combination of compiler flags.
+ fn is_enabled(&self, _sess: &Session) -> bool {
+ true
+ }
+
fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>);
+
+ /// If this pass causes the MIR to enter a new phase, return that phase.
+ fn phase_change(&self) -> Option<MirPhase> {
+ None
+ }
+
+ fn is_mir_dump_enabled(&self) -> bool {
+ true
+ }
}
/// The various "big phases" that MIR goes through.
@@ -488,6 +507,16 @@ impl<'tcx> Body<'tcx> {
Location { block: bb, statement_index: self[bb].statements.len() }
}
+ pub fn stmt_at(&self, location: Location) -> Either<&Statement<'tcx>, &Terminator<'tcx>> {
+ let Location { block, statement_index } = location;
+ let block_data = &self.basic_blocks[block];
+ block_data
+ .statements
+ .get(statement_index)
+ .map(Either::Left)
+ .unwrap_or_else(|| Either::Right(block_data.terminator()))
+ }
+
#[inline]
pub fn predecessors(&self) -> &Predecessors {
self.predecessor_cache.compute(&self.basic_blocks)
@@ -1504,6 +1533,7 @@ impl Statement<'_> {
}
/// Changes a statement to a nop and returns the original statement.
+ #[must_use = "If you don't need the statement, use `make_nop` instead"]
pub fn replace_nop(&mut self) -> Self {
Statement {
source_info: self.source_info,
@@ -1803,6 +1833,16 @@ impl<V, T> ProjectionElem<V, T> {
| Self::Downcast(_, _) => false,
}
}
+
+ /// Returns `true` if this is a `Downcast` projection with the given `VariantIdx`.
+ pub fn is_downcast_to(&self, v: VariantIdx) -> bool {
+ matches!(*self, Self::Downcast(_, x) if x == v)
+ }
+
+ /// Returns `true` if this is a `Field` projection with the given index.
+ pub fn is_field_to(&self, f: Field) -> bool {
+ matches!(*self, Self::Field(x, _) if x == f)
+ }
}
/// Alias for projections as they appear in places, where the base is a place
@@ -2246,8 +2286,12 @@ pub enum BinOp {
/// The `*` operator (multiplication)
Mul,
/// The `/` operator (division)
+ ///
+ /// Division by zero is UB.
Div,
/// The `%` operator (modulus)
+ ///
+ /// Using zero as the modulus (second operand) is UB.
Rem,
/// The `^` operator (bitwise xor)
BitXor,
@@ -2256,8 +2300,12 @@ pub enum BinOp {
/// The `|` operator (bitwise or)
BitOr,
/// The `<<` operator (shift left)
+ ///
+ /// The offset is truncated to the size of the first operand before shifting.
Shl,
/// The `>>` operator (shift right)
+ ///
+ /// The offset is truncated to the size of the first operand before shifting.
Shr,
/// The `==` operator (equality)
Eq,
@@ -2752,11 +2800,14 @@ impl UserTypeProjection {
TrivialTypeFoldableAndLiftImpls! { ProjectionKind, }
impl<'tcx> TypeFoldable<'tcx> for UserTypeProjection {
- fn super_fold_with<F: TypeFolder<'tcx>>(self, folder: &mut F) -> Self {
- UserTypeProjection {
- base: self.base.fold_with(folder),
- projs: self.projs.fold_with(folder),
- }
+ fn try_super_fold_with<F: FallibleTypeFolder<'tcx>>(
+ self,
+ folder: &mut F,
+ ) -> Result<Self, F::Error> {
+ Ok(UserTypeProjection {
+ base: self.base.try_fold_with(folder)?,
+ projs: self.projs.try_fold_with(folder)?,
+ })
}
fn super_visit_with<Vs: TypeVisitor<'tcx>>(
diff --git a/compiler/rustc_middle/src/mir/mono.rs b/compiler/rustc_middle/src/mir/mono.rs
index 06b42320049..f48e27e02cd 100644
--- a/compiler/rustc_middle/src/mir/mono.rs
+++ b/compiler/rustc_middle/src/mir/mono.rs
@@ -530,6 +530,6 @@ impl CodegenUnitNameBuilder<'tcx> {
write!(cgu_name, ".{}", special_suffix).unwrap();
}
- Symbol::intern(&cgu_name[..])
+ Symbol::intern(&cgu_name)
}
}
diff --git a/compiler/rustc_middle/src/mir/spanview.rs b/compiler/rustc_middle/src/mir/spanview.rs
index 1260c691e78..507f9971981 100644
--- a/compiler/rustc_middle/src/mir/spanview.rs
+++ b/compiler/rustc_middle/src/mir/spanview.rs
@@ -681,13 +681,13 @@ fn hir_body<'tcx>(tcx: TyCtxt<'tcx>, def_id: DefId) -> Option<&'tcx rustc_hir::B
}
fn escape_html(s: &str) -> String {
- s.replace("&", "&amp;").replace("<", "&lt;").replace(">", "&gt;")
+ s.replace('&', "&amp;").replace('<', "&lt;").replace('>', "&gt;")
}
fn escape_attr(s: &str) -> String {
- s.replace("&", "&amp;")
- .replace("\"", "&quot;")
- .replace("'", "&#39;")
- .replace("<", "&lt;")
- .replace(">", "&gt;")
+ s.replace('&', "&amp;")
+ .replace('\"', "&quot;")
+ .replace('\'', "&#39;")
+ .replace('<', "&lt;")
+ .replace('>', "&gt;")
}
diff --git a/compiler/rustc_middle/src/mir/terminator.rs b/compiler/rustc_middle/src/mir/terminator.rs
index e78b6fd092d..51e4afaf220 100644
--- a/compiler/rustc_middle/src/mir/terminator.rs
+++ b/compiler/rustc_middle/src/mir/terminator.rs
@@ -78,6 +78,13 @@ impl SwitchTargets {
pub fn all_targets_mut(&mut self) -> &mut [BasicBlock] {
&mut self.targets
}
+
+ /// Finds the `BasicBlock` to which this `SwitchInt` will branch given the
+ /// specific value. This cannot fail, as it'll return the `otherwise`
+ /// branch if there's not a specific match for the value.
+ pub fn target_for_value(&self, value: u128) -> BasicBlock {
+ self.iter().find_map(|(v, t)| (v == value).then_some(t)).unwrap_or_else(|| self.otherwise())
+ }
}
pub struct SwitchTargetsIter<'a> {
@@ -260,6 +267,10 @@ pub enum TerminatorKind<'tcx> {
/// Destination block after the inline assembly returns, unless it is
/// diverging (InlineAsmOptions::NORETURN).
destination: Option<BasicBlock>,
+
+ /// Cleanup to be done if the inline assembly unwinds. This is present
+ /// if and only if InlineAsmOptions::MAY_UNWIND is set.
+ cleanup: Option<BasicBlock>,
},
}
#[derive(Clone, Debug, TyEncodable, TyDecodable, HashStable)]
@@ -309,7 +320,7 @@ impl<'tcx> TerminatorKind<'tcx> {
| Return
| Unreachable
| Call { destination: None, cleanup: None, .. }
- | InlineAsm { destination: None, .. } => None.into_iter().chain(&[]),
+ | InlineAsm { destination: None, cleanup: None, .. } => None.into_iter().chain(&[]),
Goto { target: ref t }
| Call { destination: None, cleanup: Some(ref t), .. }
| Call { destination: Some((_, ref t)), cleanup: None, .. }
@@ -318,16 +329,20 @@ impl<'tcx> TerminatorKind<'tcx> {
| Drop { target: ref t, unwind: None, .. }
| Assert { target: ref t, cleanup: None, .. }
| FalseUnwind { real_target: ref t, unwind: None }
- | InlineAsm { destination: Some(ref t), .. } => Some(t).into_iter().chain(&[]),
+ | InlineAsm { destination: Some(ref t), cleanup: None, .. }
+ | InlineAsm { destination: None, cleanup: Some(ref t), .. } => {
+ Some(t).into_iter().chain(&[])
+ }
Call { destination: Some((_, ref t)), cleanup: Some(ref u), .. }
| Yield { resume: ref t, drop: Some(ref u), .. }
| DropAndReplace { target: ref t, unwind: Some(ref u), .. }
| Drop { target: ref t, unwind: Some(ref u), .. }
| Assert { target: ref t, cleanup: Some(ref u), .. }
- | FalseUnwind { real_target: ref t, unwind: Some(ref u) } => {
+ | FalseUnwind { real_target: ref t, unwind: Some(ref u) }
+ | InlineAsm { destination: Some(ref t), cleanup: Some(ref u), .. } => {
Some(t).into_iter().chain(slice::from_ref(u))
}
- SwitchInt { ref targets, .. } => None.into_iter().chain(&targets.targets[..]),
+ SwitchInt { ref targets, .. } => None.into_iter().chain(&targets.targets),
FalseEdge { ref real_target, ref imaginary_target } => {
Some(real_target).into_iter().chain(slice::from_ref(imaginary_target))
}
@@ -343,7 +358,7 @@ impl<'tcx> TerminatorKind<'tcx> {
| Return
| Unreachable
| Call { destination: None, cleanup: None, .. }
- | InlineAsm { destination: None, .. } => None.into_iter().chain(&mut []),
+ | InlineAsm { destination: None, cleanup: None, .. } => None.into_iter().chain(&mut []),
Goto { target: ref mut t }
| Call { destination: None, cleanup: Some(ref mut t), .. }
| Call { destination: Some((_, ref mut t)), cleanup: None, .. }
@@ -352,16 +367,20 @@ impl<'tcx> TerminatorKind<'tcx> {
| Drop { target: ref mut t, unwind: None, .. }
| Assert { target: ref mut t, cleanup: None, .. }
| FalseUnwind { real_target: ref mut t, unwind: None }
- | InlineAsm { destination: Some(ref mut t), .. } => Some(t).into_iter().chain(&mut []),
+ | InlineAsm { destination: Some(ref mut t), cleanup: None, .. }
+ | InlineAsm { destination: None, cleanup: Some(ref mut t), .. } => {
+ Some(t).into_iter().chain(&mut [])
+ }
Call { destination: Some((_, ref mut t)), cleanup: Some(ref mut u), .. }
| Yield { resume: ref mut t, drop: Some(ref mut u), .. }
| DropAndReplace { target: ref mut t, unwind: Some(ref mut u), .. }
| Drop { target: ref mut t, unwind: Some(ref mut u), .. }
| Assert { target: ref mut t, cleanup: Some(ref mut u), .. }
- | FalseUnwind { real_target: ref mut t, unwind: Some(ref mut u) } => {
+ | FalseUnwind { real_target: ref mut t, unwind: Some(ref mut u) }
+ | InlineAsm { destination: Some(ref mut t), cleanup: Some(ref mut u), .. } => {
Some(t).into_iter().chain(slice::from_mut(u))
}
- SwitchInt { ref mut targets, .. } => None.into_iter().chain(&mut targets.targets[..]),
+ SwitchInt { ref mut targets, .. } => None.into_iter().chain(&mut targets.targets),
FalseEdge { ref mut real_target, ref mut imaginary_target } => {
Some(real_target).into_iter().chain(slice::from_mut(imaginary_target))
}
@@ -378,13 +397,13 @@ impl<'tcx> TerminatorKind<'tcx> {
| TerminatorKind::GeneratorDrop
| TerminatorKind::Yield { .. }
| TerminatorKind::SwitchInt { .. }
- | TerminatorKind::FalseEdge { .. }
- | TerminatorKind::InlineAsm { .. } => None,
+ | TerminatorKind::FalseEdge { .. } => None,
TerminatorKind::Call { cleanup: ref unwind, .. }
| TerminatorKind::Assert { cleanup: ref unwind, .. }
| TerminatorKind::DropAndReplace { ref unwind, .. }
| TerminatorKind::Drop { ref unwind, .. }
- | TerminatorKind::FalseUnwind { ref unwind, .. } => Some(unwind),
+ | TerminatorKind::FalseUnwind { ref unwind, .. }
+ | TerminatorKind::InlineAsm { cleanup: ref unwind, .. } => Some(unwind),
}
}
@@ -398,13 +417,13 @@ impl<'tcx> TerminatorKind<'tcx> {
| TerminatorKind::GeneratorDrop
| TerminatorKind::Yield { .. }
| TerminatorKind::SwitchInt { .. }
- | TerminatorKind::FalseEdge { .. }
- | TerminatorKind::InlineAsm { .. } => None,
+ | TerminatorKind::FalseEdge { .. } => None,
TerminatorKind::Call { cleanup: ref mut unwind, .. }
| TerminatorKind::Assert { cleanup: ref mut unwind, .. }
| TerminatorKind::DropAndReplace { ref mut unwind, .. }
| TerminatorKind::Drop { ref mut unwind, .. }
- | TerminatorKind::FalseUnwind { ref mut unwind, .. } => Some(unwind),
+ | TerminatorKind::FalseUnwind { ref mut unwind, .. }
+ | TerminatorKind::InlineAsm { cleanup: ref mut unwind, .. } => Some(unwind),
}
}
@@ -583,8 +602,12 @@ impl<'tcx> TerminatorKind<'tcx> {
FalseEdge { .. } => vec!["real".into(), "imaginary".into()],
FalseUnwind { unwind: Some(_), .. } => vec!["real".into(), "cleanup".into()],
FalseUnwind { unwind: None, .. } => vec!["real".into()],
- InlineAsm { destination: Some(_), .. } => vec!["".into()],
- InlineAsm { destination: None, .. } => vec![],
+ InlineAsm { destination: Some(_), cleanup: Some(_), .. } => {
+ vec!["return".into(), "unwind".into()]
+ }
+ InlineAsm { destination: Some(_), cleanup: None, .. } => vec!["return".into()],
+ InlineAsm { destination: None, cleanup: Some(_), .. } => vec!["unwind".into()],
+ InlineAsm { destination: None, cleanup: None, .. } => vec![],
}
}
}
diff --git a/compiler/rustc_middle/src/mir/type_foldable.rs b/compiler/rustc_middle/src/mir/type_foldable.rs
index b7201f7acf3..901f3bf4f7d 100644
--- a/compiler/rustc_middle/src/mir/type_foldable.rs
+++ b/compiler/rustc_middle/src/mir/type_foldable.rs
@@ -16,37 +16,42 @@ TrivialTypeFoldableAndLiftImpls! {
}
impl<'tcx> TypeFoldable<'tcx> for Terminator<'tcx> {
- fn super_fold_with<F: TypeFolder<'tcx>>(self, folder: &mut F) -> Self {
+ fn try_super_fold_with<F: FallibleTypeFolder<'tcx>>(
+ self,
+ folder: &mut F,
+ ) -> Result<Self, F::Error> {
use crate::mir::TerminatorKind::*;
let kind = match self.kind {
Goto { target } => Goto { target },
SwitchInt { discr, switch_ty, targets } => SwitchInt {
- discr: discr.fold_with(folder),
- switch_ty: switch_ty.fold_with(folder),
+ discr: discr.try_fold_with(folder)?,
+ switch_ty: switch_ty.try_fold_with(folder)?,
targets,
},
Drop { place, target, unwind } => {
- Drop { place: place.fold_with(folder), target, unwind }
+ Drop { place: place.try_fold_with(folder)?, target, unwind }
}
DropAndReplace { place, value, target, unwind } => DropAndReplace {
- place: place.fold_with(folder),
- value: value.fold_with(folder),
+ place: place.try_fold_with(folder)?,
+ value: value.try_fold_with(folder)?,
target,
unwind,
},
Yield { value, resume, resume_arg, drop } => Yield {
- value: value.fold_with(folder),
+ value: value.try_fold_with(folder)?,
resume,
- resume_arg: resume_arg.fold_with(folder),
+ resume_arg: resume_arg.try_fold_with(folder)?,
drop,
},
Call { func, args, destination, cleanup, from_hir_call, fn_span } => {
- let dest = destination.map(|(loc, dest)| (loc.fold_with(folder), dest));
+ let dest = destination
+ .map(|(loc, dest)| (loc.try_fold_with(folder).map(|loc| (loc, dest))))
+ .transpose()?;
Call {
- func: func.fold_with(folder),
- args: args.fold_with(folder),
+ func: func.try_fold_with(folder)?,
+ args: args.try_fold_with(folder)?,
destination: dest,
cleanup,
from_hir_call,
@@ -56,16 +61,19 @@ impl<'tcx> TypeFoldable<'tcx> for Terminator<'tcx> {
Assert { cond, expected, msg, target, cleanup } => {
use AssertKind::*;
let msg = match msg {
- BoundsCheck { len, index } => {
- BoundsCheck { len: len.fold_with(folder), index: index.fold_with(folder) }
+ BoundsCheck { len, index } => BoundsCheck {
+ len: len.try_fold_with(folder)?,
+ index: index.try_fold_with(folder)?,
+ },
+ Overflow(op, l, r) => {
+ Overflow(op, l.try_fold_with(folder)?, r.try_fold_with(folder)?)
}
- Overflow(op, l, r) => Overflow(op, l.fold_with(folder), r.fold_with(folder)),
- OverflowNeg(op) => OverflowNeg(op.fold_with(folder)),
- DivisionByZero(op) => DivisionByZero(op.fold_with(folder)),
- RemainderByZero(op) => RemainderByZero(op.fold_with(folder)),
+ OverflowNeg(op) => OverflowNeg(op.try_fold_with(folder)?),
+ DivisionByZero(op) => DivisionByZero(op.try_fold_with(folder)?),
+ RemainderByZero(op) => RemainderByZero(op.try_fold_with(folder)?),
ResumedAfterReturn(_) | ResumedAfterPanic(_) => msg,
};
- Assert { cond: cond.fold_with(folder), expected, msg, target, cleanup }
+ Assert { cond: cond.try_fold_with(folder)?, expected, msg, target, cleanup }
}
GeneratorDrop => GeneratorDrop,
Resume => Resume,
@@ -76,15 +84,18 @@ impl<'tcx> TypeFoldable<'tcx> for Terminator<'tcx> {
FalseEdge { real_target, imaginary_target }
}
FalseUnwind { real_target, unwind } => FalseUnwind { real_target, unwind },
- InlineAsm { template, operands, options, line_spans, destination } => InlineAsm {
- template,
- operands: operands.fold_with(folder),
- options,
- line_spans,
- destination,
- },
+ InlineAsm { template, operands, options, line_spans, destination, cleanup } => {
+ InlineAsm {
+ template,
+ operands: operands.try_fold_with(folder)?,
+ options,
+ line_spans,
+ destination,
+ cleanup,
+ }
+ }
};
- Terminator { source_info: self.source_info, kind }
+ Ok(Terminator { source_info: self.source_info, kind })
}
fn super_visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> ControlFlow<V::BreakTy> {
@@ -140,8 +151,8 @@ impl<'tcx> TypeFoldable<'tcx> for Terminator<'tcx> {
}
impl<'tcx> TypeFoldable<'tcx> for GeneratorKind {
- fn super_fold_with<F: TypeFolder<'tcx>>(self, _: &mut F) -> Self {
- self
+ fn try_super_fold_with<F: FallibleTypeFolder<'tcx>>(self, _: &mut F) -> Result<Self, F::Error> {
+ Ok(self)
}
fn super_visit_with<V: TypeVisitor<'tcx>>(&self, _: &mut V) -> ControlFlow<V::BreakTy> {
@@ -150,8 +161,14 @@ impl<'tcx> TypeFoldable<'tcx> for GeneratorKind {
}
impl<'tcx> TypeFoldable<'tcx> for Place<'tcx> {
- fn super_fold_with<F: TypeFolder<'tcx>>(self, folder: &mut F) -> Self {
- Place { local: self.local.fold_with(folder), projection: self.projection.fold_with(folder) }
+ fn try_super_fold_with<F: FallibleTypeFolder<'tcx>>(
+ self,
+ folder: &mut F,
+ ) -> Result<Self, F::Error> {
+ Ok(Place {
+ local: self.local.try_fold_with(folder)?,
+ projection: self.projection.try_fold_with(folder)?,
+ })
}
fn super_visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> ControlFlow<V::BreakTy> {
@@ -161,7 +178,10 @@ impl<'tcx> TypeFoldable<'tcx> for Place<'tcx> {
}
impl<'tcx> TypeFoldable<'tcx> for &'tcx ty::List<PlaceElem<'tcx>> {
- fn super_fold_with<F: TypeFolder<'tcx>>(self, folder: &mut F) -> Self {
+ fn try_super_fold_with<F: FallibleTypeFolder<'tcx>>(
+ self,
+ folder: &mut F,
+ ) -> Result<Self, F::Error> {
ty::util::fold_list(self, folder, |tcx, v| tcx.intern_place_elems(v))
}
@@ -171,47 +191,57 @@ impl<'tcx> TypeFoldable<'tcx> for &'tcx ty::List<PlaceElem<'tcx>> {
}
impl<'tcx> TypeFoldable<'tcx> for Rvalue<'tcx> {
- fn super_fold_with<F: TypeFolder<'tcx>>(self, folder: &mut F) -> Self {
+ fn try_super_fold_with<F: FallibleTypeFolder<'tcx>>(
+ self,
+ folder: &mut F,
+ ) -> Result<Self, F::Error> {
use crate::mir::Rvalue::*;
- match self {
- Use(op) => Use(op.fold_with(folder)),
- Repeat(op, len) => Repeat(op.fold_with(folder), len.fold_with(folder)),
- ThreadLocalRef(did) => ThreadLocalRef(did.fold_with(folder)),
- Ref(region, bk, place) => Ref(region.fold_with(folder), bk, place.fold_with(folder)),
- AddressOf(mutability, place) => AddressOf(mutability, place.fold_with(folder)),
- Len(place) => Len(place.fold_with(folder)),
- Cast(kind, op, ty) => Cast(kind, op.fold_with(folder), ty.fold_with(folder)),
- BinaryOp(op, box (rhs, lhs)) => {
- BinaryOp(op, Box::new((rhs.fold_with(folder), lhs.fold_with(folder))))
+ Ok(match self {
+ Use(op) => Use(op.try_fold_with(folder)?),
+ Repeat(op, len) => Repeat(op.try_fold_with(folder)?, len.try_fold_with(folder)?),
+ ThreadLocalRef(did) => ThreadLocalRef(did.try_fold_with(folder)?),
+ Ref(region, bk, place) => {
+ Ref(region.try_fold_with(folder)?, bk, place.try_fold_with(folder)?)
}
- CheckedBinaryOp(op, box (rhs, lhs)) => {
- CheckedBinaryOp(op, Box::new((rhs.fold_with(folder), lhs.fold_with(folder))))
+ AddressOf(mutability, place) => AddressOf(mutability, place.try_fold_with(folder)?),
+ Len(place) => Len(place.try_fold_with(folder)?),
+ Cast(kind, op, ty) => Cast(kind, op.try_fold_with(folder)?, ty.try_fold_with(folder)?),
+ BinaryOp(op, box (rhs, lhs)) => {
+ BinaryOp(op, Box::new((rhs.try_fold_with(folder)?, lhs.try_fold_with(folder)?)))
}
- UnaryOp(op, val) => UnaryOp(op, val.fold_with(folder)),
- Discriminant(place) => Discriminant(place.fold_with(folder)),
- NullaryOp(op, ty) => NullaryOp(op, ty.fold_with(folder)),
+ CheckedBinaryOp(op, box (rhs, lhs)) => CheckedBinaryOp(
+ op,
+ Box::new((rhs.try_fold_with(folder)?, lhs.try_fold_with(folder)?)),
+ ),
+ UnaryOp(op, val) => UnaryOp(op, val.try_fold_with(folder)?),
+ Discriminant(place) => Discriminant(place.try_fold_with(folder)?),
+ NullaryOp(op, ty) => NullaryOp(op, ty.try_fold_with(folder)?),
Aggregate(kind, fields) => {
- let kind = kind.map_id(|kind| match kind {
- AggregateKind::Array(ty) => AggregateKind::Array(ty.fold_with(folder)),
- AggregateKind::Tuple => AggregateKind::Tuple,
- AggregateKind::Adt(def, v, substs, user_ty, n) => AggregateKind::Adt(
- def,
- v,
- substs.fold_with(folder),
- user_ty.fold_with(folder),
- n,
- ),
- AggregateKind::Closure(id, substs) => {
- AggregateKind::Closure(id, substs.fold_with(folder))
- }
- AggregateKind::Generator(id, substs, movablity) => {
- AggregateKind::Generator(id, substs.fold_with(folder), movablity)
- }
- });
- Aggregate(kind, fields.fold_with(folder))
+ let kind = kind.try_map_id(|kind| {
+ Ok(match kind {
+ AggregateKind::Array(ty) => AggregateKind::Array(ty.try_fold_with(folder)?),
+ AggregateKind::Tuple => AggregateKind::Tuple,
+ AggregateKind::Adt(def, v, substs, user_ty, n) => AggregateKind::Adt(
+ def,
+ v,
+ substs.try_fold_with(folder)?,
+ user_ty.try_fold_with(folder)?,
+ n,
+ ),
+ AggregateKind::Closure(id, substs) => {
+ AggregateKind::Closure(id, substs.try_fold_with(folder)?)
+ }
+ AggregateKind::Generator(id, substs, movablity) => {
+ AggregateKind::Generator(id, substs.try_fold_with(folder)?, movablity)
+ }
+ })
+ })?;
+ Aggregate(kind, fields.try_fold_with(folder)?)
}
- ShallowInitBox(op, ty) => ShallowInitBox(op.fold_with(folder), ty.fold_with(folder)),
- }
+ ShallowInitBox(op, ty) => {
+ ShallowInitBox(op.try_fold_with(folder)?, ty.try_fold_with(folder)?)
+ }
+ })
}
fn super_visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> ControlFlow<V::BreakTy> {
@@ -265,12 +295,15 @@ impl<'tcx> TypeFoldable<'tcx> for Rvalue<'tcx> {
}
impl<'tcx> TypeFoldable<'tcx> for Operand<'tcx> {
- fn super_fold_with<F: TypeFolder<'tcx>>(self, folder: &mut F) -> Self {
- match self {
- Operand::Copy(place) => Operand::Copy(place.fold_with(folder)),
- Operand::Move(place) => Operand::Move(place.fold_with(folder)),
- Operand::Constant(c) => Operand::Constant(c.fold_with(folder)),
- }
+ fn try_super_fold_with<F: FallibleTypeFolder<'tcx>>(
+ self,
+ folder: &mut F,
+ ) -> Result<Self, F::Error> {
+ Ok(match self {
+ Operand::Copy(place) => Operand::Copy(place.try_fold_with(folder)?),
+ Operand::Move(place) => Operand::Move(place.try_fold_with(folder)?),
+ Operand::Constant(c) => Operand::Constant(c.try_fold_with(folder)?),
+ })
}
fn super_visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> ControlFlow<V::BreakTy> {
@@ -282,19 +315,22 @@ impl<'tcx> TypeFoldable<'tcx> for Operand<'tcx> {
}
impl<'tcx> TypeFoldable<'tcx> for PlaceElem<'tcx> {
- fn super_fold_with<F: TypeFolder<'tcx>>(self, folder: &mut F) -> Self {
+ fn try_super_fold_with<F: FallibleTypeFolder<'tcx>>(
+ self,
+ folder: &mut F,
+ ) -> Result<Self, F::Error> {
use crate::mir::ProjectionElem::*;
- match self {
+ Ok(match self {
Deref => Deref,
- Field(f, ty) => Field(f, ty.fold_with(folder)),
- Index(v) => Index(v.fold_with(folder)),
+ Field(f, ty) => Field(f, ty.try_fold_with(folder)?),
+ Index(v) => Index(v.try_fold_with(folder)?),
Downcast(symbol, variantidx) => Downcast(symbol, variantidx),
ConstantIndex { offset, min_length, from_end } => {
ConstantIndex { offset, min_length, from_end }
}
Subslice { from, to, from_end } => Subslice { from, to, from_end },
- }
+ })
}
fn super_visit_with<Vs: TypeVisitor<'tcx>>(
@@ -312,8 +348,8 @@ impl<'tcx> TypeFoldable<'tcx> for PlaceElem<'tcx> {
}
impl<'tcx> TypeFoldable<'tcx> for Field {
- fn super_fold_with<F: TypeFolder<'tcx>>(self, _: &mut F) -> Self {
- self
+ fn try_super_fold_with<F: FallibleTypeFolder<'tcx>>(self, _: &mut F) -> Result<Self, F::Error> {
+ Ok(self)
}
fn super_visit_with<V: TypeVisitor<'tcx>>(&self, _: &mut V) -> ControlFlow<V::BreakTy> {
ControlFlow::CONTINUE
@@ -321,8 +357,8 @@ impl<'tcx> TypeFoldable<'tcx> for Field {
}
impl<'tcx> TypeFoldable<'tcx> for GeneratorSavedLocal {
- fn super_fold_with<F: TypeFolder<'tcx>>(self, _: &mut F) -> Self {
- self
+ fn try_super_fold_with<F: FallibleTypeFolder<'tcx>>(self, _: &mut F) -> Result<Self, F::Error> {
+ Ok(self)
}
fn super_visit_with<V: TypeVisitor<'tcx>>(&self, _: &mut V) -> ControlFlow<V::BreakTy> {
ControlFlow::CONTINUE
@@ -330,8 +366,8 @@ impl<'tcx> TypeFoldable<'tcx> for GeneratorSavedLocal {
}
impl<'tcx, R: Idx, C: Idx> TypeFoldable<'tcx> for BitMatrix<R, C> {
- fn super_fold_with<F: TypeFolder<'tcx>>(self, _: &mut F) -> Self {
- self
+ fn try_super_fold_with<F: FallibleTypeFolder<'tcx>>(self, _: &mut F) -> Result<Self, F::Error> {
+ Ok(self)
}
fn super_visit_with<V: TypeVisitor<'tcx>>(&self, _: &mut V) -> ControlFlow<V::BreakTy> {
ControlFlow::CONTINUE
@@ -339,12 +375,15 @@ impl<'tcx, R: Idx, C: Idx> TypeFoldable<'tcx> for BitMatrix<R, C> {
}
impl<'tcx> TypeFoldable<'tcx> for Constant<'tcx> {
- fn super_fold_with<F: TypeFolder<'tcx>>(self, folder: &mut F) -> Self {
- Constant {
+ fn try_super_fold_with<F: FallibleTypeFolder<'tcx>>(
+ self,
+ folder: &mut F,
+ ) -> Result<Self, F::Error> {
+ Ok(Constant {
span: self.span,
- user_ty: self.user_ty.fold_with(folder),
- literal: self.literal.fold_with(folder),
- }
+ user_ty: self.user_ty.try_fold_with(folder)?,
+ literal: self.literal.try_fold_with(folder)?,
+ })
}
fn super_visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> ControlFlow<V::BreakTy> {
self.literal.visit_with(visitor)?;
@@ -354,14 +393,17 @@ impl<'tcx> TypeFoldable<'tcx> for Constant<'tcx> {
impl<'tcx> TypeFoldable<'tcx> for ConstantKind<'tcx> {
#[inline(always)]
- fn fold_with<F: TypeFolder<'tcx>>(self, folder: &mut F) -> Self {
- folder.fold_mir_const(self)
+ fn try_fold_with<F: FallibleTypeFolder<'tcx>>(self, folder: &mut F) -> Result<Self, F::Error> {
+ folder.try_fold_mir_const(self)
}
- fn super_fold_with<F: TypeFolder<'tcx>>(self, folder: &mut F) -> Self {
+ fn try_super_fold_with<F: FallibleTypeFolder<'tcx>>(
+ self,
+ folder: &mut F,
+ ) -> Result<Self, F::Error> {
match self {
- ConstantKind::Ty(c) => ConstantKind::Ty(c.fold_with(folder)),
- ConstantKind::Val(v, t) => ConstantKind::Val(v, t.fold_with(folder)),
+ ConstantKind::Ty(c) => Ok(ConstantKind::Ty(c.try_fold_with(folder)?)),
+ ConstantKind::Val(v, t) => Ok(ConstantKind::Val(v, t.try_fold_with(folder)?)),
}
}
diff --git a/compiler/rustc_middle/src/mir/visit.rs b/compiler/rustc_middle/src/mir/visit.rs
index fda7ebe1a49..d783b6330e8 100644
--- a/compiler/rustc_middle/src/mir/visit.rs
+++ b/compiler/rustc_middle/src/mir/visit.rs
@@ -412,7 +412,7 @@ macro_rules! make_mir_visitor {
for output in & $($mutability)? asm.outputs[..] {
self.visit_place(
output,
- PlaceContext::MutatingUse(MutatingUseContext::AsmOutput),
+ PlaceContext::MutatingUse(MutatingUseContext::LlvmAsmOutput),
location
);
}
@@ -581,6 +581,7 @@ macro_rules! make_mir_visitor {
options: _,
line_spans: _,
destination: _,
+ cleanup: _,
} => {
for op in operands {
match op {
@@ -590,7 +591,7 @@ macro_rules! make_mir_visitor {
InlineAsmOperand::Out { place: Some(place), .. } => {
self.visit_place(
place,
- PlaceContext::MutatingUse(MutatingUseContext::Store),
+ PlaceContext::MutatingUse(MutatingUseContext::AsmOutput),
location,
);
}
@@ -599,7 +600,7 @@ macro_rules! make_mir_visitor {
if let Some(out_place) = out_place {
self.visit_place(
out_place,
- PlaceContext::MutatingUse(MutatingUseContext::Store),
+ PlaceContext::MutatingUse(MutatingUseContext::AsmOutput),
location,
);
}
@@ -1004,8 +1005,12 @@ macro_rules! visit_place_fns {
if new_local == local { None } else { Some(PlaceElem::Index(new_local)) }
}
+ PlaceElem::Field(field, ty) => {
+ let mut new_ty = ty;
+ self.visit_ty(&mut new_ty, TyContext::Location(location));
+ if ty != new_ty { Some(PlaceElem::Field(field, new_ty)) } else { None }
+ }
PlaceElem::Deref
- | PlaceElem::Field(..)
| PlaceElem::ConstantIndex { .. }
| PlaceElem::Subslice { .. }
| PlaceElem::Downcast(..) => None,
@@ -1174,8 +1179,10 @@ pub enum MutatingUseContext {
/// Appears as LHS of an assignment.
Store,
/// Can often be treated as a `Store`, but needs to be separate because
- /// ASM is allowed to read outputs as well, so a `Store`-`AsmOutput` sequence
+ /// ASM is allowed to read outputs as well, so a `Store`-`LlvmAsmOutput` sequence
/// cannot be simplified the way a `Store`-`Store` can be.
+ LlvmAsmOutput,
+ /// Output operand of an inline assembly block.
AsmOutput,
/// Destination of a call.
Call,
@@ -1264,6 +1271,7 @@ impl PlaceContext {
PlaceContext::MutatingUse(
MutatingUseContext::Store
| MutatingUseContext::Call
+ | MutatingUseContext::LlvmAsmOutput
| MutatingUseContext::AsmOutput,
)
)
diff --git a/compiler/rustc_middle/src/query/mod.rs b/compiler/rustc_middle/src/query/mod.rs
index 9a58009a173..e2de9f12aaa 100644
--- a/compiler/rustc_middle/src/query/mod.rs
+++ b/compiler/rustc_middle/src/query/mod.rs
@@ -649,7 +649,6 @@ rustc_queries! {
/// Methods in these implementations don't need to be exported.
query inherent_impls(key: DefId) -> &'tcx [DefId] {
desc { |tcx| "collecting inherent impls for `{}`", tcx.def_path_str(key) }
- eval_always
separate_provide_extern
}
@@ -772,11 +771,24 @@ rustc_queries! {
desc { |tcx| "type-checking `{}`", tcx.def_path_str(key.to_def_id()) }
cache_on_disk_if { true }
load_cached(tcx, id) {
- let typeck_results: Option<ty::TypeckResults<'tcx>> = tcx
- .on_disk_cache().as_ref()
- .and_then(|c| c.try_load_query_result(*tcx, id));
+ #[cfg(bootstrap)]
+ {
+ match match tcx.on_disk_cache().as_ref() {
+ Some(c) => c.try_load_query_result(*tcx, id),
+ None => None,
+ } {
+ Some(x) => Some(&*tcx.arena.alloc(x)),
+ None => None,
+ }
+ }
+ #[cfg(not(bootstrap))]
+ {
+ let typeck_results: Option<ty::TypeckResults<'tcx>> = tcx
+ .on_disk_cache().as_ref()
+ .and_then(|c| c.try_load_query_result(*tcx, id));
- typeck_results.map(|x| &*tcx.arena.alloc(x))
+ typeck_results.map(|x| &*tcx.arena.alloc(x))
+ }
}
}
@@ -810,15 +822,12 @@ rustc_queries! {
/// Not meant to be used directly outside of coherence.
query crate_inherent_impls(k: ()) -> CrateInherentImpls {
storage(ArenaCacheSelector<'tcx>)
- eval_always
desc { "all inherent impls defined in crate" }
}
/// Checks all types in the crate for overlap in their inherent impls. Reports errors.
/// Not meant to be used directly outside of coherence.
- query crate_inherent_impls_overlap_check(_: ())
- -> () {
- eval_always
+ query crate_inherent_impls_overlap_check(_: ()) -> () {
desc { "check for overlap between inherent impls defined in this crate" }
}
@@ -884,6 +893,7 @@ rustc_queries! {
key: ty::ParamEnvAnd<'tcx, ConstAlloc<'tcx>>
) -> Option<ty::ValTree<'tcx>> {
desc { "destructure constant" }
+ remap_env_constness
}
/// Destructure a constant ADT or array into its variant index and its
@@ -892,6 +902,7 @@ rustc_queries! {
key: ty::ParamEnvAnd<'tcx, &'tcx ty::Const<'tcx>>
) -> mir::DestructuredConst<'tcx> {
desc { "destructure constant" }
+ remap_env_constness
}
/// Dereference a constant reference or raw pointer and turn the result into a constant
@@ -900,6 +911,7 @@ rustc_queries! {
key: ty::ParamEnvAnd<'tcx, &'tcx ty::Const<'tcx>>
) -> &'tcx ty::Const<'tcx> {
desc { "deref constant" }
+ remap_env_constness
}
query const_caller_location(key: (rustc_span::Symbol, u32, u32)) -> ConstValue<'tcx> {
@@ -1104,26 +1116,32 @@ rustc_queries! {
/// `ty.is_copy()`, etc, since that will prune the environment where possible.
query is_copy_raw(env: ty::ParamEnvAnd<'tcx, Ty<'tcx>>) -> bool {
desc { "computing whether `{}` is `Copy`", env.value }
+ remap_env_constness
}
/// Query backing `TyS::is_sized`.
query is_sized_raw(env: ty::ParamEnvAnd<'tcx, Ty<'tcx>>) -> bool {
desc { "computing whether `{}` is `Sized`", env.value }
+ remap_env_constness
}
/// Query backing `TyS::is_freeze`.
query is_freeze_raw(env: ty::ParamEnvAnd<'tcx, Ty<'tcx>>) -> bool {
desc { "computing whether `{}` is freeze", env.value }
+ remap_env_constness
}
/// Query backing `TyS::is_unpin`.
query is_unpin_raw(env: ty::ParamEnvAnd<'tcx, Ty<'tcx>>) -> bool {
desc { "computing whether `{}` is `Unpin`", env.value }
+ remap_env_constness
}
/// Query backing `TyS::needs_drop`.
query needs_drop_raw(env: ty::ParamEnvAnd<'tcx, Ty<'tcx>>) -> bool {
desc { "computing whether `{}` needs drop", env.value }
+ remap_env_constness
}
/// Query backing `TyS::has_significant_drop_raw`.
query has_significant_drop_raw(env: ty::ParamEnvAnd<'tcx, Ty<'tcx>>) -> bool {
desc { "computing whether `{}` has a significant drop", env.value }
+ remap_env_constness
}
/// Query backing `TyS::is_structural_eq_shallow`.
@@ -1162,6 +1180,7 @@ rustc_queries! {
key: ty::ParamEnvAnd<'tcx, Ty<'tcx>>
) -> Result<ty::layout::TyAndLayout<'tcx>, ty::layout::LayoutError<'tcx>> {
desc { "computing layout of `{}`", key.value }
+ remap_env_constness
}
/// Compute a `FnAbi` suitable for indirect calls, i.e. to `fn` pointers.
@@ -1172,6 +1191,7 @@ rustc_queries! {
key: ty::ParamEnvAnd<'tcx, (ty::PolyFnSig<'tcx>, &'tcx ty::List<Ty<'tcx>>)>
) -> Result<&'tcx abi::call::FnAbi<'tcx, Ty<'tcx>>, ty::layout::FnAbiError<'tcx>> {
desc { "computing call ABI of `{}` function pointers", key.value.0 }
+ remap_env_constness
}
/// Compute a `FnAbi` suitable for declaring/defining an `fn` instance, and for
@@ -1183,6 +1203,7 @@ rustc_queries! {
key: ty::ParamEnvAnd<'tcx, (ty::Instance<'tcx>, &'tcx ty::List<Ty<'tcx>>)>
) -> Result<&'tcx abi::call::FnAbi<'tcx, Ty<'tcx>>, ty::layout::FnAbiError<'tcx>> {
desc { "computing call ABI of `{}`", key.value.0 }
+ remap_env_constness
}
query dylib_dependency_formats(_: CrateNum)
@@ -1467,6 +1488,7 @@ rustc_queries! {
key: ty::ParamEnvAnd<'tcx, Ty<'tcx>>
) -> ty::inhabitedness::DefIdForest {
desc { "computing the inhabitedness of `{:?}`", key }
+ remap_env_constness
}
query dep_kind(_: CrateNum) -> CrateDepKind {
@@ -1489,9 +1511,8 @@ rustc_queries! {
desc { |tcx| "computing crate imported by `{}`", tcx.def_path_str(def_id.to_def_id()) }
}
- query get_lib_features(_: ()) -> LibFeatures {
+ query lib_features(_: ()) -> LibFeatures {
storage(ArenaCacheSelector<'tcx>)
- eval_always
desc { "calculating the lib features map" }
}
query defined_lib_features(_: CrateNum)
@@ -1566,7 +1587,6 @@ rustc_queries! {
query upvars_mentioned(def_id: DefId) -> Option<&'tcx FxIndexMap<hir::HirId, hir::Upvar>> {
desc { |tcx| "collecting upvars mentioned in `{}`", tcx.def_path_str(def_id) }
- eval_always
}
query maybe_unused_trait_import(def_id: LocalDefId) -> bool {
desc { |tcx| "maybe_unused_trait_import for `{}`", tcx.def_path_str(def_id.to_def_id()) }
@@ -1648,20 +1668,23 @@ rustc_queries! {
NoSolution,
> {
desc { "normalizing `{:?}`", goal }
+ remap_env_constness
}
- /// Do not call this query directly: invoke `normalize_erasing_regions` instead.
- query normalize_generic_arg_after_erasing_regions(
+ /// Do not call this query directly: invoke `try_normalize_erasing_regions` instead.
+ query try_normalize_generic_arg_after_erasing_regions(
goal: ParamEnvAnd<'tcx, GenericArg<'tcx>>
- ) -> GenericArg<'tcx> {
+ ) -> Result<GenericArg<'tcx>, NoSolution> {
desc { "normalizing `{}`", goal.value }
+ remap_env_constness
}
- /// Do not call this query directly: invoke `normalize_erasing_regions` instead.
- query normalize_mir_const_after_erasing_regions(
+ /// Do not call this query directly: invoke `try_normalize_erasing_regions` instead.
+ query try_normalize_mir_const_after_erasing_regions(
goal: ParamEnvAnd<'tcx, mir::ConstantKind<'tcx>>
- ) -> mir::ConstantKind<'tcx> {
+ ) -> Result<mir::ConstantKind<'tcx>, NoSolution> {
desc { "normalizing `{}`", goal.value }
+ remap_env_constness
}
query implied_outlives_bounds(
@@ -1671,6 +1694,7 @@ rustc_queries! {
NoSolution,
> {
desc { "computing implied outlives bounds for `{:?}`", goal }
+ remap_env_constness
}
/// Do not call this query directly: invoke `infcx.at().dropck_outlives()` instead.
@@ -1681,6 +1705,7 @@ rustc_queries! {
NoSolution,
> {
desc { "computing dropck types for `{:?}`", goal }
+ remap_env_constness
}
/// Do not call this query directly: invoke `infcx.predicate_may_hold()` or
@@ -1708,6 +1733,7 @@ rustc_queries! {
NoSolution,
> {
desc { "evaluating `type_op_ascribe_user_type` `{:?}`", goal }
+ remap_env_constness
}
/// Do not call this query directly: part of the `Eq` type-op
@@ -1718,6 +1744,7 @@ rustc_queries! {
NoSolution,
> {
desc { "evaluating `type_op_eq` `{:?}`", goal }
+ remap_env_constness
}
/// Do not call this query directly: part of the `Subtype` type-op
@@ -1728,6 +1755,7 @@ rustc_queries! {
NoSolution,
> {
desc { "evaluating `type_op_subtype` `{:?}`", goal }
+ remap_env_constness
}
/// Do not call this query directly: part of the `ProvePredicate` type-op
@@ -1748,6 +1776,7 @@ rustc_queries! {
NoSolution,
> {
desc { "normalizing `{:?}`", goal }
+ remap_env_constness
}
/// Do not call this query directly: part of the `Normalize` type-op
@@ -1758,6 +1787,7 @@ rustc_queries! {
NoSolution,
> {
desc { "normalizing `{:?}`", goal }
+ remap_env_constness
}
/// Do not call this query directly: part of the `Normalize` type-op
@@ -1768,6 +1798,7 @@ rustc_queries! {
NoSolution,
> {
desc { "normalizing `{:?}`", goal }
+ remap_env_constness
}
/// Do not call this query directly: part of the `Normalize` type-op
@@ -1778,6 +1809,7 @@ rustc_queries! {
NoSolution,
> {
desc { "normalizing `{:?}`", goal }
+ remap_env_constness
}
query subst_and_check_impossible_predicates(key: (DefId, SubstsRef<'tcx>)) -> bool {
@@ -1791,6 +1823,7 @@ rustc_queries! {
goal: CanonicalTyGoal<'tcx>
) -> MethodAutoderefStepsResult<'tcx> {
desc { "computing autoderef types for `{:?}`", goal }
+ remap_env_constness
}
query supported_target_features(_: CrateNum) -> FxHashMap<String, Option<Symbol>> {
@@ -1823,6 +1856,7 @@ rustc_queries! {
key: ty::ParamEnvAnd<'tcx, (DefId, SubstsRef<'tcx>)>
) -> Result<Option<ty::Instance<'tcx>>, ErrorReported> {
desc { "resolving instance `{}`", ty::Instance::new(key.value.0, key.value.1) }
+ remap_env_constness
}
query resolve_instance_of_const_arg(
@@ -1832,6 +1866,7 @@ rustc_queries! {
"resolving instance of the const argument `{}`",
ty::Instance::new(key.value.0.to_def_id(), key.value.2),
}
+ remap_env_constness
}
query normalize_opaque_types(key: &'tcx ty::List<ty::Predicate<'tcx>>) -> &'tcx ty::List<ty::Predicate<'tcx>> {
@@ -1846,6 +1881,7 @@ rustc_queries! {
/// size, to account for partial initialisation. See #49298 for details.)
query conservative_is_privately_uninhabited(key: ty::ParamEnvAnd<'tcx, Ty<'tcx>>) -> bool {
desc { "conservatively checking if {:?} is privately uninhabited", key }
+ remap_env_constness
}
query limits(key: ()) -> Limits {
diff --git a/compiler/rustc_middle/src/traits/mod.rs b/compiler/rustc_middle/src/traits/mod.rs
index 49071e7995b..a5bd246712b 100644
--- a/compiler/rustc_middle/src/traits/mod.rs
+++ b/compiler/rustc_middle/src/traits/mod.rs
@@ -7,6 +7,7 @@ pub mod query;
pub mod select;
pub mod specialization_graph;
mod structural_impls;
+pub mod util;
use crate::infer::canonical::Canonical;
use crate::thir::abstract_const::NotConstEvaluatable;
@@ -347,6 +348,12 @@ pub enum ObligationCauseCode<'tcx> {
/// If `X` is the concrete type of an opaque type `impl Y`, then `X` must implement `Y`
OpaqueType,
+ AwaitableExpr(Option<hir::HirId>),
+
+ ForLoopIterator,
+
+ QuestionMark,
+
/// Well-formed checking. If a `WellFormedLoc` is provided,
/// then it will be used to eprform HIR-based wf checking
/// after an error occurs, in order to generate a more precise error span.
@@ -586,18 +593,18 @@ impl<'tcx, N> ImplSource<'tcx, N> {
pub fn borrow_nested_obligations(&self) -> &[N] {
match &self {
ImplSource::UserDefined(i) => &i.nested[..],
- ImplSource::Param(n, _) => &n[..],
- ImplSource::Builtin(i) => &i.nested[..],
- ImplSource::AutoImpl(d) => &d.nested[..],
- ImplSource::Closure(c) => &c.nested[..],
- ImplSource::Generator(c) => &c.nested[..],
- ImplSource::Object(d) => &d.nested[..],
- ImplSource::FnPointer(d) => &d.nested[..],
+ ImplSource::Param(n, _) => &n,
+ ImplSource::Builtin(i) => &i.nested,
+ ImplSource::AutoImpl(d) => &d.nested,
+ ImplSource::Closure(c) => &c.nested,
+ ImplSource::Generator(c) => &c.nested,
+ ImplSource::Object(d) => &d.nested,
+ ImplSource::FnPointer(d) => &d.nested,
ImplSource::DiscriminantKind(ImplSourceDiscriminantKindData)
| ImplSource::Pointee(ImplSourcePointeeData)
| ImplSource::ConstDrop(ImplSourceConstDropData) => &[],
- ImplSource::TraitAlias(d) => &d.nested[..],
- ImplSource::TraitUpcasting(d) => &d.nested[..],
+ ImplSource::TraitAlias(d) => &d.nested,
+ ImplSource::TraitUpcasting(d) => &d.nested,
}
}
diff --git a/compiler/rustc_middle/src/traits/select.rs b/compiler/rustc_middle/src/traits/select.rs
index 560660517f3..71ee00c602a 100644
--- a/compiler/rustc_middle/src/traits/select.rs
+++ b/compiler/rustc_middle/src/traits/select.rs
@@ -12,14 +12,12 @@ use rustc_hir::def_id::DefId;
use rustc_query_system::cache::Cache;
pub type SelectionCache<'tcx> = Cache<
- (ty::ConstnessAnd<ty::ParamEnvAnd<'tcx, ty::TraitRef<'tcx>>>, ty::ImplPolarity),
+ ty::ParamEnvAnd<'tcx, ty::TraitPredicate<'tcx>>,
SelectionResult<'tcx, SelectionCandidate<'tcx>>,
>;
-pub type EvaluationCache<'tcx> = Cache<
- (ty::ParamEnvAnd<'tcx, ty::ConstnessAnd<ty::PolyTraitRef<'tcx>>>, ty::ImplPolarity),
- EvaluationResult,
->;
+pub type EvaluationCache<'tcx> =
+ Cache<ty::ParamEnvAnd<'tcx, ty::PolyTraitPredicate<'tcx>>, EvaluationResult>;
/// The selection process begins by considering all impls, where
/// clauses, and so forth that might resolve an obligation. Sometimes
@@ -103,7 +101,7 @@ pub enum SelectionCandidate<'tcx> {
/// `false` if there are no *further* obligations.
has_nested: bool,
},
- ParamCandidate((ty::ConstnessAnd<ty::PolyTraitRef<'tcx>>, ty::ImplPolarity)),
+ ParamCandidate(ty::PolyTraitPredicate<'tcx>),
ImplCandidate(DefId),
AutoImplCandidate(DefId),
diff --git a/compiler/rustc_middle/src/traits/util.rs b/compiler/rustc_middle/src/traits/util.rs
new file mode 100644
index 00000000000..815f4824bc1
--- /dev/null
+++ b/compiler/rustc_middle/src/traits/util.rs
@@ -0,0 +1,49 @@
+use rustc_data_structures::stable_set::FxHashSet;
+
+use crate::ty::{PolyTraitRef, TyCtxt};
+
+/// Given a PolyTraitRef, get the PolyTraitRefs of the trait's (transitive) supertraits.
+///
+/// A simplfied version of the same function at `rustc_infer::traits::util::supertraits`.
+pub fn supertraits<'tcx>(
+ tcx: TyCtxt<'tcx>,
+ trait_ref: PolyTraitRef<'tcx>,
+) -> impl Iterator<Item = PolyTraitRef<'tcx>> {
+ Elaborator { tcx, visited: FxHashSet::from_iter([trait_ref]), stack: vec![trait_ref] }
+}
+
+struct Elaborator<'tcx> {
+ tcx: TyCtxt<'tcx>,
+ visited: FxHashSet<PolyTraitRef<'tcx>>,
+ stack: Vec<PolyTraitRef<'tcx>>,
+}
+
+impl<'tcx> Elaborator<'tcx> {
+ fn elaborate(&mut self, trait_ref: PolyTraitRef<'tcx>) {
+ let supertrait_refs = self
+ .tcx
+ .super_predicates_of(trait_ref.def_id())
+ .predicates
+ .into_iter()
+ .flat_map(|(pred, _)| {
+ pred.subst_supertrait(self.tcx, &trait_ref).to_opt_poly_trait_pred()
+ })
+ .map(|t| t.map_bound(|pred| pred.trait_ref))
+ .filter(|supertrait_ref| self.visited.insert(*supertrait_ref));
+
+ self.stack.extend(supertrait_refs);
+ }
+}
+
+impl<'tcx> Iterator for Elaborator<'tcx> {
+ type Item = PolyTraitRef<'tcx>;
+
+ fn next(&mut self) -> Option<PolyTraitRef<'tcx>> {
+ if let Some(trait_ref) = self.stack.pop() {
+ self.elaborate(trait_ref);
+ Some(trait_ref)
+ } else {
+ None
+ }
+ }
+}
diff --git a/compiler/rustc_middle/src/ty/adt.rs b/compiler/rustc_middle/src/ty/adt.rs
index 44f741c5df1..771ce2eb884 100644
--- a/compiler/rustc_middle/src/ty/adt.rs
+++ b/compiler/rustc_middle/src/ty/adt.rs
@@ -7,7 +7,7 @@ use rustc_data_structures::fx::FxHashMap;
use rustc_data_structures::stable_hasher::{HashStable, StableHasher};
use rustc_errors::ErrorReported;
use rustc_hir as hir;
-use rustc_hir::def::{DefKind, Res};
+use rustc_hir::def::{CtorKind, DefKind, Res};
use rustc_hir::def_id::DefId;
use rustc_index::vec::{Idx, IndexVec};
use rustc_query_system::ich::StableHashingContext;
@@ -64,6 +64,30 @@ bitflags! {
/// Moreover, Rust only allows recursive data types through indirection.
///
/// [adt]: https://en.wikipedia.org/wiki/Algebraic_data_type
+///
+/// # Recursive types
+///
+/// It may seem impossible to represent recursive types using [`Ty`],
+/// since [`TyKind::Adt`] includes [`AdtDef`], which includes its fields,
+/// creating a cycle. However, `AdtDef` does not actually include the *types*
+/// of its fields; it includes just their [`DefId`]s.
+///
+/// [`TyKind::Adt`]: ty::TyKind::Adt
+///
+/// For example, the following type:
+///
+/// ```
+/// struct S { x: Box<S> }
+/// ```
+///
+/// is essentially represented with [`Ty`] as the following pseudocode:
+///
+/// ```
+/// struct S { x }
+/// ```
+///
+/// where `x` here represents the `DefId` of `S.x`. Then, the `DefId`
+/// can be used with [`TyCtxt::type_of()`] to get the type of the field.
pub struct AdtDef {
/// The `DefId` of the struct, enum or union item.
pub did: DefId,
@@ -314,6 +338,22 @@ impl<'tcx> AdtDef {
/// Whether the ADT lacks fields. Note that this includes uninhabited enums,
/// e.g., `enum Void {}` is considered payload free as well.
pub fn is_payloadfree(&self) -> bool {
+ // Treat the ADT as not payload-free if arbitrary_enum_discriminant is used (#88621).
+ // This would disallow the following kind of enum from being casted into integer.
+ // ```
+ // enum Enum {
+ // Foo() = 1,
+ // Bar{} = 2,
+ // Baz = 3,
+ // }
+ // ```
+ if self
+ .variants
+ .iter()
+ .any(|v| matches!(v.discr, VariantDiscr::Explicit(_)) && v.ctor_kind != CtorKind::Const)
+ {
+ return false;
+ }
self.variants.iter().all(|v| v.fields.is_empty())
}
diff --git a/compiler/rustc_middle/src/ty/context.rs b/compiler/rustc_middle/src/ty/context.rs
index 8240273acad..0bf457ca8a8 100644
--- a/compiler/rustc_middle/src/ty/context.rs
+++ b/compiler/rustc_middle/src/ty/context.rs
@@ -5,7 +5,6 @@ use crate::dep_graph::{DepGraph, DepKind, DepKindStruct};
use crate::hir::place::Place as HirPlace;
use crate::infer::canonical::{Canonical, CanonicalVarInfo, CanonicalVarInfos};
use crate::lint::{struct_lint_level, LintDiagnosticBuilder, LintLevelSource};
-use crate::middle;
use crate::middle::resolve_lifetime::{self, LifetimeScopeForPath, ObjectLifetimeDefault};
use crate::middle::stability;
use crate::mir::interpret::{self, Allocation, ConstValue, Scalar};
@@ -1112,7 +1111,11 @@ impl<'tcx> TyCtxt<'tcx> {
};
debug!("layout_scalar_valid_range: attr={:?}", attr);
if let Some(
- &[ast::NestedMetaItem::Literal(ast::Lit { kind: ast::LitKind::Int(a, _), .. })],
+ &[
+ ast::NestedMetaItem::Literal(ast::Lit {
+ kind: ast::LitKind::Int(a, _), ..
+ }),
+ ],
) = attr.meta_item_list().as_deref()
{
Bound::Included(a)
@@ -1217,10 +1220,6 @@ impl<'tcx> TyCtxt<'tcx> {
self.sess.consider_optimizing(&cname, msg)
}
- pub fn lib_features(self) -> &'tcx middle::lib_features::LibFeatures {
- self.get_lib_features(())
- }
-
/// Obtain all lang items of this crate and all dependencies (recursively)
pub fn lang_items(self) -> &'tcx rustc_hir::lang_items::LanguageItems {
self.get_lang_items(())
@@ -1482,40 +1481,8 @@ impl<'tcx> TyCtxt<'tcx> {
scope_def_id: LocalDefId,
) -> Vec<&'tcx hir::Ty<'tcx>> {
let hir_id = self.hir().local_def_id_to_hir_id(scope_def_id);
- let hir_output = match self.hir().get(hir_id) {
- Node::Item(hir::Item {
- kind:
- ItemKind::Fn(
- hir::FnSig {
- decl: hir::FnDecl { output: hir::FnRetTy::Return(ty), .. },
- ..
- },
- ..,
- ),
- ..
- })
- | Node::ImplItem(hir::ImplItem {
- kind:
- hir::ImplItemKind::Fn(
- hir::FnSig {
- decl: hir::FnDecl { output: hir::FnRetTy::Return(ty), .. },
- ..
- },
- _,
- ),
- ..
- })
- | Node::TraitItem(hir::TraitItem {
- kind:
- hir::TraitItemKind::Fn(
- hir::FnSig {
- decl: hir::FnDecl { output: hir::FnRetTy::Return(ty), .. },
- ..
- },
- _,
- ),
- ..
- }) => ty,
+ let hir_output = match self.hir().fn_decl_by_hir_id(hir_id) {
+ Some(hir::FnDecl { output: hir::FnRetTy::Return(ty), .. }) => ty,
_ => return vec![],
};
diff --git a/compiler/rustc_middle/src/ty/diagnostics.rs b/compiler/rustc_middle/src/ty/diagnostics.rs
index 1b32c8a6698..ee00f6c62f3 100644
--- a/compiler/rustc_middle/src/ty/diagnostics.rs
+++ b/compiler/rustc_middle/src/ty/diagnostics.rs
@@ -1,11 +1,17 @@
//! Diagnostics related methods for `TyS`.
+use crate::ty::subst::{GenericArg, GenericArgKind};
use crate::ty::TyKind::*;
-use crate::ty::{InferTy, TyCtxt, TyS};
+use crate::ty::{
+ ConstKind, ExistentialPredicate, ExistentialProjection, ExistentialTraitRef, InferTy,
+ ProjectionTy, TyCtxt, TyS, TypeAndMut,
+};
+
use rustc_errors::{Applicability, DiagnosticBuilder};
use rustc_hir as hir;
use rustc_hir::def_id::DefId;
use rustc_hir::{QPath, TyKind, WhereBoundPredicate, WherePredicate};
+use rustc_span::Span;
impl<'tcx> TyS<'tcx> {
/// Similar to `TyS::is_primitive`, but also considers inferred numeric values to be primitive.
@@ -62,16 +68,55 @@ impl<'tcx> TyS<'tcx> {
/// Whether the type can be safely suggested during error recovery.
pub fn is_suggestable(&self) -> bool {
- !matches!(
- self.kind(),
+ fn generic_arg_is_suggestible(arg: GenericArg<'_>) -> bool {
+ match arg.unpack() {
+ GenericArgKind::Type(ty) => ty.is_suggestable(),
+ GenericArgKind::Const(c) => const_is_suggestable(c.val),
+ _ => true,
+ }
+ }
+
+ fn const_is_suggestable(kind: ConstKind<'_>) -> bool {
+ match kind {
+ ConstKind::Infer(..)
+ | ConstKind::Bound(..)
+ | ConstKind::Placeholder(..)
+ | ConstKind::Error(..) => false,
+ _ => true,
+ }
+ }
+
+ // FIXME(compiler-errors): Some types are still not good to suggest,
+ // specifically references with lifetimes within the function. Not
+ //sure we have enough information to resolve whether a region is
+ // temporary, so I'll leave this as a fixme.
+
+ match self.kind() {
Opaque(..)
- | FnDef(..)
- | FnPtr(..)
- | Dynamic(..)
- | Closure(..)
- | Infer(..)
- | Projection(..)
- )
+ | FnDef(..)
+ | Closure(..)
+ | Infer(..)
+ | Generator(..)
+ | GeneratorWitness(..)
+ | Bound(_, _)
+ | Placeholder(_)
+ | Error(_) => false,
+ Dynamic(dty, _) => dty.iter().all(|pred| match pred.skip_binder() {
+ ExistentialPredicate::Trait(ExistentialTraitRef { substs, .. }) => {
+ substs.iter().all(generic_arg_is_suggestible)
+ }
+ ExistentialPredicate::Projection(ExistentialProjection { substs, ty, .. }) => {
+ ty.is_suggestable() && substs.iter().all(generic_arg_is_suggestible)
+ }
+ _ => true,
+ }),
+ Projection(ProjectionTy { substs: args, .. }) | Adt(_, args) | Tuple(args) => {
+ args.iter().all(generic_arg_is_suggestible)
+ }
+ Slice(ty) | RawPtr(TypeAndMut { ty, .. }) | Ref(_, ty, _) => ty.is_suggestable(),
+ Array(ty, c) => ty.is_suggestable() && const_is_suggestable(c.val),
+ _ => true,
+ }
}
}
@@ -270,7 +315,7 @@ pub fn suggest_constraining_type_param(
// `where` clause instead of `trait Base<T: Copy = String>: Super<T>`.
&& !matches!(param.kind, hir::GenericParamKind::Type { default: Some(_), .. })
{
- if let Some(bounds_span) = param.bounds_span() {
+ if let Some(span) = param.bounds_span_for_suggestions() {
// If user has provided some bounds, suggest restricting them:
//
// fn foo<T: Foo>(t: T) { ... }
@@ -284,7 +329,7 @@ pub fn suggest_constraining_type_param(
// --
// |
// replace with: `T: Bar +`
- suggest_restrict(bounds_span.shrink_to_hi());
+ suggest_restrict(span);
} else {
// If user hasn't provided any bounds, suggest adding a new one:
//
@@ -432,3 +477,22 @@ impl<'v> hir::intravisit::Visitor<'v> for TraitObjectVisitor<'v> {
hir::intravisit::walk_ty(self, ty);
}
}
+
+/// Collect al types that have an implicit `'static` obligation that we could suggest `'_` for.
+pub struct StaticLifetimeVisitor<'tcx>(pub Vec<Span>, pub crate::hir::map::Map<'tcx>);
+
+impl<'v> hir::intravisit::Visitor<'v> for StaticLifetimeVisitor<'v> {
+ type Map = rustc_hir::intravisit::ErasedMap<'v>;
+
+ fn nested_visit_map(&mut self) -> hir::intravisit::NestedVisitorMap<Self::Map> {
+ hir::intravisit::NestedVisitorMap::None
+ }
+
+ fn visit_lifetime(&mut self, lt: &'v hir::Lifetime) {
+ if let hir::LifetimeName::ImplicitObjectLifetimeDefault | hir::LifetimeName::Static =
+ lt.name
+ {
+ self.0.push(lt.span);
+ }
+ }
+}
diff --git a/compiler/rustc_middle/src/ty/error.rs b/compiler/rustc_middle/src/ty/error.rs
index b14a6989265..1b4566fd026 100644
--- a/compiler/rustc_middle/src/ty/error.rs
+++ b/compiler/rustc_middle/src/ty/error.rs
@@ -118,8 +118,7 @@ impl<'tcx> fmt::Display for TypeError<'tcx> {
ArgumentMutability(_) | Mutability => write!(f, "types differ in mutability"),
TupleSize(values) => write!(
f,
- "expected a tuple with {} element{}, \
- found one with {} element{}",
+ "expected a tuple with {} element{}, found one with {} element{}",
values.expected,
pluralize!(values.expected),
values.found,
@@ -127,8 +126,7 @@ impl<'tcx> fmt::Display for TypeError<'tcx> {
),
FixedArraySize(values) => write!(
f,
- "expected an array with a fixed size of {} element{}, \
- found one with {} element{}",
+ "expected an array with a fixed size of {} element{}, found one with {} element{}",
values.expected,
pluralize!(values.expected),
values.found,
@@ -777,9 +775,7 @@ fn foo(&self) -> Self::T { String::new() }
if let ty::Opaque(def_id, _) = *proj_ty.self_ty().kind() {
let opaque_local_def_id = def_id.as_local();
let opaque_hir_ty = if let Some(opaque_local_def_id) = opaque_local_def_id {
- let hir = self.hir();
- let opaque_hir_id = hir.local_def_id_to_hir_id(opaque_local_def_id);
- match &hir.expect_item(opaque_hir_id).kind {
+ match &self.hir().expect_item(opaque_local_def_id).kind {
hir::ItemKind::OpaqueTy(opaque_hir_ty) => opaque_hir_ty,
_ => bug!("The HirId comes from a `ty::Opaque`"),
}
diff --git a/compiler/rustc_middle/src/ty/fast_reject.rs b/compiler/rustc_middle/src/ty/fast_reject.rs
index 11ee942b83e..c4043d9698c 100644
--- a/compiler/rustc_middle/src/ty/fast_reject.rs
+++ b/compiler/rustc_middle/src/ty/fast_reject.rs
@@ -1,3 +1,4 @@
+use crate::mir::Mutability;
use crate::ty::{self, Ty, TyCtxt};
use rustc_data_structures::stable_hasher::{HashStable, StableHasher};
use rustc_hir::def_id::DefId;
@@ -27,9 +28,12 @@ where
UintSimplifiedType(ty::UintTy),
FloatSimplifiedType(ty::FloatTy),
AdtSimplifiedType(D),
+ ForeignSimplifiedType(D),
StrSimplifiedType,
ArraySimplifiedType,
- PtrSimplifiedType,
+ SliceSimplifiedType,
+ RefSimplifiedType(Mutability),
+ PtrSimplifiedType(Mutability),
NeverSimplifiedType,
TupleSimplifiedType(usize),
/// A trait object, all of whose components are markers
@@ -42,22 +46,48 @@ where
OpaqueSimplifiedType(D),
FunctionSimplifiedType(usize),
ParameterSimplifiedType,
- ForeignSimplifiedType(DefId),
}
-/// Tries to simplify a type by dropping type parameters, deref'ing away any reference types, etc.
-/// The idea is to get something simple that we can use to quickly decide if two types could unify
-/// during method lookup.
+#[derive(PartialEq, Eq, Debug, Clone, Copy)]
+pub enum SimplifyParams {
+ Yes,
+ No,
+}
+
+#[derive(PartialEq, Eq, Debug, Clone, Copy)]
+pub enum StripReferences {
+ Yes,
+ No,
+}
+
+/// Tries to simplify a type by only returning the outermost injective¹ layer, if one exists.
+///
+/// The idea is to get something simple that we can use to quickly decide if two types could unify,
+/// for example during method lookup.
///
-/// If `can_simplify_params` is false, then we will fail to simplify type parameters entirely. This
-/// is useful when those type parameters would be instantiated with fresh type variables, since
-/// then we can't say much about whether two types would unify. Put another way,
-/// `can_simplify_params` should be true if type parameters appear free in `ty` and `false` if they
-/// are to be considered bound.
+/// A special case here are parameters and projections. Projections can be normalized to
+/// a different type, meaning that `<T as Trait>::Assoc` and `u8` can be unified, even though
+/// their outermost layer is different while parameters like `T` of impls are later replaced
+/// with an inference variable, which then also allows unification with other types.
+///
+/// When using `SimplifyParams::Yes`, we still return a simplified type for params and projections²,
+/// the reasoning for this can be seen at the places doing this.
+///
+/// For diagnostics we strip references with `StripReferences::Yes`. This is currently the best
+/// way to skip some unhelpful suggestions.
+///
+/// ¹ meaning that if two outermost layers are different, then the whole types are also different.
+/// ² FIXME(@lcnr): this seems like it can actually end up being unsound with the way it's used during
+/// candidate selection. We do not consider non blanket impls for `<_ as Trait>::Assoc` even
+/// though `_` can be inferred to a concrete type later at which point a concrete impl
+/// could actually apply. After experimenting for about an hour I wasn't able to cause any issues
+/// this way so I am not going to change this until we actually find an issue as I am really
+/// interesting in getting an actual test for this.
pub fn simplify_type(
tcx: TyCtxt<'_>,
ty: Ty<'_>,
- can_simplify_params: bool,
+ can_simplify_params: SimplifyParams,
+ strip_references: StripReferences,
) -> Option<SimplifiedType> {
match *ty.kind() {
ty::Bool => Some(BoolSimplifiedType),
@@ -67,19 +97,24 @@ pub fn simplify_type(
ty::Float(float_type) => Some(FloatSimplifiedType(float_type)),
ty::Adt(def, _) => Some(AdtSimplifiedType(def.did)),
ty::Str => Some(StrSimplifiedType),
- ty::Array(..) | ty::Slice(_) => Some(ArraySimplifiedType),
- ty::RawPtr(_) => Some(PtrSimplifiedType),
+ ty::Array(..) => Some(ArraySimplifiedType),
+ ty::Slice(..) => Some(SliceSimplifiedType),
+ ty::RawPtr(ptr) => Some(PtrSimplifiedType(ptr.mutbl)),
ty::Dynamic(ref trait_info, ..) => match trait_info.principal_def_id() {
Some(principal_def_id) if !tcx.trait_is_auto(principal_def_id) => {
Some(TraitSimplifiedType(principal_def_id))
}
_ => Some(MarkerTraitObjectSimplifiedType),
},
- ty::Ref(_, ty, _) => {
- // since we introduce auto-refs during method lookup, we
- // just treat &T and T as equivalent from the point of
- // view of possibly unifying
- simplify_type(tcx, ty, can_simplify_params)
+ ty::Ref(_, ty, mutbl) => {
+ if strip_references == StripReferences::Yes {
+ // For diagnostics, when recommending similar impls we want to
+ // recommend impls even when there is a reference mismatch,
+ // so we treat &T and T equivalently in that case.
+ simplify_type(tcx, ty, can_simplify_params, strip_references)
+ } else {
+ Some(RefSimplifiedType(mutbl))
+ }
}
ty::FnDef(def_id, _) | ty::Closure(def_id, _) => Some(ClosureSimplifiedType(def_id)),
ty::Generator(def_id, _, _) => Some(GeneratorSimplifiedType(def_id)),
@@ -90,7 +125,7 @@ pub fn simplify_type(
ty::Tuple(ref tys) => Some(TupleSimplifiedType(tys.len())),
ty::FnPtr(ref f) => Some(FunctionSimplifiedType(f.skip_binder().inputs().len())),
ty::Projection(_) | ty::Param(_) => {
- if can_simplify_params {
+ if can_simplify_params == SimplifyParams::Yes {
// In normalized types, projections don't unify with
// anything. when lazy normalization happens, this
// will change. It would still be nice to have a way
@@ -120,9 +155,12 @@ impl<D: Copy + Debug + Ord + Eq> SimplifiedTypeGen<D> {
UintSimplifiedType(t) => UintSimplifiedType(t),
FloatSimplifiedType(t) => FloatSimplifiedType(t),
AdtSimplifiedType(d) => AdtSimplifiedType(map(d)),
+ ForeignSimplifiedType(d) => ForeignSimplifiedType(map(d)),
StrSimplifiedType => StrSimplifiedType,
ArraySimplifiedType => ArraySimplifiedType,
- PtrSimplifiedType => PtrSimplifiedType,
+ SliceSimplifiedType => SliceSimplifiedType,
+ RefSimplifiedType(m) => RefSimplifiedType(m),
+ PtrSimplifiedType(m) => PtrSimplifiedType(m),
NeverSimplifiedType => NeverSimplifiedType,
MarkerTraitObjectSimplifiedType => MarkerTraitObjectSimplifiedType,
TupleSimplifiedType(n) => TupleSimplifiedType(n),
@@ -133,7 +171,6 @@ impl<D: Copy + Debug + Ord + Eq> SimplifiedTypeGen<D> {
OpaqueSimplifiedType(d) => OpaqueSimplifiedType(map(d)),
FunctionSimplifiedType(n) => FunctionSimplifiedType(n),
ParameterSimplifiedType => ParameterSimplifiedType,
- ForeignSimplifiedType(d) => ForeignSimplifiedType(d),
}
}
}
@@ -149,12 +186,13 @@ where
| CharSimplifiedType
| StrSimplifiedType
| ArraySimplifiedType
- | PtrSimplifiedType
+ | SliceSimplifiedType
| NeverSimplifiedType
| ParameterSimplifiedType
| MarkerTraitObjectSimplifiedType => {
// nothing to do
}
+ RefSimplifiedType(m) | PtrSimplifiedType(m) => m.hash_stable(hcx, hasher),
IntSimplifiedType(t) => t.hash_stable(hcx, hasher),
UintSimplifiedType(t) => t.hash_stable(hcx, hasher),
FloatSimplifiedType(t) => t.hash_stable(hcx, hasher),
diff --git a/compiler/rustc_middle/src/ty/fold.rs b/compiler/rustc_middle/src/ty/fold.rs
index e16491dcc90..aff485a4132 100644
--- a/compiler/rustc_middle/src/ty/fold.rs
+++ b/compiler/rustc_middle/src/ty/fold.rs
@@ -46,9 +46,30 @@ use std::ops::ControlFlow;
///
/// To implement this conveniently, use the derive macro located in `rustc_macros`.
pub trait TypeFoldable<'tcx>: fmt::Debug + Clone {
- fn super_fold_with<F: TypeFolder<'tcx>>(self, folder: &mut F) -> Self;
- fn fold_with<F: TypeFolder<'tcx>>(self, folder: &mut F) -> Self {
- self.super_fold_with(folder)
+ /// Consumers may find this more convenient to use with infallible folders than
+ /// [`try_super_fold_with`][`TypeFoldable::try_super_fold_with`], to which the
+ /// provided default definition delegates. Implementors **should not** override
+ /// this provided default definition, to ensure that the two methods are coherent
+ /// (provide a definition of `try_super_fold_with` instead).
+ fn super_fold_with<F: TypeFolder<'tcx, Error = !>>(self, folder: &mut F) -> Self {
+ self.try_super_fold_with(folder).into_ok()
+ }
+ /// Consumers may find this more convenient to use with infallible folders than
+ /// [`try_fold_with`][`TypeFoldable::try_fold_with`], to which the provided
+ /// default definition delegates. Implementors **should not** override this
+ /// provided default definition, to ensure that the two methods are coherent
+ /// (provide a definition of `try_fold_with` instead).
+ fn fold_with<F: TypeFolder<'tcx, Error = !>>(self, folder: &mut F) -> Self {
+ self.try_fold_with(folder).into_ok()
+ }
+
+ fn try_super_fold_with<F: FallibleTypeFolder<'tcx>>(
+ self,
+ folder: &mut F,
+ ) -> Result<Self, F::Error>;
+
+ fn try_fold_with<F: FallibleTypeFolder<'tcx>>(self, folder: &mut F) -> Result<Self, F::Error> {
+ self.try_super_fold_with(folder)
}
fn super_visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> ControlFlow<V::BreakTy>;
@@ -179,8 +200,8 @@ pub trait TypeFoldable<'tcx>: fmt::Debug + Clone {
}
impl TypeFoldable<'tcx> for hir::Constness {
- fn super_fold_with<F: TypeFolder<'tcx>>(self, _: &mut F) -> Self {
- self
+ fn try_super_fold_with<F: TypeFolder<'tcx>>(self, _: &mut F) -> Result<Self, F::Error> {
+ Ok(self)
}
fn super_visit_with<V: TypeVisitor<'tcx>>(&self, _: &mut V) -> ControlFlow<V::BreakTy> {
ControlFlow::CONTINUE
@@ -192,37 +213,152 @@ impl TypeFoldable<'tcx> for hir::Constness {
/// default implementation that does an "identity" fold. Within each
/// identity fold, it should invoke `foo.fold_with(self)` to fold each
/// sub-item.
+///
+/// If this folder is fallible (and therefore its [`Error`][`TypeFolder::Error`]
+/// associated type is something other than the default, never),
+/// [`FallibleTypeFolder`] should be implemented manually; otherwise,
+/// a blanket implementation of [`FallibleTypeFolder`] will defer to
+/// the infallible methods of this trait to ensure that the two APIs
+/// are coherent.
pub trait TypeFolder<'tcx>: Sized {
+ type Error = !;
+
fn tcx<'a>(&'a self) -> TyCtxt<'tcx>;
fn fold_binder<T>(&mut self, t: Binder<'tcx, T>) -> Binder<'tcx, T>
where
T: TypeFoldable<'tcx>,
+ Self: TypeFolder<'tcx, Error = !>,
{
t.super_fold_with(self)
}
- fn fold_ty(&mut self, t: Ty<'tcx>) -> Ty<'tcx> {
+ fn fold_ty(&mut self, t: Ty<'tcx>) -> Ty<'tcx>
+ where
+ Self: TypeFolder<'tcx, Error = !>,
+ {
t.super_fold_with(self)
}
- fn fold_region(&mut self, r: ty::Region<'tcx>) -> ty::Region<'tcx> {
+ fn fold_region(&mut self, r: ty::Region<'tcx>) -> ty::Region<'tcx>
+ where
+ Self: TypeFolder<'tcx, Error = !>,
+ {
r.super_fold_with(self)
}
- fn fold_const(&mut self, c: &'tcx ty::Const<'tcx>) -> &'tcx ty::Const<'tcx> {
+ fn fold_const(&mut self, c: &'tcx ty::Const<'tcx>) -> &'tcx ty::Const<'tcx>
+ where
+ Self: TypeFolder<'tcx, Error = !>,
+ {
c.super_fold_with(self)
}
- fn fold_predicate(&mut self, p: ty::Predicate<'tcx>) -> ty::Predicate<'tcx> {
+ fn fold_predicate(&mut self, p: ty::Predicate<'tcx>) -> ty::Predicate<'tcx>
+ where
+ Self: TypeFolder<'tcx, Error = !>,
+ {
p.super_fold_with(self)
}
- fn fold_mir_const(&mut self, c: mir::ConstantKind<'tcx>) -> mir::ConstantKind<'tcx> {
+ fn fold_mir_const(&mut self, c: mir::ConstantKind<'tcx>) -> mir::ConstantKind<'tcx>
+ where
+ Self: TypeFolder<'tcx, Error = !>,
+ {
bug!("most type folders should not be folding MIR datastructures: {:?}", c)
}
}
+/// The `FallibleTypeFolder` trait defines the actual *folding*. There is a
+/// method defined for every foldable type. Each of these has a
+/// default implementation that does an "identity" fold. Within each
+/// identity fold, it should invoke `foo.try_fold_with(self)` to fold each
+/// sub-item.
+///
+/// A blanket implementation of this trait (that defers to the relevant
+/// method of [`TypeFolder`]) is provided for all infallible folders in
+/// order to ensure the two APIs are coherent.
+pub trait FallibleTypeFolder<'tcx>: TypeFolder<'tcx> {
+ fn try_fold_binder<T>(&mut self, t: Binder<'tcx, T>) -> Result<Binder<'tcx, T>, Self::Error>
+ where
+ T: TypeFoldable<'tcx>,
+ {
+ t.try_super_fold_with(self)
+ }
+
+ fn try_fold_ty(&mut self, t: Ty<'tcx>) -> Result<Ty<'tcx>, Self::Error> {
+ t.try_super_fold_with(self)
+ }
+
+ fn try_fold_region(&mut self, r: ty::Region<'tcx>) -> Result<ty::Region<'tcx>, Self::Error> {
+ r.try_super_fold_with(self)
+ }
+
+ fn try_fold_const(
+ &mut self,
+ c: &'tcx ty::Const<'tcx>,
+ ) -> Result<&'tcx ty::Const<'tcx>, Self::Error> {
+ c.try_super_fold_with(self)
+ }
+
+ fn try_fold_predicate(
+ &mut self,
+ p: ty::Predicate<'tcx>,
+ ) -> Result<ty::Predicate<'tcx>, Self::Error> {
+ p.try_super_fold_with(self)
+ }
+
+ fn try_fold_mir_const(
+ &mut self,
+ c: mir::ConstantKind<'tcx>,
+ ) -> Result<mir::ConstantKind<'tcx>, Self::Error> {
+ bug!("most type folders should not be folding MIR datastructures: {:?}", c)
+ }
+}
+
+// Blanket implementation of fallible trait for infallible folders
+// delegates to infallible methods to prevent incoherence
+impl<'tcx, F> FallibleTypeFolder<'tcx> for F
+where
+ F: TypeFolder<'tcx, Error = !>,
+{
+ fn try_fold_binder<T>(&mut self, t: Binder<'tcx, T>) -> Result<Binder<'tcx, T>, Self::Error>
+ where
+ T: TypeFoldable<'tcx>,
+ {
+ Ok(self.fold_binder(t))
+ }
+
+ fn try_fold_ty(&mut self, t: Ty<'tcx>) -> Result<Ty<'tcx>, Self::Error> {
+ Ok(self.fold_ty(t))
+ }
+
+ fn try_fold_region(&mut self, r: ty::Region<'tcx>) -> Result<ty::Region<'tcx>, Self::Error> {
+ Ok(self.fold_region(r))
+ }
+
+ fn try_fold_const(
+ &mut self,
+ c: &'tcx ty::Const<'tcx>,
+ ) -> Result<&'tcx ty::Const<'tcx>, Self::Error> {
+ Ok(self.fold_const(c))
+ }
+
+ fn try_fold_predicate(
+ &mut self,
+ p: ty::Predicate<'tcx>,
+ ) -> Result<ty::Predicate<'tcx>, Self::Error> {
+ Ok(self.fold_predicate(p))
+ }
+
+ fn try_fold_mir_const(
+ &mut self,
+ c: mir::ConstantKind<'tcx>,
+ ) -> Result<mir::ConstantKind<'tcx>, Self::Error> {
+ Ok(self.fold_mir_const(c))
+ }
+}
+
pub trait TypeVisitor<'tcx>: Sized {
type BreakTy = !;
/// Supplies the `tcx` for an unevaluated anonymous constant in case its default substs
diff --git a/compiler/rustc_middle/src/ty/generics.rs b/compiler/rustc_middle/src/ty/generics.rs
index f53f1871508..1c3a01e2cfa 100644
--- a/compiler/rustc_middle/src/ty/generics.rs
+++ b/compiler/rustc_middle/src/ty/generics.rs
@@ -24,13 +24,11 @@ impl GenericParamDefKind {
GenericParamDefKind::Const { .. } => "constant",
}
}
- pub fn to_ord(&self, tcx: TyCtxt<'_>) -> ast::ParamKindOrd {
+ pub fn to_ord(&self) -> ast::ParamKindOrd {
match self {
GenericParamDefKind::Lifetime => ast::ParamKindOrd::Lifetime,
GenericParamDefKind::Type { .. } => ast::ParamKindOrd::Type,
- GenericParamDefKind::Const { .. } => {
- ast::ParamKindOrd::Const { unordered: tcx.features().unordered_const_ty_params() }
- }
+ GenericParamDefKind::Const { .. } => ast::ParamKindOrd::Const,
}
}
}
diff --git a/compiler/rustc_middle/src/ty/instance.rs b/compiler/rustc_middle/src/ty/instance.rs
index 4b38105e447..2d301262730 100644
--- a/compiler/rustc_middle/src/ty/instance.rs
+++ b/compiler/rustc_middle/src/ty/instance.rs
@@ -7,6 +7,7 @@ use rustc_hir::def::Namespace;
use rustc_hir::def_id::{CrateNum, DefId};
use rustc_hir::lang_items::LangItem;
use rustc_macros::HashStable;
+use rustc_middle::ty::normalize_erasing_regions::NormalizationError;
use std::fmt;
@@ -575,6 +576,23 @@ impl<'tcx> Instance<'tcx> {
}
}
+ #[inline(always)]
+ pub fn try_subst_mir_and_normalize_erasing_regions<T>(
+ &self,
+ tcx: TyCtxt<'tcx>,
+ param_env: ty::ParamEnv<'tcx>,
+ v: T,
+ ) -> Result<T, NormalizationError<'tcx>>
+ where
+ T: TypeFoldable<'tcx> + Clone,
+ {
+ if let Some(substs) = self.substs_for_mir_body() {
+ tcx.try_subst_and_normalize_erasing_regions(substs, param_env, v)
+ } else {
+ tcx.try_normalize_erasing_regions(param_env, v)
+ }
+ }
+
/// Returns a new `Instance` where generic parameters in `instance.substs` are replaced by
/// identity parameters if they are determined to be unused in `instance.def`.
pub fn polymorphize(self, tcx: TyCtxt<'tcx>) -> Self {
diff --git a/compiler/rustc_middle/src/ty/layout.rs b/compiler/rustc_middle/src/ty/layout.rs
index b87e23af72b..727c0ba63cb 100644
--- a/compiler/rustc_middle/src/ty/layout.rs
+++ b/compiler/rustc_middle/src/ty/layout.rs
@@ -1,5 +1,6 @@
use crate::middle::codegen_fn_attrs::CodegenFnAttrFlags;
use crate::mir::{GeneratorLayout, GeneratorSavedLocal};
+use crate::ty::normalize_erasing_regions::NormalizationError;
use crate::ty::subst::Subst;
use crate::ty::{self, subst::SubstsRef, ReprOptions, Ty, TyCtxt, TypeFoldable};
use rustc_ast as ast;
@@ -199,6 +200,7 @@ pub const MAX_SIMD_LANES: u64 = 1 << 0xF;
pub enum LayoutError<'tcx> {
Unknown(Ty<'tcx>),
SizeOverflow(Ty<'tcx>),
+ NormalizationFailure(Ty<'tcx>, NormalizationError<'tcx>),
}
impl<'tcx> fmt::Display for LayoutError<'tcx> {
@@ -208,16 +210,24 @@ impl<'tcx> fmt::Display for LayoutError<'tcx> {
LayoutError::SizeOverflow(ty) => {
write!(f, "values of the type `{}` are too big for the current architecture", ty)
}
+ LayoutError::NormalizationFailure(t, e) => write!(
+ f,
+ "unable to determine layout for `{}` because `{}` cannot be normalized",
+ t,
+ e.get_type_for_failure()
+ ),
}
}
}
+#[instrument(skip(tcx, query), level = "debug")]
fn layout_of<'tcx>(
tcx: TyCtxt<'tcx>,
query: ty::ParamEnvAnd<'tcx, Ty<'tcx>>,
) -> Result<TyAndLayout<'tcx>, LayoutError<'tcx>> {
ty::tls::with_related_context(tcx, move |icx| {
let (param_env, ty) = query.into_parts();
+ debug!(?ty);
if !tcx.recursion_limit().value_within_limit(icx.layout_depth) {
tcx.sess.fatal(&format!("overflow representing the type `{}`", ty));
@@ -229,7 +239,18 @@ fn layout_of<'tcx>(
ty::tls::enter_context(&icx, |_| {
let param_env = param_env.with_reveal_all_normalized(tcx);
let unnormalized_ty = ty;
- let ty = tcx.normalize_erasing_regions(param_env, ty);
+
+ // FIXME: We might want to have two different versions of `layout_of`:
+ // One that can be called after typecheck has completed and can use
+ // `normalize_erasing_regions` here and another one that can be called
+ // before typecheck has completed and uses `try_normalize_erasing_regions`.
+ let ty = match tcx.try_normalize_erasing_regions(param_env, ty) {
+ Ok(t) => t,
+ Err(normalization_error) => {
+ return Err(LayoutError::NormalizationFailure(ty, normalization_error));
+ }
+ };
+
if ty != unnormalized_ty {
// Ensure this layout is also cached for the normalized type.
return tcx.layout_of(param_env.and(ty));
@@ -326,10 +347,6 @@ impl<'tcx> LayoutCx<'tcx, TyCtxt<'tcx>> {
let mut inverse_memory_index: Vec<u32> = (0..fields.len() as u32).collect();
- // `ReprOptions.layout_seed` is a deterministic seed that we can use to
- // randomize field ordering with
- let mut rng = Xoshiro128StarStar::seed_from_u64(repr.field_shuffle_seed);
-
let optimize = !repr.inhibit_struct_field_reordering_opt();
if optimize {
let end =
@@ -343,6 +360,10 @@ impl<'tcx> LayoutCx<'tcx, TyCtxt<'tcx>> {
// the field ordering to try and catch some code making assumptions about layouts
// we don't guarantee
if repr.can_randomize_type_layout() {
+ // `ReprOptions.layout_seed` is a deterministic seed that we can use to
+ // randomize field ordering with
+ let mut rng = Xoshiro128StarStar::seed_from_u64(repr.field_shuffle_seed);
+
// Shuffle the ordering of the fields
optimizing.shuffle(&mut rng);
@@ -512,7 +533,7 @@ impl<'tcx> LayoutCx<'tcx, TyCtxt<'tcx>> {
}
}
- if sized && fields.iter().any(|f| f.abi.is_uninhabited()) {
+ if fields.iter().any(|f| f.abi.is_uninhabited()) {
abi = Abi::Uninhabited;
}
diff --git a/compiler/rustc_middle/src/ty/list.rs b/compiler/rustc_middle/src/ty/list.rs
index 1dceda6c7aa..adba7d13159 100644
--- a/compiler/rustc_middle/src/ty/list.rs
+++ b/compiler/rustc_middle/src/ty/list.rs
@@ -1,7 +1,5 @@
use crate::arena::Arena;
-
use rustc_serialize::{Encodable, Encoder};
-
use std::alloc::Layout;
use std::cmp::Ordering;
use std::fmt;
@@ -12,49 +10,69 @@ use std::ops::Deref;
use std::ptr;
use std::slice;
-extern "C" {
- /// A dummy type used to force `List` to be unsized while not requiring references to it be wide
- /// pointers.
- type OpaqueListContents;
-}
-
-/// A wrapper for slices with the additional invariant
-/// that the slice is interned and no other slice with
-/// the same contents can exist in the same context.
-/// This means we can use pointer for both
-/// equality comparisons and hashing.
-///
-/// Unlike slices, the types contained in `List` are expected to be `Copy`
-/// and iterating over a `List` returns `T` instead of a reference.
-///
-/// Note: `Slice` was already taken by the `Ty`.
+/// `List<T>` is a bit like `&[T]`, but with some critical differences.
+/// - IMPORTANT: Every `List<T>` is *required* to have unique contents. The
+/// type's correctness relies on this, *but it does not enforce it*.
+/// Therefore, any code that creates a `List<T>` must ensure uniqueness
+/// itself. In practice this is achieved by interning.
+/// - The length is stored within the `List<T>`, so `&List<Ty>` is a thin
+/// pointer.
+/// - Because of this, you cannot get a `List<T>` that is a sub-list of another
+/// `List<T>`. You can get a sub-slice `&[T]`, however.
+/// - `List<T>` can be used with `CopyTaggedPtr`, which is useful within
+/// structs whose size must be minimized.
+/// - Because of the uniqueness assumption, we can use the address of a
+/// `List<T>` for faster equality comparisons and hashing.
+/// - `T` must be `Copy`. This lets `List<T>` be stored in a dropless arena and
+/// iterators return a `T` rather than a `&T`.
+/// - `T` must not be zero-sized.
#[repr(C)]
pub struct List<T> {
len: usize,
+
+ /// Although this claims to be a zero-length array, in practice `len`
+ /// elements are actually present.
data: [T; 0],
+
opaque: OpaqueListContents,
}
-unsafe impl<'a, T: 'a> rustc_data_structures::tagged_ptr::Pointer for &'a List<T> {
- const BITS: usize = std::mem::align_of::<usize>().trailing_zeros() as usize;
- #[inline]
- fn into_usize(self) -> usize {
- self as *const List<T> as usize
- }
- #[inline]
- unsafe fn from_usize(ptr: usize) -> Self {
- &*(ptr as *const List<T>)
- }
- unsafe fn with_ref<R, F: FnOnce(&Self) -> R>(ptr: usize, f: F) -> R {
- // Self: Copy so this is fine
- let ptr = Self::from_usize(ptr);
- f(&ptr)
- }
+extern "C" {
+ /// A dummy type used to force `List` to be unsized while not requiring
+ /// references to it be wide pointers.
+ type OpaqueListContents;
}
-unsafe impl<T: Sync> Sync for List<T> {}
+impl<T> List<T> {
+ /// Returns a reference to the (unique, static) empty list.
+ #[inline(always)]
+ pub fn empty<'a>() -> &'a List<T> {
+ #[repr(align(64))]
+ struct MaxAlign;
+
+ assert!(mem::align_of::<T>() <= mem::align_of::<MaxAlign>());
+
+ #[repr(C)]
+ struct InOrder<T, U>(T, U);
+
+ // The empty slice is static and contains a single `0` usize (for the
+ // length) that is 64-byte aligned, thus featuring the necessary
+ // trailing padding for elements with up to 64-byte alignment.
+ static EMPTY_SLICE: InOrder<usize, MaxAlign> = InOrder(0, MaxAlign);
+ unsafe { &*(&EMPTY_SLICE as *const _ as *const List<T>) }
+ }
+}
impl<T: Copy> List<T> {
+ /// Allocates a list from `arena` and copies the contents of `slice` into it.
+ ///
+ /// WARNING: the contents *must be unique*, such that no list with these
+ /// contents has been previously created. If not, operations such as `eq`
+ /// and `hash` might give incorrect results.
+ ///
+ /// Panics if `T` is `Drop`, or `T` is zero-sized, or the slice is empty
+ /// (because the empty list exists statically, and is available via
+ /// `empty()`).
#[inline]
pub(super) fn from_arena<'tcx>(arena: &'tcx Arena<'tcx>, slice: &[T]) -> &'tcx List<T> {
assert!(!mem::needs_drop::<T>());
@@ -73,7 +91,7 @@ impl<T: Copy> List<T> {
.cast::<T>()
.copy_from_nonoverlapping(slice.as_ptr(), slice.len());
- &mut *mem
+ &*mem
}
}
@@ -107,11 +125,24 @@ impl<S: Encoder, T: Encodable<S>> Encodable<S> for &List<T> {
}
}
+impl<T: PartialEq> PartialEq for List<T> {
+ #[inline]
+ fn eq(&self, other: &List<T>) -> bool {
+ // Pointer equality implies list equality (due to the unique contents
+ // assumption).
+ ptr::eq(self, other)
+ }
+}
+
+impl<T: Eq> Eq for List<T> {}
+
impl<T> Ord for List<T>
where
T: Ord,
{
fn cmp(&self, other: &List<T>) -> Ordering {
+ // Pointer equality implies list equality (due to the unique contents
+ // assumption), but the contents must be compared otherwise.
if self == other { Ordering::Equal } else { <[T] as Ord>::cmp(&**self, &**other) }
}
}
@@ -121,6 +152,8 @@ where
T: PartialOrd,
{
fn partial_cmp(&self, other: &List<T>) -> Option<Ordering> {
+ // Pointer equality implies list equality (due to the unique contents
+ // assumption), but the contents must be compared otherwise.
if self == other {
Some(Ordering::Equal)
} else {
@@ -129,17 +162,11 @@ where
}
}
-impl<T: PartialEq> PartialEq for List<T> {
- #[inline]
- fn eq(&self, other: &List<T>) -> bool {
- ptr::eq(self, other)
- }
-}
-impl<T: Eq> Eq for List<T> {}
-
impl<T> Hash for List<T> {
#[inline]
fn hash<H: Hasher>(&self, s: &mut H) {
+ // Pointer hashing is sufficient (due to the unique contents
+ // assumption).
(self as *const List<T>).hash(s)
}
}
@@ -168,13 +195,24 @@ impl<'a, T: Copy> IntoIterator for &'a List<T> {
}
}
-impl<T> List<T> {
- #[inline(always)]
- pub fn empty<'a>() -> &'a List<T> {
- #[repr(align(64), C)]
- struct EmptySlice([u8; 64]);
- static EMPTY_SLICE: EmptySlice = EmptySlice([0; 64]);
- assert!(mem::align_of::<T>() <= 64);
- unsafe { &*(&EMPTY_SLICE as *const _ as *const List<T>) }
+unsafe impl<T: Sync> Sync for List<T> {}
+
+unsafe impl<'a, T: 'a> rustc_data_structures::tagged_ptr::Pointer for &'a List<T> {
+ const BITS: usize = std::mem::align_of::<usize>().trailing_zeros() as usize;
+
+ #[inline]
+ fn into_usize(self) -> usize {
+ self as *const List<T> as usize
+ }
+
+ #[inline]
+ unsafe fn from_usize(ptr: usize) -> &'a List<T> {
+ &*(ptr as *const List<T>)
+ }
+
+ unsafe fn with_ref<R, F: FnOnce(&Self) -> R>(ptr: usize, f: F) -> R {
+ // `Self` is `&'a List<T>` which impls `Copy`, so this is fine.
+ let ptr = Self::from_usize(ptr);
+ f(&ptr)
}
}
diff --git a/compiler/rustc_middle/src/ty/mod.rs b/compiler/rustc_middle/src/ty/mod.rs
index 673733faa76..10232dc9cb6 100644
--- a/compiler/rustc_middle/src/ty/mod.rs
+++ b/compiler/rustc_middle/src/ty/mod.rs
@@ -9,7 +9,7 @@
//!
//! ["The `ty` module: representing types"]: https://rustc-dev-guide.rust-lang.org/ty.html
-pub use self::fold::{TypeFoldable, TypeFolder, TypeVisitor};
+pub use self::fold::{FallibleTypeFolder, TypeFoldable, TypeFolder, TypeVisitor};
pub use self::AssocItemContainer::*;
pub use self::BorrowKind::*;
pub use self::IntVarValue::*;
@@ -230,6 +230,19 @@ pub enum BoundConstness {
ConstIfConst,
}
+impl BoundConstness {
+ /// Reduce `self` and `constness` to two possible combined states instead of four.
+ pub fn and(&mut self, constness: hir::Constness) -> hir::Constness {
+ match (constness, self) {
+ (hir::Constness::Const, BoundConstness::ConstIfConst) => hir::Constness::Const,
+ (_, this) => {
+ *this = BoundConstness::NotConst;
+ hir::Constness::NotConst
+ }
+ }
+ }
+}
+
impl fmt::Display for BoundConstness {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
@@ -846,20 +859,6 @@ impl ToPredicate<'tcx> for Binder<'tcx, PredicateKind<'tcx>> {
}
}
-impl<'tcx> ToPredicate<'tcx> for ConstnessAnd<PolyTraitRef<'tcx>> {
- fn to_predicate(self, tcx: TyCtxt<'tcx>) -> Predicate<'tcx> {
- self.value
- .map_bound(|trait_ref| {
- PredicateKind::Trait(ty::TraitPredicate {
- trait_ref,
- constness: self.constness,
- polarity: ty::ImplPolarity::Positive,
- })
- })
- .to_predicate(tcx)
- }
-}
-
impl<'tcx> ToPredicate<'tcx> for PolyTraitPredicate<'tcx> {
fn to_predicate(self, tcx: TyCtxt<'tcx>) -> Predicate<'tcx> {
self.map_bound(PredicateKind::Trait).to_predicate(tcx)
@@ -885,12 +884,10 @@ impl<'tcx> ToPredicate<'tcx> for PolyProjectionPredicate<'tcx> {
}
impl<'tcx> Predicate<'tcx> {
- pub fn to_opt_poly_trait_ref(self) -> Option<ConstnessAnd<PolyTraitRef<'tcx>>> {
+ pub fn to_opt_poly_trait_pred(self) -> Option<PolyTraitPredicate<'tcx>> {
let predicate = self.kind();
match predicate.skip_binder() {
- PredicateKind::Trait(t) => {
- Some(ConstnessAnd { constness: t.constness, value: predicate.rebind(t.trait_ref) })
- }
+ PredicateKind::Trait(t) => Some(predicate.rebind(t)),
PredicateKind::Projection(..)
| PredicateKind::Subtype(..)
| PredicateKind::Coerce(..)
@@ -1221,23 +1218,33 @@ pub struct ParamEnv<'tcx> {
/// want `Reveal::All`.
///
/// Note: This is packed, use the reveal() method to access it.
- packed: CopyTaggedPtr<&'tcx List<Predicate<'tcx>>, traits::Reveal, true>,
+ packed: CopyTaggedPtr<&'tcx List<Predicate<'tcx>>, ParamTag, true>,
}
-unsafe impl rustc_data_structures::tagged_ptr::Tag for traits::Reveal {
- const BITS: usize = 1;
+#[derive(Copy, Clone)]
+struct ParamTag {
+ reveal: traits::Reveal,
+ constness: hir::Constness,
+}
+
+unsafe impl rustc_data_structures::tagged_ptr::Tag for ParamTag {
+ const BITS: usize = 2;
#[inline]
fn into_usize(self) -> usize {
match self {
- traits::Reveal::UserFacing => 0,
- traits::Reveal::All => 1,
+ Self { reveal: traits::Reveal::UserFacing, constness: hir::Constness::NotConst } => 0,
+ Self { reveal: traits::Reveal::All, constness: hir::Constness::NotConst } => 1,
+ Self { reveal: traits::Reveal::UserFacing, constness: hir::Constness::Const } => 2,
+ Self { reveal: traits::Reveal::All, constness: hir::Constness::Const } => 3,
}
}
#[inline]
unsafe fn from_usize(ptr: usize) -> Self {
match ptr {
- 0 => traits::Reveal::UserFacing,
- 1 => traits::Reveal::All,
+ 0 => Self { reveal: traits::Reveal::UserFacing, constness: hir::Constness::NotConst },
+ 1 => Self { reveal: traits::Reveal::All, constness: hir::Constness::NotConst },
+ 2 => Self { reveal: traits::Reveal::UserFacing, constness: hir::Constness::Const },
+ 3 => Self { reveal: traits::Reveal::All, constness: hir::Constness::Const },
_ => std::hint::unreachable_unchecked(),
}
}
@@ -1248,6 +1255,7 @@ impl<'tcx> fmt::Debug for ParamEnv<'tcx> {
f.debug_struct("ParamEnv")
.field("caller_bounds", &self.caller_bounds())
.field("reveal", &self.reveal())
+ .field("constness", &self.constness())
.finish()
}
}
@@ -1256,17 +1264,26 @@ impl<'a, 'tcx> HashStable<StableHashingContext<'a>> for ParamEnv<'tcx> {
fn hash_stable(&self, hcx: &mut StableHashingContext<'a>, hasher: &mut StableHasher) {
self.caller_bounds().hash_stable(hcx, hasher);
self.reveal().hash_stable(hcx, hasher);
+ self.constness().hash_stable(hcx, hasher);
}
}
impl<'tcx> TypeFoldable<'tcx> for ParamEnv<'tcx> {
- fn super_fold_with<F: ty::fold::TypeFolder<'tcx>>(self, folder: &mut F) -> Self {
- ParamEnv::new(self.caller_bounds().fold_with(folder), self.reveal().fold_with(folder))
+ fn try_super_fold_with<F: ty::fold::FallibleTypeFolder<'tcx>>(
+ self,
+ folder: &mut F,
+ ) -> Result<Self, F::Error> {
+ Ok(ParamEnv::new(
+ self.caller_bounds().try_fold_with(folder)?,
+ self.reveal().try_fold_with(folder)?,
+ self.constness().try_fold_with(folder)?,
+ ))
}
fn super_visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> ControlFlow<V::BreakTy> {
self.caller_bounds().visit_with(visitor)?;
- self.reveal().visit_with(visitor)
+ self.reveal().visit_with(visitor)?;
+ self.constness().visit_with(visitor)
}
}
@@ -1277,7 +1294,7 @@ impl<'tcx> ParamEnv<'tcx> {
/// type-checking.
#[inline]
pub fn empty() -> Self {
- Self::new(List::empty(), Reveal::UserFacing)
+ Self::new(List::empty(), Reveal::UserFacing, hir::Constness::NotConst)
}
#[inline]
@@ -1287,7 +1304,12 @@ impl<'tcx> ParamEnv<'tcx> {
#[inline]
pub fn reveal(self) -> traits::Reveal {
- self.packed.tag()
+ self.packed.tag().reveal
+ }
+
+ #[inline]
+ pub fn constness(self) -> hir::Constness {
+ self.packed.tag().constness
}
/// Construct a trait environment with no where-clauses in scope
@@ -1299,20 +1321,47 @@ impl<'tcx> ParamEnv<'tcx> {
/// or invoke `param_env.with_reveal_all()`.
#[inline]
pub fn reveal_all() -> Self {
- Self::new(List::empty(), Reveal::All)
+ Self::new(List::empty(), Reveal::All, hir::Constness::NotConst)
}
/// Construct a trait environment with the given set of predicates.
#[inline]
- pub fn new(caller_bounds: &'tcx List<Predicate<'tcx>>, reveal: Reveal) -> Self {
- ty::ParamEnv { packed: CopyTaggedPtr::new(caller_bounds, reveal) }
+ pub fn new(
+ caller_bounds: &'tcx List<Predicate<'tcx>>,
+ reveal: Reveal,
+ constness: hir::Constness,
+ ) -> Self {
+ ty::ParamEnv { packed: CopyTaggedPtr::new(caller_bounds, ParamTag { reveal, constness }) }
}
pub fn with_user_facing(mut self) -> Self {
- self.packed.set_tag(Reveal::UserFacing);
+ self.packed.set_tag(ParamTag { reveal: Reveal::UserFacing, ..self.packed.tag() });
+ self
+ }
+
+ #[inline]
+ pub fn with_constness(mut self, constness: hir::Constness) -> Self {
+ self.packed.set_tag(ParamTag { constness, ..self.packed.tag() });
+ self
+ }
+
+ #[inline]
+ pub fn with_const(mut self) -> Self {
+ self.packed.set_tag(ParamTag { constness: hir::Constness::Const, ..self.packed.tag() });
self
}
+ #[inline]
+ pub fn without_const(mut self) -> Self {
+ self.packed.set_tag(ParamTag { constness: hir::Constness::NotConst, ..self.packed.tag() });
+ self
+ }
+
+ #[inline]
+ pub fn remap_constness_with(&mut self, mut constness: ty::BoundConstness) {
+ *self = self.with_constness(constness.and(self.constness()))
+ }
+
/// Returns a new parameter environment with the same clauses, but
/// which "reveals" the true results of projections in all cases
/// (even for associated types that are specializable). This is
@@ -1323,17 +1372,21 @@ impl<'tcx> ParamEnv<'tcx> {
/// will be normalized to their underlying types.
/// See PR #65989 and issue #65918 for more details
pub fn with_reveal_all_normalized(self, tcx: TyCtxt<'tcx>) -> Self {
- if self.packed.tag() == traits::Reveal::All {
+ if self.packed.tag().reveal == traits::Reveal::All {
return self;
}
- ParamEnv::new(tcx.normalize_opaque_types(self.caller_bounds()), Reveal::All)
+ ParamEnv::new(
+ tcx.normalize_opaque_types(self.caller_bounds()),
+ Reveal::All,
+ self.constness(),
+ )
}
/// Returns this same environment but with no caller bounds.
#[inline]
pub fn without_caller_bounds(self) -> Self {
- Self::new(List::empty(), self.reveal())
+ Self::new(List::empty(), self.reveal(), self.constness())
}
/// Creates a suitable environment in which to perform trait
@@ -1363,33 +1416,23 @@ impl<'tcx> ParamEnv<'tcx> {
}
}
-#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, TypeFoldable)]
-pub struct ConstnessAnd<T> {
- pub constness: BoundConstness,
- pub value: T,
-}
-
// FIXME(ecstaticmorse): Audit all occurrences of `without_const().to_predicate(tcx)` to ensure that
// the constness of trait bounds is being propagated correctly.
-pub trait WithConstness: Sized {
+impl PolyTraitRef<'tcx> {
#[inline]
- fn with_constness(self, constness: BoundConstness) -> ConstnessAnd<Self> {
- ConstnessAnd { constness, value: self }
- }
-
- #[inline]
- fn with_const_if_const(self) -> ConstnessAnd<Self> {
- self.with_constness(BoundConstness::ConstIfConst)
+ pub fn with_constness(self, constness: BoundConstness) -> PolyTraitPredicate<'tcx> {
+ self.map_bound(|trait_ref| ty::TraitPredicate {
+ trait_ref,
+ constness,
+ polarity: ty::ImplPolarity::Positive,
+ })
}
-
#[inline]
- fn without_const(self) -> ConstnessAnd<Self> {
+ pub fn without_const(self) -> PolyTraitPredicate<'tcx> {
self.with_constness(BoundConstness::NotConst)
}
}
-impl<T> WithConstness for T {}
-
#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, TypeFoldable)]
pub struct ParamEnvAnd<'tcx, T> {
pub param_env: ParamEnv<'tcx>,
@@ -1400,6 +1443,12 @@ impl<'tcx, T> ParamEnvAnd<'tcx, T> {
pub fn into_parts(self) -> (ParamEnv<'tcx>, T) {
(self.param_env, self.value)
}
+
+ #[inline]
+ pub fn without_const(mut self) -> Self {
+ self.param_env = self.param_env.without_const();
+ self
+ }
}
impl<'a, 'tcx, T> HashStable<StableHashingContext<'a>> for ParamEnvAnd<'tcx, T>
@@ -1559,9 +1608,9 @@ bitflags! {
// the seed stored in `ReprOptions.layout_seed`
const RANDOMIZE_LAYOUT = 1 << 5;
// Any of these flags being set prevent field reordering optimisation.
- const IS_UNOPTIMISABLE = ReprFlags::IS_C.bits |
- ReprFlags::IS_SIMD.bits |
- ReprFlags::IS_LINEAR.bits;
+ const IS_UNOPTIMISABLE = ReprFlags::IS_C.bits
+ | ReprFlags::IS_SIMD.bits
+ | ReprFlags::IS_LINEAR.bits;
}
}
@@ -1591,7 +1640,14 @@ impl ReprOptions {
// Generate a deterministically-derived seed from the item's path hash
// to allow for cross-crate compilation to actually work
- let field_shuffle_seed = tcx.def_path_hash(did).0.to_smaller_hash();
+ let mut field_shuffle_seed = tcx.def_path_hash(did).0.to_smaller_hash();
+
+ // If the user defined a custom seed for layout randomization, xor the item's
+ // path hash with the user defined seed, this will allowing determinism while
+ // still allowing users to further randomize layout generation for e.g. fuzzing
+ if let Some(user_seed) = tcx.sess.opts.debugging_opts.layout_seed {
+ field_shuffle_seed ^= user_seed;
+ }
for attr in tcx.get_attrs(did).iter() {
for r in attr::find_repr_attrs(&tcx.sess, attr) {
@@ -1705,7 +1761,7 @@ impl ReprOptions {
impl<'tcx> FieldDef {
/// Returns the type of this field. The resulting type is not normalized. The `subst` is
- /// typically obtained via the second field of `TyKind::AdtDef`.
+ /// typically obtained via the second field of [`TyKind::Adt`].
pub fn ty(&self, tcx: TyCtxt<'tcx>, subst: SubstsRef<'tcx>) -> Ty<'tcx> {
tcx.type_of(self.did).subst(tcx, subst)
}
@@ -2049,13 +2105,17 @@ impl<'tcx> TyCtxt<'tcx> {
}
}
-/// Yields the parent function's `DefId` if `def_id` is an `impl Trait` definition.
-pub fn is_impl_trait_defn(tcx: TyCtxt<'_>, def_id: DefId) -> Option<DefId> {
- if let Some(def_id) = def_id.as_local() {
- if let Node::Item(item) = tcx.hir().get(tcx.hir().local_def_id_to_hir_id(def_id)) {
- if let hir::ItemKind::OpaqueTy(ref opaque_ty) = item.kind {
- return opaque_ty.impl_trait_fn;
- }
+/// Yields the parent function's `LocalDefId` if `def_id` is an `impl Trait` definition.
+pub fn is_impl_trait_defn(tcx: TyCtxt<'_>, def_id: DefId) -> Option<LocalDefId> {
+ let def_id = def_id.as_local()?;
+ if let Node::Item(item) = tcx.hir().get(tcx.hir().local_def_id_to_hir_id(def_id)) {
+ if let hir::ItemKind::OpaqueTy(ref opaque_ty) = item.kind {
+ return match opaque_ty.origin {
+ hir::OpaqueTyOrigin::FnReturn(parent) | hir::OpaqueTyOrigin::AsyncFn(parent) => {
+ Some(parent)
+ }
+ hir::OpaqueTyOrigin::TyAlias => None,
+ };
}
}
None
diff --git a/compiler/rustc_middle/src/ty/normalize_erasing_regions.rs b/compiler/rustc_middle/src/ty/normalize_erasing_regions.rs
index 11399506b96..312093b4f88 100644
--- a/compiler/rustc_middle/src/ty/normalize_erasing_regions.rs
+++ b/compiler/rustc_middle/src/ty/normalize_erasing_regions.rs
@@ -8,10 +8,28 @@
//! or constant found within. (This underlying query is what is cached.)
use crate::mir;
-use crate::ty::fold::{TypeFoldable, TypeFolder};
+use crate::traits::query::NoSolution;
+use crate::ty::fold::{FallibleTypeFolder, TypeFoldable, TypeFolder};
use crate::ty::subst::{Subst, SubstsRef};
use crate::ty::{self, Ty, TyCtxt};
+#[derive(Debug, Copy, Clone, HashStable, TyEncodable, TyDecodable)]
+pub enum NormalizationError<'tcx> {
+ Type(Ty<'tcx>),
+ Const(ty::Const<'tcx>),
+ ConstantKind(mir::ConstantKind<'tcx>),
+}
+
+impl<'tcx> NormalizationError<'tcx> {
+ pub fn get_type_for_failure(&self) -> String {
+ match self {
+ NormalizationError::Type(t) => format!("{}", t),
+ NormalizationError::Const(c) => format!("{}", c),
+ NormalizationError::ConstantKind(ck) => format!("{}", ck),
+ }
+ }
+}
+
impl<'tcx> TyCtxt<'tcx> {
/// Erase the regions in `value` and then fully normalize all the
/// types found within. The result will also have regions erased.
@@ -32,6 +50,8 @@ impl<'tcx> TyCtxt<'tcx> {
// Erase first before we do the real query -- this keeps the
// cache from being too polluted.
let value = self.erase_regions(value);
+ debug!(?value);
+
if !value.has_projections() {
value
} else {
@@ -39,6 +59,39 @@ impl<'tcx> TyCtxt<'tcx> {
}
}
+ /// Tries to erase the regions in `value` and then fully normalize all the
+ /// types found within. The result will also have regions erased.
+ ///
+ /// Contrary to `normalize_erasing_regions` this function does not assume that normalization
+ /// succeeds.
+ pub fn try_normalize_erasing_regions<T>(
+ self,
+ param_env: ty::ParamEnv<'tcx>,
+ value: T,
+ ) -> Result<T, NormalizationError<'tcx>>
+ where
+ T: TypeFoldable<'tcx>,
+ {
+ debug!(
+ "try_normalize_erasing_regions::<{}>(value={:?}, param_env={:?})",
+ std::any::type_name::<T>(),
+ value,
+ param_env,
+ );
+
+ // Erase first before we do the real query -- this keeps the
+ // cache from being too polluted.
+ let value = self.erase_regions(value);
+ debug!(?value);
+
+ if !value.has_projections() {
+ Ok(value)
+ } else {
+ let mut folder = TryNormalizeAfterErasingRegionsFolder::new(self, param_env);
+ value.try_fold_with(&mut folder)
+ }
+ }
+
/// If you have a `Binder<'tcx, T>`, you can do this to strip out the
/// late-bound regions and then normalize the result, yielding up
/// a `T` (with regions erased). This is appropriate when the
@@ -62,6 +115,8 @@ impl<'tcx> TyCtxt<'tcx> {
/// Monomorphizes a type from the AST by first applying the
/// in-scope substitutions and then normalizing any associated
/// types.
+ /// Panics if normalization fails. In case normalization might fail
+ /// use `try_subst_and_normalize_erasing_regions` instead.
pub fn subst_and_normalize_erasing_regions<T>(
self,
param_substs: SubstsRef<'tcx>,
@@ -81,6 +136,30 @@ impl<'tcx> TyCtxt<'tcx> {
let substituted = value.subst(self, param_substs);
self.normalize_erasing_regions(param_env, substituted)
}
+
+ /// Monomorphizes a type from the AST by first applying the
+ /// in-scope substitutions and then trying to normalize any associated
+ /// types. Contrary to `subst_and_normalize_erasing_regions` this does
+ /// not assume that normalization succeeds.
+ pub fn try_subst_and_normalize_erasing_regions<T>(
+ self,
+ param_substs: SubstsRef<'tcx>,
+ param_env: ty::ParamEnv<'tcx>,
+ value: T,
+ ) -> Result<T, NormalizationError<'tcx>>
+ where
+ T: TypeFoldable<'tcx>,
+ {
+ debug!(
+ "subst_and_normalize_erasing_regions(\
+ param_substs={:?}, \
+ value={:?}, \
+ param_env={:?})",
+ param_substs, value, param_env,
+ );
+ let substituted = value.subst(self, param_substs);
+ self.try_normalize_erasing_regions(param_env, substituted)
+ }
}
struct NormalizeAfterErasingRegionsFolder<'tcx> {
@@ -89,12 +168,18 @@ struct NormalizeAfterErasingRegionsFolder<'tcx> {
}
impl<'tcx> NormalizeAfterErasingRegionsFolder<'tcx> {
+ #[instrument(skip(self), level = "debug")]
fn normalize_generic_arg_after_erasing_regions(
&self,
arg: ty::GenericArg<'tcx>,
) -> ty::GenericArg<'tcx> {
let arg = self.param_env.and(arg);
- self.tcx.normalize_generic_arg_after_erasing_regions(arg)
+ debug!(?arg);
+
+ self.tcx.try_normalize_generic_arg_after_erasing_regions(arg).unwrap_or_else(|_| bug!(
+ "Failed to normalize {:?}, maybe try to call `try_normalize_erasing_regions` instead",
+ arg.value
+ ))
}
}
@@ -115,6 +200,69 @@ impl TypeFolder<'tcx> for NormalizeAfterErasingRegionsFolder<'tcx> {
fn fold_mir_const(&mut self, c: mir::ConstantKind<'tcx>) -> mir::ConstantKind<'tcx> {
// FIXME: This *probably* needs canonicalization too!
let arg = self.param_env.and(c);
- self.tcx.normalize_mir_const_after_erasing_regions(arg)
+ self.tcx
+ .try_normalize_mir_const_after_erasing_regions(arg)
+ .unwrap_or_else(|_| bug!("failed to normalize {:?}", c))
+ }
+}
+
+struct TryNormalizeAfterErasingRegionsFolder<'tcx> {
+ tcx: TyCtxt<'tcx>,
+ param_env: ty::ParamEnv<'tcx>,
+}
+
+impl<'tcx> TryNormalizeAfterErasingRegionsFolder<'tcx> {
+ fn new(tcx: TyCtxt<'tcx>, param_env: ty::ParamEnv<'tcx>) -> Self {
+ TryNormalizeAfterErasingRegionsFolder { tcx, param_env }
+ }
+
+ #[instrument(skip(self), level = "debug")]
+ fn try_normalize_generic_arg_after_erasing_regions(
+ &self,
+ arg: ty::GenericArg<'tcx>,
+ ) -> Result<ty::GenericArg<'tcx>, NoSolution> {
+ let arg = self.param_env.and(arg);
+ debug!(?arg);
+
+ self.tcx.try_normalize_generic_arg_after_erasing_regions(arg)
+ }
+}
+
+impl TypeFolder<'tcx> for TryNormalizeAfterErasingRegionsFolder<'tcx> {
+ type Error = NormalizationError<'tcx>;
+
+ fn tcx(&self) -> TyCtxt<'tcx> {
+ self.tcx
+ }
+}
+
+impl FallibleTypeFolder<'tcx> for TryNormalizeAfterErasingRegionsFolder<'tcx> {
+ fn try_fold_ty(&mut self, ty: Ty<'tcx>) -> Result<Ty<'tcx>, Self::Error> {
+ match self.try_normalize_generic_arg_after_erasing_regions(ty.into()) {
+ Ok(t) => Ok(t.expect_ty()),
+ Err(_) => Err(NormalizationError::Type(ty)),
+ }
+ }
+
+ fn try_fold_const(
+ &mut self,
+ c: &'tcx ty::Const<'tcx>,
+ ) -> Result<&'tcx ty::Const<'tcx>, Self::Error> {
+ match self.try_normalize_generic_arg_after_erasing_regions(c.into()) {
+ Ok(t) => Ok(t.expect_const()),
+ Err(_) => Err(NormalizationError::Const(*c)),
+ }
+ }
+
+ fn try_fold_mir_const(
+ &mut self,
+ c: mir::ConstantKind<'tcx>,
+ ) -> Result<mir::ConstantKind<'tcx>, Self::Error> {
+ // FIXME: This *probably* needs canonicalization too!
+ let arg = self.param_env.and(c);
+ match self.tcx.try_normalize_mir_const_after_erasing_regions(arg) {
+ Ok(c) => Ok(c),
+ Err(_) => Err(NormalizationError::ConstantKind(c)),
+ }
}
}
diff --git a/compiler/rustc_middle/src/ty/print/pretty.rs b/compiler/rustc_middle/src/ty/print/pretty.rs
index 3846cf19d91..b3b8183d313 100644
--- a/compiler/rustc_middle/src/ty/print/pretty.rs
+++ b/compiler/rustc_middle/src/ty/print/pretty.rs
@@ -643,81 +643,8 @@ pub trait PrettyPrinter<'tcx>:
}
return Ok(self);
}
- // Grab the "TraitA + TraitB" from `impl TraitA + TraitB`,
- // by looking up the projections associated with the def_id.
- let bounds = self.tcx().explicit_item_bounds(def_id);
-
- let mut first = true;
- let mut is_sized = false;
- let mut is_future = false;
- let mut future_output_ty = None;
-
- p!("impl");
- for (predicate, _) in bounds {
- let predicate = predicate.subst(self.tcx(), substs);
- let bound_predicate = predicate.kind();
-
- match bound_predicate.skip_binder() {
- ty::PredicateKind::Projection(projection_predicate) => {
- let Some(future_trait) = self.tcx().lang_items().future_trait() else { continue };
- let future_output_def_id =
- self.tcx().associated_item_def_ids(future_trait)[0];
-
- if projection_predicate.projection_ty.item_def_id
- == future_output_def_id
- {
- // We don't account for multiple `Future::Output = Ty` contraints.
- is_future = true;
- future_output_ty = Some(projection_predicate.ty);
- }
- }
- ty::PredicateKind::Trait(pred) => {
- let trait_ref = bound_predicate.rebind(pred.trait_ref);
- // Don't print +Sized, but rather +?Sized if absent.
- if Some(trait_ref.def_id()) == self.tcx().lang_items().sized_trait()
- {
- is_sized = true;
- continue;
- }
-
- if Some(trait_ref.def_id())
- == self.tcx().lang_items().future_trait()
- {
- is_future = true;
- continue;
- }
-
- p!(
- write("{}", if first { " " } else { " + " }),
- print(trait_ref.print_only_trait_path())
- );
-
- first = false;
- }
- _ => {}
- }
- }
-
- if is_future {
- p!(write("{}Future", if first { " " } else { " + " }));
- first = false;
-
- if let Some(future_output_ty) = future_output_ty {
- // Don't print projection types, which we (unfortunately) see often
- // in the error outputs involving async blocks.
- if !matches!(future_output_ty.kind(), ty::Projection(_)) {
- p!("<Output = ", print(future_output_ty), ">");
- }
- }
- }
- if !is_sized {
- p!(write("{}?Sized", if first { " " } else { " + " }));
- } else if first {
- p!(" Sized");
- }
-
- Ok(self)
+ self.pretty_print_opaque_impl_type(def_id, substs)
});
}
ty::Str => p!("str"),
@@ -826,6 +753,225 @@ pub trait PrettyPrinter<'tcx>:
Ok(self)
}
+ fn pretty_print_opaque_impl_type(
+ mut self,
+ def_id: DefId,
+ substs: &'tcx ty::List<ty::GenericArg<'tcx>>,
+ ) -> Result<Self::Type, Self::Error> {
+ define_scoped_cx!(self);
+
+ // Grab the "TraitA + TraitB" from `impl TraitA + TraitB`,
+ // by looking up the projections associated with the def_id.
+ let bounds = self.tcx().explicit_item_bounds(def_id);
+
+ let mut traits = BTreeMap::new();
+ let mut fn_traits = BTreeMap::new();
+ let mut is_sized = false;
+
+ for (predicate, _) in bounds {
+ let predicate = predicate.subst(self.tcx(), substs);
+ let bound_predicate = predicate.kind();
+
+ match bound_predicate.skip_binder() {
+ ty::PredicateKind::Trait(pred) => {
+ let trait_ref = bound_predicate.rebind(pred.trait_ref);
+
+ // Don't print + Sized, but rather + ?Sized if absent.
+ if Some(trait_ref.def_id()) == self.tcx().lang_items().sized_trait() {
+ is_sized = true;
+ continue;
+ }
+
+ self.insert_trait_and_projection(trait_ref, None, &mut traits, &mut fn_traits);
+ }
+ ty::PredicateKind::Projection(pred) => {
+ let proj_ref = bound_predicate.rebind(pred);
+ let trait_ref = proj_ref.required_poly_trait_ref(self.tcx());
+
+ // Projection type entry -- the def-id for naming, and the ty.
+ let proj_ty = (proj_ref.projection_def_id(), proj_ref.ty());
+
+ self.insert_trait_and_projection(
+ trait_ref,
+ Some(proj_ty),
+ &mut traits,
+ &mut fn_traits,
+ );
+ }
+ _ => {}
+ }
+ }
+
+ let mut first = true;
+ // Insert parenthesis around (Fn(A, B) -> C) if the opaque ty has more than one other trait
+ let paren_needed = fn_traits.len() > 1 || traits.len() > 0 || !is_sized;
+
+ p!("impl");
+
+ for (fn_once_trait_ref, entry) in fn_traits {
+ // Get the (single) generic ty (the args) of this FnOnce trait ref.
+ let generics = self.generic_args_to_print(
+ self.tcx().generics_of(fn_once_trait_ref.def_id()),
+ fn_once_trait_ref.skip_binder().substs,
+ );
+
+ match (entry.return_ty, generics[0].expect_ty()) {
+ // We can only print `impl Fn() -> ()` if we have a tuple of args and we recorded
+ // a return type.
+ (Some(return_ty), arg_tys) if matches!(arg_tys.kind(), ty::Tuple(_)) => {
+ let name = if entry.fn_trait_ref.is_some() {
+ "Fn"
+ } else if entry.fn_mut_trait_ref.is_some() {
+ "FnMut"
+ } else {
+ "FnOnce"
+ };
+
+ p!(
+ write("{}", if first { " " } else { " + " }),
+ write("{}{}(", if paren_needed { "(" } else { "" }, name)
+ );
+
+ for (idx, ty) in arg_tys.tuple_fields().enumerate() {
+ if idx > 0 {
+ p!(", ");
+ }
+ p!(print(ty));
+ }
+
+ p!(")");
+ if !return_ty.skip_binder().is_unit() {
+ p!("-> ", print(return_ty));
+ }
+ p!(write("{}", if paren_needed { ")" } else { "" }));
+
+ first = false;
+ }
+ // If we got here, we can't print as a `impl Fn(A, B) -> C`. Just record the
+ // trait_refs we collected in the OpaqueFnEntry as normal trait refs.
+ _ => {
+ if entry.has_fn_once {
+ traits.entry(fn_once_trait_ref).or_default().extend(
+ // Group the return ty with its def id, if we had one.
+ entry
+ .return_ty
+ .map(|ty| (self.tcx().lang_items().fn_once_output().unwrap(), ty)),
+ );
+ }
+ if let Some(trait_ref) = entry.fn_mut_trait_ref {
+ traits.entry(trait_ref).or_default();
+ }
+ if let Some(trait_ref) = entry.fn_trait_ref {
+ traits.entry(trait_ref).or_default();
+ }
+ }
+ }
+ }
+
+ // Print the rest of the trait types (that aren't Fn* family of traits)
+ for (trait_ref, assoc_items) in traits {
+ p!(
+ write("{}", if first { " " } else { " + " }),
+ print(trait_ref.skip_binder().print_only_trait_name())
+ );
+
+ let generics = self.generic_args_to_print(
+ self.tcx().generics_of(trait_ref.def_id()),
+ trait_ref.skip_binder().substs,
+ );
+
+ if !generics.is_empty() || !assoc_items.is_empty() {
+ p!("<");
+ let mut first = true;
+
+ for ty in generics {
+ if !first {
+ p!(", ");
+ }
+ p!(print(trait_ref.rebind(*ty)));
+ first = false;
+ }
+
+ for (assoc_item_def_id, ty) in assoc_items {
+ if !first {
+ p!(", ");
+ }
+ p!(write("{} = ", self.tcx().associated_item(assoc_item_def_id).ident));
+
+ // Skip printing `<[generator@] as Generator<_>>::Return` from async blocks
+ match ty.skip_binder().kind() {
+ ty::Projection(ty::ProjectionTy { item_def_id, .. })
+ if Some(*item_def_id) == self.tcx().lang_items().generator_return() =>
+ {
+ p!("[async output]")
+ }
+ _ => {
+ p!(print(ty))
+ }
+ }
+
+ first = false;
+ }
+
+ p!(">");
+ }
+
+ first = false;
+ }
+
+ if !is_sized {
+ p!(write("{}?Sized", if first { " " } else { " + " }));
+ } else if first {
+ p!(" Sized");
+ }
+
+ Ok(self)
+ }
+
+ /// Insert the trait ref and optionally a projection type associated with it into either the
+ /// traits map or fn_traits map, depending on if the trait is in the Fn* family of traits.
+ fn insert_trait_and_projection(
+ &mut self,
+ trait_ref: ty::PolyTraitRef<'tcx>,
+ proj_ty: Option<(DefId, ty::Binder<'tcx, Ty<'tcx>>)>,
+ traits: &mut BTreeMap<ty::PolyTraitRef<'tcx>, BTreeMap<DefId, ty::Binder<'tcx, Ty<'tcx>>>>,
+ fn_traits: &mut BTreeMap<ty::PolyTraitRef<'tcx>, OpaqueFnEntry<'tcx>>,
+ ) {
+ let trait_def_id = trait_ref.def_id();
+
+ // If our trait_ref is FnOnce or any of its children, project it onto the parent FnOnce
+ // super-trait ref and record it there.
+ if let Some(fn_once_trait) = self.tcx().lang_items().fn_once_trait() {
+ // If we have a FnOnce, then insert it into
+ if trait_def_id == fn_once_trait {
+ let entry = fn_traits.entry(trait_ref).or_default();
+ // Optionally insert the return_ty as well.
+ if let Some((_, ty)) = proj_ty {
+ entry.return_ty = Some(ty);
+ }
+ entry.has_fn_once = true;
+ return;
+ } else if Some(trait_def_id) == self.tcx().lang_items().fn_mut_trait() {
+ let super_trait_ref = crate::traits::util::supertraits(self.tcx(), trait_ref)
+ .find(|super_trait_ref| super_trait_ref.def_id() == fn_once_trait)
+ .unwrap();
+
+ fn_traits.entry(super_trait_ref).or_default().fn_mut_trait_ref = Some(trait_ref);
+ return;
+ } else if Some(trait_def_id) == self.tcx().lang_items().fn_trait() {
+ let super_trait_ref = crate::traits::util::supertraits(self.tcx(), trait_ref)
+ .find(|super_trait_ref| super_trait_ref.def_id() == fn_once_trait)
+ .unwrap();
+
+ fn_traits.entry(super_trait_ref).or_default().fn_trait_ref = Some(trait_ref);
+ return;
+ }
+ }
+
+ // Otherwise, just group our traits and projection types.
+ traits.entry(trait_ref).or_default().extend(proj_ty);
+ }
+
fn pretty_print_bound_var(
&mut self,
debruijn: ty::DebruijnIndex,
@@ -1594,30 +1740,26 @@ impl<F: fmt::Write> Printer<'tcx> for FmtPrinter<'_, 'tcx, F> {
) -> Result<Self::Path, Self::Error> {
self = print_prefix(self)?;
- // Skip `::{{constructor}}` on tuple/unit structs.
- if let DefPathData::Ctor = disambiguated_data.data {
+ // Skip `::{{extern}}` blocks and `::{{constructor}}` on tuple/unit structs.
+ if let DefPathData::ForeignMod | DefPathData::Ctor = disambiguated_data.data {
return Ok(self);
}
- // FIXME(eddyb) `name` should never be empty, but it
- // currently is for `extern { ... }` "foreign modules".
let name = disambiguated_data.data.name();
- if name != DefPathDataName::Named(kw::Empty) {
- if !self.empty_path {
- write!(self, "::")?;
- }
+ if !self.empty_path {
+ write!(self, "::")?;
+ }
- if let DefPathDataName::Named(name) = name {
- if Ident::with_dummy_span(name).is_raw_guess() {
- write!(self, "r#")?;
- }
+ if let DefPathDataName::Named(name) = name {
+ if Ident::with_dummy_span(name).is_raw_guess() {
+ write!(self, "r#")?;
}
+ }
- let verbose = self.tcx.sess.verbose();
- disambiguated_data.fmt_maybe_verbose(&mut self, verbose)?;
+ let verbose = self.tcx.sess.verbose();
+ disambiguated_data.fmt_maybe_verbose(&mut self, verbose)?;
- self.empty_path = false;
- }
+ self.empty_path = false;
Ok(self)
}
@@ -2553,3 +2695,12 @@ fn trimmed_def_paths(tcx: TyCtxt<'_>, (): ()) -> FxHashMap<DefId, Symbol> {
pub fn provide(providers: &mut ty::query::Providers) {
*providers = ty::query::Providers { trimmed_def_paths, ..*providers };
}
+
+#[derive(Default)]
+pub struct OpaqueFnEntry<'tcx> {
+ // The trait ref is already stored as a key, so just track if we have it as a real predicate
+ has_fn_once: bool,
+ fn_mut_trait_ref: Option<ty::PolyTraitRef<'tcx>>,
+ fn_trait_ref: Option<ty::PolyTraitRef<'tcx>>,
+ return_ty: Option<ty::Binder<'tcx, Ty<'tcx>>>,
+}
diff --git a/compiler/rustc_middle/src/ty/query.rs b/compiler/rustc_middle/src/ty/query.rs
index 34f80627197..f18517eee04 100644
--- a/compiler/rustc_middle/src/ty/query.rs
+++ b/compiler/rustc_middle/src/ty/query.rs
@@ -156,6 +156,16 @@ macro_rules! separate_provide_extern_default {
};
}
+macro_rules! opt_remap_env_constness {
+ ([][$name:ident]) => {};
+ ([(remap_env_constness) $($rest:tt)*][$name:ident]) => {
+ let $name = $name.without_const();
+ };
+ ([$other:tt $($modifiers:tt)*][$name:ident]) => {
+ opt_remap_env_constness!([$($modifiers)*][$name])
+ };
+}
+
macro_rules! define_callbacks {
(<$tcx:tt>
$($(#[$attr:meta])*
@@ -202,6 +212,8 @@ macro_rules! define_callbacks {
#[inline(always)]
pub fn $name(self, key: query_helper_param_ty!($($K)*)) {
let key = key.into_query_param();
+ opt_remap_env_constness!([$($modifiers)*][key]);
+
let cached = try_get_cached(self.tcx, &self.tcx.query_caches.$name, &key, noop);
let lookup = match cached {
@@ -229,6 +241,8 @@ macro_rules! define_callbacks {
pub fn $name(self, key: query_helper_param_ty!($($K)*)) -> query_stored::$name<$tcx>
{
let key = key.into_query_param();
+ opt_remap_env_constness!([$($modifiers)*][key]);
+
let cached = try_get_cached(self.tcx, &self.tcx.query_caches.$name, &key, Clone::clone);
let lookup = match cached {
diff --git a/compiler/rustc_middle/src/ty/relate.rs b/compiler/rustc_middle/src/ty/relate.rs
index c7d8bec506f..aaef137c7e0 100644
--- a/compiler/rustc_middle/src/ty/relate.rs
+++ b/compiler/rustc_middle/src/ty/relate.rs
@@ -218,19 +218,6 @@ impl<'tcx> Relate<'tcx> for ty::BoundConstness {
}
}
-impl<'tcx, T: Relate<'tcx>> Relate<'tcx> for ty::ConstnessAnd<T> {
- fn relate<R: TypeRelation<'tcx>>(
- relation: &mut R,
- a: ty::ConstnessAnd<T>,
- b: ty::ConstnessAnd<T>,
- ) -> RelateResult<'tcx, ty::ConstnessAnd<T>> {
- Ok(ty::ConstnessAnd {
- constness: relation.relate(a.constness, b.constness)?,
- value: relation.relate(a.value, b.value)?,
- })
- }
-}
-
impl<'tcx> Relate<'tcx> for ast::Unsafety {
fn relate<R: TypeRelation<'tcx>>(
relation: &mut R,
@@ -849,13 +836,5 @@ pub fn expected_found<R, T>(relation: &mut R, a: T, b: T) -> ExpectedFound<T>
where
R: TypeRelation<'tcx>,
{
- expected_found_bool(relation.a_is_expected(), a, b)
-}
-
-pub fn expected_found_bool<T>(a_is_expected: bool, a: T, b: T) -> ExpectedFound<T> {
- if a_is_expected {
- ExpectedFound { expected: a, found: b }
- } else {
- ExpectedFound { expected: b, found: a }
- }
+ ExpectedFound::new(relation.a_is_expected(), a, b)
}
diff --git a/compiler/rustc_middle/src/ty/structural_impls.rs b/compiler/rustc_middle/src/ty/structural_impls.rs
index 0f8e80806e3..28dc9767b78 100644
--- a/compiler/rustc_middle/src/ty/structural_impls.rs
+++ b/compiler/rustc_middle/src/ty/structural_impls.rs
@@ -4,7 +4,7 @@
use crate::mir::interpret;
use crate::mir::ProjectionKind;
-use crate::ty::fold::{TypeFoldable, TypeFolder, TypeVisitor};
+use crate::ty::fold::{FallibleTypeFolder, TypeFoldable, TypeVisitor};
use crate::ty::print::{with_no_trimmed_paths, FmtPrinter, Printer};
use crate::ty::{self, InferConst, Lift, Ty, TyCtxt};
use rustc_data_structures::functor::IdFunctor;
@@ -13,6 +13,7 @@ use rustc_hir::def_id::CRATE_DEF_INDEX;
use rustc_index::vec::{Idx, IndexVec};
use std::fmt;
+use std::mem::ManuallyDrop;
use std::ops::ControlFlow;
use std::rc::Rc;
use std::sync::Arc;
@@ -480,7 +481,7 @@ impl<'a, 'tcx> Lift<'tcx> for ty::ParamEnv<'a> {
type Lifted = ty::ParamEnv<'tcx>;
fn lift_to_tcx(self, tcx: TyCtxt<'tcx>) -> Option<Self::Lifted> {
tcx.lift(self.caller_bounds())
- .map(|caller_bounds| ty::ParamEnv::new(caller_bounds, self.reveal()))
+ .map(|caller_bounds| ty::ParamEnv::new(caller_bounds, self.reveal(), self.constness()))
}
}
@@ -669,8 +670,11 @@ impl<'a, 'tcx> Lift<'tcx> for ty::InstanceDef<'a> {
/// AdtDefs are basically the same as a DefId.
impl<'tcx> TypeFoldable<'tcx> for &'tcx ty::AdtDef {
- fn super_fold_with<F: TypeFolder<'tcx>>(self, _folder: &mut F) -> Self {
- self
+ fn try_super_fold_with<F: FallibleTypeFolder<'tcx>>(
+ self,
+ _folder: &mut F,
+ ) -> Result<Self, F::Error> {
+ Ok(self)
}
fn super_visit_with<V: TypeVisitor<'tcx>>(&self, _visitor: &mut V) -> ControlFlow<V::BreakTy> {
@@ -679,8 +683,11 @@ impl<'tcx> TypeFoldable<'tcx> for &'tcx ty::AdtDef {
}
impl<'tcx, T: TypeFoldable<'tcx>, U: TypeFoldable<'tcx>> TypeFoldable<'tcx> for (T, U) {
- fn super_fold_with<F: TypeFolder<'tcx>>(self, folder: &mut F) -> (T, U) {
- (self.0.fold_with(folder), self.1.fold_with(folder))
+ fn try_super_fold_with<F: FallibleTypeFolder<'tcx>>(
+ self,
+ folder: &mut F,
+ ) -> Result<(T, U), F::Error> {
+ Ok((self.0.try_fold_with(folder)?, self.1.try_fold_with(folder)?))
}
fn super_visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> ControlFlow<V::BreakTy> {
@@ -692,8 +699,15 @@ impl<'tcx, T: TypeFoldable<'tcx>, U: TypeFoldable<'tcx>> TypeFoldable<'tcx> for
impl<'tcx, A: TypeFoldable<'tcx>, B: TypeFoldable<'tcx>, C: TypeFoldable<'tcx>> TypeFoldable<'tcx>
for (A, B, C)
{
- fn super_fold_with<F: TypeFolder<'tcx>>(self, folder: &mut F) -> (A, B, C) {
- (self.0.fold_with(folder), self.1.fold_with(folder), self.2.fold_with(folder))
+ fn try_super_fold_with<F: FallibleTypeFolder<'tcx>>(
+ self,
+ folder: &mut F,
+ ) -> Result<(A, B, C), F::Error> {
+ Ok((
+ self.0.try_fold_with(folder)?,
+ self.1.try_fold_with(folder)?,
+ self.2.try_fold_with(folder)?,
+ ))
}
fn super_visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> ControlFlow<V::BreakTy> {
@@ -718,9 +732,42 @@ EnumTypeFoldableImpl! {
}
impl<'tcx, T: TypeFoldable<'tcx>> TypeFoldable<'tcx> for Rc<T> {
- fn super_fold_with<F: TypeFolder<'tcx>>(self, folder: &mut F) -> Self {
- // FIXME: Reuse the `Rc` here.
- Rc::new((*self).clone().fold_with(folder))
+ fn try_super_fold_with<F: FallibleTypeFolder<'tcx>>(
+ mut self,
+ folder: &mut F,
+ ) -> Result<Self, F::Error> {
+ // We merely want to replace the contained `T`, if at all possible,
+ // so that we don't needlessly allocate a new `Rc` or indeed clone
+ // the contained type.
+ unsafe {
+ // First step is to ensure that we have a unique reference to
+ // the contained type, which `Rc::make_mut` will accomplish (by
+ // allocating a new `Rc` and cloning the `T` only if required).
+ // This is done *before* casting to `Rc<ManuallyDrop<T>>` so that
+ // panicking during `make_mut` does not leak the `T`.
+ Rc::make_mut(&mut self);
+
+ // Casting to `Rc<ManuallyDrop<T>>` is safe because `ManuallyDrop`
+ // is `repr(transparent)`.
+ let ptr = Rc::into_raw(self).cast::<ManuallyDrop<T>>();
+ let mut unique = Rc::from_raw(ptr);
+
+ // Call to `Rc::make_mut` above guarantees that `unique` is the
+ // sole reference to the contained value, so we can avoid doing
+ // a checked `get_mut` here.
+ let slot = Rc::get_mut_unchecked(&mut unique);
+
+ // Semantically move the contained type out from `unique`, fold
+ // it, then move the folded value back into `unique`. Should
+ // folding fail, `ManuallyDrop` ensures that the "moved-out"
+ // value is not re-dropped.
+ let owned = ManuallyDrop::take(slot);
+ let folded = owned.try_fold_with(folder)?;
+ *slot = ManuallyDrop::new(folded);
+
+ // Cast back to `Rc<T>`.
+ Ok(Rc::from_raw(Rc::into_raw(unique).cast()))
+ }
}
fn super_visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> ControlFlow<V::BreakTy> {
@@ -729,9 +776,42 @@ impl<'tcx, T: TypeFoldable<'tcx>> TypeFoldable<'tcx> for Rc<T> {
}
impl<'tcx, T: TypeFoldable<'tcx>> TypeFoldable<'tcx> for Arc<T> {
- fn super_fold_with<F: TypeFolder<'tcx>>(self, folder: &mut F) -> Self {
- // FIXME: Reuse the `Arc` here.
- Arc::new((*self).clone().fold_with(folder))
+ fn try_super_fold_with<F: FallibleTypeFolder<'tcx>>(
+ mut self,
+ folder: &mut F,
+ ) -> Result<Self, F::Error> {
+ // We merely want to replace the contained `T`, if at all possible,
+ // so that we don't needlessly allocate a new `Arc` or indeed clone
+ // the contained type.
+ unsafe {
+ // First step is to ensure that we have a unique reference to
+ // the contained type, which `Arc::make_mut` will accomplish (by
+ // allocating a new `Arc` and cloning the `T` only if required).
+ // This is done *before* casting to `Arc<ManuallyDrop<T>>` so that
+ // panicking during `make_mut` does not leak the `T`.
+ Arc::make_mut(&mut self);
+
+ // Casting to `Arc<ManuallyDrop<T>>` is safe because `ManuallyDrop`
+ // is `repr(transparent)`.
+ let ptr = Arc::into_raw(self).cast::<ManuallyDrop<T>>();
+ let mut unique = Arc::from_raw(ptr);
+
+ // Call to `Arc::make_mut` above guarantees that `unique` is the
+ // sole reference to the contained value, so we can avoid doing
+ // a checked `get_mut` here.
+ let slot = Arc::get_mut_unchecked(&mut unique);
+
+ // Semantically move the contained type out from `unique`, fold
+ // it, then move the folded value back into `unique`. Should
+ // folding fail, `ManuallyDrop` ensures that the "moved-out"
+ // value is not re-dropped.
+ let owned = ManuallyDrop::take(slot);
+ let folded = owned.try_fold_with(folder)?;
+ *slot = ManuallyDrop::new(folded);
+
+ // Cast back to `Arc<T>`.
+ Ok(Arc::from_raw(Arc::into_raw(unique).cast()))
+ }
}
fn super_visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> ControlFlow<V::BreakTy> {
@@ -740,8 +820,11 @@ impl<'tcx, T: TypeFoldable<'tcx>> TypeFoldable<'tcx> for Arc<T> {
}
impl<'tcx, T: TypeFoldable<'tcx>> TypeFoldable<'tcx> for Box<T> {
- fn super_fold_with<F: TypeFolder<'tcx>>(self, folder: &mut F) -> Self {
- self.map_id(|value| value.fold_with(folder))
+ fn try_super_fold_with<F: FallibleTypeFolder<'tcx>>(
+ self,
+ folder: &mut F,
+ ) -> Result<Self, F::Error> {
+ self.try_map_id(|value| value.try_fold_with(folder))
}
fn super_visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> ControlFlow<V::BreakTy> {
@@ -750,8 +833,11 @@ impl<'tcx, T: TypeFoldable<'tcx>> TypeFoldable<'tcx> for Box<T> {
}
impl<'tcx, T: TypeFoldable<'tcx>> TypeFoldable<'tcx> for Vec<T> {
- fn super_fold_with<F: TypeFolder<'tcx>>(self, folder: &mut F) -> Self {
- self.map_id(|t| t.fold_with(folder))
+ fn try_super_fold_with<F: FallibleTypeFolder<'tcx>>(
+ self,
+ folder: &mut F,
+ ) -> Result<Self, F::Error> {
+ self.try_map_id(|t| t.try_fold_with(folder))
}
fn super_visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> ControlFlow<V::BreakTy> {
@@ -760,8 +846,11 @@ impl<'tcx, T: TypeFoldable<'tcx>> TypeFoldable<'tcx> for Vec<T> {
}
impl<'tcx, T: TypeFoldable<'tcx>> TypeFoldable<'tcx> for Box<[T]> {
- fn super_fold_with<F: TypeFolder<'tcx>>(self, folder: &mut F) -> Self {
- self.map_id(|t| t.fold_with(folder))
+ fn try_super_fold_with<F: FallibleTypeFolder<'tcx>>(
+ self,
+ folder: &mut F,
+ ) -> Result<Self, F::Error> {
+ self.try_map_id(|t| t.try_fold_with(folder))
}
fn super_visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> ControlFlow<V::BreakTy> {
@@ -770,12 +859,15 @@ impl<'tcx, T: TypeFoldable<'tcx>> TypeFoldable<'tcx> for Box<[T]> {
}
impl<'tcx, T: TypeFoldable<'tcx>> TypeFoldable<'tcx> for ty::Binder<'tcx, T> {
- fn super_fold_with<F: TypeFolder<'tcx>>(self, folder: &mut F) -> Self {
- self.map_bound(|ty| ty.fold_with(folder))
+ fn try_super_fold_with<F: FallibleTypeFolder<'tcx>>(
+ self,
+ folder: &mut F,
+ ) -> Result<Self, F::Error> {
+ self.try_map_bound(|ty| ty.try_fold_with(folder))
}
- fn fold_with<F: TypeFolder<'tcx>>(self, folder: &mut F) -> Self {
- folder.fold_binder(self)
+ fn try_fold_with<F: FallibleTypeFolder<'tcx>>(self, folder: &mut F) -> Result<Self, F::Error> {
+ folder.try_fold_binder(self)
}
fn super_visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> ControlFlow<V::BreakTy> {
@@ -788,7 +880,10 @@ impl<'tcx, T: TypeFoldable<'tcx>> TypeFoldable<'tcx> for ty::Binder<'tcx, T> {
}
impl<'tcx> TypeFoldable<'tcx> for &'tcx ty::List<ty::Binder<'tcx, ty::ExistentialPredicate<'tcx>>> {
- fn super_fold_with<F: TypeFolder<'tcx>>(self, folder: &mut F) -> Self {
+ fn try_super_fold_with<F: FallibleTypeFolder<'tcx>>(
+ self,
+ folder: &mut F,
+ ) -> Result<Self, F::Error> {
ty::util::fold_list(self, folder, |tcx, v| tcx.intern_poly_existential_predicates(v))
}
@@ -798,7 +893,10 @@ impl<'tcx> TypeFoldable<'tcx> for &'tcx ty::List<ty::Binder<'tcx, ty::Existentia
}
impl<'tcx> TypeFoldable<'tcx> for &'tcx ty::List<Ty<'tcx>> {
- fn super_fold_with<F: TypeFolder<'tcx>>(self, folder: &mut F) -> Self {
+ fn try_super_fold_with<F: FallibleTypeFolder<'tcx>>(
+ self,
+ folder: &mut F,
+ ) -> Result<Self, F::Error> {
ty::util::fold_list(self, folder, |tcx, v| tcx.intern_type_list(v))
}
@@ -808,7 +906,10 @@ impl<'tcx> TypeFoldable<'tcx> for &'tcx ty::List<Ty<'tcx>> {
}
impl<'tcx> TypeFoldable<'tcx> for &'tcx ty::List<ProjectionKind> {
- fn super_fold_with<F: TypeFolder<'tcx>>(self, folder: &mut F) -> Self {
+ fn try_super_fold_with<F: FallibleTypeFolder<'tcx>>(
+ self,
+ folder: &mut F,
+ ) -> Result<Self, F::Error> {
ty::util::fold_list(self, folder, |tcx, v| tcx.intern_projs(v))
}
@@ -818,24 +919,33 @@ impl<'tcx> TypeFoldable<'tcx> for &'tcx ty::List<ProjectionKind> {
}
impl<'tcx> TypeFoldable<'tcx> for ty::instance::Instance<'tcx> {
- fn super_fold_with<F: TypeFolder<'tcx>>(self, folder: &mut F) -> Self {
+ fn try_super_fold_with<F: FallibleTypeFolder<'tcx>>(
+ self,
+ folder: &mut F,
+ ) -> Result<Self, F::Error> {
use crate::ty::InstanceDef::*;
- Self {
- substs: self.substs.fold_with(folder),
+ Ok(Self {
+ substs: self.substs.try_fold_with(folder)?,
def: match self.def {
- Item(def) => Item(def.fold_with(folder)),
- VtableShim(did) => VtableShim(did.fold_with(folder)),
- ReifyShim(did) => ReifyShim(did.fold_with(folder)),
- Intrinsic(did) => Intrinsic(did.fold_with(folder)),
- FnPtrShim(did, ty) => FnPtrShim(did.fold_with(folder), ty.fold_with(folder)),
- Virtual(did, i) => Virtual(did.fold_with(folder), i),
+ Item(def) => Item(def.try_fold_with(folder)?),
+ VtableShim(did) => VtableShim(did.try_fold_with(folder)?),
+ ReifyShim(did) => ReifyShim(did.try_fold_with(folder)?),
+ Intrinsic(did) => Intrinsic(did.try_fold_with(folder)?),
+ FnPtrShim(did, ty) => {
+ FnPtrShim(did.try_fold_with(folder)?, ty.try_fold_with(folder)?)
+ }
+ Virtual(did, i) => Virtual(did.try_fold_with(folder)?, i),
ClosureOnceShim { call_once, track_caller } => {
- ClosureOnceShim { call_once: call_once.fold_with(folder), track_caller }
+ ClosureOnceShim { call_once: call_once.try_fold_with(folder)?, track_caller }
+ }
+ DropGlue(did, ty) => {
+ DropGlue(did.try_fold_with(folder)?, ty.try_fold_with(folder)?)
+ }
+ CloneShim(did, ty) => {
+ CloneShim(did.try_fold_with(folder)?, ty.try_fold_with(folder)?)
}
- DropGlue(did, ty) => DropGlue(did.fold_with(folder), ty.fold_with(folder)),
- CloneShim(did, ty) => CloneShim(did.fold_with(folder), ty.fold_with(folder)),
},
- }
+ })
}
fn super_visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> ControlFlow<V::BreakTy> {
@@ -860,8 +970,11 @@ impl<'tcx> TypeFoldable<'tcx> for ty::instance::Instance<'tcx> {
}
impl<'tcx> TypeFoldable<'tcx> for interpret::GlobalId<'tcx> {
- fn super_fold_with<F: TypeFolder<'tcx>>(self, folder: &mut F) -> Self {
- Self { instance: self.instance.fold_with(folder), promoted: self.promoted }
+ fn try_super_fold_with<F: FallibleTypeFolder<'tcx>>(
+ self,
+ folder: &mut F,
+ ) -> Result<Self, F::Error> {
+ Ok(Self { instance: self.instance.try_fold_with(folder)?, promoted: self.promoted })
}
fn super_visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> ControlFlow<V::BreakTy> {
@@ -870,26 +983,31 @@ impl<'tcx> TypeFoldable<'tcx> for interpret::GlobalId<'tcx> {
}
impl<'tcx> TypeFoldable<'tcx> for Ty<'tcx> {
- fn super_fold_with<F: TypeFolder<'tcx>>(self, folder: &mut F) -> Self {
+ fn try_super_fold_with<F: FallibleTypeFolder<'tcx>>(
+ self,
+ folder: &mut F,
+ ) -> Result<Self, F::Error> {
let kind = match *self.kind() {
- ty::RawPtr(tm) => ty::RawPtr(tm.fold_with(folder)),
- ty::Array(typ, sz) => ty::Array(typ.fold_with(folder), sz.fold_with(folder)),
- ty::Slice(typ) => ty::Slice(typ.fold_with(folder)),
- ty::Adt(tid, substs) => ty::Adt(tid, substs.fold_with(folder)),
+ ty::RawPtr(tm) => ty::RawPtr(tm.try_fold_with(folder)?),
+ ty::Array(typ, sz) => ty::Array(typ.try_fold_with(folder)?, sz.try_fold_with(folder)?),
+ ty::Slice(typ) => ty::Slice(typ.try_fold_with(folder)?),
+ ty::Adt(tid, substs) => ty::Adt(tid, substs.try_fold_with(folder)?),
ty::Dynamic(trait_ty, region) => {
- ty::Dynamic(trait_ty.fold_with(folder), region.fold_with(folder))
+ ty::Dynamic(trait_ty.try_fold_with(folder)?, region.try_fold_with(folder)?)
+ }
+ ty::Tuple(ts) => ty::Tuple(ts.try_fold_with(folder)?),
+ ty::FnDef(def_id, substs) => ty::FnDef(def_id, substs.try_fold_with(folder)?),
+ ty::FnPtr(f) => ty::FnPtr(f.try_fold_with(folder)?),
+ ty::Ref(r, ty, mutbl) => {
+ ty::Ref(r.try_fold_with(folder)?, ty.try_fold_with(folder)?, mutbl)
}
- ty::Tuple(ts) => ty::Tuple(ts.fold_with(folder)),
- ty::FnDef(def_id, substs) => ty::FnDef(def_id, substs.fold_with(folder)),
- ty::FnPtr(f) => ty::FnPtr(f.fold_with(folder)),
- ty::Ref(r, ty, mutbl) => ty::Ref(r.fold_with(folder), ty.fold_with(folder), mutbl),
ty::Generator(did, substs, movability) => {
- ty::Generator(did, substs.fold_with(folder), movability)
+ ty::Generator(did, substs.try_fold_with(folder)?, movability)
}
- ty::GeneratorWitness(types) => ty::GeneratorWitness(types.fold_with(folder)),
- ty::Closure(did, substs) => ty::Closure(did, substs.fold_with(folder)),
- ty::Projection(data) => ty::Projection(data.fold_with(folder)),
- ty::Opaque(did, substs) => ty::Opaque(did, substs.fold_with(folder)),
+ ty::GeneratorWitness(types) => ty::GeneratorWitness(types.try_fold_with(folder)?),
+ ty::Closure(did, substs) => ty::Closure(did, substs.try_fold_with(folder)?),
+ ty::Projection(data) => ty::Projection(data.try_fold_with(folder)?),
+ ty::Opaque(did, substs) => ty::Opaque(did, substs.try_fold_with(folder)?),
ty::Bool
| ty::Char
@@ -903,14 +1021,14 @@ impl<'tcx> TypeFoldable<'tcx> for Ty<'tcx> {
| ty::Bound(..)
| ty::Placeholder(..)
| ty::Never
- | ty::Foreign(..) => return self,
+ | ty::Foreign(..) => return Ok(self),
};
- if *self.kind() == kind { self } else { folder.tcx().mk_ty(kind) }
+ Ok(if *self.kind() == kind { self } else { folder.tcx().mk_ty(kind) })
}
- fn fold_with<F: TypeFolder<'tcx>>(self, folder: &mut F) -> Self {
- folder.fold_ty(self)
+ fn try_fold_with<F: FallibleTypeFolder<'tcx>>(self, folder: &mut F) -> Result<Self, F::Error> {
+ folder.try_fold_ty(self)
}
fn super_visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> ControlFlow<V::BreakTy> {
@@ -961,12 +1079,15 @@ impl<'tcx> TypeFoldable<'tcx> for Ty<'tcx> {
}
impl<'tcx> TypeFoldable<'tcx> for ty::Region<'tcx> {
- fn super_fold_with<F: TypeFolder<'tcx>>(self, _folder: &mut F) -> Self {
- self
+ fn try_super_fold_with<F: FallibleTypeFolder<'tcx>>(
+ self,
+ _folder: &mut F,
+ ) -> Result<Self, F::Error> {
+ Ok(self)
}
- fn fold_with<F: TypeFolder<'tcx>>(self, folder: &mut F) -> Self {
- folder.fold_region(self)
+ fn try_fold_with<F: FallibleTypeFolder<'tcx>>(self, folder: &mut F) -> Result<Self, F::Error> {
+ folder.try_fold_region(self)
}
fn super_visit_with<V: TypeVisitor<'tcx>>(&self, _visitor: &mut V) -> ControlFlow<V::BreakTy> {
@@ -979,13 +1100,16 @@ impl<'tcx> TypeFoldable<'tcx> for ty::Region<'tcx> {
}
impl<'tcx> TypeFoldable<'tcx> for ty::Predicate<'tcx> {
- fn fold_with<F: TypeFolder<'tcx>>(self, folder: &mut F) -> Self {
- folder.fold_predicate(self)
+ fn try_fold_with<F: FallibleTypeFolder<'tcx>>(self, folder: &mut F) -> Result<Self, F::Error> {
+ folder.try_fold_predicate(self)
}
- fn super_fold_with<F: TypeFolder<'tcx>>(self, folder: &mut F) -> Self {
- let new = self.inner.kind.fold_with(folder);
- folder.tcx().reuse_or_mk_predicate(self, new)
+ fn try_super_fold_with<F: FallibleTypeFolder<'tcx>>(
+ self,
+ folder: &mut F,
+ ) -> Result<Self, F::Error> {
+ let new = self.inner.kind.try_fold_with(folder)?;
+ Ok(folder.tcx().reuse_or_mk_predicate(self, new))
}
fn super_visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> ControlFlow<V::BreakTy> {
@@ -1006,7 +1130,10 @@ impl<'tcx> TypeFoldable<'tcx> for ty::Predicate<'tcx> {
}
impl<'tcx> TypeFoldable<'tcx> for &'tcx ty::List<ty::Predicate<'tcx>> {
- fn super_fold_with<F: TypeFolder<'tcx>>(self, folder: &mut F) -> Self {
+ fn try_super_fold_with<F: FallibleTypeFolder<'tcx>>(
+ self,
+ folder: &mut F,
+ ) -> Result<Self, F::Error> {
ty::util::fold_list(self, folder, |tcx, v| tcx.intern_predicates(v))
}
@@ -1016,8 +1143,11 @@ impl<'tcx> TypeFoldable<'tcx> for &'tcx ty::List<ty::Predicate<'tcx>> {
}
impl<'tcx, T: TypeFoldable<'tcx>, I: Idx> TypeFoldable<'tcx> for IndexVec<I, T> {
- fn super_fold_with<F: TypeFolder<'tcx>>(self, folder: &mut F) -> Self {
- self.map_id(|x| x.fold_with(folder))
+ fn try_super_fold_with<F: FallibleTypeFolder<'tcx>>(
+ self,
+ folder: &mut F,
+ ) -> Result<Self, F::Error> {
+ self.try_map_id(|x| x.try_fold_with(folder))
}
fn super_visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> ControlFlow<V::BreakTy> {
@@ -1026,18 +1156,21 @@ impl<'tcx, T: TypeFoldable<'tcx>, I: Idx> TypeFoldable<'tcx> for IndexVec<I, T>
}
impl<'tcx> TypeFoldable<'tcx> for &'tcx ty::Const<'tcx> {
- fn super_fold_with<F: TypeFolder<'tcx>>(self, folder: &mut F) -> Self {
- let ty = self.ty.fold_with(folder);
- let val = self.val.fold_with(folder);
+ fn try_super_fold_with<F: FallibleTypeFolder<'tcx>>(
+ self,
+ folder: &mut F,
+ ) -> Result<Self, F::Error> {
+ let ty = self.ty.try_fold_with(folder)?;
+ let val = self.val.try_fold_with(folder)?;
if ty != self.ty || val != self.val {
- folder.tcx().mk_const(ty::Const { ty, val })
+ Ok(folder.tcx().mk_const(ty::Const { ty, val }))
} else {
- self
+ Ok(self)
}
}
- fn fold_with<F: TypeFolder<'tcx>>(self, folder: &mut F) -> Self {
- folder.fold_const(self)
+ fn try_fold_with<F: FallibleTypeFolder<'tcx>>(self, folder: &mut F) -> Result<Self, F::Error> {
+ folder.try_fold_const(self)
}
fn super_visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> ControlFlow<V::BreakTy> {
@@ -1051,16 +1184,19 @@ impl<'tcx> TypeFoldable<'tcx> for &'tcx ty::Const<'tcx> {
}
impl<'tcx> TypeFoldable<'tcx> for ty::ConstKind<'tcx> {
- fn super_fold_with<F: TypeFolder<'tcx>>(self, folder: &mut F) -> Self {
- match self {
- ty::ConstKind::Infer(ic) => ty::ConstKind::Infer(ic.fold_with(folder)),
- ty::ConstKind::Param(p) => ty::ConstKind::Param(p.fold_with(folder)),
- ty::ConstKind::Unevaluated(uv) => ty::ConstKind::Unevaluated(uv.fold_with(folder)),
+ fn try_super_fold_with<F: FallibleTypeFolder<'tcx>>(
+ self,
+ folder: &mut F,
+ ) -> Result<Self, F::Error> {
+ Ok(match self {
+ ty::ConstKind::Infer(ic) => ty::ConstKind::Infer(ic.try_fold_with(folder)?),
+ ty::ConstKind::Param(p) => ty::ConstKind::Param(p.try_fold_with(folder)?),
+ ty::ConstKind::Unevaluated(uv) => ty::ConstKind::Unevaluated(uv.try_fold_with(folder)?),
ty::ConstKind::Value(_)
| ty::ConstKind::Bound(..)
| ty::ConstKind::Placeholder(..)
| ty::ConstKind::Error(_) => self,
- }
+ })
}
fn super_visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> ControlFlow<V::BreakTy> {
@@ -1077,8 +1213,11 @@ impl<'tcx> TypeFoldable<'tcx> for ty::ConstKind<'tcx> {
}
impl<'tcx> TypeFoldable<'tcx> for InferConst<'tcx> {
- fn super_fold_with<F: TypeFolder<'tcx>>(self, _folder: &mut F) -> Self {
- self
+ fn try_super_fold_with<F: FallibleTypeFolder<'tcx>>(
+ self,
+ _folder: &mut F,
+ ) -> Result<Self, F::Error> {
+ Ok(self)
}
fn super_visit_with<V: TypeVisitor<'tcx>>(&self, _visitor: &mut V) -> ControlFlow<V::BreakTy> {
@@ -1087,12 +1226,15 @@ impl<'tcx> TypeFoldable<'tcx> for InferConst<'tcx> {
}
impl<'tcx> TypeFoldable<'tcx> for ty::Unevaluated<'tcx> {
- fn super_fold_with<F: TypeFolder<'tcx>>(self, folder: &mut F) -> Self {
- ty::Unevaluated {
+ fn try_super_fold_with<F: FallibleTypeFolder<'tcx>>(
+ self,
+ folder: &mut F,
+ ) -> Result<Self, F::Error> {
+ Ok(ty::Unevaluated {
def: self.def,
- substs_: Some(self.substs(folder.tcx()).fold_with(folder)),
+ substs_: Some(self.substs(folder.tcx()).try_fold_with(folder)?),
promoted: self.promoted,
- }
+ })
}
fn visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> ControlFlow<V::BreakTy> {
@@ -1112,12 +1254,15 @@ impl<'tcx> TypeFoldable<'tcx> for ty::Unevaluated<'tcx> {
}
impl<'tcx> TypeFoldable<'tcx> for ty::Unevaluated<'tcx, ()> {
- fn super_fold_with<F: TypeFolder<'tcx>>(self, folder: &mut F) -> Self {
- ty::Unevaluated {
+ fn try_super_fold_with<F: FallibleTypeFolder<'tcx>>(
+ self,
+ folder: &mut F,
+ ) -> Result<Self, F::Error> {
+ Ok(ty::Unevaluated {
def: self.def,
- substs_: Some(self.substs(folder.tcx()).fold_with(folder)),
+ substs_: Some(self.substs(folder.tcx()).try_fold_with(folder)?),
promoted: self.promoted,
- }
+ })
}
fn visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> ControlFlow<V::BreakTy> {
diff --git a/compiler/rustc_middle/src/ty/sty.rs b/compiler/rustc_middle/src/ty/sty.rs
index c79e25f4781..1c525fb55e1 100644
--- a/compiler/rustc_middle/src/ty/sty.rs
+++ b/compiler/rustc_middle/src/ty/sty.rs
@@ -8,9 +8,7 @@ use crate::infer::canonical::Canonical;
use crate::ty::fold::ValidateBoundVars;
use crate::ty::subst::{GenericArg, InternalSubsts, Subst, SubstsRef};
use crate::ty::InferTy::{self, *};
-use crate::ty::{
- self, AdtDef, DefIdTree, Discr, Ty, TyCtxt, TypeFlags, TypeFoldable, WithConstness,
-};
+use crate::ty::{self, AdtDef, DefIdTree, Discr, Ty, TyCtxt, TypeFlags, TypeFoldable};
use crate::ty::{DelaySpanBugEmitted, List, ParamEnv, TyS};
use polonius_engine::Atom;
use rustc_data_structures::captures::Captures;
@@ -356,14 +354,17 @@ impl<'tcx> ClosureSubsts<'tcx> {
/// The ordering assumed here must match that used by `ClosureSubsts::new` above.
fn split(self) -> ClosureSubstsParts<'tcx, GenericArg<'tcx>> {
match self.substs[..] {
- [ref parent_substs @ .., closure_kind_ty, closure_sig_as_fn_ptr_ty, tupled_upvars_ty] => {
- ClosureSubstsParts {
- parent_substs,
- closure_kind_ty,
- closure_sig_as_fn_ptr_ty,
- tupled_upvars_ty,
- }
- }
+ [
+ ref parent_substs @ ..,
+ closure_kind_ty,
+ closure_sig_as_fn_ptr_ty,
+ tupled_upvars_ty,
+ ] => ClosureSubstsParts {
+ parent_substs,
+ closure_kind_ty,
+ closure_sig_as_fn_ptr_ty,
+ tupled_upvars_ty,
+ },
_ => bug!("closure substs missing synthetics"),
}
}
@@ -786,7 +787,7 @@ impl<'tcx> ExistentialPredicate<'tcx> {
tcx.def_path_hash(a.item_def_id).cmp(&tcx.def_path_hash(b.item_def_id))
}
(AutoTrait(ref a), AutoTrait(ref b)) => {
- tcx.trait_def(*a).def_path_hash.cmp(&tcx.trait_def(*b).def_path_hash)
+ tcx.def_path_hash(*a).cmp(&tcx.def_path_hash(*b))
}
(Trait(_), _) => Ordering::Less,
(Projection(_), Trait(_)) => Ordering::Greater,
@@ -890,7 +891,7 @@ impl<'tcx> List<ty::Binder<'tcx, ExistentialPredicate<'tcx>>> {
///
/// Trait references also appear in object types like `Foo<U>`, but in
/// that case the `Self` parameter is absent from the substitutions.
-#[derive(Copy, Clone, PartialEq, Eq, Hash, TyEncodable, TyDecodable)]
+#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, TyEncodable, TyDecodable)]
#[derive(HashStable, TypeFoldable)]
pub struct TraitRef<'tcx> {
pub def_id: DefId,
@@ -1101,6 +1102,18 @@ impl<'tcx, T> Binder<'tcx, T> {
Binder(value, self.1)
}
+ pub fn try_map_bound<F, U: TypeFoldable<'tcx>, E>(self, f: F) -> Result<Binder<'tcx, U>, E>
+ where
+ F: FnOnce(T) -> Result<U, E>,
+ {
+ let value = f(self.0)?;
+ if cfg!(debug_assertions) {
+ let mut validator = ValidateBoundVars::new(self.1);
+ value.visit_with(&mut validator);
+ }
+ Ok(Binder(value, self.1))
+ }
+
/// Wraps a `value` in a binder, using the same bound variables as the
/// current `Binder`. This should not be used if the new value *changes*
/// the bound variables. Note: the (old or new) value itself does not
@@ -2263,10 +2276,11 @@ impl<'tcx> TyS<'tcx> {
/// a miscompilation or unsoundness.
///
/// When in doubt, use `VarianceDiagInfo::default()`
-#[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord)]
+#[derive(Copy, Clone, Debug, Default, PartialEq, Eq, PartialOrd, Ord)]
pub enum VarianceDiagInfo<'tcx> {
/// No additional information - this is the default.
/// We will not add any additional information to error messages.
+ #[default]
None,
/// We switched our variance because a type occurs inside
/// the generic argument of a mutable reference or pointer
@@ -2301,9 +2315,3 @@ impl<'tcx> VarianceDiagInfo<'tcx> {
}
}
}
-
-impl<'tcx> Default for VarianceDiagInfo<'tcx> {
- fn default() -> Self {
- Self::None
- }
-}
diff --git a/compiler/rustc_middle/src/ty/subst.rs b/compiler/rustc_middle/src/ty/subst.rs
index 73a8e18949d..8fddafaf620 100644
--- a/compiler/rustc_middle/src/ty/subst.rs
+++ b/compiler/rustc_middle/src/ty/subst.rs
@@ -2,7 +2,7 @@
use crate::mir;
use crate::ty::codec::{TyDecoder, TyEncoder};
-use crate::ty::fold::{TypeFoldable, TypeFolder, TypeVisitor};
+use crate::ty::fold::{FallibleTypeFolder, TypeFoldable, TypeFolder, TypeVisitor};
use crate::ty::sty::{ClosureSubsts, GeneratorSubsts, InlineConstSubsts};
use crate::ty::{self, Lift, List, ParamConst, Ty, TyCtxt};
@@ -153,11 +153,14 @@ impl<'a, 'tcx> Lift<'tcx> for GenericArg<'a> {
}
impl<'tcx> TypeFoldable<'tcx> for GenericArg<'tcx> {
- fn super_fold_with<F: TypeFolder<'tcx>>(self, folder: &mut F) -> Self {
+ fn try_super_fold_with<F: FallibleTypeFolder<'tcx>>(
+ self,
+ folder: &mut F,
+ ) -> Result<Self, F::Error> {
match self.unpack() {
- GenericArgKind::Lifetime(lt) => lt.fold_with(folder).into(),
- GenericArgKind::Type(ty) => ty.fold_with(folder).into(),
- GenericArgKind::Const(ct) => ct.fold_with(folder).into(),
+ GenericArgKind::Lifetime(lt) => lt.try_fold_with(folder).map(Into::into),
+ GenericArgKind::Type(ty) => ty.try_fold_with(folder).map(Into::into),
+ GenericArgKind::Const(ct) => ct.try_fold_with(folder).map(Into::into),
}
}
@@ -372,7 +375,10 @@ impl<'a, 'tcx> InternalSubsts<'tcx> {
}
impl<'tcx> TypeFoldable<'tcx> for SubstsRef<'tcx> {
- fn super_fold_with<F: TypeFolder<'tcx>>(self, folder: &mut F) -> Self {
+ fn try_super_fold_with<F: FallibleTypeFolder<'tcx>>(
+ self,
+ folder: &mut F,
+ ) -> Result<Self, F::Error> {
// This code is hot enough that it's worth specializing for the most
// common length lists, to avoid the overhead of `SmallVec` creation.
// The match arms are in order of frequency. The 1, 2, and 0 cases are
@@ -381,22 +387,27 @@ impl<'tcx> TypeFoldable<'tcx> for SubstsRef<'tcx> {
// calling `intern_substs`.
match self.len() {
1 => {
- let param0 = self[0].fold_with(folder);
- if param0 == self[0] { self } else { folder.tcx().intern_substs(&[param0]) }
+ let param0 = self[0].try_fold_with(folder)?;
+ if param0 == self[0] { Ok(self) } else { Ok(folder.tcx().intern_substs(&[param0])) }
}
2 => {
- let param0 = self[0].fold_with(folder);
- let param1 = self[1].fold_with(folder);
+ let param0 = self[0].try_fold_with(folder)?;
+ let param1 = self[1].try_fold_with(folder)?;
if param0 == self[0] && param1 == self[1] {
- self
+ Ok(self)
} else {
- folder.tcx().intern_substs(&[param0, param1])
+ Ok(folder.tcx().intern_substs(&[param0, param1]))
}
}
- 0 => self,
+ 0 => Ok(self),
_ => {
- let params: SmallVec<[_; 8]> = self.iter().map(|k| k.fold_with(folder)).collect();
- if params[..] == self[..] { self } else { folder.tcx().intern_substs(&params) }
+ let params: SmallVec<[_; 8]> =
+ self.iter().map(|k| k.try_fold_with(folder)).collect::<Result<_, _>>()?;
+ if params[..] == self[..] {
+ Ok(self)
+ } else {
+ Ok(folder.tcx().intern_substs(&params))
+ }
}
}
}
diff --git a/compiler/rustc_middle/src/ty/trait_def.rs b/compiler/rustc_middle/src/ty/trait_def.rs
index 25a310b12db..cbb88def7e2 100644
--- a/compiler/rustc_middle/src/ty/trait_def.rs
+++ b/compiler/rustc_middle/src/ty/trait_def.rs
@@ -1,5 +1,5 @@
use crate::traits::specialization_graph;
-use crate::ty::fast_reject;
+use crate::ty::fast_reject::{self, SimplifyParams, StripReferences};
use crate::ty::fold::TypeFoldable;
use crate::ty::{Ty, TyCtxt};
use rustc_hir as hir;
@@ -146,6 +146,11 @@ impl<'tcx> TyCtxt<'tcx> {
self_ty: Ty<'tcx>,
mut f: F,
) -> Option<T> {
+ // FIXME: This depends on the set of all impls for the trait. That is
+ // unfortunate wrt. incremental compilation.
+ //
+ // If we want to be faster, we could have separate queries for
+ // blanket and non-blanket impls, and compare them separately.
let impls = self.trait_impls_of(def_id);
for &impl_def_id in impls.blanket_impls.iter() {
@@ -154,32 +159,16 @@ impl<'tcx> TyCtxt<'tcx> {
}
}
- // simplify_type(.., false) basically replaces type parameters and
- // projections with infer-variables. This is, of course, done on
- // the impl trait-ref when it is instantiated, but not on the
- // predicate trait-ref which is passed here.
- //
- // for example, if we match `S: Copy` against an impl like
- // `impl<T:Copy> Copy for Option<T>`, we replace the type variable
- // in `Option<T>` with an infer variable, to `Option<_>` (this
- // doesn't actually change fast_reject output), but we don't
- // replace `S` with anything - this impl of course can't be
- // selected, and as there are hundreds of similar impls,
- // considering them would significantly harm performance.
-
- // This depends on the set of all impls for the trait. That is
- // unfortunate. When we get red-green recompilation, we would like
- // to have a way of knowing whether the set of relevant impls
- // changed. The most naive
- // way would be to compute the Vec of relevant impls and see whether
- // it differs between compilations. That shouldn't be too slow by
- // itself - we do quite a bit of work for each relevant impl anyway.
- //
- // If we want to be faster, we could have separate queries for
- // blanket and non-blanket impls, and compare them separately.
+ // Note that we're using `SimplifyParams::Yes` to query `non_blanket_impls` while using
+ // `SimplifyParams::No` while actually adding them.
//
- // I think we'll cross that bridge when we get to it.
- if let Some(simp) = fast_reject::simplify_type(self, self_ty, true) {
+ // This way, when searching for some impl for `T: Trait`, we do not look at any impls
+ // whose outer level is not a parameter or projection. Especially for things like
+ // `T: Clone` this is incredibly useful as we would otherwise look at all the impls
+ // of `Clone` for `Option<T>`, `Vec<T>`, `ConcreteType` and so on.
+ if let Some(simp) =
+ fast_reject::simplify_type(self, self_ty, SimplifyParams::Yes, StripReferences::No)
+ {
if let Some(impls) = impls.non_blanket_impls.get(&simp) {
for &impl_def_id in impls {
if let result @ Some(_) = f(impl_def_id) {
@@ -238,7 +227,9 @@ pub(super) fn trait_impls_of_provider(tcx: TyCtxt<'_>, trait_id: DefId) -> Trait
continue;
}
- if let Some(simplified_self_ty) = fast_reject::simplify_type(tcx, impl_self_ty, false) {
+ if let Some(simplified_self_ty) =
+ fast_reject::simplify_type(tcx, impl_self_ty, SimplifyParams::No, StripReferences::No)
+ {
impls.non_blanket_impls.entry(simplified_self_ty).or_default().push(impl_def_id);
} else {
impls.blanket_impls.push(impl_def_id);
diff --git a/compiler/rustc_middle/src/ty/util.rs b/compiler/rustc_middle/src/ty/util.rs
index 6e7acb244d1..ba9b2eae2c8 100644
--- a/compiler/rustc_middle/src/ty/util.rs
+++ b/compiler/rustc_middle/src/ty/util.rs
@@ -1,7 +1,7 @@
//! Miscellaneous type-system utilities that are too small to deserve their own modules.
use crate::middle::codegen_fn_attrs::CodegenFnAttrFlags;
-use crate::ty::fold::TypeFolder;
+use crate::ty::fold::{FallibleTypeFolder, TypeFolder};
use crate::ty::layout::IntegerExt;
use crate::ty::query::TyCtxtAt;
use crate::ty::subst::{GenericArgKind, Subst, SubstsRef};
@@ -788,10 +788,14 @@ impl<'tcx> ty::TyS<'tcx> {
[component_ty] => component_ty,
_ => self,
};
+
// This doesn't depend on regions, so try to minimize distinct
// query keys used.
- let erased = tcx.normalize_erasing_regions(param_env, query_ty);
- tcx.needs_drop_raw(param_env.and(erased))
+ // If normalization fails, we just use `query_ty`.
+ let query_ty =
+ tcx.try_normalize_erasing_regions(param_env, query_ty).unwrap_or(query_ty);
+
+ tcx.needs_drop_raw(param_env.and(query_ty))
}
}
}
@@ -1046,25 +1050,31 @@ pub fn fold_list<'tcx, F, T>(
list: &'tcx ty::List<T>,
folder: &mut F,
intern: impl FnOnce(TyCtxt<'tcx>, &[T]) -> &'tcx ty::List<T>,
-) -> &'tcx ty::List<T>
+) -> Result<&'tcx ty::List<T>, F::Error>
where
- F: TypeFolder<'tcx>,
+ F: FallibleTypeFolder<'tcx>,
T: TypeFoldable<'tcx> + PartialEq + Copy,
{
let mut iter = list.iter();
// Look for the first element that changed
- if let Some((i, new_t)) = iter.by_ref().enumerate().find_map(|(i, t)| {
- let new_t = t.fold_with(folder);
- if new_t == t { None } else { Some((i, new_t)) }
+ match iter.by_ref().enumerate().find_map(|(i, t)| match t.try_fold_with(folder) {
+ Ok(new_t) if new_t == t => None,
+ new_t => Some((i, new_t)),
}) {
- // An element changed, prepare to intern the resulting list
- let mut new_list = SmallVec::<[_; 8]>::with_capacity(list.len());
- new_list.extend_from_slice(&list[..i]);
- new_list.push(new_t);
- new_list.extend(iter.map(|t| t.fold_with(folder)));
- intern(folder.tcx(), &new_list)
- } else {
- list
+ Some((i, Ok(new_t))) => {
+ // An element changed, prepare to intern the resulting list
+ let mut new_list = SmallVec::<[_; 8]>::with_capacity(list.len());
+ new_list.extend_from_slice(&list[..i]);
+ new_list.push(new_t);
+ for t in iter {
+ new_list.push(t.try_fold_with(folder)?)
+ }
+ Ok(intern(folder.tcx(), &new_list))
+ }
+ Some((_, Err(err))) => {
+ return Err(err);
+ }
+ None => Ok(list),
}
}
diff --git a/compiler/rustc_mir_build/src/build/expr/into.rs b/compiler/rustc_mir_build/src/build/expr/into.rs
index 53868f28557..abec67af08b 100644
--- a/compiler/rustc_mir_build/src/build/expr/into.rs
+++ b/compiler/rustc_mir_build/src/build/expr/into.rs
@@ -467,8 +467,12 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
} else {
Some(destination_block)
},
+ cleanup: None,
},
);
+ if options.contains(InlineAsmOptions::MAY_UNWIND) {
+ this.diverge_from(block);
+ }
destination_block.unit()
}
diff --git a/compiler/rustc_mir_build/src/build/scope.rs b/compiler/rustc_mir_build/src/build/scope.rs
index 8dadbf5f02b..fc46c54c2fc 100644
--- a/compiler/rustc_mir_build/src/build/scope.rs
+++ b/compiler/rustc_mir_build/src/build/scope.rs
@@ -1034,6 +1034,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
| TerminatorKind::Call { .. }
| TerminatorKind::DropAndReplace { .. }
| TerminatorKind::FalseUnwind { .. }
+ | TerminatorKind::InlineAsm { .. }
),
"diverge_from called on block with terminator that cannot unwind."
);
@@ -1373,7 +1374,8 @@ impl<'tcx> DropTreeBuilder<'tcx> for Unwind {
| TerminatorKind::DropAndReplace { unwind, .. }
| TerminatorKind::FalseUnwind { unwind, .. }
| TerminatorKind::Call { cleanup: unwind, .. }
- | TerminatorKind::Assert { cleanup: unwind, .. } => {
+ | TerminatorKind::Assert { cleanup: unwind, .. }
+ | TerminatorKind::InlineAsm { cleanup: unwind, .. } => {
*unwind = Some(to);
}
TerminatorKind::Goto { .. }
@@ -1384,8 +1386,7 @@ impl<'tcx> DropTreeBuilder<'tcx> for Unwind {
| TerminatorKind::Unreachable
| TerminatorKind::Yield { .. }
| TerminatorKind::GeneratorDrop
- | TerminatorKind::FalseEdge { .. }
- | TerminatorKind::InlineAsm { .. } => {
+ | TerminatorKind::FalseEdge { .. } => {
span_bug!(term.source_info.span, "cannot unwind from {:?}", term.kind)
}
}
diff --git a/compiler/rustc_mir_build/src/lib.rs b/compiler/rustc_mir_build/src/lib.rs
index b0f1e08562c..38bb00f985a 100644
--- a/compiler/rustc_mir_build/src/lib.rs
+++ b/compiler/rustc_mir_build/src/lib.rs
@@ -5,7 +5,6 @@
#![feature(control_flow_enum)]
#![feature(crate_visibility_modifier)]
#![feature(bool_to_option)]
-#![feature(iter_zip)]
#![feature(let_else)]
#![feature(once_cell)]
#![feature(min_specialization)]
diff --git a/compiler/rustc_mir_build/src/thir/cx/expr.rs b/compiler/rustc_mir_build/src/thir/cx/expr.rs
index b4005ccd1cc..092fe131174 100644
--- a/compiler/rustc_mir_build/src/thir/cx/expr.rs
+++ b/compiler/rustc_mir_build/src/thir/cx/expr.rs
@@ -605,9 +605,10 @@ impl<'tcx> Cx<'tcx> {
},
Err(err) => bug!("invalid loop id for continue: {}", err),
},
- hir::ExprKind::Let(ref pat, ref expr, _) => {
- ExprKind::Let { expr: self.mirror_expr(expr), pat: self.pattern_from_hir(pat) }
- }
+ hir::ExprKind::Let(let_expr) => ExprKind::Let {
+ expr: self.mirror_expr(let_expr.init),
+ pat: self.pattern_from_hir(let_expr.pat),
+ },
hir::ExprKind::If(cond, then, else_opt) => ExprKind::If {
if_then_scope: region::Scope {
id: then.hir_id.local_id,
diff --git a/compiler/rustc_mir_build/src/thir/pattern/check_match.rs b/compiler/rustc_mir_build/src/thir/pattern/check_match.rs
index d74c53fae53..7a4fd6ffc4a 100644
--- a/compiler/rustc_mir_build/src/thir/pattern/check_match.rs
+++ b/compiler/rustc_mir_build/src/thir/pattern/check_match.rs
@@ -64,7 +64,9 @@ impl<'tcx> Visitor<'tcx> for MatchVisitor<'_, '_, 'tcx> {
intravisit::walk_expr(self, ex);
match &ex.kind {
hir::ExprKind::Match(scrut, arms, source) => self.check_match(scrut, arms, *source),
- hir::ExprKind::Let(pat, scrut, span) => self.check_let(pat, scrut, *span),
+ hir::ExprKind::Let(hir::Let { pat, init, span, .. }) => {
+ self.check_let(pat, init, *span)
+ }
_ => {}
}
}
@@ -148,9 +150,9 @@ impl<'p, 'tcx> MatchVisitor<'_, 'p, 'tcx> {
}
}
- fn check_let(&mut self, pat: &'tcx hir::Pat<'tcx>, expr: &hir::Expr<'_>, span: Span) {
+ fn check_let(&mut self, pat: &'tcx hir::Pat<'tcx>, scrutinee: &hir::Expr<'_>, span: Span) {
self.check_patterns(pat, Refutable);
- let mut cx = self.new_cx(expr.hir_id);
+ let mut cx = self.new_cx(scrutinee.hir_id);
let tpat = self.lower_pattern(&mut cx, pat, &mut false);
check_let_reachability(&mut cx, pat.hir_id, tpat, span);
}
diff --git a/compiler/rustc_mir_build/src/thir/pattern/mod.rs b/compiler/rustc_mir_build/src/thir/pattern/mod.rs
index ce80214c875..55cf807172e 100644
--- a/compiler/rustc_mir_build/src/thir/pattern/mod.rs
+++ b/compiler/rustc_mir_build/src/thir/pattern/mod.rs
@@ -533,43 +533,64 @@ impl<'a, 'tcx> PatCtxt<'a, 'tcx> {
}
}
+ /// Converts inline const patterns.
+ fn lower_inline_const(
+ &mut self,
+ anon_const: &'tcx hir::AnonConst,
+ id: hir::HirId,
+ span: Span,
+ ) -> PatKind<'tcx> {
+ let anon_const_def_id = self.tcx.hir().local_def_id(anon_const.hir_id);
+ let value = ty::Const::from_inline_const(self.tcx, anon_const_def_id);
+
+ // Evaluate early like we do in `lower_path`.
+ let value = value.eval(self.tcx, self.param_env);
+
+ match value.val {
+ ConstKind::Param(_) => {
+ self.errors.push(PatternError::ConstParamInPattern(span));
+ return PatKind::Wild;
+ }
+ ConstKind::Unevaluated(_) => {
+ // If we land here it means the const can't be evaluated because it's `TooGeneric`.
+ self.tcx.sess.span_err(span, "constant pattern depends on a generic parameter");
+ return PatKind::Wild;
+ }
+ _ => (),
+ }
+
+ *self.const_to_pat(value, id, span, false).kind
+ }
+
/// Converts literals, paths and negation of literals to patterns.
/// The special case for negation exists to allow things like `-128_i8`
/// which would overflow if we tried to evaluate `128_i8` and then negate
/// afterwards.
fn lower_lit(&mut self, expr: &'tcx hir::Expr<'tcx>) -> PatKind<'tcx> {
- if let hir::ExprKind::Path(ref qpath) = expr.kind {
- *self.lower_path(qpath, expr.hir_id, expr.span).kind
- } else {
- let (lit, neg) = match expr.kind {
- hir::ExprKind::ConstBlock(ref anon_const) => {
- let anon_const_def_id = self.tcx.hir().local_def_id(anon_const.hir_id);
- let value = ty::Const::from_inline_const(self.tcx, anon_const_def_id);
- if matches!(value.val, ConstKind::Param(_)) {
- let span = self.tcx.hir().span(anon_const.hir_id);
- self.errors.push(PatternError::ConstParamInPattern(span));
- return PatKind::Wild;
- }
- return *self.const_to_pat(value, expr.hir_id, expr.span, false).kind;
- }
- hir::ExprKind::Lit(ref lit) => (lit, false),
- hir::ExprKind::Unary(hir::UnOp::Neg, ref expr) => {
- let lit = match expr.kind {
- hir::ExprKind::Lit(ref lit) => lit,
- _ => span_bug!(expr.span, "not a literal: {:?}", expr),
- };
- (lit, true)
- }
- _ => span_bug!(expr.span, "not a literal: {:?}", expr),
- };
-
- let lit_input =
- LitToConstInput { lit: &lit.node, ty: self.typeck_results.expr_ty(expr), neg };
- match self.tcx.at(expr.span).lit_to_const(lit_input) {
- Ok(val) => *self.const_to_pat(val, expr.hir_id, lit.span, false).kind,
- Err(LitToConstError::Reported) => PatKind::Wild,
- Err(LitToConstError::TypeError) => bug!("lower_lit: had type error"),
+ let (lit, neg) = match expr.kind {
+ hir::ExprKind::Path(ref qpath) => {
+ return *self.lower_path(qpath, expr.hir_id, expr.span).kind;
+ }
+ hir::ExprKind::ConstBlock(ref anon_const) => {
+ return self.lower_inline_const(anon_const, expr.hir_id, expr.span);
+ }
+ hir::ExprKind::Lit(ref lit) => (lit, false),
+ hir::ExprKind::Unary(hir::UnOp::Neg, ref expr) => {
+ let lit = match expr.kind {
+ hir::ExprKind::Lit(ref lit) => lit,
+ _ => span_bug!(expr.span, "not a literal: {:?}", expr),
+ };
+ (lit, true)
}
+ _ => span_bug!(expr.span, "not a literal: {:?}", expr),
+ };
+
+ let lit_input =
+ LitToConstInput { lit: &lit.node, ty: self.typeck_results.expr_ty(expr), neg };
+ match self.tcx.at(expr.span).lit_to_const(lit_input) {
+ Ok(val) => *self.const_to_pat(val, expr.hir_id, lit.span, false).kind,
+ Err(LitToConstError::Reported) => PatKind::Wild,
+ Err(LitToConstError::TypeError) => bug!("lower_lit: had type error"),
}
}
}
diff --git a/compiler/rustc_mir_build/src/thir/pattern/usefulness.rs b/compiler/rustc_mir_build/src/thir/pattern/usefulness.rs
index 3ed434131b2..286473c38e3 100644
--- a/compiler/rustc_mir_build/src/thir/pattern/usefulness.rs
+++ b/compiler/rustc_mir_build/src/thir/pattern/usefulness.rs
@@ -289,6 +289,7 @@ use super::deconstruct_pat::{Constructor, DeconstructedPat, Fields, SplitWildcar
use rustc_data_structures::captures::Captures;
use rustc_arena::TypedArena;
+use rustc_data_structures::stack::ensure_sufficient_stack;
use rustc_hir::def_id::DefId;
use rustc_hir::HirId;
use rustc_middle::ty::{self, Ty, TyCtxt};
@@ -808,8 +809,9 @@ fn is_useful<'p, 'tcx>(
// We try each or-pattern branch in turn.
let mut matrix = matrix.clone();
for v in v.expand_or_pat() {
- let usefulness =
- is_useful(cx, &matrix, &v, witness_preference, hir_id, is_under_guard, false);
+ let usefulness = ensure_sufficient_stack(|| {
+ is_useful(cx, &matrix, &v, witness_preference, hir_id, is_under_guard, false)
+ });
ret.extend(usefulness);
// If pattern has a guard don't add it to the matrix.
if !is_under_guard {
@@ -840,8 +842,9 @@ fn is_useful<'p, 'tcx>(
// We cache the result of `Fields::wildcards` because it is used a lot.
let spec_matrix = start_matrix.specialize_constructor(pcx, &ctor);
let v = v.pop_head_constructor(cx, &ctor);
- let usefulness =
- is_useful(cx, &spec_matrix, &v, witness_preference, hir_id, is_under_guard, false);
+ let usefulness = ensure_sufficient_stack(|| {
+ is_useful(cx, &spec_matrix, &v, witness_preference, hir_id, is_under_guard, false)
+ });
let usefulness = usefulness.apply_constructor(pcx, start_matrix, &ctor);
// When all the conditions are met we have a match with a `non_exhaustive` enum
diff --git a/compiler/rustc_mir_dataflow/src/framework/direction.rs b/compiler/rustc_mir_dataflow/src/framework/direction.rs
index 8a9ced91eb3..102e7439772 100644
--- a/compiler/rustc_mir_dataflow/src/framework/direction.rs
+++ b/compiler/rustc_mir_dataflow/src/framework/direction.rs
@@ -4,7 +4,9 @@ use rustc_middle::ty::TyCtxt;
use std::ops::RangeInclusive;
use super::visitor::{ResultsVisitable, ResultsVisitor};
-use super::{Analysis, Effect, EffectIndex, GenKillAnalysis, GenKillSet, SwitchIntTarget};
+use super::{
+ Analysis, CallReturnPlaces, Effect, EffectIndex, GenKillAnalysis, GenKillSet, SwitchIntTarget,
+};
pub trait Direction {
fn is_forward() -> bool;
@@ -16,7 +18,7 @@ pub trait Direction {
/// Applies all effects between the given `EffectIndex`s.
///
/// `effects.start()` must precede or equal `effects.end()` in this direction.
- fn apply_effects_in_range<A>(
+ fn apply_effects_in_range<'tcx, A>(
analysis: &A,
state: &mut A::Domain,
block: BasicBlock,
@@ -25,7 +27,7 @@ pub trait Direction {
) where
A: Analysis<'tcx>;
- fn apply_effects_in_block<A>(
+ fn apply_effects_in_block<'tcx, A>(
analysis: &A,
state: &mut A::Domain,
block: BasicBlock,
@@ -33,7 +35,7 @@ pub trait Direction {
) where
A: Analysis<'tcx>;
- fn gen_kill_effects_in_block<A>(
+ fn gen_kill_effects_in_block<'tcx, A>(
analysis: &A,
trans: &mut GenKillSet<A::Idx>,
block: BasicBlock,
@@ -41,7 +43,7 @@ pub trait Direction {
) where
A: GenKillAnalysis<'tcx>;
- fn visit_results_in_block<F, R>(
+ fn visit_results_in_block<'mir, 'tcx, F, R>(
state: &mut F,
block: BasicBlock,
block_data: &'mir mir::BasicBlockData<'tcx>,
@@ -50,7 +52,7 @@ pub trait Direction {
) where
R: ResultsVisitable<'tcx, FlowState = F>;
- fn join_state_into_successors_of<A>(
+ fn join_state_into_successors_of<'tcx, A>(
analysis: &A,
tcx: TyCtxt<'tcx>,
body: &mir::Body<'tcx>,
@@ -70,7 +72,7 @@ impl Direction for Backward {
false
}
- fn apply_effects_in_block<A>(
+ fn apply_effects_in_block<'tcx, A>(
analysis: &A,
state: &mut A::Domain,
block: BasicBlock,
@@ -90,7 +92,7 @@ impl Direction for Backward {
}
}
- fn gen_kill_effects_in_block<A>(
+ fn gen_kill_effects_in_block<'tcx, A>(
analysis: &A,
trans: &mut GenKillSet<A::Idx>,
block: BasicBlock,
@@ -110,7 +112,7 @@ impl Direction for Backward {
}
}
- fn apply_effects_in_range<A>(
+ fn apply_effects_in_range<'tcx, A>(
analysis: &A,
state: &mut A::Domain,
block: BasicBlock,
@@ -187,7 +189,7 @@ impl Direction for Backward {
analysis.apply_statement_effect(state, statement, location);
}
- fn visit_results_in_block<F, R>(
+ fn visit_results_in_block<'mir, 'tcx, F, R>(
state: &mut F,
block: BasicBlock,
block_data: &'mir mir::BasicBlockData<'tcx>,
@@ -219,7 +221,7 @@ impl Direction for Backward {
vis.visit_block_start(state, block_data, block);
}
- fn join_state_into_successors_of<A>(
+ fn join_state_into_successors_of<'tcx, A>(
analysis: &A,
_tcx: TyCtxt<'tcx>,
body: &mir::Body<'tcx>,
@@ -235,14 +237,26 @@ impl Direction for Backward {
// Apply terminator-specific edge effects.
//
// FIXME(ecstaticmorse): Avoid cloning the exit state unconditionally.
- mir::TerminatorKind::Call {
- destination: Some((return_place, dest)),
- ref func,
- ref args,
- ..
+ mir::TerminatorKind::Call { destination: Some((return_place, dest)), .. }
+ if dest == bb =>
+ {
+ let mut tmp = exit_state.clone();
+ analysis.apply_call_return_effect(
+ &mut tmp,
+ pred,
+ CallReturnPlaces::Call(return_place),
+ );
+ propagate(pred, &tmp);
+ }
+ mir::TerminatorKind::InlineAsm {
+ destination: Some(dest), ref operands, ..
} if dest == bb => {
let mut tmp = exit_state.clone();
- analysis.apply_call_return_effect(&mut tmp, pred, func, args, return_place);
+ analysis.apply_call_return_effect(
+ &mut tmp,
+ pred,
+ CallReturnPlaces::InlineAsm(operands),
+ );
propagate(pred, &tmp);
}
@@ -258,6 +272,7 @@ impl Direction for Backward {
| mir::TerminatorKind::Drop { unwind: Some(unwind), .. }
| mir::TerminatorKind::DropAndReplace { unwind: Some(unwind), .. }
| mir::TerminatorKind::FalseUnwind { unwind: Some(unwind), .. }
+ | mir::TerminatorKind::InlineAsm { cleanup: Some(unwind), .. }
if unwind == bb =>
{
if dead_unwinds.map_or(true, |dead| !dead.contains(bb)) {
@@ -279,7 +294,7 @@ impl Direction for Forward {
true
}
- fn apply_effects_in_block<A>(
+ fn apply_effects_in_block<'tcx, A>(
analysis: &A,
state: &mut A::Domain,
block: BasicBlock,
@@ -299,7 +314,7 @@ impl Direction for Forward {
analysis.apply_terminator_effect(state, terminator, location);
}
- fn gen_kill_effects_in_block<A>(
+ fn gen_kill_effects_in_block<'tcx, A>(
analysis: &A,
trans: &mut GenKillSet<A::Idx>,
block: BasicBlock,
@@ -319,7 +334,7 @@ impl Direction for Forward {
analysis.terminator_effect(trans, terminator, location);
}
- fn apply_effects_in_range<A>(
+ fn apply_effects_in_range<'tcx, A>(
analysis: &A,
state: &mut A::Domain,
block: BasicBlock,
@@ -392,7 +407,7 @@ impl Direction for Forward {
}
}
- fn visit_results_in_block<F, R>(
+ fn visit_results_in_block<'mir, 'tcx, F, R>(
state: &mut F,
block: BasicBlock,
block_data: &'mir mir::BasicBlockData<'tcx>,
@@ -423,7 +438,7 @@ impl Direction for Forward {
vis.visit_block_end(state, block_data, block);
}
- fn join_state_into_successors_of<A>(
+ fn join_state_into_successors_of<'tcx, A>(
analysis: &A,
_tcx: TyCtxt<'tcx>,
_body: &mir::Body<'tcx>,
@@ -467,7 +482,7 @@ impl Direction for Forward {
propagate(target, exit_state);
}
- Call { cleanup, destination, ref func, ref args, from_hir_call: _, fn_span: _ } => {
+ Call { cleanup, destination, func: _, args: _, from_hir_call: _, fn_span: _ } => {
if let Some(unwind) = cleanup {
if dead_unwinds.map_or(true, |dead| !dead.contains(bb)) {
propagate(unwind, exit_state);
@@ -477,13 +492,37 @@ impl Direction for Forward {
if let Some((dest_place, target)) = destination {
// N.B.: This must be done *last*, otherwise the unwind path will see the call
// return effect.
- analysis.apply_call_return_effect(exit_state, bb, func, args, dest_place);
+ analysis.apply_call_return_effect(
+ exit_state,
+ bb,
+ CallReturnPlaces::Call(dest_place),
+ );
propagate(target, exit_state);
}
}
- InlineAsm { template: _, operands: _, options: _, line_spans: _, destination } => {
+ InlineAsm {
+ template: _,
+ ref operands,
+ options: _,
+ line_spans: _,
+ destination,
+ cleanup,
+ } => {
+ if let Some(unwind) = cleanup {
+ if dead_unwinds.map_or(true, |dead| !dead.contains(bb)) {
+ propagate(unwind, exit_state);
+ }
+ }
+
if let Some(target) = destination {
+ // N.B.: This must be done *last*, otherwise the unwind path will see the call
+ // return effect.
+ analysis.apply_call_return_effect(
+ exit_state,
+ bb,
+ CallReturnPlaces::InlineAsm(operands),
+ );
propagate(target, exit_state);
}
}
@@ -552,7 +591,7 @@ where
//
// FIXME: Figure out how to express this using `Option::clone_from`, or maybe lift it into the
// standard library?
-fn opt_clone_from_or_clone<T: Clone>(opt: &'a mut Option<T>, val: &T) -> &'a mut T {
+fn opt_clone_from_or_clone<'a, T: Clone>(opt: &'a mut Option<T>, val: &T) -> &'a mut T {
if opt.is_some() {
let ret = opt.as_mut().unwrap();
ret.clone_from(val);
diff --git a/compiler/rustc_mir_dataflow/src/framework/engine.rs b/compiler/rustc_mir_dataflow/src/framework/engine.rs
index 804abc3b42b..e8a6d8dad43 100644
--- a/compiler/rustc_mir_dataflow/src/framework/engine.rs
+++ b/compiler/rustc_mir_dataflow/src/framework/engine.rs
@@ -31,12 +31,15 @@ where
pub(super) entry_sets: IndexVec<BasicBlock, A::Domain>,
}
-impl<A> Results<'tcx, A>
+impl<'tcx, A> Results<'tcx, A>
where
A: Analysis<'tcx>,
{
/// Creates a `ResultsCursor` that can inspect these `Results`.
- pub fn into_results_cursor(self, body: &'mir mir::Body<'tcx>) -> ResultsCursor<'mir, 'tcx, A> {
+ pub fn into_results_cursor<'mir>(
+ self,
+ body: &'mir mir::Body<'tcx>,
+ ) -> ResultsCursor<'mir, 'tcx, A> {
ResultsCursor::new(body, self)
}
@@ -45,7 +48,7 @@ where
&self.entry_sets[block]
}
- pub fn visit_with(
+ pub fn visit_with<'mir>(
&self,
body: &'mir mir::Body<'tcx>,
blocks: impl IntoIterator<Item = BasicBlock>,
@@ -54,7 +57,7 @@ where
visit_results(body, blocks, self, vis)
}
- pub fn visit_reachable_with(
+ pub fn visit_reachable_with<'mir>(
&self,
body: &'mir mir::Body<'tcx>,
vis: &mut impl ResultsVisitor<'mir, 'tcx, FlowState = A::Domain>,
@@ -85,7 +88,7 @@ where
apply_trans_for_block: Option<Box<dyn Fn(BasicBlock, &mut A::Domain)>>,
}
-impl<A, D, T> Engine<'a, 'tcx, A>
+impl<'a, 'tcx, A, D, T> Engine<'a, 'tcx, A>
where
A: GenKillAnalysis<'tcx, Idx = T, Domain = D>,
D: Clone + JoinSemiLattice + GenKill<T> + BorrowMut<BitSet<T>>,
@@ -119,7 +122,7 @@ where
}
}
-impl<A, D> Engine<'a, 'tcx, A>
+impl<'a, 'tcx, A, D> Engine<'a, 'tcx, A>
where
A: Analysis<'tcx, Domain = D>,
D: Clone + JoinSemiLattice,
@@ -257,7 +260,7 @@ where
/// Writes a DOT file containing the results of a dataflow analysis if the user requested it via
/// `rustc_mir` attributes.
-fn write_graphviz_results<A>(
+fn write_graphviz_results<'tcx, A>(
tcx: TyCtxt<'tcx>,
body: &mir::Body<'tcx>,
results: &Results<'tcx, A>,
@@ -330,7 +333,7 @@ struct RustcMirAttrs {
}
impl RustcMirAttrs {
- fn parse(tcx: TyCtxt<'tcx>, def_id: DefId) -> Result<Self, ()> {
+ fn parse(tcx: TyCtxt<'_>, def_id: DefId) -> Result<Self, ()> {
let attrs = tcx.get_attrs(def_id);
let mut result = Ok(());
@@ -373,7 +376,7 @@ impl RustcMirAttrs {
fn set_field<T>(
field: &mut Option<T>,
- tcx: TyCtxt<'tcx>,
+ tcx: TyCtxt<'_>,
attr: &ast::NestedMetaItem,
mapper: impl FnOnce(Symbol) -> Result<T, ()>,
) -> Result<(), ()> {
diff --git a/compiler/rustc_mir_dataflow/src/framework/graphviz.rs b/compiler/rustc_mir_dataflow/src/framework/graphviz.rs
index a370f8e40f9..34bc157a744 100644
--- a/compiler/rustc_mir_dataflow/src/framework/graphviz.rs
+++ b/compiler/rustc_mir_dataflow/src/framework/graphviz.rs
@@ -10,7 +10,7 @@ use rustc_middle::mir::graphviz_safe_def_name;
use rustc_middle::mir::{self, BasicBlock, Body, Location};
use super::fmt::{DebugDiffWithAdapter, DebugWithAdapter, DebugWithContext};
-use super::{Analysis, Direction, Results, ResultsRefCursor, ResultsVisitor};
+use super::{Analysis, CallReturnPlaces, Direction, Results, ResultsRefCursor, ResultsVisitor};
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub enum OutputStyle {
@@ -36,7 +36,7 @@ where
style: OutputStyle,
}
-impl<A> Formatter<'a, 'tcx, A>
+impl<'a, 'tcx, A> Formatter<'a, 'tcx, A>
where
A: Analysis<'tcx>,
{
@@ -52,7 +52,7 @@ pub struct CfgEdge {
index: usize,
}
-fn dataflow_successors(body: &Body<'tcx>, bb: BasicBlock) -> Vec<CfgEdge> {
+fn dataflow_successors(body: &Body<'_>, bb: BasicBlock) -> Vec<CfgEdge> {
body[bb]
.terminator()
.successors()
@@ -61,7 +61,7 @@ fn dataflow_successors(body: &Body<'tcx>, bb: BasicBlock) -> Vec<CfgEdge> {
.collect()
}
-impl<A> dot::Labeller<'_> for Formatter<'a, 'tcx, A>
+impl<'tcx, A> dot::Labeller<'_> for Formatter<'_, 'tcx, A>
where
A: Analysis<'tcx>,
A::Domain: DebugWithContext<A>,
@@ -100,7 +100,7 @@ where
}
}
-impl<A> dot::GraphWalk<'a> for Formatter<'a, 'tcx, A>
+impl<'a, 'tcx, A> dot::GraphWalk<'a> for Formatter<'a, 'tcx, A>
where
A: Analysis<'tcx>,
{
@@ -138,7 +138,7 @@ where
style: OutputStyle,
}
-impl<A> BlockFormatter<'a, 'tcx, A>
+impl<'a, 'tcx, A> BlockFormatter<'a, 'tcx, A>
where
A: Analysis<'tcx>,
A::Domain: DebugWithContext<A>,
@@ -231,16 +231,15 @@ where
// for the basic block itself. That way, we could display terminator-specific effects for
// backward dataflow analyses as well as effects for `SwitchInt` terminators.
match terminator.kind {
- mir::TerminatorKind::Call {
- destination: Some((return_place, _)),
- ref func,
- ref args,
- ..
- } => {
+ mir::TerminatorKind::Call { destination: Some((return_place, _)), .. } => {
self.write_row(w, "", "(on successful return)", |this, w, fmt| {
let state_on_unwind = this.results.get().clone();
this.results.apply_custom_effect(|analysis, state| {
- analysis.apply_call_return_effect(state, block, func, args, return_place);
+ analysis.apply_call_return_effect(
+ state,
+ block,
+ CallReturnPlaces::Call(return_place),
+ );
});
write!(
@@ -278,6 +277,31 @@ where
})?;
}
+ mir::TerminatorKind::InlineAsm { destination: Some(_), ref operands, .. } => {
+ self.write_row(w, "", "(on successful return)", |this, w, fmt| {
+ let state_on_unwind = this.results.get().clone();
+ this.results.apply_custom_effect(|analysis, state| {
+ analysis.apply_call_return_effect(
+ state,
+ block,
+ CallReturnPlaces::InlineAsm(operands),
+ );
+ });
+
+ write!(
+ w,
+ r#"<td balign="left" colspan="{colspan}" {fmt} align="left">{diff}</td>"#,
+ colspan = this.style.num_state_columns(),
+ fmt = fmt,
+ diff = diff_pretty(
+ this.results.get(),
+ &state_on_unwind,
+ this.results.analysis()
+ ),
+ )
+ })?;
+ }
+
_ => {}
};
@@ -467,7 +491,7 @@ where
after: Vec<String>,
}
-impl<A> StateDiffCollector<'a, 'tcx, A>
+impl<'a, 'tcx, A> StateDiffCollector<'a, 'tcx, A>
where
A: Analysis<'tcx>,
A::Domain: DebugWithContext<A>,
@@ -490,7 +514,7 @@ where
}
}
-impl<A> ResultsVisitor<'a, 'tcx> for StateDiffCollector<'a, 'tcx, A>
+impl<'a, 'tcx, A> ResultsVisitor<'a, 'tcx> for StateDiffCollector<'a, 'tcx, A>
where
A: Analysis<'tcx>,
A::Domain: DebugWithContext<A>,
@@ -500,7 +524,7 @@ where
fn visit_block_start(
&mut self,
state: &Self::FlowState,
- _block_data: &'mir mir::BasicBlockData<'tcx>,
+ _block_data: &mir::BasicBlockData<'tcx>,
_block: BasicBlock,
) {
if A::Direction::is_forward() {
@@ -511,7 +535,7 @@ where
fn visit_block_end(
&mut self,
state: &Self::FlowState,
- _block_data: &'mir mir::BasicBlockData<'tcx>,
+ _block_data: &mir::BasicBlockData<'tcx>,
_block: BasicBlock,
) {
if A::Direction::is_backward() {
@@ -522,7 +546,7 @@ where
fn visit_statement_before_primary_effect(
&mut self,
state: &Self::FlowState,
- _statement: &'mir mir::Statement<'tcx>,
+ _statement: &mir::Statement<'tcx>,
_location: Location,
) {
if let Some(before) = self.before.as_mut() {
@@ -534,7 +558,7 @@ where
fn visit_statement_after_primary_effect(
&mut self,
state: &Self::FlowState,
- _statement: &'mir mir::Statement<'tcx>,
+ _statement: &mir::Statement<'tcx>,
_location: Location,
) {
self.after.push(diff_pretty(state, &self.prev_state, self.analysis));
@@ -544,7 +568,7 @@ where
fn visit_terminator_before_primary_effect(
&mut self,
state: &Self::FlowState,
- _terminator: &'mir mir::Terminator<'tcx>,
+ _terminator: &mir::Terminator<'tcx>,
_location: Location,
) {
if let Some(before) = self.before.as_mut() {
@@ -556,7 +580,7 @@ where
fn visit_terminator_after_primary_effect(
&mut self,
state: &Self::FlowState,
- _terminator: &'mir mir::Terminator<'tcx>,
+ _terminator: &mir::Terminator<'tcx>,
_location: Location,
) {
self.after.push(diff_pretty(state, &self.prev_state, self.analysis));
diff --git a/compiler/rustc_mir_dataflow/src/framework/mod.rs b/compiler/rustc_mir_dataflow/src/framework/mod.rs
index f0c9ac4c504..dac6720a6e5 100644
--- a/compiler/rustc_mir_dataflow/src/framework/mod.rs
+++ b/compiler/rustc_mir_dataflow/src/framework/mod.rs
@@ -160,9 +160,7 @@ pub trait Analysis<'tcx>: AnalysisDomain<'tcx> {
&self,
state: &mut Self::Domain,
block: BasicBlock,
- func: &mir::Operand<'tcx>,
- args: &[mir::Operand<'tcx>],
- return_place: mir::Place<'tcx>,
+ return_places: CallReturnPlaces<'_, 'tcx>,
);
/// Updates the current dataflow state with the effect of resuming from a `Yield` terminator.
@@ -216,7 +214,11 @@ pub trait Analysis<'tcx>: AnalysisDomain<'tcx> {
/// .iterate_to_fixpoint()
/// .into_results_cursor(body);
/// ```
- fn into_engine(self, tcx: TyCtxt<'tcx>, body: &'mir mir::Body<'tcx>) -> Engine<'mir, 'tcx, Self>
+ fn into_engine<'mir>(
+ self,
+ tcx: TyCtxt<'tcx>,
+ body: &'mir mir::Body<'tcx>,
+ ) -> Engine<'mir, 'tcx, Self>
where
Self: Sized,
{
@@ -276,9 +278,7 @@ pub trait GenKillAnalysis<'tcx>: Analysis<'tcx> {
&self,
trans: &mut impl GenKill<Self::Idx>,
block: BasicBlock,
- func: &mir::Operand<'tcx>,
- args: &[mir::Operand<'tcx>],
- return_place: mir::Place<'tcx>,
+ return_places: CallReturnPlaces<'_, 'tcx>,
);
/// See `Analysis::apply_yield_resume_effect`.
@@ -300,7 +300,7 @@ pub trait GenKillAnalysis<'tcx>: Analysis<'tcx> {
}
}
-impl<A> Analysis<'tcx> for A
+impl<'tcx, A> Analysis<'tcx> for A
where
A: GenKillAnalysis<'tcx>,
A::Domain: GenKill<A::Idx> + BorrowMut<BitSet<A::Idx>>,
@@ -347,11 +347,9 @@ where
&self,
state: &mut A::Domain,
block: BasicBlock,
- func: &mir::Operand<'tcx>,
- args: &[mir::Operand<'tcx>],
- return_place: mir::Place<'tcx>,
+ return_places: CallReturnPlaces<'_, 'tcx>,
) {
- self.call_return_effect(state, block, func, args, return_place);
+ self.call_return_effect(state, block, return_places);
}
fn apply_yield_resume_effect(
@@ -374,7 +372,11 @@ where
/* Extension methods */
- fn into_engine(self, tcx: TyCtxt<'tcx>, body: &'mir mir::Body<'tcx>) -> Engine<'mir, 'tcx, Self>
+ fn into_engine<'mir>(
+ self,
+ tcx: TyCtxt<'tcx>,
+ body: &'mir mir::Body<'tcx>,
+ ) -> Engine<'mir, 'tcx, Self>
where
Self: Sized,
{
@@ -542,5 +544,29 @@ pub trait SwitchIntEdgeEffects<D> {
fn apply(&mut self, apply_edge_effect: impl FnMut(&mut D, SwitchIntTarget));
}
+/// List of places that are written to after a successful (non-unwind) return
+/// from a `Call` or `InlineAsm`.
+pub enum CallReturnPlaces<'a, 'tcx> {
+ Call(mir::Place<'tcx>),
+ InlineAsm(&'a [mir::InlineAsmOperand<'tcx>]),
+}
+
+impl<'tcx> CallReturnPlaces<'_, 'tcx> {
+ pub fn for_each(&self, mut f: impl FnMut(mir::Place<'tcx>)) {
+ match *self {
+ Self::Call(place) => f(place),
+ Self::InlineAsm(operands) => {
+ for op in operands {
+ match *op {
+ mir::InlineAsmOperand::Out { place: Some(place), .. }
+ | mir::InlineAsmOperand::InOut { out_place: Some(place), .. } => f(place),
+ _ => {}
+ }
+ }
+ }
+ }
+ }
+}
+
#[cfg(test)]
mod tests;
diff --git a/compiler/rustc_mir_dataflow/src/framework/tests.rs b/compiler/rustc_mir_dataflow/src/framework/tests.rs
index 6efa8daec48..3cc8d30259c 100644
--- a/compiler/rustc_mir_dataflow/src/framework/tests.rs
+++ b/compiler/rustc_mir_dataflow/src/framework/tests.rs
@@ -85,7 +85,7 @@ struct MockAnalysis<'tcx, D> {
dir: PhantomData<D>,
}
-impl<D: Direction> MockAnalysis<'tcx, D> {
+impl<D: Direction> MockAnalysis<'_, D> {
const BASIC_BLOCK_OFFSET: usize = 100;
/// The entry set for each `BasicBlock` is the ID of that block offset by a fixed amount to
@@ -160,7 +160,7 @@ impl<D: Direction> MockAnalysis<'tcx, D> {
}
}
-impl<D: Direction> AnalysisDomain<'tcx> for MockAnalysis<'tcx, D> {
+impl<'tcx, D: Direction> AnalysisDomain<'tcx> for MockAnalysis<'tcx, D> {
type Domain = BitSet<usize>;
type Direction = D;
@@ -175,7 +175,7 @@ impl<D: Direction> AnalysisDomain<'tcx> for MockAnalysis<'tcx, D> {
}
}
-impl<D: Direction> Analysis<'tcx> for MockAnalysis<'tcx, D> {
+impl<'tcx, D: Direction> Analysis<'tcx> for MockAnalysis<'tcx, D> {
fn apply_statement_effect(
&self,
state: &mut Self::Domain,
@@ -220,9 +220,7 @@ impl<D: Direction> Analysis<'tcx> for MockAnalysis<'tcx, D> {
&self,
_state: &mut Self::Domain,
_block: BasicBlock,
- _func: &mir::Operand<'tcx>,
- _args: &[mir::Operand<'tcx>],
- _return_place: mir::Place<'tcx>,
+ _return_places: CallReturnPlaces<'_, 'tcx>,
) {
}
}
@@ -262,7 +260,7 @@ impl SeekTarget {
}
}
-fn test_cursor<D: Direction>(analysis: MockAnalysis<'tcx, D>) {
+fn test_cursor<D: Direction>(analysis: MockAnalysis<'_, D>) {
let body = analysis.body;
let mut cursor =
diff --git a/compiler/rustc_mir_dataflow/src/framework/visitor.rs b/compiler/rustc_mir_dataflow/src/framework/visitor.rs
index 84136c4d78c..75b4e150a8a 100644
--- a/compiler/rustc_mir_dataflow/src/framework/visitor.rs
+++ b/compiler/rustc_mir_dataflow/src/framework/visitor.rs
@@ -4,7 +4,7 @@ use super::{Analysis, Direction, Results};
/// Calls the corresponding method in `ResultsVisitor` for every location in a `mir::Body` with the
/// dataflow state at that location.
-pub fn visit_results<F, V>(
+pub fn visit_results<'mir, 'tcx, F, V>(
body: &'mir mir::Body<'tcx>,
blocks: impl IntoIterator<Item = BasicBlock>,
results: &V,
diff --git a/compiler/rustc_mir_dataflow/src/impls/borrowed_locals.rs b/compiler/rustc_mir_dataflow/src/impls/borrowed_locals.rs
index d38b567a958..bb9755e4f48 100644
--- a/compiler/rustc_mir_dataflow/src/impls/borrowed_locals.rs
+++ b/compiler/rustc_mir_dataflow/src/impls/borrowed_locals.rs
@@ -1,6 +1,6 @@
use super::*;
-use crate::{AnalysisDomain, GenKill, GenKillAnalysis};
+use crate::{AnalysisDomain, CallReturnPlaces, GenKill, GenKillAnalysis};
use rustc_middle::mir::visit::Visitor;
use rustc_middle::mir::*;
@@ -45,7 +45,7 @@ impl MaybeBorrowedLocals {
}
}
-impl AnalysisDomain<'tcx> for MaybeBorrowedLocals {
+impl<'tcx> AnalysisDomain<'tcx> for MaybeBorrowedLocals {
type Domain = BitSet<Local>;
const NAME: &'static str = "maybe_borrowed_locals";
@@ -59,7 +59,7 @@ impl AnalysisDomain<'tcx> for MaybeBorrowedLocals {
}
}
-impl GenKillAnalysis<'tcx> for MaybeBorrowedLocals {
+impl<'tcx> GenKillAnalysis<'tcx> for MaybeBorrowedLocals {
type Idx = Local;
fn statement_effect(
@@ -84,9 +84,7 @@ impl GenKillAnalysis<'tcx> for MaybeBorrowedLocals {
&self,
_trans: &mut impl GenKill<Self::Idx>,
_block: mir::BasicBlock,
- _func: &mir::Operand<'tcx>,
- _args: &[mir::Operand<'tcx>],
- _dest_place: mir::Place<'tcx>,
+ _return_places: CallReturnPlaces<'_, 'tcx>,
) {
}
}
@@ -97,7 +95,7 @@ struct TransferFunction<'a, T> {
ignore_borrow_on_drop: bool,
}
-impl<T> Visitor<'tcx> for TransferFunction<'a, T>
+impl<'tcx, T> Visitor<'tcx> for TransferFunction<'_, T>
where
T: GenKill<Local>,
{
diff --git a/compiler/rustc_mir_dataflow/src/impls/init_locals.rs b/compiler/rustc_mir_dataflow/src/impls/init_locals.rs
index 07570e764f5..b355871d64f 100644
--- a/compiler/rustc_mir_dataflow/src/impls/init_locals.rs
+++ b/compiler/rustc_mir_dataflow/src/impls/init_locals.rs
@@ -2,7 +2,7 @@
//!
//! A local will be maybe initialized if *any* projections of that local might be initialized.
-use crate::GenKill;
+use crate::{CallReturnPlaces, GenKill};
use rustc_index::bit_set::BitSet;
use rustc_middle::mir::visit::{PlaceContext, Visitor};
@@ -10,7 +10,7 @@ use rustc_middle::mir::{self, BasicBlock, Local, Location};
pub struct MaybeInitializedLocals;
-impl crate::AnalysisDomain<'tcx> for MaybeInitializedLocals {
+impl<'tcx> crate::AnalysisDomain<'tcx> for MaybeInitializedLocals {
type Domain = BitSet<Local>;
const NAME: &'static str = "maybe_init_locals";
@@ -28,7 +28,7 @@ impl crate::AnalysisDomain<'tcx> for MaybeInitializedLocals {
}
}
-impl crate::GenKillAnalysis<'tcx> for MaybeInitializedLocals {
+impl<'tcx> crate::GenKillAnalysis<'tcx> for MaybeInitializedLocals {
type Idx = Local;
fn statement_effect(
@@ -53,11 +53,9 @@ impl crate::GenKillAnalysis<'tcx> for MaybeInitializedLocals {
&self,
trans: &mut impl GenKill<Self::Idx>,
_block: BasicBlock,
- _func: &mir::Operand<'tcx>,
- _args: &[mir::Operand<'tcx>],
- return_place: mir::Place<'tcx>,
+ return_places: CallReturnPlaces<'_, 'tcx>,
) {
- trans.gen(return_place.local)
+ return_places.for_each(|place| trans.gen(place.local));
}
/// See `Analysis::apply_yield_resume_effect`.
@@ -75,7 +73,7 @@ struct TransferFunction<'a, T> {
trans: &'a mut T,
}
-impl<T> Visitor<'tcx> for TransferFunction<'a, T>
+impl<T> Visitor<'_> for TransferFunction<'_, T>
where
T: GenKill<Local>,
{
@@ -83,7 +81,11 @@ where
use rustc_middle::mir::visit::{MutatingUseContext, NonMutatingUseContext, NonUseContext};
match context {
// These are handled specially in `call_return_effect` and `yield_resume_effect`.
- PlaceContext::MutatingUse(MutatingUseContext::Call | MutatingUseContext::Yield) => {}
+ PlaceContext::MutatingUse(
+ MutatingUseContext::Call
+ | MutatingUseContext::AsmOutput
+ | MutatingUseContext::Yield,
+ ) => {}
// Otherwise, when a place is mutated, we must consider it possibly initialized.
PlaceContext::MutatingUse(_) => self.trans.gen(local),
diff --git a/compiler/rustc_mir_dataflow/src/impls/liveness.rs b/compiler/rustc_mir_dataflow/src/impls/liveness.rs
index 3e2548845e2..65c388f8124 100644
--- a/compiler/rustc_mir_dataflow/src/impls/liveness.rs
+++ b/compiler/rustc_mir_dataflow/src/impls/liveness.rs
@@ -2,7 +2,7 @@ use rustc_index::bit_set::BitSet;
use rustc_middle::mir::visit::{MutatingUseContext, NonMutatingUseContext, PlaceContext, Visitor};
use rustc_middle::mir::{self, Local, Location};
-use crate::{AnalysisDomain, Backward, GenKill, GenKillAnalysis};
+use crate::{AnalysisDomain, Backward, CallReturnPlaces, GenKill, GenKillAnalysis};
/// A [live-variable dataflow analysis][liveness].
///
@@ -48,12 +48,12 @@ use crate::{AnalysisDomain, Backward, GenKill, GenKillAnalysis};
pub struct MaybeLiveLocals;
impl MaybeLiveLocals {
- fn transfer_function<T>(&self, trans: &'a mut T) -> TransferFunction<'a, T> {
+ fn transfer_function<'a, T>(&self, trans: &'a mut T) -> TransferFunction<'a, T> {
TransferFunction(trans)
}
}
-impl AnalysisDomain<'tcx> for MaybeLiveLocals {
+impl<'tcx> AnalysisDomain<'tcx> for MaybeLiveLocals {
type Domain = BitSet<Local>;
type Direction = Backward;
@@ -69,7 +69,7 @@ impl AnalysisDomain<'tcx> for MaybeLiveLocals {
}
}
-impl GenKillAnalysis<'tcx> for MaybeLiveLocals {
+impl<'tcx> GenKillAnalysis<'tcx> for MaybeLiveLocals {
type Idx = Local;
fn statement_effect(
@@ -94,13 +94,13 @@ impl GenKillAnalysis<'tcx> for MaybeLiveLocals {
&self,
trans: &mut impl GenKill<Self::Idx>,
_block: mir::BasicBlock,
- _func: &mir::Operand<'tcx>,
- _args: &[mir::Operand<'tcx>],
- dest_place: mir::Place<'tcx>,
+ return_places: CallReturnPlaces<'_, 'tcx>,
) {
- if let Some(local) = dest_place.as_local() {
- trans.kill(local);
- }
+ return_places.for_each(|place| {
+ if let Some(local) = place.as_local() {
+ trans.kill(local);
+ }
+ });
}
fn yield_resume_effect(
@@ -167,12 +167,16 @@ impl DefUse {
// destination place for a `Call` return or `Yield` resume respectively. Since this is
// only a `Def` when the function returns successfully, we handle this case separately
// in `call_return_effect` above.
- PlaceContext::MutatingUse(MutatingUseContext::Call | MutatingUseContext::Yield) => None,
+ PlaceContext::MutatingUse(
+ MutatingUseContext::Call
+ | MutatingUseContext::AsmOutput
+ | MutatingUseContext::Yield,
+ ) => None,
// All other contexts are uses...
PlaceContext::MutatingUse(
MutatingUseContext::AddressOf
- | MutatingUseContext::AsmOutput
+ | MutatingUseContext::LlvmAsmOutput
| MutatingUseContext::Borrow
| MutatingUseContext::Drop
| MutatingUseContext::Retag,
diff --git a/compiler/rustc_mir_dataflow/src/impls/mod.rs b/compiler/rustc_mir_dataflow/src/impls/mod.rs
index 91dddc6cd55..5dc8a003b47 100644
--- a/compiler/rustc_mir_dataflow/src/impls/mod.rs
+++ b/compiler/rustc_mir_dataflow/src/impls/mod.rs
@@ -4,17 +4,18 @@
use rustc_index::bit_set::BitSet;
use rustc_index::vec::Idx;
+use rustc_middle::mir::visit::{MirVisitable, Visitor};
use rustc_middle::mir::{self, Body, Location};
use rustc_middle::ty::{self, TyCtxt};
-use crate::drop_flag_effects;
use crate::drop_flag_effects_for_function_entry;
use crate::drop_flag_effects_for_location;
use crate::elaborate_drops::DropFlagState;
-use crate::framework::SwitchIntEdgeEffects;
-use crate::move_paths::{HasMoveData, InitIndex, InitKind, MoveData, MovePathIndex};
+use crate::framework::{CallReturnPlaces, SwitchIntEdgeEffects};
+use crate::move_paths::{HasMoveData, InitIndex, InitKind, LookupResult, MoveData, MovePathIndex};
use crate::on_lookup_result_bits;
use crate::MoveDataParamEnv;
+use crate::{drop_flag_effects, on_all_children_bits};
use crate::{lattice, AnalysisDomain, GenKill, GenKillAnalysis};
mod borrowed_locals;
@@ -307,22 +308,45 @@ impl<'tcx> GenKillAnalysis<'tcx> for MaybeInitializedPlaces<'_, 'tcx> {
fn statement_effect(
&self,
trans: &mut impl GenKill<Self::Idx>,
- _statement: &mir::Statement<'tcx>,
+ statement: &mir::Statement<'tcx>,
location: Location,
) {
drop_flag_effects_for_location(self.tcx, self.body, self.mdpe, location, |path, s| {
Self::update_bits(trans, path, s)
+ });
+
+ if !self.tcx.sess.opts.debugging_opts.precise_enum_drop_elaboration {
+ return;
+ }
+
+ // Mark all places as "maybe init" if they are mutably borrowed. See #90752.
+ for_each_mut_borrow(statement, location, |place| {
+ let LookupResult::Exact(mpi) = self.move_data().rev_lookup.find(place.as_ref()) else { return };
+ on_all_children_bits(self.tcx, self.body, self.move_data(), mpi, |child| {
+ trans.gen(child);
+ })
})
}
fn terminator_effect(
&self,
trans: &mut impl GenKill<Self::Idx>,
- _terminator: &mir::Terminator<'tcx>,
+ terminator: &mir::Terminator<'tcx>,
location: Location,
) {
drop_flag_effects_for_location(self.tcx, self.body, self.mdpe, location, |path, s| {
Self::update_bits(trans, path, s)
+ });
+
+ if !self.tcx.sess.opts.debugging_opts.precise_enum_drop_elaboration {
+ return;
+ }
+
+ for_each_mut_borrow(terminator, location, |place| {
+ let LookupResult::Exact(mpi) = self.move_data().rev_lookup.find(place.as_ref()) else { return };
+ on_all_children_bits(self.tcx, self.body, self.move_data(), mpi, |child| {
+ trans.gen(child);
+ })
})
}
@@ -330,21 +354,21 @@ impl<'tcx> GenKillAnalysis<'tcx> for MaybeInitializedPlaces<'_, 'tcx> {
&self,
trans: &mut impl GenKill<Self::Idx>,
_block: mir::BasicBlock,
- _func: &mir::Operand<'tcx>,
- _args: &[mir::Operand<'tcx>],
- dest_place: mir::Place<'tcx>,
+ return_places: CallReturnPlaces<'_, 'tcx>,
) {
- // when a call returns successfully, that means we need to set
- // the bits for that dest_place to 1 (initialized).
- on_lookup_result_bits(
- self.tcx,
- self.body,
- self.move_data(),
- self.move_data().rev_lookup.find(dest_place.as_ref()),
- |mpi| {
- trans.gen(mpi);
- },
- );
+ return_places.for_each(|place| {
+ // when a call returns successfully, that means we need to set
+ // the bits for that dest_place to 1 (initialized).
+ on_lookup_result_bits(
+ self.tcx,
+ self.body,
+ self.move_data(),
+ self.move_data().rev_lookup.find(place.as_ref()),
+ |mpi| {
+ trans.gen(mpi);
+ },
+ );
+ });
}
fn switch_int_edge_effects<G: GenKill<Self::Idx>>(
@@ -427,7 +451,10 @@ impl<'tcx> GenKillAnalysis<'tcx> for MaybeUninitializedPlaces<'_, 'tcx> {
) {
drop_flag_effects_for_location(self.tcx, self.body, self.mdpe, location, |path, s| {
Self::update_bits(trans, path, s)
- })
+ });
+
+ // Unlike in `MaybeInitializedPlaces` above, we don't need to change the state when a
+ // mutable borrow occurs. Places cannot become uninitialized through a mutable reference.
}
fn terminator_effect(
@@ -438,28 +465,28 @@ impl<'tcx> GenKillAnalysis<'tcx> for MaybeUninitializedPlaces<'_, 'tcx> {
) {
drop_flag_effects_for_location(self.tcx, self.body, self.mdpe, location, |path, s| {
Self::update_bits(trans, path, s)
- })
+ });
}
fn call_return_effect(
&self,
trans: &mut impl GenKill<Self::Idx>,
_block: mir::BasicBlock,
- _func: &mir::Operand<'tcx>,
- _args: &[mir::Operand<'tcx>],
- dest_place: mir::Place<'tcx>,
+ return_places: CallReturnPlaces<'_, 'tcx>,
) {
- // when a call returns successfully, that means we need to set
- // the bits for that dest_place to 0 (initialized).
- on_lookup_result_bits(
- self.tcx,
- self.body,
- self.move_data(),
- self.move_data().rev_lookup.find(dest_place.as_ref()),
- |mpi| {
- trans.kill(mpi);
- },
- );
+ return_places.for_each(|place| {
+ // when a call returns successfully, that means we need to set
+ // the bits for that dest_place to 0 (initialized).
+ on_lookup_result_bits(
+ self.tcx,
+ self.body,
+ self.move_data(),
+ self.move_data().rev_lookup.find(place.as_ref()),
+ |mpi| {
+ trans.kill(mpi);
+ },
+ );
+ });
}
fn switch_int_edge_effects<G: GenKill<Self::Idx>>(
@@ -564,21 +591,21 @@ impl<'tcx> GenKillAnalysis<'tcx> for DefinitelyInitializedPlaces<'_, 'tcx> {
&self,
trans: &mut impl GenKill<Self::Idx>,
_block: mir::BasicBlock,
- _func: &mir::Operand<'tcx>,
- _args: &[mir::Operand<'tcx>],
- dest_place: mir::Place<'tcx>,
+ return_places: CallReturnPlaces<'_, 'tcx>,
) {
- // when a call returns successfully, that means we need to set
- // the bits for that dest_place to 1 (initialized).
- on_lookup_result_bits(
- self.tcx,
- self.body,
- self.move_data(),
- self.move_data().rev_lookup.find(dest_place.as_ref()),
- |mpi| {
- trans.gen(mpi);
- },
- );
+ return_places.for_each(|place| {
+ // when a call returns successfully, that means we need to set
+ // the bits for that dest_place to 1 (initialized).
+ on_lookup_result_bits(
+ self.tcx,
+ self.body,
+ self.move_data(),
+ self.move_data().rev_lookup.find(place.as_ref()),
+ |mpi| {
+ trans.gen(mpi);
+ },
+ );
+ });
}
}
@@ -652,9 +679,7 @@ impl<'tcx> GenKillAnalysis<'tcx> for EverInitializedPlaces<'_, 'tcx> {
&self,
trans: &mut impl GenKill<Self::Idx>,
block: mir::BasicBlock,
- _func: &mir::Operand<'tcx>,
- _args: &[mir::Operand<'tcx>],
- _dest_place: mir::Place<'tcx>,
+ _return_places: CallReturnPlaces<'_, 'tcx>,
) {
let move_data = self.move_data();
let init_loc_map = &move_data.init_loc_map;
@@ -679,7 +704,7 @@ impl<'tcx> GenKillAnalysis<'tcx> for EverInitializedPlaces<'_, 'tcx> {
///
/// If the basic block matches this pattern, this function returns the place corresponding to the
/// enum (`_1` in the example above) as well as the `AdtDef` of that enum.
-fn switch_on_enum_discriminant(
+fn switch_on_enum_discriminant<'mir, 'tcx>(
tcx: TyCtxt<'tcx>,
body: &'mir mir::Body<'tcx>,
block: &'mir mir::BasicBlockData<'tcx>,
@@ -704,3 +729,37 @@ fn switch_on_enum_discriminant(
_ => None,
}
}
+
+struct OnMutBorrow<F>(F);
+
+impl<F> Visitor<'_> for OnMutBorrow<F>
+where
+ F: FnMut(&mir::Place<'_>),
+{
+ fn visit_rvalue(&mut self, rvalue: &mir::Rvalue<'_>, location: Location) {
+ // FIXME: Does `&raw const foo` allow mutation? See #90413.
+ match rvalue {
+ mir::Rvalue::Ref(_, mir::BorrowKind::Mut { .. }, place)
+ | mir::Rvalue::AddressOf(_, place) => (self.0)(place),
+
+ _ => {}
+ }
+
+ self.super_rvalue(rvalue, location)
+ }
+}
+
+/// Calls `f` for each mutable borrow or raw reference in the program.
+///
+/// This DOES NOT call `f` for a shared borrow of a type with interior mutability. That's okay for
+/// initializedness, because we cannot move from an `UnsafeCell` (outside of `core::cell`), but
+/// other analyses will likely need to check for `!Freeze`.
+fn for_each_mut_borrow<'tcx>(
+ mir: &impl MirVisitable<'tcx>,
+ location: Location,
+ f: impl FnMut(&mir::Place<'_>),
+) {
+ let mut vis = OnMutBorrow(f);
+
+ mir.apply(location, &mut vis);
+}
diff --git a/compiler/rustc_mir_dataflow/src/impls/storage_liveness.rs b/compiler/rustc_mir_dataflow/src/impls/storage_liveness.rs
index b468e50b391..896377f2bc3 100644
--- a/compiler/rustc_mir_dataflow/src/impls/storage_liveness.rs
+++ b/compiler/rustc_mir_dataflow/src/impls/storage_liveness.rs
@@ -1,7 +1,7 @@
pub use super::*;
use crate::storage::AlwaysLiveLocals;
-use crate::{GenKill, Results, ResultsRefCursor};
+use crate::{CallReturnPlaces, GenKill, Results, ResultsRefCursor};
use rustc_middle::mir::visit::{NonMutatingUseContext, PlaceContext, Visitor};
use rustc_middle::mir::*;
use std::cell::RefCell;
@@ -17,7 +17,7 @@ impl MaybeStorageLive {
}
}
-impl crate::AnalysisDomain<'tcx> for MaybeStorageLive {
+impl<'tcx> crate::AnalysisDomain<'tcx> for MaybeStorageLive {
type Domain = BitSet<Local>;
const NAME: &'static str = "maybe_storage_live";
@@ -39,7 +39,7 @@ impl crate::AnalysisDomain<'tcx> for MaybeStorageLive {
}
}
-impl crate::GenKillAnalysis<'tcx> for MaybeStorageLive {
+impl<'tcx> crate::GenKillAnalysis<'tcx> for MaybeStorageLive {
type Idx = Local;
fn statement_effect(
@@ -68,9 +68,7 @@ impl crate::GenKillAnalysis<'tcx> for MaybeStorageLive {
&self,
_trans: &mut impl GenKill<Self::Idx>,
_block: BasicBlock,
- _func: &mir::Operand<'tcx>,
- _args: &[mir::Operand<'tcx>],
- _return_place: mir::Place<'tcx>,
+ _return_places: CallReturnPlaces<'_, 'tcx>,
) {
// Nothing to do when a call returns successfully
}
@@ -226,7 +224,7 @@ impl<'mir, 'tcx> crate::GenKillAnalysis<'tcx> for MaybeRequiresStorage<'mir, 'tc
terminator: &mir::Terminator<'tcx>,
loc: Location,
) {
- match &terminator.kind {
+ match terminator.kind {
// For call terminators the destination requires storage for the call
// and after the call returns successfully, but not after a panic.
// Since `propagate_call_unwind` doesn't exist, we have to kill the
@@ -235,6 +233,11 @@ impl<'mir, 'tcx> crate::GenKillAnalysis<'tcx> for MaybeRequiresStorage<'mir, 'tc
trans.kill(place.local);
}
+ // The same applies to InlineAsm outputs.
+ TerminatorKind::InlineAsm { ref operands, .. } => {
+ CallReturnPlaces::InlineAsm(operands).for_each(|place| trans.kill(place.local));
+ }
+
// Nothing to do for these. Match exhaustively so this fails to compile when new
// variants are added.
TerminatorKind::Call { destination: None, .. }
@@ -247,7 +250,6 @@ impl<'mir, 'tcx> crate::GenKillAnalysis<'tcx> for MaybeRequiresStorage<'mir, 'tc
| TerminatorKind::FalseUnwind { .. }
| TerminatorKind::GeneratorDrop
| TerminatorKind::Goto { .. }
- | TerminatorKind::InlineAsm { .. }
| TerminatorKind::Resume
| TerminatorKind::Return
| TerminatorKind::SwitchInt { .. }
@@ -261,11 +263,9 @@ impl<'mir, 'tcx> crate::GenKillAnalysis<'tcx> for MaybeRequiresStorage<'mir, 'tc
&self,
trans: &mut impl GenKill<Self::Idx>,
_block: BasicBlock,
- _func: &mir::Operand<'tcx>,
- _args: &[mir::Operand<'tcx>],
- return_place: mir::Place<'tcx>,
+ return_places: CallReturnPlaces<'_, 'tcx>,
) {
- trans.gen(return_place.local);
+ return_places.for_each(|place| trans.gen(place.local));
}
fn yield_resume_effect(
diff --git a/compiler/rustc_mir_dataflow/src/lib.rs b/compiler/rustc_mir_dataflow/src/lib.rs
index 77a72ce63ce..6c2d1b85646 100644
--- a/compiler/rustc_mir_dataflow/src/lib.rs
+++ b/compiler/rustc_mir_dataflow/src/lib.rs
@@ -3,8 +3,6 @@
#![feature(box_patterns)]
#![feature(box_syntax)]
#![feature(exact_size_is_empty)]
-#![feature(in_band_lifetimes)]
-#![feature(iter_zip)]
#![feature(let_else)]
#![feature(min_specialization)]
#![feature(once_cell)]
@@ -28,9 +26,9 @@ pub use self::drop_flag_effects::{
on_lookup_result_bits,
};
pub use self::framework::{
- fmt, graphviz, lattice, visit_results, Analysis, AnalysisDomain, Backward, Direction, Engine,
- Forward, GenKill, GenKillAnalysis, JoinSemiLattice, Results, ResultsCursor, ResultsRefCursor,
- ResultsVisitable, ResultsVisitor,
+ fmt, graphviz, lattice, visit_results, Analysis, AnalysisDomain, Backward, CallReturnPlaces,
+ Direction, Engine, Forward, GenKill, GenKillAnalysis, JoinSemiLattice, Results, ResultsCursor,
+ ResultsRefCursor, ResultsVisitable, ResultsVisitor,
};
use self::move_paths::MoveData;
diff --git a/compiler/rustc_mir_dataflow/src/move_paths/builder.rs b/compiler/rustc_mir_dataflow/src/move_paths/builder.rs
index e404b49ecb9..feb85d4ffdf 100644
--- a/compiler/rustc_mir_dataflow/src/move_paths/builder.rs
+++ b/compiler/rustc_mir_dataflow/src/move_paths/builder.rs
@@ -419,6 +419,7 @@ impl<'b, 'a, 'tcx> Gatherer<'b, 'a, 'tcx> {
options: _,
line_spans: _,
destination: _,
+ cleanup: _,
} => {
for op in operands {
match *op {
diff --git a/compiler/rustc_mir_dataflow/src/rustc_peek.rs b/compiler/rustc_mir_dataflow/src/rustc_peek.rs
index 28e5d76783a..1746d5ee38b 100644
--- a/compiler/rustc_mir_dataflow/src/rustc_peek.rs
+++ b/compiler/rustc_mir_dataflow/src/rustc_peek.rs
@@ -20,6 +20,7 @@ use crate::{Analysis, JoinSemiLattice, Results, ResultsCursor};
pub struct SanityCheck;
+// FIXME: This should be a `MirLint`, but it needs to be moved back to `rustc_mir_transform` first.
impl<'tcx> MirPass<'tcx> for SanityCheck {
fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
use crate::has_rustc_mir_with;
diff --git a/compiler/rustc_mir_dataflow/src/storage.rs b/compiler/rustc_mir_dataflow/src/storage.rs
index 18b8ef557d6..218d4557215 100644
--- a/compiler/rustc_mir_dataflow/src/storage.rs
+++ b/compiler/rustc_mir_dataflow/src/storage.rs
@@ -11,7 +11,7 @@ use rustc_middle::mir::{self, Local};
pub struct AlwaysLiveLocals(BitSet<Local>);
impl AlwaysLiveLocals {
- pub fn new(body: &mir::Body<'tcx>) -> Self {
+ pub fn new(body: &mir::Body<'_>) -> Self {
let mut always_live_locals = AlwaysLiveLocals(BitSet::new_filled(body.local_decls.len()));
for block in body.basic_blocks() {
diff --git a/compiler/rustc_mir_transform/src/add_retag.rs b/compiler/rustc_mir_transform/src/add_retag.rs
index 7a8dee09c29..28a5a22dd9d 100644
--- a/compiler/rustc_mir_transform/src/add_retag.rs
+++ b/compiler/rustc_mir_transform/src/add_retag.rs
@@ -34,7 +34,7 @@ fn is_stable(place: PlaceRef<'_>) -> bool {
}
/// Determine whether this type may be a reference (or box), and thus needs retagging.
-fn may_be_reference(ty: Ty<'tcx>) -> bool {
+fn may_be_reference(ty: Ty<'_>) -> bool {
match ty.kind() {
// Primitive types that are not references
ty::Bool
@@ -58,11 +58,11 @@ fn may_be_reference(ty: Ty<'tcx>) -> bool {
}
impl<'tcx> MirPass<'tcx> for AddRetag {
- fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
- if !tcx.sess.opts.debugging_opts.mir_emit_retag {
- return;
- }
+ fn is_enabled(&self, sess: &rustc_session::Session) -> bool {
+ sess.opts.debugging_opts.mir_emit_retag
+ }
+ fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
// We need an `AllCallEdges` pass before we can do any work.
super::add_call_guards::AllCallEdges.run_pass(tcx, body);
diff --git a/compiler/rustc_mir_transform/src/check_const_item_mutation.rs b/compiler/rustc_mir_transform/src/check_const_item_mutation.rs
index 27fe80a456f..a19a3c8b1d5 100644
--- a/compiler/rustc_mir_transform/src/check_const_item_mutation.rs
+++ b/compiler/rustc_mir_transform/src/check_const_item_mutation.rs
@@ -6,12 +6,12 @@ use rustc_middle::ty::TyCtxt;
use rustc_session::lint::builtin::CONST_ITEM_MUTATION;
use rustc_span::def_id::DefId;
-use crate::MirPass;
+use crate::MirLint;
pub struct CheckConstItemMutation;
-impl<'tcx> MirPass<'tcx> for CheckConstItemMutation {
- fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
+impl<'tcx> MirLint<'tcx> for CheckConstItemMutation {
+ fn run_lint(&self, tcx: TyCtxt<'tcx>, body: &Body<'tcx>) {
let mut checker = ConstMutationChecker { body, tcx, target_local: None };
checker.visit_body(&body);
}
@@ -23,7 +23,7 @@ struct ConstMutationChecker<'a, 'tcx> {
target_local: Option<Local>,
}
-impl<'a, 'tcx> ConstMutationChecker<'a, 'tcx> {
+impl<'tcx> ConstMutationChecker<'_, 'tcx> {
fn is_const_item(&self, local: Local) -> Option<DefId> {
if let Some(box LocalInfo::ConstRef { def_id }) = self.body.local_decls[local].local_info {
Some(def_id)
@@ -95,7 +95,7 @@ impl<'a, 'tcx> ConstMutationChecker<'a, 'tcx> {
}
}
-impl<'a, 'tcx> Visitor<'tcx> for ConstMutationChecker<'a, 'tcx> {
+impl<'tcx> Visitor<'tcx> for ConstMutationChecker<'_, 'tcx> {
fn visit_statement(&mut self, stmt: &Statement<'tcx>, loc: Location) {
if let StatementKind::Assign(box (lhs, _)) = &stmt.kind {
// Check for assignment to fields of a constant
diff --git a/compiler/rustc_mir_transform/src/check_packed_ref.rs b/compiler/rustc_mir_transform/src/check_packed_ref.rs
index 49be34c7a28..23d59c80071 100644
--- a/compiler/rustc_mir_transform/src/check_packed_ref.rs
+++ b/compiler/rustc_mir_transform/src/check_packed_ref.rs
@@ -7,7 +7,7 @@ use rustc_session::lint::builtin::UNALIGNED_REFERENCES;
use rustc_span::symbol::sym;
use crate::util;
-use crate::MirPass;
+use crate::MirLint;
pub(crate) fn provide(providers: &mut Providers) {
*providers = Providers { unsafe_derive_on_repr_packed, ..*providers };
@@ -15,8 +15,8 @@ pub(crate) fn provide(providers: &mut Providers) {
pub struct CheckPackedRef;
-impl<'tcx> MirPass<'tcx> for CheckPackedRef {
- fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
+impl<'tcx> MirLint<'tcx> for CheckPackedRef {
+ fn run_lint(&self, tcx: TyCtxt<'tcx>, body: &Body<'tcx>) {
let param_env = tcx.param_env(body.source.def_id());
let source_info = SourceInfo::outermost(body.span);
let mut checker = PackedRefChecker { body, tcx, param_env, source_info };
@@ -66,7 +66,7 @@ fn builtin_derive_def_id(tcx: TyCtxt<'_>, def_id: DefId) -> Option<DefId> {
}
}
-impl<'a, 'tcx> Visitor<'tcx> for PackedRefChecker<'a, 'tcx> {
+impl<'tcx> Visitor<'tcx> for PackedRefChecker<'_, 'tcx> {
fn visit_terminator(&mut self, terminator: &Terminator<'tcx>, location: Location) {
// Make sure we know where in the MIR we are.
self.source_info = terminator.source_info;
@@ -105,6 +105,11 @@ impl<'a, 'tcx> Visitor<'tcx> for PackedRefChecker<'a, 'tcx> {
a misaligned reference is undefined behavior (even if that \
reference is never dereferenced)",
)
+ .help(
+ "copy the field contents to a local variable, or replace the \
+ reference with a raw pointer and use `read_unaligned`/`write_unaligned` \
+ (loads and stores via `*p` must be properly aligned even when using raw pointers)"
+ )
.emit()
},
);
diff --git a/compiler/rustc_mir_transform/src/check_unsafety.rs b/compiler/rustc_mir_transform/src/check_unsafety.rs
index 1ff9bd15721..2dda19badd7 100644
--- a/compiler/rustc_mir_transform/src/check_unsafety.rs
+++ b/compiler/rustc_mir_transform/src/check_unsafety.rs
@@ -46,7 +46,7 @@ impl<'a, 'tcx> UnsafetyChecker<'a, 'tcx> {
}
}
-impl<'a, 'tcx> Visitor<'tcx> for UnsafetyChecker<'a, 'tcx> {
+impl<'tcx> Visitor<'tcx> for UnsafetyChecker<'_, 'tcx> {
fn visit_terminator(&mut self, terminator: &Terminator<'tcx>, location: Location) {
self.source_info = terminator.source_info;
match terminator.kind {
@@ -208,6 +208,7 @@ impl<'a, 'tcx> Visitor<'tcx> for UnsafetyChecker<'a, 'tcx> {
MutatingUseContext::Store
| MutatingUseContext::Drop
| MutatingUseContext::AsmOutput
+ | MutatingUseContext::LlvmAsmOutput
)
);
// If this is just an assignment, determine if the assigned type needs dropping.
@@ -243,7 +244,7 @@ impl<'a, 'tcx> Visitor<'tcx> for UnsafetyChecker<'a, 'tcx> {
}
}
-impl<'a, 'tcx> UnsafetyChecker<'a, 'tcx> {
+impl<'tcx> UnsafetyChecker<'_, 'tcx> {
fn require_unsafe(&mut self, kind: UnsafetyViolationKind, details: UnsafetyViolationDetails) {
// Violations can turn out to be `UnsafeFn` during analysis, but they should not start out as such.
assert_ne!(kind, UnsafetyViolationKind::UnsafeFn);
@@ -396,7 +397,7 @@ struct UnusedUnsafeVisitor<'a> {
unsafe_blocks: &'a mut Vec<(hir::HirId, bool)>,
}
-impl<'a, 'tcx> intravisit::Visitor<'tcx> for UnusedUnsafeVisitor<'a> {
+impl<'tcx> intravisit::Visitor<'tcx> for UnusedUnsafeVisitor<'_> {
type Map = intravisit::ErasedMap<'tcx>;
fn nested_visit_map(&mut self) -> intravisit::NestedVisitorMap<Self::Map> {
diff --git a/compiler/rustc_mir_transform/src/const_debuginfo.rs b/compiler/rustc_mir_transform/src/const_debuginfo.rs
index b613634560f..839d94167fe 100644
--- a/compiler/rustc_mir_transform/src/const_debuginfo.rs
+++ b/compiler/rustc_mir_transform/src/const_debuginfo.rs
@@ -15,11 +15,11 @@ use rustc_index::{bit_set::BitSet, vec::IndexVec};
pub struct ConstDebugInfo;
impl<'tcx> MirPass<'tcx> for ConstDebugInfo {
- fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
- if !tcx.sess.opts.debugging_opts.unsound_mir_opts {
- return;
- }
+ fn is_enabled(&self, sess: &rustc_session::Session) -> bool {
+ sess.opts.debugging_opts.unsound_mir_opts && sess.mir_opt_level() > 0
+ }
+ fn run_pass(&self, _: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
trace!("running ConstDebugInfo on {:?}", body.source);
for (local, constant) in find_optimization_oportunities(body) {
@@ -89,7 +89,7 @@ fn find_optimization_oportunities<'tcx>(body: &Body<'tcx>) -> Vec<(Local, Consta
eligable_locals
}
-impl<'tcx> Visitor<'tcx> for LocalUseVisitor {
+impl Visitor<'_> for LocalUseVisitor {
fn visit_local(&mut self, local: &Local, context: PlaceContext, location: Location) {
if context.is_mutating_use() {
self.local_mutating_uses[*local] = self.local_mutating_uses[*local].saturating_add(1);
diff --git a/compiler/rustc_mir_transform/src/const_goto.rs b/compiler/rustc_mir_transform/src/const_goto.rs
index d319fdcaa6b..905173b0457 100644
--- a/compiler/rustc_mir_transform/src/const_goto.rs
+++ b/compiler/rustc_mir_transform/src/const_goto.rs
@@ -27,10 +27,11 @@ use super::simplify::{simplify_cfg, simplify_locals};
pub struct ConstGoto;
impl<'tcx> MirPass<'tcx> for ConstGoto {
+ fn is_enabled(&self, sess: &rustc_session::Session) -> bool {
+ sess.mir_opt_level() >= 4
+ }
+
fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
- if tcx.sess.mir_opt_level() < 4 {
- return;
- }
trace!("Running ConstGoto on {:?}", body.source);
let param_env = tcx.param_env_reveal_all_normalized(body.source.def_id());
let mut opt_finder =
@@ -53,7 +54,7 @@ impl<'tcx> MirPass<'tcx> for ConstGoto {
}
}
-impl<'a, 'tcx> Visitor<'tcx> for ConstGotoOptimizationFinder<'a, 'tcx> {
+impl<'tcx> Visitor<'tcx> for ConstGotoOptimizationFinder<'_, 'tcx> {
fn visit_terminator(&mut self, terminator: &Terminator<'tcx>, location: Location) {
let _: Option<_> = try {
let target = terminator.kind.as_goto()?;
@@ -82,20 +83,7 @@ impl<'a, 'tcx> Visitor<'tcx> for ConstGotoOptimizationFinder<'a, 'tcx> {
// Now find which value in the Switch matches the const value.
let const_value =
_const.literal.try_eval_bits(self.tcx, self.param_env, switch_ty)?;
- let found_value_idx_option = targets
- .iter()
- .enumerate()
- .find(|(_, (value, _))| const_value == *value)
- .map(|(idx, _)| idx);
-
- let target_to_use_in_goto =
- if let Some(found_value_idx) = found_value_idx_option {
- targets.iter().nth(found_value_idx).unwrap().1
- } else {
- // If we did not find the const value in values, it must be the otherwise case
- targets.otherwise()
- };
-
+ let target_to_use_in_goto = targets.target_for_value(const_value);
self.optimizations.push(OptimizationToApply {
bb_with_goto: location.block,
target_to_use_in_goto,
diff --git a/compiler/rustc_mir_transform/src/const_prop.rs b/compiler/rustc_mir_transform/src/const_prop.rs
index 63c637af5c2..84bdb8eece6 100644
--- a/compiler/rustc_mir_transform/src/const_prop.rs
+++ b/compiler/rustc_mir_transform/src/const_prop.rs
@@ -62,6 +62,13 @@ macro_rules! throw_machine_stop_str {
pub struct ConstProp;
impl<'tcx> MirPass<'tcx> for ConstProp {
+ fn is_enabled(&self, _sess: &rustc_session::Session) -> bool {
+ // FIXME(#70073): Unlike the other passes in "optimizations", this one emits errors, so it
+ // runs even when MIR optimizations are disabled. We should separate the lint out from the
+ // transform and move the lint as early in the pipeline as possible.
+ true
+ }
+
fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
// will be evaluated by miri and produce its errors there
if body.source.promoted.is_some() {
@@ -164,7 +171,7 @@ struct ConstPropMachine<'mir, 'tcx> {
can_const_prop: IndexVec<Local, ConstPropMode>,
}
-impl<'mir, 'tcx> ConstPropMachine<'mir, 'tcx> {
+impl ConstPropMachine<'_, '_> {
fn new(
only_propagate_inside_block_locals: BitSet<Local>,
can_const_prop: IndexVec<Local, ConstPropMode>,
@@ -301,14 +308,14 @@ impl<'mir, 'tcx> interpret::Machine<'mir, 'tcx> for ConstPropMachine<'mir, 'tcx>
}
#[inline(always)]
- fn stack(
+ fn stack<'a>(
ecx: &'a InterpCx<'mir, 'tcx, Self>,
) -> &'a [Frame<'mir, 'tcx, Self::PointerTag, Self::FrameExtra>] {
&ecx.machine.stack
}
#[inline(always)]
- fn stack_mut(
+ fn stack_mut<'a>(
ecx: &'a mut InterpCx<'mir, 'tcx, Self>,
) -> &'a mut Vec<Frame<'mir, 'tcx, Self::PointerTag, Self::FrameExtra>> {
&mut ecx.machine.stack
@@ -329,7 +336,7 @@ struct ConstPropagator<'mir, 'tcx> {
source_info: Option<SourceInfo>,
}
-impl<'mir, 'tcx> LayoutOfHelpers<'tcx> for ConstPropagator<'mir, 'tcx> {
+impl<'tcx> LayoutOfHelpers<'tcx> for ConstPropagator<'_, 'tcx> {
type LayoutOfResult = Result<TyAndLayout<'tcx>, LayoutError<'tcx>>;
#[inline]
@@ -338,21 +345,21 @@ impl<'mir, 'tcx> LayoutOfHelpers<'tcx> for ConstPropagator<'mir, 'tcx> {
}
}
-impl<'mir, 'tcx> HasDataLayout for ConstPropagator<'mir, 'tcx> {
+impl HasDataLayout for ConstPropagator<'_, '_> {
#[inline]
fn data_layout(&self) -> &TargetDataLayout {
&self.tcx.data_layout
}
}
-impl<'mir, 'tcx> ty::layout::HasTyCtxt<'tcx> for ConstPropagator<'mir, 'tcx> {
+impl<'tcx> ty::layout::HasTyCtxt<'tcx> for ConstPropagator<'_, 'tcx> {
#[inline]
fn tcx(&self) -> TyCtxt<'tcx> {
self.tcx
}
}
-impl<'mir, 'tcx> ty::layout::HasParamEnv<'tcx> for ConstPropagator<'mir, 'tcx> {
+impl<'tcx> ty::layout::HasParamEnv<'tcx> for ConstPropagator<'_, 'tcx> {
#[inline]
fn param_env(&self) -> ty::ParamEnv<'tcx> {
self.param_env
@@ -745,62 +752,44 @@ impl<'mir, 'tcx> ConstPropagator<'mir, 'tcx> {
rvalue: &Rvalue<'tcx>,
place: Place<'tcx>,
) -> Option<()> {
- self.use_ecx(|this| {
- match rvalue {
- Rvalue::BinaryOp(op, box (left, right))
- | Rvalue::CheckedBinaryOp(op, box (left, right)) => {
- let l = this.ecx.eval_operand(left, None);
- let r = this.ecx.eval_operand(right, None);
-
- let const_arg = match (l, r) {
- (Ok(ref x), Err(_)) | (Err(_), Ok(ref x)) => this.ecx.read_immediate(x)?,
- (Err(e), Err(_)) => return Err(e),
- (Ok(_), Ok(_)) => {
- this.ecx.eval_rvalue_into_place(rvalue, place)?;
- return Ok(());
- }
- };
-
- let arg_value = const_arg.to_scalar()?.to_bits(const_arg.layout.size)?;
- let dest = this.ecx.eval_place(place)?;
-
- match op {
- BinOp::BitAnd => {
- if arg_value == 0 {
- this.ecx.write_immediate(*const_arg, &dest)?;
- }
- }
- BinOp::BitOr => {
- if arg_value == const_arg.layout.size.truncate(u128::MAX)
- || (const_arg.layout.ty.is_bool() && arg_value == 1)
- {
- this.ecx.write_immediate(*const_arg, &dest)?;
- }
- }
- BinOp::Mul => {
- if const_arg.layout.ty.is_integral() && arg_value == 0 {
- if let Rvalue::CheckedBinaryOp(_, _) = rvalue {
- let val = Immediate::ScalarPair(
- const_arg.to_scalar()?.into(),
- Scalar::from_bool(false).into(),
- );
- this.ecx.write_immediate(val, &dest)?;
- } else {
- this.ecx.write_immediate(*const_arg, &dest)?;
- }
- }
- }
- _ => {
- this.ecx.eval_rvalue_into_place(rvalue, place)?;
+ self.use_ecx(|this| match rvalue {
+ Rvalue::BinaryOp(op, box (left, right))
+ | Rvalue::CheckedBinaryOp(op, box (left, right)) => {
+ let l = this.ecx.eval_operand(left, None);
+ let r = this.ecx.eval_operand(right, None);
+
+ let const_arg = match (l, r) {
+ (Ok(ref x), Err(_)) | (Err(_), Ok(ref x)) => this.ecx.read_immediate(x)?,
+ (Err(e), Err(_)) => return Err(e),
+ (Ok(_), Ok(_)) => return this.ecx.eval_rvalue_into_place(rvalue, place),
+ };
+
+ let arg_value = const_arg.to_scalar()?.to_bits(const_arg.layout.size)?;
+ let dest = this.ecx.eval_place(place)?;
+
+ match op {
+ BinOp::BitAnd if arg_value == 0 => this.ecx.write_immediate(*const_arg, &dest),
+ BinOp::BitOr
+ if arg_value == const_arg.layout.size.truncate(u128::MAX)
+ || (const_arg.layout.ty.is_bool() && arg_value == 1) =>
+ {
+ this.ecx.write_immediate(*const_arg, &dest)
+ }
+ BinOp::Mul if const_arg.layout.ty.is_integral() && arg_value == 0 => {
+ if let Rvalue::CheckedBinaryOp(_, _) = rvalue {
+ let val = Immediate::ScalarPair(
+ const_arg.to_scalar()?.into(),
+ Scalar::from_bool(false).into(),
+ );
+ this.ecx.write_immediate(val, &dest)
+ } else {
+ this.ecx.write_immediate(*const_arg, &dest)
}
}
- }
- _ => {
- this.ecx.eval_rvalue_into_place(rvalue, place)?;
+ _ => this.ecx.eval_rvalue_into_place(rvalue, place),
}
}
-
- Ok(())
+ _ => this.ecx.eval_rvalue_into_place(rvalue, place),
})
}
@@ -964,7 +953,7 @@ struct CanConstProp {
impl CanConstProp {
/// Returns true if `local` can be propagated
- fn check(
+ fn check<'tcx>(
tcx: TyCtxt<'tcx>,
param_env: ParamEnv<'tcx>,
body: &Body<'tcx>,
@@ -1012,7 +1001,7 @@ impl CanConstProp {
}
}
-impl<'tcx> Visitor<'tcx> for CanConstProp {
+impl Visitor<'_> for CanConstProp {
fn visit_local(&mut self, &local: &Local, context: PlaceContext, _: Location) {
use rustc_middle::mir::visit::PlaceContext::*;
match context {
@@ -1022,6 +1011,7 @@ impl<'tcx> Visitor<'tcx> for CanConstProp {
// These are just stores, where the storing is not propagatable, but there may be later
// mutations of the same local via `Store`
| MutatingUse(MutatingUseContext::Call)
+ | MutatingUse(MutatingUseContext::AsmOutput)
// Actual store that can possibly even propagate a value
| MutatingUse(MutatingUseContext::Store) => {
if !self.found_assignment.insert(local) {
@@ -1052,7 +1042,7 @@ impl<'tcx> Visitor<'tcx> for CanConstProp {
// These could be propagated with a smarter analysis or just some careful thinking about
// whether they'd be fine right now.
- MutatingUse(MutatingUseContext::AsmOutput)
+ MutatingUse(MutatingUseContext::LlvmAsmOutput)
| MutatingUse(MutatingUseContext::Yield)
| MutatingUse(MutatingUseContext::Drop)
| MutatingUse(MutatingUseContext::Retag)
@@ -1071,7 +1061,7 @@ impl<'tcx> Visitor<'tcx> for CanConstProp {
}
}
-impl<'mir, 'tcx> MutVisitor<'tcx> for ConstPropagator<'mir, 'tcx> {
+impl<'tcx> MutVisitor<'tcx> for ConstPropagator<'_, 'tcx> {
fn tcx(&self) -> TyCtxt<'tcx> {
self.tcx
}
diff --git a/compiler/rustc_mir_transform/src/coverage/debug.rs b/compiler/rustc_mir_transform/src/coverage/debug.rs
index 513a85b5913..c61ee6f7e6c 100644
--- a/compiler/rustc_mir_transform/src/coverage/debug.rs
+++ b/compiler/rustc_mir_transform/src/coverage/debug.rs
@@ -148,7 +148,7 @@ impl DebugOptions {
let mut counter_format = ExpressionFormat::default();
if let Ok(env_debug_options) = std::env::var(RUSTC_COVERAGE_DEBUG_OPTIONS) {
- for setting_str in env_debug_options.replace(" ", "").replace("-", "_").split(',') {
+ for setting_str in env_debug_options.replace(' ', "").replace('-', "_").split(',') {
let (option, value) = match setting_str.split_once('=') {
None => (setting_str, None),
Some((k, v)) => (k, Some(v)),
@@ -629,7 +629,7 @@ impl UsedExpressions {
}
/// Generates the MIR pass `CoverageSpan`-specific spanview dump file.
-pub(super) fn dump_coverage_spanview(
+pub(super) fn dump_coverage_spanview<'tcx>(
tcx: TyCtxt<'tcx>,
mir_body: &mir::Body<'tcx>,
basic_coverage_blocks: &CoverageGraph,
@@ -651,7 +651,7 @@ pub(super) fn dump_coverage_spanview(
}
/// Converts the computed `BasicCoverageBlockData`s into `SpanViewable`s.
-fn span_viewables(
+fn span_viewables<'tcx>(
tcx: TyCtxt<'tcx>,
mir_body: &mir::Body<'tcx>,
basic_coverage_blocks: &CoverageGraph,
@@ -670,7 +670,7 @@ fn span_viewables(
}
/// Generates the MIR pass coverage-specific graphviz dump file.
-pub(super) fn dump_coverage_graphviz(
+pub(super) fn dump_coverage_graphviz<'tcx>(
tcx: TyCtxt<'tcx>,
mir_body: &mir::Body<'tcx>,
pass_name: &str,
@@ -750,7 +750,7 @@ pub(super) fn dump_coverage_graphviz(
.expect("Unexpected error writing BasicCoverageBlock graphviz DOT file");
}
-fn bcb_to_string_sections(
+fn bcb_to_string_sections<'tcx>(
tcx: TyCtxt<'tcx>,
mir_body: &mir::Body<'tcx>,
debug_counters: &DebugCounters,
@@ -817,7 +817,7 @@ fn bcb_to_string_sections(
/// Returns a simple string representation of a `TerminatorKind` variant, independent of any
/// values it might hold.
-pub(super) fn term_type(kind: &TerminatorKind<'tcx>) -> &'static str {
+pub(super) fn term_type(kind: &TerminatorKind<'_>) -> &'static str {
match kind {
TerminatorKind::Goto { .. } => "Goto",
TerminatorKind::SwitchInt { .. } => "SwitchInt",
diff --git a/compiler/rustc_mir_transform/src/coverage/graph.rs b/compiler/rustc_mir_transform/src/coverage/graph.rs
index d78ad6ce97f..a25402a1ff9 100644
--- a/compiler/rustc_mir_transform/src/coverage/graph.rs
+++ b/compiler/rustc_mir_transform/src/coverage/graph.rs
@@ -27,7 +27,7 @@ pub(super) struct CoverageGraph {
}
impl CoverageGraph {
- pub fn from_mir(mir_body: &mir::Body<'tcx>) -> Self {
+ pub fn from_mir(mir_body: &mir::Body<'_>) -> Self {
let (bcbs, bb_to_bcb) = Self::compute_basic_coverage_blocks(mir_body);
// Pre-transform MIR `BasicBlock` successors and predecessors into the BasicCoverageBlock
@@ -74,7 +74,7 @@ impl CoverageGraph {
}
fn compute_basic_coverage_blocks(
- mir_body: &mir::Body<'tcx>,
+ mir_body: &mir::Body<'_>,
) -> (
IndexVec<BasicCoverageBlock, BasicCoverageBlockData>,
IndexVec<BasicBlock, Option<BasicCoverageBlock>>,
@@ -267,7 +267,7 @@ impl graph::WithSuccessors for CoverageGraph {
}
}
-impl graph::GraphPredecessors<'graph> for CoverageGraph {
+impl<'graph> graph::GraphPredecessors<'graph> for CoverageGraph {
type Item = BasicCoverageBlock;
type Iter = std::iter::Copied<std::slice::Iter<'graph, BasicCoverageBlock>>;
}
diff --git a/compiler/rustc_mir_transform/src/coverage/mod.rs b/compiler/rustc_mir_transform/src/coverage/mod.rs
index 6807d02519e..b009e2fd0e4 100644
--- a/compiler/rustc_mir_transform/src/coverage/mod.rs
+++ b/compiler/rustc_mir_transform/src/coverage/mod.rs
@@ -49,6 +49,10 @@ impl Error {
pub struct InstrumentCoverage;
impl<'tcx> MirPass<'tcx> for InstrumentCoverage {
+ fn is_enabled(&self, sess: &rustc_session::Session) -> bool {
+ sess.instrument_coverage()
+ }
+
fn run_pass(&self, tcx: TyCtxt<'tcx>, mir_body: &mut mir::Body<'tcx>) {
let mir_source = mir_body.source;
@@ -439,7 +443,7 @@ impl<'a, 'tcx> Instrumentor<'a, 'tcx> {
}
fn inject_edge_counter_basic_block(
- mir_body: &mut mir::Body<'tcx>,
+ mir_body: &mut mir::Body<'_>,
from_bb: BasicBlock,
to_bb: BasicBlock,
) -> BasicBlock {
@@ -462,7 +466,7 @@ fn inject_edge_counter_basic_block(
}
fn inject_statement(
- mir_body: &mut mir::Body<'tcx>,
+ mir_body: &mut mir::Body<'_>,
counter_kind: CoverageKind,
bb: BasicBlock,
some_code_region: Option<CodeRegion>,
@@ -484,7 +488,7 @@ fn inject_statement(
}
// Non-code expressions are injected into the coverage map, without generating executable code.
-fn inject_intermediate_expression(mir_body: &mut mir::Body<'tcx>, expression: CoverageKind) {
+fn inject_intermediate_expression(mir_body: &mut mir::Body<'_>, expression: CoverageKind) {
debug_assert!(matches!(expression, CoverageKind::Expression { .. }));
debug!(" injecting non-code expression {:?}", expression);
let inject_in_bb = mir::START_BLOCK;
diff --git a/compiler/rustc_mir_transform/src/coverage/query.rs b/compiler/rustc_mir_transform/src/coverage/query.rs
index 760f16eae6b..1721fb5cde0 100644
--- a/compiler/rustc_mir_transform/src/coverage/query.rs
+++ b/compiler/rustc_mir_transform/src/coverage/query.rs
@@ -137,7 +137,7 @@ fn coverageinfo<'tcx>(tcx: TyCtxt<'tcx>, instance_def: ty::InstanceDef<'tcx>) ->
coverage_visitor.info
}
-fn covered_file_name<'tcx>(tcx: TyCtxt<'tcx>, def_id: DefId) -> Option<Symbol> {
+fn covered_file_name(tcx: TyCtxt<'_>, def_id: DefId) -> Option<Symbol> {
if tcx.is_mir_available(def_id) {
let body = mir_body(tcx, def_id);
for bb_data in body.basic_blocks().iter() {
diff --git a/compiler/rustc_mir_transform/src/coverage/spans.rs b/compiler/rustc_mir_transform/src/coverage/spans.rs
index d13fa0729cd..b5356a817f7 100644
--- a/compiler/rustc_mir_transform/src/coverage/spans.rs
+++ b/compiler/rustc_mir_transform/src/coverage/spans.rs
@@ -21,7 +21,7 @@ pub(super) enum CoverageStatement {
}
impl CoverageStatement {
- pub fn format(&self, tcx: TyCtxt<'tcx>, mir_body: &'a mir::Body<'tcx>) -> String {
+ pub fn format<'tcx>(&self, tcx: TyCtxt<'tcx>, mir_body: &mir::Body<'tcx>) -> String {
match *self {
Self::Statement(bb, span, stmt_index) => {
let stmt = &mir_body[bb].statements[stmt_index];
@@ -86,7 +86,7 @@ impl CoverageSpan {
}
pub fn for_statement(
- statement: &Statement<'tcx>,
+ statement: &Statement<'_>,
span: Span,
expn_span: Span,
bcb: BasicCoverageBlock,
@@ -151,18 +151,18 @@ impl CoverageSpan {
self.bcb == other.bcb
}
- pub fn format(&self, tcx: TyCtxt<'tcx>, mir_body: &'a mir::Body<'tcx>) -> String {
+ pub fn format<'tcx>(&self, tcx: TyCtxt<'tcx>, mir_body: &mir::Body<'tcx>) -> String {
format!(
"{}\n {}",
source_range_no_file(tcx, &self.span),
- self.format_coverage_statements(tcx, mir_body).replace("\n", "\n "),
+ self.format_coverage_statements(tcx, mir_body).replace('\n', "\n "),
)
}
- pub fn format_coverage_statements(
+ pub fn format_coverage_statements<'tcx>(
&self,
tcx: TyCtxt<'tcx>,
- mir_body: &'a mir::Body<'tcx>,
+ mir_body: &mir::Body<'tcx>,
) -> String {
let mut sorted_coverage_statements = self.coverage_statements.clone();
sorted_coverage_statements.sort_unstable_by_key(|covstmt| match *covstmt {
@@ -329,9 +329,7 @@ impl<'a, 'tcx> CoverageSpans<'a, 'tcx> {
fn mir_to_initial_sorted_coverage_spans(&self) -> Vec<CoverageSpan> {
let mut initial_spans = Vec::<CoverageSpan>::with_capacity(self.mir_body.num_nodes() * 2);
for (bcb, bcb_data) in self.basic_coverage_blocks.iter_enumerated() {
- for coverage_span in self.bcb_to_initial_coverage_spans(bcb, bcb_data) {
- initial_spans.push(coverage_span);
- }
+ initial_spans.extend(self.bcb_to_initial_coverage_spans(bcb, bcb_data));
}
if initial_spans.is_empty() {
@@ -803,7 +801,7 @@ impl<'a, 'tcx> CoverageSpans<'a, 'tcx> {
/// If the MIR `Statement` has a span contributive to computing coverage spans,
/// return it; otherwise return `None`.
-pub(super) fn filtered_statement_span(statement: &'a Statement<'tcx>) -> Option<Span> {
+pub(super) fn filtered_statement_span(statement: &Statement<'_>) -> Option<Span> {
match statement.kind {
// These statements have spans that are often outside the scope of the executed source code
// for their parent `BasicBlock`.
@@ -847,7 +845,7 @@ pub(super) fn filtered_statement_span(statement: &'a Statement<'tcx>) -> Option<
/// If the MIR `Terminator` has a span contributive to computing coverage spans,
/// return it; otherwise return `None`.
-pub(super) fn filtered_terminator_span(terminator: &'a Terminator<'tcx>) -> Option<Span> {
+pub(super) fn filtered_terminator_span(terminator: &Terminator<'_>) -> Option<Span> {
match terminator.kind {
// These terminators have spans that don't positively contribute to computing a reasonable
// span of actually executed source code. (For example, SwitchInt terminators extracted from
diff --git a/compiler/rustc_mir_transform/src/coverage/tests.rs b/compiler/rustc_mir_transform/src/coverage/tests.rs
index 14dd0a8b924..b9c79d4cf2d 100644
--- a/compiler/rustc_mir_transform/src/coverage/tests.rs
+++ b/compiler/rustc_mir_transform/src/coverage/tests.rs
@@ -180,7 +180,7 @@ impl<'tcx> MockBlocks<'tcx> {
}
}
-fn debug_basic_blocks(mir_body: &Body<'tcx>) -> String {
+fn debug_basic_blocks<'tcx>(mir_body: &Body<'tcx>) -> String {
format!(
"{:?}",
mir_body
@@ -273,7 +273,7 @@ fn print_coverage_graphviz(
}
/// Create a mock `Body` with a simple flow.
-fn goto_switchint() -> Body<'a> {
+fn goto_switchint<'a>() -> Body<'a> {
let mut blocks = MockBlocks::new();
let start = blocks.call(None);
let goto = blocks.goto(Some(start));
@@ -363,7 +363,7 @@ fn test_covgraph_goto_switchint() {
}
/// Create a mock `Body` with a loop.
-fn switchint_then_loop_else_return() -> Body<'a> {
+fn switchint_then_loop_else_return<'a>() -> Body<'a> {
let mut blocks = MockBlocks::new();
let start = blocks.call(None);
let switchint = blocks.switchint(Some(start));
@@ -449,7 +449,7 @@ fn test_covgraph_switchint_then_loop_else_return() {
}
/// Create a mock `Body` with nested loops.
-fn switchint_loop_then_inner_loop_else_break() -> Body<'a> {
+fn switchint_loop_then_inner_loop_else_break<'a>() -> Body<'a> {
let mut blocks = MockBlocks::new();
let start = blocks.call(None);
let switchint = blocks.switchint(Some(start));
diff --git a/compiler/rustc_mir_transform/src/deduplicate_blocks.rs b/compiler/rustc_mir_transform/src/deduplicate_blocks.rs
index 8d2413433a9..d1977ed49fe 100644
--- a/compiler/rustc_mir_transform/src/deduplicate_blocks.rs
+++ b/compiler/rustc_mir_transform/src/deduplicate_blocks.rs
@@ -15,10 +15,11 @@ use super::simplify::simplify_cfg;
pub struct DeduplicateBlocks;
impl<'tcx> MirPass<'tcx> for DeduplicateBlocks {
+ fn is_enabled(&self, sess: &rustc_session::Session) -> bool {
+ sess.mir_opt_level() >= 4
+ }
+
fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
- if tcx.sess.mir_opt_level() < 4 {
- return;
- }
debug!("Running DeduplicateBlocks on `{:?}`", body.source);
let duplicates = find_duplicates(body);
let has_opts_to_apply = !duplicates.is_empty();
@@ -53,7 +54,7 @@ impl<'tcx> MutVisitor<'tcx> for OptApplier<'tcx> {
}
}
-fn find_duplicates<'a, 'tcx>(body: &'a Body<'tcx>) -> FxHashMap<BasicBlock, BasicBlock> {
+fn find_duplicates(body: &Body<'_>) -> FxHashMap<BasicBlock, BasicBlock> {
let mut duplicates = FxHashMap::default();
let bbs_to_go_through =
@@ -101,7 +102,7 @@ struct BasicBlockHashable<'tcx, 'a> {
basic_block_data: &'a BasicBlockData<'tcx>,
}
-impl<'tcx, 'a> Hash for BasicBlockHashable<'tcx, 'a> {
+impl Hash for BasicBlockHashable<'_, '_> {
fn hash<H: Hasher>(&self, state: &mut H) {
hash_statements(state, self.basic_block_data.statements.iter());
// Note that since we only hash the kind, we lose span information if we deduplicate the blocks
@@ -109,9 +110,9 @@ impl<'tcx, 'a> Hash for BasicBlockHashable<'tcx, 'a> {
}
}
-impl<'tcx, 'a> Eq for BasicBlockHashable<'tcx, 'a> {}
+impl Eq for BasicBlockHashable<'_, '_> {}
-impl<'tcx, 'a> PartialEq for BasicBlockHashable<'tcx, 'a> {
+impl PartialEq for BasicBlockHashable<'_, '_> {
fn eq(&self, other: &Self) -> bool {
self.basic_block_data.statements.len() == other.basic_block_data.statements.len()
&& &self.basic_block_data.terminator().kind == &other.basic_block_data.terminator().kind
@@ -131,7 +132,7 @@ fn hash_statements<'a, 'tcx, H: Hasher>(
}
}
-fn statement_hash<'tcx, H: Hasher>(hasher: &mut H, stmt: &StatementKind<'tcx>) {
+fn statement_hash<H: Hasher>(hasher: &mut H, stmt: &StatementKind<'_>) {
match stmt {
StatementKind::Assign(box (place, rvalue)) => {
place.hash(hasher);
@@ -141,14 +142,14 @@ fn statement_hash<'tcx, H: Hasher>(hasher: &mut H, stmt: &StatementKind<'tcx>) {
};
}
-fn rvalue_hash<H: Hasher>(hasher: &mut H, rvalue: &Rvalue<'tcx>) {
+fn rvalue_hash<H: Hasher>(hasher: &mut H, rvalue: &Rvalue<'_>) {
match rvalue {
Rvalue::Use(op) => operand_hash(hasher, op),
x => x.hash(hasher),
};
}
-fn operand_hash<H: Hasher>(hasher: &mut H, operand: &Operand<'tcx>) {
+fn operand_hash<H: Hasher>(hasher: &mut H, operand: &Operand<'_>) {
match operand {
Operand::Constant(box Constant { user_ty: _, literal, span: _ }) => literal.hash(hasher),
x => x.hash(hasher),
@@ -167,7 +168,7 @@ fn statement_eq<'tcx>(lhs: &StatementKind<'tcx>, rhs: &StatementKind<'tcx>) -> b
res
}
-fn rvalue_eq(lhs: &Rvalue<'tcx>, rhs: &Rvalue<'tcx>) -> bool {
+fn rvalue_eq<'tcx>(lhs: &Rvalue<'tcx>, rhs: &Rvalue<'tcx>) -> bool {
let res = match (lhs, rhs) {
(Rvalue::Use(op1), Rvalue::Use(op2)) => operand_eq(op1, op2),
(x, y) => x == y,
@@ -176,7 +177,7 @@ fn rvalue_eq(lhs: &Rvalue<'tcx>, rhs: &Rvalue<'tcx>) -> bool {
res
}
-fn operand_eq(lhs: &Operand<'tcx>, rhs: &Operand<'tcx>) -> bool {
+fn operand_eq<'tcx>(lhs: &Operand<'tcx>, rhs: &Operand<'tcx>) -> bool {
let res = match (lhs, rhs) {
(
Operand::Constant(box Constant { user_ty: _, literal, span: _ }),
diff --git a/compiler/rustc_mir_transform/src/dest_prop.rs b/compiler/rustc_mir_transform/src/dest_prop.rs
index 790d9243fba..2b382468be0 100644
--- a/compiler/rustc_mir_transform/src/dest_prop.rs
+++ b/compiler/rustc_mir_transform/src/dest_prop.rs
@@ -124,18 +124,15 @@ const MAX_BLOCKS: usize = 250;
pub struct DestinationPropagation;
impl<'tcx> MirPass<'tcx> for DestinationPropagation {
- fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
- // FIXME(#79191, #82678)
- if !tcx.sess.opts.debugging_opts.unsound_mir_opts {
- return;
- }
-
+ fn is_enabled(&self, sess: &rustc_session::Session) -> bool {
+ // FIXME(#79191, #82678): This is unsound.
+ //
// Only run at mir-opt-level=3 or higher for now (we don't fix up debuginfo and remove
// storage statements at the moment).
- if tcx.sess.mir_opt_level() < 3 {
- return;
- }
+ sess.opts.debugging_opts.unsound_mir_opts && sess.mir_opt_level() >= 3
+ }
+ fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
let def_id = body.source.def_id();
let candidates = find_candidates(tcx, body);
@@ -244,7 +241,7 @@ struct Replacements<'tcx> {
kill: BitSet<Local>,
}
-impl Replacements<'tcx> {
+impl<'tcx> Replacements<'tcx> {
fn new(locals: usize) -> Self {
Self { map: IndexVec::from_elem_n(None, locals), kill: BitSet::new_empty(locals) }
}
@@ -301,7 +298,7 @@ struct Replacer<'tcx> {
}
impl<'tcx> MutVisitor<'tcx> for Replacer<'tcx> {
- fn tcx<'a>(&'a self) -> TyCtxt<'tcx> {
+ fn tcx(&self) -> TyCtxt<'tcx> {
self.tcx
}
@@ -316,28 +313,6 @@ impl<'tcx> MutVisitor<'tcx> for Replacer<'tcx> {
}
}
- fn process_projection_elem(
- &mut self,
- elem: PlaceElem<'tcx>,
- _: Location,
- ) -> Option<PlaceElem<'tcx>> {
- match elem {
- PlaceElem::Index(local) => {
- if let Some(replacement) = self.replacements.for_src(local) {
- bug!(
- "cannot replace {:?} with {:?} in index projection {:?}",
- local,
- replacement,
- elem,
- );
- } else {
- None
- }
- }
- _ => None,
- }
- }
-
fn visit_place(&mut self, place: &mut Place<'tcx>, context: PlaceContext, location: Location) {
if let Some(replacement) = self.replacements.for_src(place.local) {
// Rebase `place`s projections onto `replacement`'s.
@@ -397,7 +372,7 @@ struct Conflicts<'a> {
unified_locals: InPlaceUnificationTable<UnifyLocal>,
}
-impl Conflicts<'a> {
+impl<'a> Conflicts<'a> {
fn build<'tcx>(
tcx: TyCtxt<'tcx>,
body: &'_ Body<'tcx>,
@@ -646,6 +621,7 @@ impl Conflicts<'a> {
options: _,
line_spans: _,
destination: _,
+ cleanup: _,
} => {
// The intended semantics here aren't documented, we just assume that nothing that
// could be written to by the assembly may overlap with any other operands.
@@ -844,10 +820,7 @@ struct CandidateAssignment<'tcx> {
/// comment) and also throw out assignments that involve a local that has its address taken or is
/// otherwise ineligible (eg. locals used as array indices are ignored because we cannot propagate
/// arbitrary places into array indices).
-fn find_candidates<'a, 'tcx>(
- tcx: TyCtxt<'tcx>,
- body: &'a Body<'tcx>,
-) -> Vec<CandidateAssignment<'tcx>> {
+fn find_candidates<'tcx>(tcx: TyCtxt<'tcx>, body: &Body<'tcx>) -> Vec<CandidateAssignment<'tcx>> {
let mut visitor = FindAssignments {
tcx,
body,
@@ -867,7 +840,7 @@ struct FindAssignments<'a, 'tcx> {
locals_used_as_array_index: BitSet<Local>,
}
-impl<'a, 'tcx> Visitor<'tcx> for FindAssignments<'a, 'tcx> {
+impl<'tcx> Visitor<'tcx> for FindAssignments<'_, 'tcx> {
fn visit_statement(&mut self, statement: &Statement<'tcx>, location: Location) {
if let StatementKind::Assign(box (
dest,
diff --git a/compiler/rustc_mir_transform/src/early_otherwise_branch.rs b/compiler/rustc_mir_transform/src/early_otherwise_branch.rs
index f191911a6c7..ac88060f0d3 100644
--- a/compiler/rustc_mir_transform/src/early_otherwise_branch.rs
+++ b/compiler/rustc_mir_transform/src/early_otherwise_branch.rs
@@ -25,16 +25,14 @@ use super::simplify::simplify_cfg;
pub struct EarlyOtherwiseBranch;
impl<'tcx> MirPass<'tcx> for EarlyOtherwiseBranch {
- fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
+ fn is_enabled(&self, sess: &rustc_session::Session) -> bool {
// FIXME(#78496)
- if !tcx.sess.opts.debugging_opts.unsound_mir_opts {
- return;
- }
+ sess.opts.debugging_opts.unsound_mir_opts && sess.mir_opt_level() >= 3
+ }
- if tcx.sess.mir_opt_level() < 3 {
- return;
- }
+ fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
trace!("running EarlyOtherwiseBranch on {:?}", body.source);
+
// we are only interested in this bb if the terminator is a switchInt
let bbs_with_switch =
body.basic_blocks().iter_enumerated().filter(|(_, bb)| is_switch(bb.terminator()));
@@ -169,7 +167,7 @@ impl<'tcx> MirPass<'tcx> for EarlyOtherwiseBranch {
}
}
-fn is_switch<'tcx>(terminator: &Terminator<'tcx>) -> bool {
+fn is_switch(terminator: &Terminator<'_>) -> bool {
matches!(terminator.kind, TerminatorKind::SwitchInt { .. })
}
@@ -210,7 +208,7 @@ struct OptimizationInfo<'tcx> {
second_switch_info: SwitchDiscriminantInfo<'tcx>,
}
-impl<'a, 'tcx> Helper<'a, 'tcx> {
+impl<'tcx> Helper<'_, 'tcx> {
pub fn go(
&self,
bb: &BasicBlockData<'tcx>,
diff --git a/compiler/rustc_mir_transform/src/elaborate_drops.rs b/compiler/rustc_mir_transform/src/elaborate_drops.rs
index b9a48197a35..d346dfb1772 100644
--- a/compiler/rustc_mir_transform/src/elaborate_drops.rs
+++ b/compiler/rustc_mir_transform/src/elaborate_drops.rs
@@ -19,6 +19,10 @@ use std::fmt;
pub struct ElaborateDrops;
impl<'tcx> MirPass<'tcx> for ElaborateDrops {
+ fn phase_change(&self) -> Option<MirPhase> {
+ Some(MirPhase::DropLowering)
+ }
+
fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
debug!("elaborate_drops({:?} @ {:?})", body.source, body.span);
@@ -145,13 +149,13 @@ struct Elaborator<'a, 'b, 'tcx> {
ctxt: &'a mut ElaborateDropsCtxt<'b, 'tcx>,
}
-impl<'a, 'b, 'tcx> fmt::Debug for Elaborator<'a, 'b, 'tcx> {
+impl fmt::Debug for Elaborator<'_, '_, '_> {
fn fmt(&self, _f: &mut fmt::Formatter<'_>) -> fmt::Result {
Ok(())
}
}
-impl<'a, 'b, 'tcx> DropElaborator<'a, 'tcx> for Elaborator<'a, 'b, 'tcx> {
+impl<'a, 'tcx> DropElaborator<'a, 'tcx> for Elaborator<'a, '_, 'tcx> {
type Path = MovePathIndex;
fn patch(&mut self) -> &mut MirPatch<'tcx> {
diff --git a/compiler/rustc_mir_transform/src/function_item_references.rs b/compiler/rustc_mir_transform/src/function_item_references.rs
index 996c158c062..05834b443d0 100644
--- a/compiler/rustc_mir_transform/src/function_item_references.rs
+++ b/compiler/rustc_mir_transform/src/function_item_references.rs
@@ -11,12 +11,12 @@ use rustc_session::lint::builtin::FUNCTION_ITEM_REFERENCES;
use rustc_span::{symbol::sym, Span};
use rustc_target::spec::abi::Abi;
-use crate::MirPass;
+use crate::MirLint;
pub struct FunctionItemReferences;
-impl<'tcx> MirPass<'tcx> for FunctionItemReferences {
- fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
+impl<'tcx> MirLint<'tcx> for FunctionItemReferences {
+ fn run_lint(&self, tcx: TyCtxt<'tcx>, body: &Body<'tcx>) {
let mut checker = FunctionItemRefChecker { tcx, body };
checker.visit_body(&body);
}
@@ -27,7 +27,7 @@ struct FunctionItemRefChecker<'a, 'tcx> {
body: &'a Body<'tcx>,
}
-impl<'a, 'tcx> Visitor<'tcx> for FunctionItemRefChecker<'a, 'tcx> {
+impl<'tcx> Visitor<'tcx> for FunctionItemRefChecker<'_, 'tcx> {
/// Emits a lint for function reference arguments bound by `fmt::Pointer` or passed to
/// `transmute`. This only handles arguments in calls outside macro expansions to avoid double
/// counting function references formatted as pointers by macros.
@@ -92,7 +92,7 @@ impl<'a, 'tcx> Visitor<'tcx> for FunctionItemRefChecker<'a, 'tcx> {
}
}
-impl<'a, 'tcx> FunctionItemRefChecker<'a, 'tcx> {
+impl<'tcx> FunctionItemRefChecker<'_, 'tcx> {
/// Emits a lint for function reference arguments bound by `fmt::Pointer` in calls to the
/// function defined by `def_id` with the substitutions `substs_ref`.
fn check_bound_args(
diff --git a/compiler/rustc_mir_transform/src/generator.rs b/compiler/rustc_mir_transform/src/generator.rs
index bc72e9d94a9..6220cee8d21 100644
--- a/compiler/rustc_mir_transform/src/generator.rs
+++ b/compiler/rustc_mir_transform/src/generator.rs
@@ -233,7 +233,7 @@ struct TransformVisitor<'tcx> {
new_ret_local: Local,
}
-impl TransformVisitor<'tcx> {
+impl<'tcx> TransformVisitor<'tcx> {
// Make a GeneratorState variant assignment. `core::ops::GeneratorState` only has single
// element tuple variants, so we can just write to the downcasted first field and then set the
// discriminant to the appropriate variant.
@@ -295,7 +295,7 @@ impl TransformVisitor<'tcx> {
}
}
-impl MutVisitor<'tcx> for TransformVisitor<'tcx> {
+impl<'tcx> MutVisitor<'tcx> for TransformVisitor<'tcx> {
fn tcx(&self) -> TyCtxt<'tcx> {
self.tcx
}
@@ -446,7 +446,7 @@ struct LivenessInfo {
storage_liveness: IndexVec<BasicBlock, Option<BitSet<Local>>>,
}
-fn locals_live_across_suspend_points(
+fn locals_live_across_suspend_points<'tcx>(
tcx: TyCtxt<'tcx>,
body: &Body<'tcx>,
always_live_locals: &storage::AlwaysLiveLocals,
@@ -613,7 +613,7 @@ impl ops::Deref for GeneratorSavedLocals {
/// time. Generates a bitset for every local of all the other locals that may be
/// StorageLive simultaneously with that local. This is used in the layout
/// computation; see `GeneratorLayout` for more.
-fn compute_storage_conflicts(
+fn compute_storage_conflicts<'mir, 'tcx>(
body: &'mir Body<'tcx>,
saved_locals: &GeneratorSavedLocals,
always_live_locals: storage::AlwaysLiveLocals,
@@ -672,7 +672,9 @@ struct StorageConflictVisitor<'mir, 'tcx, 's> {
local_conflicts: BitMatrix<Local, Local>,
}
-impl rustc_mir_dataflow::ResultsVisitor<'mir, 'tcx> for StorageConflictVisitor<'mir, 'tcx, '_> {
+impl<'mir, 'tcx> rustc_mir_dataflow::ResultsVisitor<'mir, 'tcx>
+ for StorageConflictVisitor<'mir, 'tcx, '_>
+{
type FlowState = BitSet<Local>;
fn visit_statement_before_primary_effect(
@@ -694,7 +696,7 @@ impl rustc_mir_dataflow::ResultsVisitor<'mir, 'tcx> for StorageConflictVisitor<'
}
}
-impl<'body, 'tcx, 's> StorageConflictVisitor<'body, 'tcx, 's> {
+impl StorageConflictVisitor<'_, '_, '_> {
fn apply_state(&mut self, flow_state: &BitSet<Local>, loc: Location) {
// Ignore unreachable blocks.
if self.body.basic_blocks()[loc.block].terminator().kind == TerminatorKind::Unreachable {
@@ -1232,6 +1234,10 @@ fn create_cases<'tcx>(
}
impl<'tcx> MirPass<'tcx> for StateTransform {
+ fn phase_change(&self) -> Option<MirPhase> {
+ Some(MirPhase::GeneratorLowering)
+ }
+
fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
let yield_ty = if let Some(yield_ty) = body.yield_ty() {
yield_ty
@@ -1394,7 +1400,7 @@ impl EnsureGeneratorFieldAssignmentsNeverAlias<'_> {
self.saved_locals.get(place.local)
}
- fn check_assigned_place(&mut self, place: Place<'tcx>, f: impl FnOnce(&mut Self)) {
+ fn check_assigned_place(&mut self, place: Place<'_>, f: impl FnOnce(&mut Self)) {
if let Some(assigned_local) = self.saved_local_for_direct_place(place) {
assert!(self.assigned_local.is_none(), "`check_assigned_place` must not recurse");
@@ -1405,7 +1411,7 @@ impl EnsureGeneratorFieldAssignmentsNeverAlias<'_> {
}
}
-impl Visitor<'tcx> for EnsureGeneratorFieldAssignmentsNeverAlias<'_> {
+impl<'tcx> Visitor<'tcx> for EnsureGeneratorFieldAssignmentsNeverAlias<'_> {
fn visit_place(&mut self, place: &Place<'tcx>, context: PlaceContext, location: Location) {
let lhs = match self.assigned_local {
Some(l) => l,
diff --git a/compiler/rustc_mir_transform/src/inline.rs b/compiler/rustc_mir_transform/src/inline.rs
index 84a1e3fb600..8be95b2d95a 100644
--- a/compiler/rustc_mir_transform/src/inline.rs
+++ b/compiler/rustc_mir_transform/src/inline.rs
@@ -37,21 +37,16 @@ struct CallSite<'tcx> {
source_info: SourceInfo,
}
-/// Returns true if MIR inlining is enabled in the current compilation session.
-crate fn is_enabled(tcx: TyCtxt<'_>) -> bool {
- if let Some(enabled) = tcx.sess.opts.debugging_opts.inline_mir {
- return enabled;
- }
-
- tcx.sess.mir_opt_level() >= 3
-}
-
impl<'tcx> MirPass<'tcx> for Inline {
- fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
- if !is_enabled(tcx) {
- return;
+ fn is_enabled(&self, sess: &rustc_session::Session) -> bool {
+ if let Some(enabled) = sess.opts.debugging_opts.inline_mir {
+ return enabled;
}
+ sess.opts.mir_opt_level() >= 3
+ }
+
+ fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
let span = trace_span!("inline", body = %tcx.def_path_str(body.source.def_id()));
let _guard = span.enter();
if inline(tcx, body) {
@@ -62,7 +57,7 @@ impl<'tcx> MirPass<'tcx> for Inline {
}
}
-fn inline(tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) -> bool {
+fn inline<'tcx>(tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) -> bool {
let def_id = body.source.def_id();
let hir_id = tcx.hir().local_def_id_to_hir_id(def_id.expect_local());
@@ -73,6 +68,12 @@ fn inline(tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) -> bool {
if body.source.promoted.is_some() {
return false;
}
+ // Avoid inlining into generators, since their `optimized_mir` is used for layout computation,
+ // which can create a cycle, even when no attempt is made to inline the function in the other
+ // direction.
+ if body.generator.is_some() {
+ return false;
+ }
let mut this = Inliner {
tcx,
@@ -100,7 +101,7 @@ struct Inliner<'tcx> {
changed: bool,
}
-impl Inliner<'tcx> {
+impl<'tcx> Inliner<'tcx> {
fn process_blocks(&mut self, caller_body: &mut Body<'tcx>, blocks: Range<BasicBlock>) {
for bb in blocks {
let bb_data = &caller_body[bb];
@@ -207,14 +208,6 @@ impl Inliner<'tcx> {
if let Some(callee_def_id) = callee.def_id().as_local() {
let callee_hir_id = self.tcx.hir().local_def_id_to_hir_id(callee_def_id);
- // Avoid inlining into generators,
- // since their `optimized_mir` is used for layout computation, which can
- // create a cycle, even when no attempt is made to inline the function
- // in the other direction.
- if caller_body.generator.is_some() {
- return Err("local generator (query cycle avoidance)");
- }
-
// Avoid a cycle here by only using `instance_mir` only if we have
// a lower `HirId` than the callee. This ensures that the callee will
// not inline us. This trick only works without incremental compilation.
@@ -441,6 +434,13 @@ impl Inliner<'tcx> {
}
}
TerminatorKind::Resume => cost += RESUME_PENALTY,
+ TerminatorKind::InlineAsm { cleanup, .. } => {
+ cost += INSTR_COST;
+
+ if cleanup.is_some() {
+ cost += LANDINGPAD_PENALTY;
+ }
+ }
_ => cost += INSTR_COST,
}
@@ -784,7 +784,7 @@ struct Integrator<'a, 'tcx> {
always_live_locals: BitSet<Local>,
}
-impl<'a, 'tcx> Integrator<'a, 'tcx> {
+impl Integrator<'_, '_> {
fn map_local(&self, local: Local) -> Local {
let new = if local == RETURN_PLACE {
self.destination.local
@@ -813,7 +813,7 @@ impl<'a, 'tcx> Integrator<'a, 'tcx> {
}
}
-impl<'a, 'tcx> MutVisitor<'tcx> for Integrator<'a, 'tcx> {
+impl<'tcx> MutVisitor<'tcx> for Integrator<'_, 'tcx> {
fn tcx(&self) -> TyCtxt<'tcx> {
self.tcx
}
@@ -954,9 +954,13 @@ impl<'a, 'tcx> MutVisitor<'tcx> for Integrator<'a, 'tcx> {
{
bug!("False unwinds should have been removed before inlining")
}
- TerminatorKind::InlineAsm { ref mut destination, .. } => {
+ TerminatorKind::InlineAsm { ref mut destination, ref mut cleanup, .. } => {
if let Some(ref mut tgt) = *destination {
*tgt = self.map_block(*tgt);
+ } else if !self.in_cleanup_block {
+ // Unless this inline asm is in a cleanup block, add an unwind edge to
+ // the original call's cleanup block
+ *cleanup = self.cleanup_block;
}
}
}
diff --git a/compiler/rustc_mir_transform/src/inline/cycle.rs b/compiler/rustc_mir_transform/src/inline/cycle.rs
index 385394ba67d..747e760a18b 100644
--- a/compiler/rustc_mir_transform/src/inline/cycle.rs
+++ b/compiler/rustc_mir_transform/src/inline/cycle.rs
@@ -10,7 +10,7 @@ use rustc_session::Limit;
// FIXME: check whether it is cheaper to precompute the entire call graph instead of invoking
// this query riddiculously often.
#[instrument(level = "debug", skip(tcx, root, target))]
-crate fn mir_callgraph_reachable(
+crate fn mir_callgraph_reachable<'tcx>(
tcx: TyCtxt<'tcx>,
(root, target): (ty::Instance<'tcx>, LocalDefId),
) -> bool {
@@ -33,7 +33,7 @@ crate fn mir_callgraph_reachable(
level = "debug",
skip(tcx, param_env, target, stack, seen, recursion_limiter, caller, recursion_limit)
)]
- fn process(
+ fn process<'tcx>(
tcx: TyCtxt<'tcx>,
param_env: ty::ParamEnv<'tcx>,
caller: ty::Instance<'tcx>,
diff --git a/compiler/rustc_mir_transform/src/instcombine.rs b/compiler/rustc_mir_transform/src/instcombine.rs
index e15a69c95ae..792ac68671e 100644
--- a/compiler/rustc_mir_transform/src/instcombine.rs
+++ b/compiler/rustc_mir_transform/src/instcombine.rs
@@ -11,6 +11,10 @@ use rustc_middle::ty::{self, TyCtxt};
pub struct InstCombine;
impl<'tcx> MirPass<'tcx> for InstCombine {
+ fn is_enabled(&self, sess: &rustc_session::Session) -> bool {
+ sess.mir_opt_level() > 0
+ }
+
fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
let (basic_blocks, local_decls) = body.basic_blocks_and_local_decls_mut();
let ctx = InstCombineContext { tcx, local_decls };
@@ -34,7 +38,7 @@ struct InstCombineContext<'tcx, 'a> {
local_decls: &'a LocalDecls<'tcx>,
}
-impl<'tcx, 'a> InstCombineContext<'tcx, 'a> {
+impl<'tcx> InstCombineContext<'tcx, '_> {
fn should_combine(&self, source_info: &SourceInfo, rvalue: &Rvalue<'tcx>) -> bool {
self.tcx.consider_optimizing(|| {
format!("InstCombine - Rvalue: {:?} SourceInfo: {:?}", rvalue, source_info)
diff --git a/compiler/rustc_mir_transform/src/lib.rs b/compiler/rustc_mir_transform/src/lib.rs
index f9ef3146278..638baa0b8d3 100644
--- a/compiler/rustc_mir_transform/src/lib.rs
+++ b/compiler/rustc_mir_transform/src/lib.rs
@@ -1,8 +1,6 @@
#![feature(box_patterns)]
#![feature(box_syntax)]
#![feature(crate_visibility_modifier)]
-#![feature(in_band_lifetimes)]
-#![feature(iter_zip)]
#![feature(let_else)]
#![feature(map_try_insert)]
#![feature(min_specialization)]
@@ -27,11 +25,16 @@ use rustc_hir::def_id::{DefId, LocalDefId};
use rustc_hir::intravisit::{self, NestedVisitorMap, Visitor};
use rustc_index::vec::IndexVec;
use rustc_middle::mir::visit::Visitor as _;
-use rustc_middle::mir::{dump_mir, traversal, Body, ConstQualifs, MirPhase, Promoted};
+use rustc_middle::mir::{traversal, Body, ConstQualifs, MirPass, MirPhase, Promoted};
use rustc_middle::ty::query::Providers;
use rustc_middle::ty::{self, TyCtxt, TypeFoldable};
use rustc_span::{Span, Symbol};
+#[macro_use]
+mod pass_manager;
+
+use pass_manager::{self as pm, Lint, MirLint, WithMinOptLevel};
+
mod abort_unwinding_calls;
mod add_call_guards;
mod add_moves_for_packed_drops;
@@ -56,12 +59,15 @@ mod inline;
mod instcombine;
mod lower_intrinsics;
mod lower_slice_len;
+mod marker;
mod match_branches;
mod multiple_return_terminators;
mod normalize_array_len;
mod nrvo;
+mod remove_false_edges;
mod remove_noop_landing_pads;
mod remove_storage_markers;
+mod remove_uninit_drops;
mod remove_unneeded_drops;
mod remove_zsts;
mod required_consts;
@@ -75,10 +81,9 @@ mod simplify_try;
mod uninhabited_enum_branching;
mod unreachable_prop;
-use rustc_const_eval::transform::check_consts;
+use rustc_const_eval::transform::check_consts::{self, ConstCx};
use rustc_const_eval::transform::promote_consts;
use rustc_const_eval::transform::validate;
-pub use rustc_const_eval::transform::MirPass;
use rustc_mir_dataflow::rustc_peek;
pub fn provide(providers: &mut Providers) {
@@ -143,7 +148,7 @@ fn mir_keys(tcx: TyCtxt<'_>, (): ()) -> FxHashSet<LocalDefId> {
tcx: TyCtxt<'tcx>,
set: &'a mut FxHashSet<LocalDefId>,
}
- impl<'a, 'tcx> Visitor<'tcx> for GatherCtors<'a, 'tcx> {
+ impl<'tcx> Visitor<'tcx> for GatherCtors<'_, 'tcx> {
fn visit_variant_data(
&mut self,
v: &'tcx hir::VariantData<'tcx>,
@@ -167,66 +172,6 @@ fn mir_keys(tcx: TyCtxt<'_>, (): ()) -> FxHashSet<LocalDefId> {
set
}
-fn run_passes(
- tcx: TyCtxt<'tcx>,
- body: &mut Body<'tcx>,
- mir_phase: MirPhase,
- passes: &[&[&dyn MirPass<'tcx>]],
-) {
- let phase_index = mir_phase.phase_index();
- let validate = tcx.sess.opts.debugging_opts.validate_mir;
-
- if body.phase >= mir_phase {
- return;
- }
-
- if validate {
- validate::Validator { when: format!("input to phase {:?}", mir_phase), mir_phase }
- .run_pass(tcx, body);
- }
-
- let mut index = 0;
- let mut run_pass = |pass: &dyn MirPass<'tcx>| {
- let run_hooks = |body: &_, index, is_after| {
- let disambiguator = if is_after { "after" } else { "before" };
- dump_mir(
- tcx,
- Some(&format_args!("{:03}-{:03}", phase_index, index)),
- &pass.name(),
- &disambiguator,
- body,
- |_, _| Ok(()),
- );
- };
- run_hooks(body, index, false);
- pass.run_pass(tcx, body);
- run_hooks(body, index, true);
-
- if validate {
- validate::Validator {
- when: format!("after {} in phase {:?}", pass.name(), mir_phase),
- mir_phase,
- }
- .run_pass(tcx, body);
- }
-
- index += 1;
- };
-
- for pass_group in passes {
- for pass in *pass_group {
- run_pass(*pass);
- }
- }
-
- body.phase = mir_phase;
-
- if mir_phase == MirPhase::Optimization {
- validate::Validator { when: format!("end of phase {:?}", mir_phase), mir_phase }
- .run_pass(tcx, body);
- }
-}
-
fn mir_const_qualif(tcx: TyCtxt<'_>, def: ty::WithOptConstParam<LocalDefId>) -> ConstQualifs {
let const_kind = tcx.hir().body_const_context(def.did);
@@ -278,25 +223,25 @@ fn mir_const<'tcx>(
rustc_middle::mir::dump_mir(tcx, None, "mir_map", &0, &body, |_, _| Ok(()));
- run_passes(
+ pm::run_passes(
tcx,
&mut body,
- MirPhase::Const,
- &[&[
+ &[
// MIR-level lints.
- &check_packed_ref::CheckPackedRef,
- &check_const_item_mutation::CheckConstItemMutation,
- &function_item_references::FunctionItemReferences,
+ &Lint(check_packed_ref::CheckPackedRef),
+ &Lint(check_const_item_mutation::CheckConstItemMutation),
+ &Lint(function_item_references::FunctionItemReferences),
// What we need to do constant evaluation.
&simplify::SimplifyCfg::new("initial"),
- &rustc_peek::SanityCheck,
- ]],
+ &rustc_peek::SanityCheck, // Just a lint
+ &marker::PhaseChange(MirPhase::Const),
+ ],
);
tcx.alloc_steal_mir(body)
}
/// Compute the main MIR body and the list of MIR bodies of the promoteds.
-fn mir_promoted(
+fn mir_promoted<'tcx>(
tcx: TyCtxt<'tcx>,
def: ty::WithOptConstParam<LocalDefId>,
) -> (&'tcx Steal<Body<'tcx>>, &'tcx Steal<IndexVec<Promoted, Body<'tcx>>>) {
@@ -317,17 +262,17 @@ fn mir_promoted(
}
body.required_consts = required_consts;
+ // What we need to run borrowck etc.
let promote_pass = promote_consts::PromoteTemps::default();
- let promote: &[&dyn MirPass<'tcx>] = &[
- // What we need to run borrowck etc.
- &promote_pass,
- &simplify::SimplifyCfg::new("promote-consts"),
- ];
-
- let opt_coverage: &[&dyn MirPass<'tcx>] =
- if tcx.sess.instrument_coverage() { &[&coverage::InstrumentCoverage] } else { &[] };
-
- run_passes(tcx, &mut body, MirPhase::ConstPromotion, &[promote, opt_coverage]);
+ pm::run_passes(
+ tcx,
+ &mut body,
+ &[
+ &promote_pass,
+ &simplify::SimplifyCfg::new("promote-consts"),
+ &coverage::InstrumentCoverage,
+ ],
+ );
let promoted = promote_pass.promoted_fragments.into_inner();
(tcx.alloc_steal_mir(body), tcx.alloc_steal_promoted(promoted))
@@ -389,19 +334,10 @@ fn inner_mir_for_ctfe(tcx: TyCtxt<'_>, def: ty::WithOptConstParam<LocalDefId>) -
// Technically we want to not run on regular const items, but oli-obk doesn't know how to
// conveniently detect that at this point without looking at the HIR.
hir::ConstContext::Const => {
- #[rustfmt::skip]
- let optimizations: &[&dyn MirPass<'_>] = &[
- &const_prop::ConstProp,
- ];
-
- #[rustfmt::skip]
- run_passes(
+ pm::run_passes(
tcx,
&mut body,
- MirPhase::Optimization,
- &[
- optimizations,
- ],
+ &[&const_prop::ConstProp, &marker::PhaseChange(MirPhase::Optimization)],
);
}
}
@@ -437,7 +373,7 @@ fn mir_drops_elaborated_and_const_checked<'tcx>(
let def = ty::WithOptConstParam::unknown(did);
// Do not compute the mir call graph without said call graph actually being used.
- if inline::is_enabled(tcx) {
+ if inline::Inline.is_enabled(&tcx.sess) {
let _ = tcx.mir_inliner_callees(ty::InstanceDef::Item(def));
}
}
@@ -445,8 +381,24 @@ fn mir_drops_elaborated_and_const_checked<'tcx>(
let (body, _) = tcx.mir_promoted(def);
let mut body = body.steal();
+ // IMPORTANT
+ pm::run_passes(tcx, &mut body, &[&remove_false_edges::RemoveFalseEdges]);
+
+ // Do a little drop elaboration before const-checking if `const_precise_live_drops` is enabled.
+ if check_consts::post_drop_elaboration::checking_enabled(&ConstCx::new(tcx, &body)) {
+ pm::run_passes(
+ tcx,
+ &mut body,
+ &[
+ &simplify::SimplifyCfg::new("remove-false-edges"),
+ &remove_uninit_drops::RemoveUninitDrops,
+ ],
+ );
+ check_consts::post_drop_elaboration::check_live_drops(tcx, &body); // FIXME: make this a MIR lint
+ }
+
run_post_borrowck_cleanup_passes(tcx, &mut body);
- check_consts::post_drop_elaboration::check_live_drops(tcx, &body);
+ assert!(body.phase == MirPhase::DropLowering);
tcx.alloc_steal_mir(body)
}
@@ -456,7 +408,7 @@ fn run_post_borrowck_cleanup_passes<'tcx>(tcx: TyCtxt<'tcx>, body: &mut Body<'tc
let post_borrowck_cleanup: &[&dyn MirPass<'tcx>] = &[
// Remove all things only needed by analysis
- &simplify_branches::SimplifyBranches::new("initial"),
+ &simplify_branches::SimplifyConstCondition::new("initial"),
&remove_noop_landing_pads::RemoveNoopLandingPads,
&cleanup_post_borrowck::CleanupNonCodegenStatements,
&simplify::SimplifyCfg::new("early-opt"),
@@ -480,95 +432,72 @@ fn run_post_borrowck_cleanup_passes<'tcx>(tcx: TyCtxt<'tcx>, body: &mut Body<'tc
&deaggregator::Deaggregator,
];
- run_passes(tcx, body, MirPhase::DropLowering, &[post_borrowck_cleanup]);
+ pm::run_passes(tcx, body, post_borrowck_cleanup);
}
fn run_optimization_passes<'tcx>(tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
- let mir_opt_level = tcx.sess.mir_opt_level();
+ fn o1<T>(x: T) -> WithMinOptLevel<T> {
+ WithMinOptLevel(1, x)
+ }
// Lowering generator control-flow and variables has to happen before we do anything else
// to them. We run some optimizations before that, because they may be harder to do on the state
// machine than on MIR with async primitives.
- let optimizations_with_generators: &[&dyn MirPass<'tcx>] = &[
- &reveal_all::RevealAll, // has to be done before inlining, since inlined code is in RevealAll mode.
- &lower_slice_len::LowerSliceLenCalls, // has to be done before inlining, otherwise actual call will be almost always inlined. Also simple, so can just do first
- &normalize_array_len::NormalizeArrayLen, // has to run after `slice::len` lowering
- &unreachable_prop::UnreachablePropagation,
- &uninhabited_enum_branching::UninhabitedEnumBranching,
- &simplify::SimplifyCfg::new("after-uninhabited-enum-branching"),
- &inline::Inline,
- &generator::StateTransform,
- ];
-
- // Even if we don't do optimizations, we still have to lower generators for codegen.
- let no_optimizations_with_generators: &[&dyn MirPass<'tcx>] = &[&generator::StateTransform];
-
- // The main optimizations that we do on MIR.
- let optimizations: &[&dyn MirPass<'tcx>] = &[
- &remove_storage_markers::RemoveStorageMarkers,
- &remove_zsts::RemoveZsts,
- &const_goto::ConstGoto,
- &remove_unneeded_drops::RemoveUnneededDrops,
- &match_branches::MatchBranchSimplification,
- // inst combine is after MatchBranchSimplification to clean up Ne(_1, false)
- &multiple_return_terminators::MultipleReturnTerminators,
- &instcombine::InstCombine,
- &separate_const_switch::SeparateConstSwitch,
- &const_prop::ConstProp,
- &simplify_branches::SimplifyBranches::new("after-const-prop"),
- &early_otherwise_branch::EarlyOtherwiseBranch,
- &simplify_comparison_integral::SimplifyComparisonIntegral,
- &simplify_try::SimplifyArmIdentity,
- &simplify_try::SimplifyBranchSame,
- &dest_prop::DestinationPropagation,
- &simplify_branches::SimplifyBranches::new("final"),
- &remove_noop_landing_pads::RemoveNoopLandingPads,
- &simplify::SimplifyCfg::new("final"),
- &nrvo::RenameReturnPlace,
- &const_debuginfo::ConstDebugInfo,
- &simplify::SimplifyLocals,
- &multiple_return_terminators::MultipleReturnTerminators,
- &deduplicate_blocks::DeduplicateBlocks,
- ];
-
- // Optimizations to run even if mir optimizations have been disabled.
- let no_optimizations: &[&dyn MirPass<'tcx>] = &[
- // FIXME(#70073): This pass is responsible for both optimization as well as some lints.
- &const_prop::ConstProp,
- ];
-
- // Some cleanup necessary at least for LLVM and potentially other codegen backends.
- let pre_codegen_cleanup: &[&dyn MirPass<'tcx>] = &[
- &add_call_guards::CriticalCallEdges,
- // Dump the end result for testing and debugging purposes.
- &dump_mir::Marker("PreCodegen"),
- ];
-
- // End of pass declarations, now actually run the passes.
- // Generator Lowering
- #[rustfmt::skip]
- run_passes(
+ pm::run_passes(
tcx,
body,
- MirPhase::GeneratorLowering,
&[
- if mir_opt_level > 0 {
- optimizations_with_generators
- } else {
- no_optimizations_with_generators
- }
+ &reveal_all::RevealAll, // has to be done before inlining, since inlined code is in RevealAll mode.
+ &lower_slice_len::LowerSliceLenCalls, // has to be done before inlining, otherwise actual call will be almost always inlined. Also simple, so can just do first
+ &normalize_array_len::NormalizeArrayLen, // has to run after `slice::len` lowering
+ &unreachable_prop::UnreachablePropagation,
+ &uninhabited_enum_branching::UninhabitedEnumBranching,
+ &o1(simplify::SimplifyCfg::new("after-uninhabited-enum-branching")),
+ &inline::Inline,
+ &generator::StateTransform,
],
);
- // Main optimization passes
- #[rustfmt::skip]
- run_passes(
+ assert!(body.phase == MirPhase::GeneratorLowering);
+
+ // The main optimizations that we do on MIR.
+ pm::run_passes(
tcx,
body,
- MirPhase::Optimization,
&[
- if mir_opt_level > 0 { optimizations } else { no_optimizations },
- pre_codegen_cleanup,
+ &remove_storage_markers::RemoveStorageMarkers,
+ &remove_zsts::RemoveZsts,
+ &const_goto::ConstGoto,
+ &remove_unneeded_drops::RemoveUnneededDrops,
+ &match_branches::MatchBranchSimplification,
+ // inst combine is after MatchBranchSimplification to clean up Ne(_1, false)
+ &multiple_return_terminators::MultipleReturnTerminators,
+ &instcombine::InstCombine,
+ &separate_const_switch::SeparateConstSwitch,
+ //
+ // FIXME(#70073): This pass is responsible for both optimization as well as some lints.
+ &const_prop::ConstProp,
+ //
+ // Const-prop runs unconditionally, but doesn't mutate the MIR at mir-opt-level=0.
+ &o1(simplify_branches::SimplifyConstCondition::new("after-const-prop")),
+ &early_otherwise_branch::EarlyOtherwiseBranch,
+ &simplify_comparison_integral::SimplifyComparisonIntegral,
+ &simplify_try::SimplifyArmIdentity,
+ &simplify_try::SimplifyBranchSame,
+ &dest_prop::DestinationPropagation,
+ &o1(simplify_branches::SimplifyConstCondition::new("final")),
+ &o1(remove_noop_landing_pads::RemoveNoopLandingPads),
+ &o1(simplify::SimplifyCfg::new("final")),
+ &nrvo::RenameReturnPlace,
+ &const_debuginfo::ConstDebugInfo,
+ &simplify::SimplifyLocals,
+ &multiple_return_terminators::MultipleReturnTerminators,
+ &deduplicate_blocks::DeduplicateBlocks,
+ // Some cleanup necessary at least for LLVM and potentially other codegen backends.
+ &add_call_guards::CriticalCallEdges,
+ &marker::PhaseChange(MirPhase::Optimization),
+ // Dump the end result for testing and debugging purposes.
+ &dump_mir::Marker("PreCodegen"),
],
);
}
diff --git a/compiler/rustc_mir_transform/src/lower_intrinsics.rs b/compiler/rustc_mir_transform/src/lower_intrinsics.rs
index 5848163af72..4c4497ad629 100644
--- a/compiler/rustc_mir_transform/src/lower_intrinsics.rs
+++ b/compiler/rustc_mir_transform/src/lower_intrinsics.rs
@@ -135,7 +135,7 @@ impl<'tcx> MirPass<'tcx> for LowerIntrinsics {
}
}
-fn resolve_rust_intrinsic(
+fn resolve_rust_intrinsic<'tcx>(
tcx: TyCtxt<'tcx>,
func_ty: Ty<'tcx>,
) -> Option<(Symbol, SubstsRef<'tcx>)> {
@@ -148,7 +148,7 @@ fn resolve_rust_intrinsic(
None
}
-fn validate_simd_shuffle(tcx: TyCtxt<'tcx>, args: &[Operand<'tcx>], span: Span) {
+fn validate_simd_shuffle<'tcx>(tcx: TyCtxt<'tcx>, args: &[Operand<'tcx>], span: Span) {
match &args[2] {
Operand::Constant(_) => {} // all good
_ => {
diff --git a/compiler/rustc_mir_transform/src/lower_slice_len.rs b/compiler/rustc_mir_transform/src/lower_slice_len.rs
index 822a372d8ce..c8297744873 100644
--- a/compiler/rustc_mir_transform/src/lower_slice_len.rs
+++ b/compiler/rustc_mir_transform/src/lower_slice_len.rs
@@ -10,6 +10,10 @@ use rustc_middle::ty::{self, TyCtxt};
pub struct LowerSliceLenCalls;
impl<'tcx> MirPass<'tcx> for LowerSliceLenCalls {
+ fn is_enabled(&self, sess: &rustc_session::Session) -> bool {
+ sess.opts.mir_opt_level() > 0
+ }
+
fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
lower_slice_len_calls(tcx, body)
}
diff --git a/compiler/rustc_mir_transform/src/marker.rs b/compiler/rustc_mir_transform/src/marker.rs
new file mode 100644
index 00000000000..06819fc1d37
--- /dev/null
+++ b/compiler/rustc_mir_transform/src/marker.rs
@@ -0,0 +1,20 @@
+use std::borrow::Cow;
+
+use crate::MirPass;
+use rustc_middle::mir::{Body, MirPhase};
+use rustc_middle::ty::TyCtxt;
+
+/// Changes the MIR phase without changing the MIR itself.
+pub struct PhaseChange(pub MirPhase);
+
+impl<'tcx> MirPass<'tcx> for PhaseChange {
+ fn phase_change(&self) -> Option<MirPhase> {
+ Some(self.0)
+ }
+
+ fn name(&self) -> Cow<'_, str> {
+ Cow::from(format!("PhaseChange-{:?}", self.0))
+ }
+
+ fn run_pass(&self, _: TyCtxt<'tcx>, _body: &mut Body<'tcx>) {}
+}
diff --git a/compiler/rustc_mir_transform/src/match_branches.rs b/compiler/rustc_mir_transform/src/match_branches.rs
index c618abe9d05..3c14a324c36 100644
--- a/compiler/rustc_mir_transform/src/match_branches.rs
+++ b/compiler/rustc_mir_transform/src/match_branches.rs
@@ -40,11 +40,11 @@ pub struct MatchBranchSimplification;
/// ```
impl<'tcx> MirPass<'tcx> for MatchBranchSimplification {
- fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
- if tcx.sess.mir_opt_level() < 3 {
- return;
- }
+ fn is_enabled(&self, sess: &rustc_session::Session) -> bool {
+ sess.mir_opt_level() >= 3
+ }
+ fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
let def_id = body.source.def_id();
let param_env = tcx.param_env(def_id);
diff --git a/compiler/rustc_mir_transform/src/multiple_return_terminators.rs b/compiler/rustc_mir_transform/src/multiple_return_terminators.rs
index b614917a883..22b6dead99c 100644
--- a/compiler/rustc_mir_transform/src/multiple_return_terminators.rs
+++ b/compiler/rustc_mir_transform/src/multiple_return_terminators.rs
@@ -9,11 +9,11 @@ use rustc_middle::ty::TyCtxt;
pub struct MultipleReturnTerminators;
impl<'tcx> MirPass<'tcx> for MultipleReturnTerminators {
- fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
- if tcx.sess.mir_opt_level() < 4 {
- return;
- }
+ fn is_enabled(&self, sess: &rustc_session::Session) -> bool {
+ sess.mir_opt_level() >= 4
+ }
+ fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
// find basic blocks with no statement and a return terminator
let mut bbs_simple_returns = BitSet::new_empty(body.basic_blocks().len());
let def_id = body.source.def_id();
diff --git a/compiler/rustc_mir_transform/src/normalize_array_len.rs b/compiler/rustc_mir_transform/src/normalize_array_len.rs
index a04a0b51531..e4ac57ac925 100644
--- a/compiler/rustc_mir_transform/src/normalize_array_len.rs
+++ b/compiler/rustc_mir_transform/src/normalize_array_len.rs
@@ -14,11 +14,11 @@ const MAX_NUM_LOCALS: usize = 3000;
pub struct NormalizeArrayLen;
impl<'tcx> MirPass<'tcx> for NormalizeArrayLen {
- fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
- if tcx.sess.mir_opt_level() < 4 {
- return;
- }
+ fn is_enabled(&self, sess: &rustc_session::Session) -> bool {
+ sess.mir_opt_level() >= 4
+ }
+ fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
// early returns for edge cases of highly unrolled functions
if body.basic_blocks().len() > MAX_NUM_BLOCKS {
return;
@@ -85,7 +85,7 @@ struct Patcher<'a, 'tcx> {
statement_idx: usize,
}
-impl<'a, 'tcx> Patcher<'a, 'tcx> {
+impl<'tcx> Patcher<'_, 'tcx> {
fn patch_expand_statement(
&mut self,
statement: &mut Statement<'tcx>,
diff --git a/compiler/rustc_mir_transform/src/nrvo.rs b/compiler/rustc_mir_transform/src/nrvo.rs
index 3ac4e77cf9a..797f7ee2685 100644
--- a/compiler/rustc_mir_transform/src/nrvo.rs
+++ b/compiler/rustc_mir_transform/src/nrvo.rs
@@ -33,11 +33,11 @@ use crate::MirPass;
pub struct RenameReturnPlace;
impl<'tcx> MirPass<'tcx> for RenameReturnPlace {
- fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut mir::Body<'tcx>) {
- if tcx.sess.mir_opt_level() == 0 {
- return;
- }
+ fn is_enabled(&self, sess: &rustc_session::Session) -> bool {
+ sess.mir_opt_level() > 0
+ }
+ fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut mir::Body<'tcx>) {
let def_id = body.source.def_id();
let returned_local = match local_eligible_for_nrvo(body) {
Some(l) => l,
@@ -165,7 +165,7 @@ struct RenameToReturnPlace<'tcx> {
}
/// Replaces all uses of `self.to_rename` with `_0`.
-impl MutVisitor<'tcx> for RenameToReturnPlace<'tcx> {
+impl<'tcx> MutVisitor<'tcx> for RenameToReturnPlace<'tcx> {
fn tcx(&self) -> TyCtxt<'tcx> {
self.tcx
}
@@ -221,7 +221,7 @@ impl IsReturnPlaceRead {
}
}
-impl Visitor<'tcx> for IsReturnPlaceRead {
+impl<'tcx> Visitor<'tcx> for IsReturnPlaceRead {
fn visit_local(&mut self, &l: &Local, ctxt: PlaceContext, _: Location) {
if l == mir::RETURN_PLACE && ctxt.is_use() && !ctxt.is_place_assignment() {
self.0 = true;
diff --git a/compiler/rustc_mir_transform/src/pass_manager.rs b/compiler/rustc_mir_transform/src/pass_manager.rs
new file mode 100644
index 00000000000..8725eae8709
--- /dev/null
+++ b/compiler/rustc_mir_transform/src/pass_manager.rs
@@ -0,0 +1,144 @@
+use std::borrow::Cow;
+
+use rustc_middle::mir::{self, Body, MirPhase};
+use rustc_middle::ty::TyCtxt;
+use rustc_session::Session;
+
+use crate::{validate, MirPass};
+
+/// Just like `MirPass`, except it cannot mutate `Body`.
+pub trait MirLint<'tcx> {
+ fn name(&self) -> Cow<'_, str> {
+ let name = std::any::type_name::<Self>();
+ if let Some(tail) = name.rfind(':') {
+ Cow::from(&name[tail + 1..])
+ } else {
+ Cow::from(name)
+ }
+ }
+
+ fn is_enabled(&self, _sess: &Session) -> bool {
+ true
+ }
+
+ fn run_lint(&self, tcx: TyCtxt<'tcx>, body: &Body<'tcx>);
+}
+
+/// An adapter for `MirLint`s that implements `MirPass`.
+#[derive(Debug, Clone)]
+pub struct Lint<T>(pub T);
+
+impl<'tcx, T> MirPass<'tcx> for Lint<T>
+where
+ T: MirLint<'tcx>,
+{
+ fn name(&self) -> Cow<'_, str> {
+ self.0.name()
+ }
+
+ fn is_enabled(&self, sess: &Session) -> bool {
+ self.0.is_enabled(sess)
+ }
+
+ fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
+ self.0.run_lint(tcx, body)
+ }
+
+ fn is_mir_dump_enabled(&self) -> bool {
+ false
+ }
+}
+
+pub struct WithMinOptLevel<T>(pub u32, pub T);
+
+impl<'tcx, T> MirPass<'tcx> for WithMinOptLevel<T>
+where
+ T: MirPass<'tcx>,
+{
+ fn name(&self) -> Cow<'_, str> {
+ self.1.name()
+ }
+
+ fn is_enabled(&self, sess: &Session) -> bool {
+ sess.mir_opt_level() >= self.0 as usize
+ }
+
+ fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
+ self.1.run_pass(tcx, body)
+ }
+
+ fn phase_change(&self) -> Option<MirPhase> {
+ self.1.phase_change()
+ }
+}
+
+pub fn run_passes<'tcx>(tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>, passes: &[&dyn MirPass<'tcx>]) {
+ let start_phase = body.phase;
+ let mut cnt = 0;
+
+ let validate = tcx.sess.opts.debugging_opts.validate_mir;
+
+ if validate {
+ validate_body(tcx, body, format!("start of phase transition from {:?}", start_phase));
+ }
+
+ for pass in passes {
+ if !pass.is_enabled(&tcx.sess) {
+ continue;
+ }
+
+ let name = pass.name();
+ let dump_enabled = pass.is_mir_dump_enabled();
+
+ if dump_enabled {
+ dump_mir(tcx, body, start_phase, &name, cnt, false);
+ }
+
+ pass.run_pass(tcx, body);
+
+ if dump_enabled {
+ dump_mir(tcx, body, start_phase, &name, cnt, true);
+ cnt += 1;
+ }
+
+ if let Some(new_phase) = pass.phase_change() {
+ if body.phase >= new_phase {
+ panic!("Invalid MIR phase transition from {:?} to {:?}", body.phase, new_phase);
+ }
+
+ body.phase = new_phase;
+ }
+
+ if validate {
+ validate_body(tcx, body, format!("after pass {}", pass.name()));
+ }
+ }
+
+ if validate || body.phase == MirPhase::Optimization {
+ validate_body(tcx, body, format!("end of phase transition to {:?}", body.phase));
+ }
+}
+
+pub fn validate_body<'tcx>(tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>, when: String) {
+ validate::Validator { when, mir_phase: body.phase }.run_pass(tcx, body);
+}
+
+pub fn dump_mir<'tcx>(
+ tcx: TyCtxt<'tcx>,
+ body: &Body<'tcx>,
+ phase: MirPhase,
+ pass_name: &str,
+ cnt: usize,
+ is_after: bool,
+) {
+ let phase_index = phase as u32;
+
+ mir::dump_mir(
+ tcx,
+ Some(&format_args!("{:03}-{:03}", phase_index, cnt)),
+ pass_name,
+ if is_after { &"after" } else { &"before" },
+ body,
+ |_, _| Ok(()),
+ );
+}
diff --git a/compiler/rustc_mir_transform/src/remove_false_edges.rs b/compiler/rustc_mir_transform/src/remove_false_edges.rs
new file mode 100644
index 00000000000..71f5ccf7e24
--- /dev/null
+++ b/compiler/rustc_mir_transform/src/remove_false_edges.rs
@@ -0,0 +1,29 @@
+use rustc_middle::mir::{Body, TerminatorKind};
+use rustc_middle::ty::TyCtxt;
+
+use crate::MirPass;
+
+/// Removes `FalseEdge` and `FalseUnwind` terminators from the MIR.
+///
+/// These are only needed for borrow checking, and can be removed afterwards.
+///
+/// FIXME: This should probably have its own MIR phase.
+pub struct RemoveFalseEdges;
+
+impl<'tcx> MirPass<'tcx> for RemoveFalseEdges {
+ fn run_pass(&self, _: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
+ for block in body.basic_blocks_mut() {
+ let terminator = block.terminator_mut();
+ terminator.kind = match terminator.kind {
+ TerminatorKind::FalseEdge { real_target, .. } => {
+ TerminatorKind::Goto { target: real_target }
+ }
+ TerminatorKind::FalseUnwind { real_target, .. } => {
+ TerminatorKind::Goto { target: real_target }
+ }
+
+ _ => continue,
+ }
+ }
+ }
+}
diff --git a/compiler/rustc_mir_transform/src/remove_noop_landing_pads.rs b/compiler/rustc_mir_transform/src/remove_noop_landing_pads.rs
index 298bcd9dc24..2a73e341f16 100644
--- a/compiler/rustc_mir_transform/src/remove_noop_landing_pads.rs
+++ b/compiler/rustc_mir_transform/src/remove_noop_landing_pads.rs
@@ -10,18 +10,14 @@ use rustc_target::spec::PanicStrategy;
/// code for these.
pub struct RemoveNoopLandingPads;
-pub fn remove_noop_landing_pads<'tcx>(tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
- if tcx.sess.panic_strategy() == PanicStrategy::Abort {
- return;
+impl<'tcx> MirPass<'tcx> for RemoveNoopLandingPads {
+ fn is_enabled(&self, sess: &rustc_session::Session) -> bool {
+ sess.panic_strategy() != PanicStrategy::Abort
}
- debug!("remove_noop_landing_pads({:?})", body);
-
- RemoveNoopLandingPads.remove_nop_landing_pads(body)
-}
-impl<'tcx> MirPass<'tcx> for RemoveNoopLandingPads {
- fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
- remove_noop_landing_pads(tcx, body);
+ fn run_pass(&self, _: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
+ debug!("remove_noop_landing_pads({:?})", body);
+ self.remove_nop_landing_pads(body)
}
}
diff --git a/compiler/rustc_mir_transform/src/remove_storage_markers.rs b/compiler/rustc_mir_transform/src/remove_storage_markers.rs
index 0c7323cbac5..c9b6e1459d3 100644
--- a/compiler/rustc_mir_transform/src/remove_storage_markers.rs
+++ b/compiler/rustc_mir_transform/src/remove_storage_markers.rs
@@ -7,6 +7,10 @@ use rustc_middle::ty::TyCtxt;
pub struct RemoveStorageMarkers;
impl<'tcx> MirPass<'tcx> for RemoveStorageMarkers {
+ fn is_enabled(&self, sess: &rustc_session::Session) -> bool {
+ sess.mir_opt_level() > 0
+ }
+
fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
if tcx.sess.emit_lifetime_markers() {
return;
diff --git a/compiler/rustc_mir_transform/src/remove_uninit_drops.rs b/compiler/rustc_mir_transform/src/remove_uninit_drops.rs
new file mode 100644
index 00000000000..fc5ac97e3e1
--- /dev/null
+++ b/compiler/rustc_mir_transform/src/remove_uninit_drops.rs
@@ -0,0 +1,171 @@
+use rustc_index::bit_set::BitSet;
+use rustc_middle::mir::{Body, Field, Rvalue, Statement, StatementKind, TerminatorKind};
+use rustc_middle::ty::subst::SubstsRef;
+use rustc_middle::ty::{self, ParamEnv, Ty, TyCtxt, VariantDef};
+use rustc_mir_dataflow::impls::MaybeInitializedPlaces;
+use rustc_mir_dataflow::move_paths::{LookupResult, MoveData, MovePathIndex};
+use rustc_mir_dataflow::{self, move_path_children_matching, Analysis, MoveDataParamEnv};
+
+use crate::MirPass;
+
+/// Removes `Drop` and `DropAndReplace` terminators whose target is known to be uninitialized at
+/// that point.
+///
+/// This is redundant with drop elaboration, but we need to do it prior to const-checking, and
+/// running const-checking after drop elaboration makes it opimization dependent, causing issues
+/// like [#90770].
+///
+/// [#90770]: https://github.com/rust-lang/rust/issues/90770
+pub struct RemoveUninitDrops;
+
+impl<'tcx> MirPass<'tcx> for RemoveUninitDrops {
+ fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
+ let param_env = tcx.param_env(body.source.def_id());
+ let Ok(move_data) = MoveData::gather_moves(body, tcx, param_env) else {
+ // We could continue if there are move errors, but there's not much point since our
+ // init data isn't complete.
+ return;
+ };
+
+ let mdpe = MoveDataParamEnv { move_data, param_env };
+ let mut maybe_inits = MaybeInitializedPlaces::new(tcx, body, &mdpe)
+ .into_engine(tcx, body)
+ .pass_name("remove_uninit_drops")
+ .iterate_to_fixpoint()
+ .into_results_cursor(body);
+
+ let mut to_remove = vec![];
+ for (bb, block) in body.basic_blocks().iter_enumerated() {
+ let terminator = block.terminator();
+ let (TerminatorKind::Drop { place, .. } | TerminatorKind::DropAndReplace { place, .. })
+ = &terminator.kind
+ else { continue };
+
+ maybe_inits.seek_before_primary_effect(body.terminator_loc(bb));
+
+ // If there's no move path for the dropped place, it's probably a `Deref`. Let it alone.
+ let LookupResult::Exact(mpi) = mdpe.move_data.rev_lookup.find(place.as_ref()) else {
+ continue;
+ };
+
+ let should_keep = is_needs_drop_and_init(
+ tcx,
+ param_env,
+ maybe_inits.get(),
+ &mdpe.move_data,
+ place.ty(body, tcx).ty,
+ mpi,
+ );
+ if !should_keep {
+ to_remove.push(bb)
+ }
+ }
+
+ for bb in to_remove {
+ let block = &mut body.basic_blocks_mut()[bb];
+
+ let (TerminatorKind::Drop { target, .. } | TerminatorKind::DropAndReplace { target, .. })
+ = &block.terminator().kind
+ else { unreachable!() };
+
+ // Replace block terminator with `Goto`.
+ let target = *target;
+ let old_terminator_kind = std::mem::replace(
+ &mut block.terminator_mut().kind,
+ TerminatorKind::Goto { target },
+ );
+
+ // If this is a `DropAndReplace`, we need to emulate the assignment to the return place.
+ if let TerminatorKind::DropAndReplace { place, value, .. } = old_terminator_kind {
+ block.statements.push(Statement {
+ source_info: block.terminator().source_info,
+ kind: StatementKind::Assign(Box::new((place, Rvalue::Use(value)))),
+ });
+ }
+ }
+ }
+}
+
+fn is_needs_drop_and_init<'tcx>(
+ tcx: TyCtxt<'tcx>,
+ param_env: ParamEnv<'tcx>,
+ maybe_inits: &BitSet<MovePathIndex>,
+ move_data: &MoveData<'tcx>,
+ ty: Ty<'tcx>,
+ mpi: MovePathIndex,
+) -> bool {
+ // No need to look deeper if the root is definitely uninit or if it has no `Drop` impl.
+ if !maybe_inits.contains(mpi) || !ty.needs_drop(tcx, param_env) {
+ return false;
+ }
+
+ let field_needs_drop_and_init = |(f, f_ty, mpi)| {
+ let child = move_path_children_matching(move_data, mpi, |x| x.is_field_to(f));
+ let Some(mpi) = child else {
+ return f_ty.needs_drop(tcx, param_env);
+ };
+
+ is_needs_drop_and_init(tcx, param_env, maybe_inits, move_data, f_ty, mpi)
+ };
+
+ // This pass is only needed for const-checking, so it doesn't handle as many cases as
+ // `DropCtxt::open_drop`, since they aren't relevant in a const-context.
+ match ty.kind() {
+ ty::Adt(adt, substs) => {
+ let dont_elaborate = adt.is_union() || adt.is_manually_drop() || adt.has_dtor(tcx);
+ if dont_elaborate {
+ return true;
+ }
+
+ // Look at all our fields, or if we are an enum all our variants and their fields.
+ //
+ // If a field's projection *is not* present in `MoveData`, it has the same
+ // initializedness as its parent (maybe init).
+ //
+ // If its projection *is* present in `MoveData`, then the field may have been moved
+ // from separate from its parent. Recurse.
+ adt.variants.iter_enumerated().any(|(vid, variant)| {
+ // Enums have multiple variants, which are discriminated with a `Downcast` projection.
+ // Structs have a single variant, and don't use a `Downcast` projection.
+ let mpi = if adt.is_enum() {
+ let downcast =
+ move_path_children_matching(move_data, mpi, |x| x.is_downcast_to(vid));
+ let Some(dc_mpi) = downcast else {
+ return variant_needs_drop(tcx, param_env, substs, variant);
+ };
+
+ dc_mpi
+ } else {
+ mpi
+ };
+
+ variant
+ .fields
+ .iter()
+ .enumerate()
+ .map(|(f, field)| (Field::from_usize(f), field.ty(tcx, substs), mpi))
+ .any(field_needs_drop_and_init)
+ })
+ }
+
+ ty::Tuple(_) => ty
+ .tuple_fields()
+ .enumerate()
+ .map(|(f, f_ty)| (Field::from_usize(f), f_ty, mpi))
+ .any(field_needs_drop_and_init),
+
+ _ => true,
+ }
+}
+
+fn variant_needs_drop<'tcx>(
+ tcx: TyCtxt<'tcx>,
+ param_env: ParamEnv<'tcx>,
+ substs: SubstsRef<'tcx>,
+ variant: &VariantDef,
+) -> bool {
+ variant.fields.iter().any(|field| {
+ let f_ty = field.ty(tcx, substs);
+ f_ty.needs_drop(tcx, param_env)
+ })
+}
diff --git a/compiler/rustc_mir_transform/src/remove_unneeded_drops.rs b/compiler/rustc_mir_transform/src/remove_unneeded_drops.rs
index c71bc512c31..39f78e9555e 100644
--- a/compiler/rustc_mir_transform/src/remove_unneeded_drops.rs
+++ b/compiler/rustc_mir_transform/src/remove_unneeded_drops.rs
@@ -1,4 +1,8 @@
-//! This pass replaces a drop of a type that does not need dropping, with a goto
+//! This pass replaces a drop of a type that does not need dropping, with a goto.
+//!
+//! When the MIR is built, we check `needs_drop` before emitting a `Drop` for a place. This pass is
+//! useful because (unlike MIR building) it runs after type checking, so it can make use of
+//! `Reveal::All` to provide more precies type information.
use crate::MirPass;
use rustc_middle::mir::*;
diff --git a/compiler/rustc_mir_transform/src/remove_zsts.rs b/compiler/rustc_mir_transform/src/remove_zsts.rs
index d93ffa38c69..1d912e61409 100644
--- a/compiler/rustc_mir_transform/src/remove_zsts.rs
+++ b/compiler/rustc_mir_transform/src/remove_zsts.rs
@@ -8,6 +8,10 @@ use rustc_middle::ty::{self, Ty, TyCtxt};
pub struct RemoveZsts;
impl<'tcx> MirPass<'tcx> for RemoveZsts {
+ fn is_enabled(&self, sess: &rustc_session::Session) -> bool {
+ sess.mir_opt_level() > 0
+ }
+
fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
// Avoid query cycles (generators require optimized MIR for layout).
if tcx.type_of(body.source.def_id()).is_generator() {
diff --git a/compiler/rustc_mir_transform/src/required_consts.rs b/compiler/rustc_mir_transform/src/required_consts.rs
index 8b64ad65ab3..80c87cafea1 100644
--- a/compiler/rustc_mir_transform/src/required_consts.rs
+++ b/compiler/rustc_mir_transform/src/required_consts.rs
@@ -12,7 +12,7 @@ impl<'a, 'tcx> RequiredConstsVisitor<'a, 'tcx> {
}
}
-impl<'a, 'tcx> Visitor<'tcx> for RequiredConstsVisitor<'a, 'tcx> {
+impl<'tcx> Visitor<'tcx> for RequiredConstsVisitor<'_, 'tcx> {
fn visit_constant(&mut self, constant: &Constant<'tcx>, _: Location) {
if let Some(ct) = constant.literal.const_for_ty() {
if let ConstKind::Unevaluated(_) = ct.val {
diff --git a/compiler/rustc_mir_transform/src/reveal_all.rs b/compiler/rustc_mir_transform/src/reveal_all.rs
index 6c423a2bb57..ee661793a44 100644
--- a/compiler/rustc_mir_transform/src/reveal_all.rs
+++ b/compiler/rustc_mir_transform/src/reveal_all.rs
@@ -8,15 +8,18 @@ use rustc_middle::ty::{self, Ty, TyCtxt};
pub struct RevealAll;
impl<'tcx> MirPass<'tcx> for RevealAll {
+ fn is_enabled(&self, sess: &rustc_session::Session) -> bool {
+ sess.opts.mir_opt_level() >= 3 || super::inline::Inline.is_enabled(sess)
+ }
+
fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
- // This pass must run before inlining, since we insert callee bodies in RevealAll mode.
// Do not apply this transformation to generators.
- if (tcx.sess.mir_opt_level() >= 3 || super::inline::is_enabled(tcx))
- && body.generator.is_none()
- {
- let param_env = tcx.param_env_reveal_all_normalized(body.source.def_id());
- RevealAllVisitor { tcx, param_env }.visit_body(body);
+ if body.generator.is_some() {
+ return;
}
+
+ let param_env = tcx.param_env_reveal_all_normalized(body.source.def_id());
+ RevealAllVisitor { tcx, param_env }.visit_body(body);
}
}
@@ -33,26 +36,9 @@ impl<'tcx> MutVisitor<'tcx> for RevealAllVisitor<'tcx> {
#[inline]
fn visit_ty(&mut self, ty: &mut Ty<'tcx>, _: TyContext) {
- *ty = self.tcx.normalize_erasing_regions(self.param_env, ty);
- }
-
- #[inline]
- fn process_projection_elem(
- &mut self,
- elem: PlaceElem<'tcx>,
- _: Location,
- ) -> Option<PlaceElem<'tcx>> {
- match elem {
- PlaceElem::Field(field, ty) => {
- let new_ty = self.tcx.normalize_erasing_regions(self.param_env, ty);
- if ty != new_ty { Some(PlaceElem::Field(field, new_ty)) } else { None }
- }
- // None of those contain a Ty.
- PlaceElem::Index(..)
- | PlaceElem::Deref
- | PlaceElem::ConstantIndex { .. }
- | PlaceElem::Subslice { .. }
- | PlaceElem::Downcast(..) => None,
- }
+ // We have to use `try_normalize_erasing_regions` here, since it's
+ // possible that we visit impossible-to-satisfy where clauses here,
+ // see #91745
+ *ty = self.tcx.try_normalize_erasing_regions(self.param_env, *ty).unwrap_or(ty);
}
}
diff --git a/compiler/rustc_mir_transform/src/separate_const_switch.rs b/compiler/rustc_mir_transform/src/separate_const_switch.rs
index 3002e7041b0..612fce71f91 100644
--- a/compiler/rustc_mir_transform/src/separate_const_switch.rs
+++ b/compiler/rustc_mir_transform/src/separate_const_switch.rs
@@ -45,11 +45,11 @@ use smallvec::SmallVec;
pub struct SeparateConstSwitch;
impl<'tcx> MirPass<'tcx> for SeparateConstSwitch {
- fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
- if tcx.sess.mir_opt_level() < 4 {
- return;
- }
+ fn is_enabled(&self, sess: &rustc_session::Session) -> bool {
+ sess.mir_opt_level() >= 4
+ }
+ fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
// If execution did something, applying a simplification layer
// helps later passes optimize the copy away.
if separate_const_switch(body) > 0 {
@@ -59,7 +59,7 @@ impl<'tcx> MirPass<'tcx> for SeparateConstSwitch {
}
/// Returns the amount of blocks that were duplicated
-pub fn separate_const_switch<'tcx>(body: &mut Body<'tcx>) -> usize {
+pub fn separate_const_switch(body: &mut Body<'_>) -> usize {
let mut new_blocks: SmallVec<[(BasicBlock, BasicBlock); 6]> = SmallVec::new();
let predecessors = body.predecessors();
'block_iter: for (block_id, block) in body.basic_blocks().iter_enumerated() {
diff --git a/compiler/rustc_mir_transform/src/shim.rs b/compiler/rustc_mir_transform/src/shim.rs
index f59aaa664f3..d0039380361 100644
--- a/compiler/rustc_mir_transform/src/shim.rs
+++ b/compiler/rustc_mir_transform/src/shim.rs
@@ -17,8 +17,8 @@ use std::iter;
use crate::util::expand_aggregate;
use crate::{
- abort_unwinding_calls, add_call_guards, add_moves_for_packed_drops, remove_noop_landing_pads,
- run_passes, simplify,
+ abort_unwinding_calls, add_call_guards, add_moves_for_packed_drops, marker, pass_manager as pm,
+ remove_noop_landing_pads, simplify,
};
use rustc_middle::mir::patch::MirPatch;
use rustc_mir_dataflow::elaborate_drops::{self, DropElaborator, DropFlagMode, DropStyle};
@@ -64,7 +64,19 @@ fn make_shim<'tcx>(tcx: TyCtxt<'tcx>, instance: ty::InstanceDef<'tcx>) -> Body<'
build_call_shim(tcx, instance, Some(Adjustment::RefMut), CallKind::Direct(call_mut))
}
- ty::InstanceDef::DropGlue(def_id, ty) => build_drop_shim(tcx, def_id, ty),
+
+ ty::InstanceDef::DropGlue(def_id, ty) => {
+ // FIXME(#91576): Drop shims for generators aren't subject to the MIR passes at the end
+ // of this function. Is this intentional?
+ if let Some(ty::Generator(gen_def_id, substs, _)) = ty.map(ty::TyS::kind) {
+ let body = tcx.optimized_mir(*gen_def_id).generator_drop().unwrap();
+ let body = body.clone().subst(tcx, substs);
+ debug!("make_shim({:?}) = {:?}", instance, body);
+ return body;
+ }
+
+ build_drop_shim(tcx, def_id, ty)
+ }
ty::InstanceDef::CloneShim(def_id, ty) => build_clone_shim(tcx, def_id, ty),
ty::InstanceDef::Virtual(..) => {
bug!("InstanceDef::Virtual ({:?}) is for direct calls only", instance)
@@ -75,17 +87,17 @@ fn make_shim<'tcx>(tcx: TyCtxt<'tcx>, instance: ty::InstanceDef<'tcx>) -> Body<'
};
debug!("make_shim({:?}) = untransformed {:?}", instance, result);
- run_passes(
+ pm::run_passes(
tcx,
&mut result,
- MirPhase::Const,
- &[&[
+ &[
&add_moves_for_packed_drops::AddMovesForPackedDrops,
&remove_noop_landing_pads::RemoveNoopLandingPads,
&simplify::SimplifyCfg::new("make_shim"),
&add_call_guards::CriticalCallEdges,
&abort_unwinding_calls::AbortUnwindingCalls,
- ]],
+ &marker::PhaseChange(MirPhase::Const),
+ ],
);
debug!("make_shim({:?}) = {:?}", instance, result);
@@ -132,11 +144,7 @@ fn local_decls_for_sig<'tcx>(
fn build_drop_shim<'tcx>(tcx: TyCtxt<'tcx>, def_id: DefId, ty: Option<Ty<'tcx>>) -> Body<'tcx> {
debug!("build_drop_shim(def_id={:?}, ty={:?})", def_id, ty);
- // Check if this is a generator, if so, return the drop glue for it
- if let Some(&ty::Generator(gen_def_id, substs, _)) = ty.map(|ty| ty.kind()) {
- let body = tcx.optimized_mir(gen_def_id).generator_drop().unwrap();
- return body.clone().subst(tcx, substs);
- }
+ assert!(!matches!(ty, Some(ty) if ty.is_generator()));
let substs = if let Some(ty) = ty {
tcx.intern_substs(&[ty.into()])
@@ -239,7 +247,7 @@ pub struct DropShimElaborator<'a, 'tcx> {
pub param_env: ty::ParamEnv<'tcx>,
}
-impl<'a, 'tcx> fmt::Debug for DropShimElaborator<'a, 'tcx> {
+impl fmt::Debug for DropShimElaborator<'_, '_> {
fn fmt(&self, _f: &mut fmt::Formatter<'_>) -> Result<(), fmt::Error> {
Ok(())
}
@@ -329,7 +337,7 @@ struct CloneShimBuilder<'tcx> {
sig: ty::FnSig<'tcx>,
}
-impl CloneShimBuilder<'tcx> {
+impl<'tcx> CloneShimBuilder<'tcx> {
fn new(tcx: TyCtxt<'tcx>, def_id: DefId, self_ty: Ty<'tcx>) -> Self {
// we must subst the self_ty because it's
// otherwise going to be TySelf and we can't index
diff --git a/compiler/rustc_mir_transform/src/simplify.rs b/compiler/rustc_mir_transform/src/simplify.rs
index d6cd505cbb5..7992124bacd 100644
--- a/compiler/rustc_mir_transform/src/simplify.rs
+++ b/compiler/rustc_mir_transform/src/simplify.rs
@@ -47,7 +47,7 @@ impl SimplifyCfg {
}
}
-pub fn simplify_cfg(tcx: TyCtxt<'tcx>, body: &mut Body<'_>) {
+pub fn simplify_cfg<'tcx>(tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
CfgSimplifier::new(body).simplify();
remove_dead_blocks(tcx, body);
@@ -262,7 +262,7 @@ impl<'a, 'tcx> CfgSimplifier<'a, 'tcx> {
}
}
-pub fn remove_dead_blocks(tcx: TyCtxt<'tcx>, body: &mut Body<'_>) {
+pub fn remove_dead_blocks<'tcx>(tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
let reachable = traversal::reachable_as_bitset(body);
let num_blocks = body.basic_blocks().len();
if num_blocks == reachable.count() {
@@ -368,6 +368,10 @@ fn save_unreachable_coverage(
pub struct SimplifyLocals;
impl<'tcx> MirPass<'tcx> for SimplifyLocals {
+ fn is_enabled(&self, sess: &rustc_session::Session) -> bool {
+ sess.mir_opt_level() > 0
+ }
+
fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
trace!("running SimplifyLocals on {:?}", body.source);
simplify_locals(body, tcx);
@@ -450,7 +454,7 @@ impl UsedLocals {
}
/// Updates the use counts to reflect the removal of given statement.
- fn statement_removed(&mut self, statement: &Statement<'tcx>) {
+ fn statement_removed(&mut self, statement: &Statement<'_>) {
self.increment = false;
// The location of the statement is irrelevant.
@@ -459,7 +463,7 @@ impl UsedLocals {
}
/// Visits a left-hand side of an assignment.
- fn visit_lhs(&mut self, place: &Place<'tcx>, location: Location) {
+ fn visit_lhs(&mut self, place: &Place<'_>, location: Location) {
if place.is_indirect() {
// A use, not a definition.
self.visit_place(place, PlaceContext::MutatingUse(MutatingUseContext::Store), location);
@@ -476,7 +480,7 @@ impl UsedLocals {
}
}
-impl Visitor<'_> for UsedLocals {
+impl<'tcx> Visitor<'tcx> for UsedLocals {
fn visit_statement(&mut self, statement: &Statement<'tcx>, location: Location) {
match statement.kind {
StatementKind::LlvmInlineAsm(..)
@@ -514,7 +518,7 @@ impl Visitor<'_> for UsedLocals {
}
/// Removes unused definitions. Updates the used locals to reflect the changes made.
-fn remove_unused_definitions<'a, 'tcx>(used_locals: &'a mut UsedLocals, body: &mut Body<'tcx>) {
+fn remove_unused_definitions(used_locals: &mut UsedLocals, body: &mut Body<'_>) {
// The use counts are updated as we remove the statements. A local might become unused
// during the retain operation, leading to a temporary inconsistency (storage statements or
// definitions referencing the local might remain). For correctness it is crucial that this
diff --git a/compiler/rustc_mir_transform/src/simplify_branches.rs b/compiler/rustc_mir_transform/src/simplify_branches.rs
index df90cfa318d..3bbae5b8976 100644
--- a/compiler/rustc_mir_transform/src/simplify_branches.rs
+++ b/compiler/rustc_mir_transform/src/simplify_branches.rs
@@ -1,22 +1,21 @@
-//! A pass that simplifies branches when their condition is known.
-
use crate::MirPass;
use rustc_middle::mir::*;
use rustc_middle::ty::TyCtxt;
use std::borrow::Cow;
-pub struct SimplifyBranches {
+/// A pass that replaces a branch with a goto when its condition is known.
+pub struct SimplifyConstCondition {
label: String,
}
-impl SimplifyBranches {
+impl SimplifyConstCondition {
pub fn new(label: &str) -> Self {
- SimplifyBranches { label: format!("SimplifyBranches-{}", label) }
+ SimplifyConstCondition { label: format!("SimplifyConstCondition-{}", label) }
}
}
-impl<'tcx> MirPass<'tcx> for SimplifyBranches {
+impl<'tcx> MirPass<'tcx> for SimplifyConstCondition {
fn name(&self) -> Cow<'_, str> {
Cow::Borrowed(&self.label)
}
@@ -34,15 +33,8 @@ impl<'tcx> MirPass<'tcx> for SimplifyBranches {
} => {
let constant = c.literal.try_eval_bits(tcx, param_env, switch_ty);
if let Some(constant) = constant {
- let otherwise = targets.otherwise();
- let mut ret = TerminatorKind::Goto { target: otherwise };
- for (v, t) in targets.iter() {
- if v == constant {
- ret = TerminatorKind::Goto { target: t };
- break;
- }
- }
- ret
+ let target = targets.target_for_value(constant);
+ TerminatorKind::Goto { target }
} else {
continue;
}
@@ -53,12 +45,6 @@ impl<'tcx> MirPass<'tcx> for SimplifyBranches {
Some(v) if v == expected => TerminatorKind::Goto { target },
_ => continue,
},
- TerminatorKind::FalseEdge { real_target, .. } => {
- TerminatorKind::Goto { target: real_target }
- }
- TerminatorKind::FalseUnwind { real_target, .. } => {
- TerminatorKind::Goto { target: real_target }
- }
_ => continue,
};
}
diff --git a/compiler/rustc_mir_transform/src/simplify_comparison_integral.rs b/compiler/rustc_mir_transform/src/simplify_comparison_integral.rs
index 948fcd9f455..da683a33651 100644
--- a/compiler/rustc_mir_transform/src/simplify_comparison_integral.rs
+++ b/compiler/rustc_mir_transform/src/simplify_comparison_integral.rs
@@ -26,6 +26,10 @@ use rustc_middle::{
pub struct SimplifyComparisonIntegral;
impl<'tcx> MirPass<'tcx> for SimplifyComparisonIntegral {
+ fn is_enabled(&self, sess: &rustc_session::Session) -> bool {
+ sess.mir_opt_level() > 0
+ }
+
fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
trace!("Running SimplifyComparisonIntegral on {:?}", body.source);
@@ -144,7 +148,7 @@ struct OptimizationFinder<'a, 'tcx> {
body: &'a Body<'tcx>,
}
-impl<'a, 'tcx> OptimizationFinder<'a, 'tcx> {
+impl<'tcx> OptimizationFinder<'_, 'tcx> {
fn find_optimizations(&self) -> Vec<OptimizationInfo<'tcx>> {
self.body
.basic_blocks()
diff --git a/compiler/rustc_mir_transform/src/simplify_try.rs b/compiler/rustc_mir_transform/src/simplify_try.rs
index e436d73226a..7761d4006d3 100644
--- a/compiler/rustc_mir_transform/src/simplify_try.rs
+++ b/compiler/rustc_mir_transform/src/simplify_try.rs
@@ -102,7 +102,7 @@ fn get_arm_identity_info<'a, 'tcx>(
type StmtIter<'a, 'tcx> = Peekable<Enumerate<Iter<'a, Statement<'tcx>>>>;
- fn is_storage_stmt<'tcx>(stmt: &Statement<'tcx>) -> bool {
+ fn is_storage_stmt(stmt: &Statement<'_>) -> bool {
matches!(stmt.kind, StatementKind::StorageLive(_) | StatementKind::StorageDead(_))
}
@@ -122,8 +122,8 @@ fn get_arm_identity_info<'a, 'tcx>(
/// Eats consecutive `StorageLive` and `StorageDead` Statements.
/// The iterator `stmt_iter` is not advanced if none were found.
- fn try_eat_storage_stmts<'a, 'tcx>(
- stmt_iter: &mut StmtIter<'a, 'tcx>,
+ fn try_eat_storage_stmts(
+ stmt_iter: &mut StmtIter<'_, '_>,
storage_live_stmts: &mut Vec<(usize, Local)>,
storage_dead_stmts: &mut Vec<(usize, Local)>,
) {
@@ -136,7 +136,7 @@ fn get_arm_identity_info<'a, 'tcx>(
})
}
- fn is_tmp_storage_stmt<'tcx>(stmt: &Statement<'tcx>) -> bool {
+ fn is_tmp_storage_stmt(stmt: &Statement<'_>) -> bool {
use rustc_middle::mir::StatementKind::Assign;
if let Assign(box (place, Rvalue::Use(Operand::Copy(p) | Operand::Move(p)))) = &stmt.kind {
place.as_local().is_some() && p.as_local().is_some()
@@ -147,8 +147,8 @@ fn get_arm_identity_info<'a, 'tcx>(
/// Eats consecutive `Assign` Statements.
// The iterator `stmt_iter` is not advanced if none were found.
- fn try_eat_assign_tmp_stmts<'a, 'tcx>(
- stmt_iter: &mut StmtIter<'a, 'tcx>,
+ fn try_eat_assign_tmp_stmts(
+ stmt_iter: &mut StmtIter<'_, '_>,
tmp_assigns: &mut Vec<(Local, Local)>,
nop_stmts: &mut Vec<usize>,
) {
@@ -163,9 +163,9 @@ fn get_arm_identity_info<'a, 'tcx>(
})
}
- fn find_storage_live_dead_stmts_for_local<'tcx>(
+ fn find_storage_live_dead_stmts_for_local(
local: Local,
- stmts: &[Statement<'tcx>],
+ stmts: &[Statement<'_>],
) -> Option<(usize, usize)> {
trace!("looking for {:?}", local);
let mut storage_live_stmt = None;
@@ -452,14 +452,14 @@ struct LocalUseCounter {
}
impl LocalUseCounter {
- fn get_local_uses<'tcx>(body: &Body<'tcx>) -> IndexVec<Local, usize> {
+ fn get_local_uses(body: &Body<'_>) -> IndexVec<Local, usize> {
let mut counter = LocalUseCounter { local_uses: IndexVec::from_elem(0, &body.local_decls) };
counter.visit_body(body);
counter.local_uses
}
}
-impl<'tcx> Visitor<'tcx> for LocalUseCounter {
+impl Visitor<'_> for LocalUseCounter {
fn visit_local(&mut self, local: &Local, context: PlaceContext, _location: Location) {
if context.is_storage_marker()
|| context == PlaceContext::NonUse(NonUseContext::VarDebugInfo)
@@ -510,7 +510,7 @@ fn match_set_variant_field<'tcx>(stmt: &Statement<'tcx>) -> Option<(Local, Local
/// ```rust
/// discriminant(_LOCAL_TO_SET) = VAR_IDX;
/// ```
-fn match_set_discr<'tcx>(stmt: &Statement<'tcx>) -> Option<(Local, VariantIdx)> {
+fn match_set_discr(stmt: &Statement<'_>) -> Option<(Local, VariantIdx)> {
match &stmt.kind {
StatementKind::SetDiscriminant { place, variant_index } => {
Some((place.as_local()?, *variant_index))
@@ -588,7 +588,7 @@ struct SimplifyBranchSameOptimizationFinder<'a, 'tcx> {
tcx: TyCtxt<'tcx>,
}
-impl<'a, 'tcx> SimplifyBranchSameOptimizationFinder<'a, 'tcx> {
+impl<'tcx> SimplifyBranchSameOptimizationFinder<'_, 'tcx> {
fn find(&self) -> Vec<SimplifyBranchSameOptimization> {
self.body
.basic_blocks()
diff --git a/compiler/rustc_mir_transform/src/uninhabited_enum_branching.rs b/compiler/rustc_mir_transform/src/uninhabited_enum_branching.rs
index 2aa50611290..77bc209539b 100644
--- a/compiler/rustc_mir_transform/src/uninhabited_enum_branching.rs
+++ b/compiler/rustc_mir_transform/src/uninhabited_enum_branching.rs
@@ -70,6 +70,10 @@ fn variant_discriminants<'tcx>(
}
impl<'tcx> MirPass<'tcx> for UninhabitedEnumBranching {
+ fn is_enabled(&self, sess: &rustc_session::Session) -> bool {
+ sess.mir_opt_level() > 0
+ }
+
fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
if body.source.promoted.is_some() {
return;
diff --git a/compiler/rustc_mir_transform/src/unreachable_prop.rs b/compiler/rustc_mir_transform/src/unreachable_prop.rs
index 64cd6f56a9f..9e755ab141a 100644
--- a/compiler/rustc_mir_transform/src/unreachable_prop.rs
+++ b/compiler/rustc_mir_transform/src/unreachable_prop.rs
@@ -11,13 +11,13 @@ use rustc_middle::ty::TyCtxt;
pub struct UnreachablePropagation;
impl MirPass<'_> for UnreachablePropagation {
- fn run_pass<'tcx>(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
- if tcx.sess.mir_opt_level() < 4 {
- // Enable only under -Zmir-opt-level=4 as in some cases (check the deeply-nested-opt
- // perf benchmark) LLVM may spend quite a lot of time optimizing the generated code.
- return;
- }
+ fn is_enabled(&self, sess: &rustc_session::Session) -> bool {
+ // Enable only under -Zmir-opt-level=4 as in some cases (check the deeply-nested-opt
+ // perf benchmark) LLVM may spend quite a lot of time optimizing the generated code.
+ sess.mir_opt_level() >= 4
+ }
+ fn run_pass<'tcx>(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
let mut unreachable_blocks = FxHashSet::default();
let mut replacements = FxHashMap::default();
@@ -64,7 +64,7 @@ impl MirPass<'_> for UnreachablePropagation {
}
}
-fn remove_successors<F>(
+fn remove_successors<'tcx, F>(
terminator_kind: &TerminatorKind<'tcx>,
predicate: F,
) -> Option<TerminatorKind<'tcx>>
diff --git a/compiler/rustc_parse/src/lexer/mod.rs b/compiler/rustc_parse/src/lexer/mod.rs
index cf35c3cd53b..1a620968d56 100644
--- a/compiler/rustc_parse/src/lexer/mod.rs
+++ b/compiler/rustc_parse/src/lexer/mod.rs
@@ -1,3 +1,4 @@
+use crate::lexer::unicode_chars::UNICODE_ARRAY;
use rustc_ast::ast::{self, AttrStyle};
use rustc_ast::token::{self, CommentKind, Token, TokenKind};
use rustc_ast::tokenstream::{Spacing, TokenStream};
@@ -222,6 +223,22 @@ impl<'a> StringReader<'a> {
}
token::Ident(sym, is_raw_ident)
}
+ rustc_lexer::TokenKind::InvalidIdent
+ // Do not recover an identifier with emoji if the codepoint is a confusable
+ // with a recoverable substitution token, like `➖`.
+ if UNICODE_ARRAY
+ .iter()
+ .find(|&&(c, _, _)| {
+ let sym = self.str_from(start);
+ sym.chars().count() == 1 && c == sym.chars().next().unwrap()
+ })
+ .is_none() =>
+ {
+ let sym = nfc_normalize(self.str_from(start));
+ let span = self.mk_sp(start, self.pos);
+ self.sess.bad_unicode_identifiers.borrow_mut().entry(sym).or_default().push(span);
+ token::Ident(sym, false)
+ }
rustc_lexer::TokenKind::Literal { kind, suffix_start } => {
let suffix_start = start + BytePos(suffix_start as u32);
let (kind, symbol) = self.cook_lexer_literal(start, suffix_start, kind);
@@ -293,7 +310,7 @@ impl<'a> StringReader<'a> {
rustc_lexer::TokenKind::Caret => token::BinOp(token::Caret),
rustc_lexer::TokenKind::Percent => token::BinOp(token::Percent),
- rustc_lexer::TokenKind::Unknown => {
+ rustc_lexer::TokenKind::Unknown | rustc_lexer::TokenKind::InvalidIdent => {
let c = self.str_from(start).chars().next().unwrap();
let mut err =
self.struct_fatal_span_char(start, self.pos, "unknown start of token", c);
diff --git a/compiler/rustc_parse/src/lexer/unicode_chars.rs b/compiler/rustc_parse/src/lexer/unicode_chars.rs
index 3eebc088f3f..ccd11f06bc5 100644
--- a/compiler/rustc_parse/src/lexer/unicode_chars.rs
+++ b/compiler/rustc_parse/src/lexer/unicode_chars.rs
@@ -7,7 +7,7 @@ use rustc_errors::{Applicability, DiagnosticBuilder};
use rustc_span::{symbol::kw, BytePos, Pos, Span};
#[rustfmt::skip] // for line breaks
-const UNICODE_ARRAY: &[(char, &str, char)] = &[
+pub(crate) const UNICODE_ARRAY: &[(char, &str, char)] = &[
('
', "Line Separator", ' '),
('
', "Paragraph Separator", ' '),
(' ', "Ogham Space mark", ' '),
diff --git a/compiler/rustc_parse/src/lib.rs b/compiler/rustc_parse/src/lib.rs
index a40f47f895b..2b1b2f3fce4 100644
--- a/compiler/rustc_parse/src/lib.rs
+++ b/compiler/rustc_parse/src/lib.rs
@@ -326,6 +326,12 @@ pub fn fake_token_stream(sess: &ParseSess, nt: &Nonterminal) -> TokenStream {
parse_stream_from_source_str(filename, source, sess, Some(nt.span()))
}
+pub fn fake_token_stream_for_crate(sess: &ParseSess, krate: &ast::Crate) -> TokenStream {
+ let source = pprust::crate_to_string_for_macros(krate);
+ let filename = FileName::macro_expansion_source_code(&source);
+ parse_stream_from_source_str(filename, source, sess, Some(krate.span))
+}
+
pub fn parse_cfg_attr(
attr: &Attribute,
parse_sess: &ParseSess,
diff --git a/compiler/rustc_parse/src/parser/attr.rs b/compiler/rustc_parse/src/parser/attr.rs
index b402b8ba53a..ca92d6b7fd0 100644
--- a/compiler/rustc_parse/src/parser/attr.rs
+++ b/compiler/rustc_parse/src/parser/attr.rs
@@ -1,4 +1,4 @@
-use super::{AttrWrapper, Capturing, ForceCollect, Parser, PathStyle};
+use super::{AttrWrapper, Capturing, FnParseMode, ForceCollect, Parser, PathStyle};
use rustc_ast as ast;
use rustc_ast::attr;
use rustc_ast::token::{self, Nonterminal};
@@ -177,7 +177,7 @@ impl<'a> Parser<'a> {
AttrWrapper::empty(),
true,
false,
- |_| true,
+ FnParseMode { req_name: |_| true, req_body: true },
ForceCollect::No,
) {
Ok(Some(item)) => {
diff --git a/compiler/rustc_parse/src/parser/diagnostics.rs b/compiler/rustc_parse/src/parser/diagnostics.rs
index 81328e09156..9677e7642b8 100644
--- a/compiler/rustc_parse/src/parser/diagnostics.rs
+++ b/compiler/rustc_parse/src/parser/diagnostics.rs
@@ -1,14 +1,19 @@
+use super::pat::Expected;
use super::ty::AllowPlus;
-use super::TokenType;
-use super::{BlockMode, Parser, PathStyle, Restrictions, SemiColonMode, SeqSep, TokenExpectType};
+use super::{
+ BlockMode, Parser, PathStyle, RecoverColon, RecoverComma, Restrictions, SemiColonMode, SeqSep,
+ TokenExpectType, TokenType,
+};
use rustc_ast as ast;
use rustc_ast::ptr::P;
use rustc_ast::token::{self, Lit, LitKind, TokenKind};
use rustc_ast::util::parser::AssocOp;
-use rustc_ast::{AngleBracketedArg, AngleBracketedArgs, AnonConst, AttrVec};
-use rustc_ast::{BinOpKind, BindingMode, Block, BlockCheckMode, Expr, ExprKind, GenericArg, Item};
-use rustc_ast::{ItemKind, Mutability, Param, Pat, PatKind, Path, PathSegment, QSelf, Ty, TyKind};
+use rustc_ast::{
+ AngleBracketedArg, AngleBracketedArgs, AnonConst, AttrVec, BinOpKind, BindingMode, Block,
+ BlockCheckMode, Expr, ExprKind, GenericArg, Generics, Item, ItemKind, Mutability, Param, Pat,
+ PatKind, Path, PathSegment, QSelf, Ty, TyKind,
+};
use rustc_ast_pretty::pprust;
use rustc_data_structures::fx::FxHashSet;
use rustc_errors::{pluralize, struct_span_err};
@@ -17,6 +22,8 @@ use rustc_span::source_map::Spanned;
use rustc_span::symbol::{kw, Ident};
use rustc_span::{MultiSpan, Span, SpanSnippetError, DUMMY_SP};
+use std::mem::take;
+
use tracing::{debug, trace};
const TURBOFISH_SUGGESTION_STR: &str =
@@ -299,7 +306,7 @@ impl<'a> Parser<'a> {
}
}
- let expect = tokens_to_string(&expected[..]);
+ let expect = tokens_to_string(&expected);
let actual = super::token_descr(&self.token);
let (msg_exp, (label_sp, label_exp)) = if expected.len() > 1 {
let short_expect = if expected.len() > 6 {
@@ -662,7 +669,7 @@ impl<'a> Parser<'a> {
let snapshot = self.clone();
self.bump();
let lo = self.token.span;
- match self.parse_angle_args() {
+ match self.parse_angle_args(None) {
Ok(args) => {
let span = lo.to(self.prev_token.span);
// Detect trailing `>` like in `x.collect::Vec<_>>()`.
@@ -719,7 +726,7 @@ impl<'a> Parser<'a> {
let x = self.parse_seq_to_before_end(
&token::Gt,
SeqSep::trailing_allowed(token::Comma),
- |p| p.parse_generic_arg(),
+ |p| p.parse_generic_arg(None),
);
match x {
Ok((_, _, false)) => {
@@ -902,7 +909,7 @@ impl<'a> Parser<'a> {
// So far we have parsed `foo<bar<`, consume the rest of the type args.
let modifiers =
[(token::Lt, 1), (token::Gt, -1), (token::BinOp(token::Shr), -2)];
- self.consume_tts(1, &modifiers[..]);
+ self.consume_tts(1, &modifiers);
if !&[token::OpenDelim(token::Paren), token::ModSep]
.contains(&self.token.kind)
@@ -994,7 +1001,7 @@ impl<'a> Parser<'a> {
// Consume the fn call arguments.
let modifiers =
[(token::OpenDelim(token::Paren), 1), (token::CloseDelim(token::Paren), -1)];
- self.consume_tts(1, &modifiers[..]);
+ self.consume_tts(1, &modifiers);
if self.token.kind == token::Eof {
// Not entirely sure that what we consumed were fn arguments, rollback.
@@ -1103,7 +1110,7 @@ impl<'a> Parser<'a> {
self.expect(&token::ModSep)?;
let mut path = ast::Path { segments: Vec::new(), span: DUMMY_SP, tokens: None };
- self.parse_path_segments(&mut path.segments, T::PATH_STYLE)?;
+ self.parse_path_segments(&mut path.segments, T::PATH_STYLE, None)?;
path.span = ty_span.to(self.prev_token.span);
let ty_str = self.span_to_snippet(ty_span).unwrap_or_else(|_| pprust::ty_to_string(&ty));
@@ -1121,8 +1128,9 @@ impl<'a> Parser<'a> {
Ok(P(T::recovered(Some(QSelf { ty, path_span, position: 0 }), path)))
}
- pub(super) fn maybe_consume_incorrect_semicolon(&mut self, items: &[P<Item>]) -> bool {
- if self.eat(&token::Semi) {
+ pub fn maybe_consume_incorrect_semicolon(&mut self, items: &[P<Item>]) -> bool {
+ if self.token.kind == TokenKind::Semi {
+ self.bump();
let mut err = self.struct_span_err(self.prev_token.span, "expected item, found `;`");
err.span_suggestion_short(
self.prev_token.span,
@@ -1909,6 +1917,71 @@ impl<'a> Parser<'a> {
Ok(expr)
}
+ fn recover_const_param_decl(
+ &mut self,
+ ty_generics: Option<&Generics>,
+ ) -> PResult<'a, Option<GenericArg>> {
+ let snapshot = self.clone();
+ let param = match self.parse_const_param(vec![]) {
+ Ok(param) => param,
+ Err(mut err) => {
+ err.cancel();
+ *self = snapshot;
+ return Err(err);
+ }
+ };
+ let mut err =
+ self.struct_span_err(param.span(), "unexpected `const` parameter declaration");
+ err.span_label(param.span(), "expected a `const` expression, not a parameter declaration");
+ if let (Some(generics), Ok(snippet)) =
+ (ty_generics, self.sess.source_map().span_to_snippet(param.span()))
+ {
+ let (span, sugg) = match &generics.params[..] {
+ [] => (generics.span, format!("<{}>", snippet)),
+ [.., generic] => (generic.span().shrink_to_hi(), format!(", {}", snippet)),
+ };
+ err.multipart_suggestion(
+ "`const` parameters must be declared for the `impl`",
+ vec![(span, sugg), (param.span(), param.ident.to_string())],
+ Applicability::MachineApplicable,
+ );
+ }
+ let value = self.mk_expr_err(param.span());
+ err.emit();
+ return Ok(Some(GenericArg::Const(AnonConst { id: ast::DUMMY_NODE_ID, value })));
+ }
+
+ pub fn recover_const_param_declaration(
+ &mut self,
+ ty_generics: Option<&Generics>,
+ ) -> PResult<'a, Option<GenericArg>> {
+ // We have to check for a few different cases.
+ if let Ok(arg) = self.recover_const_param_decl(ty_generics) {
+ return Ok(arg);
+ }
+
+ // We haven't consumed `const` yet.
+ let start = self.token.span;
+ self.bump(); // `const`
+
+ // Detect and recover from the old, pre-RFC2000 syntax for const generics.
+ let mut err = self
+ .struct_span_err(start, "expected lifetime, type, or constant, found keyword `const`");
+ if self.check_const_arg() {
+ err.span_suggestion_verbose(
+ start.until(self.token.span),
+ "the `const` keyword is only needed in the definition of the type",
+ String::new(),
+ Applicability::MaybeIncorrect,
+ );
+ err.emit();
+ Ok(Some(GenericArg::Const(self.parse_const_arg()?)))
+ } else {
+ let after_kw_const = self.token.span;
+ self.recover_const_arg(after_kw_const, err).map(Some)
+ }
+ }
+
/// Try to recover from possible generic const argument without `{` and `}`.
///
/// When encountering code like `foo::< bar + 3 >` or `foo::< bar - baz >` we suggest
@@ -2008,4 +2081,177 @@ impl<'a> Parser<'a> {
);
err
}
+
+ /// Some special error handling for the "top-level" patterns in a match arm,
+ /// `for` loop, `let`, &c. (in contrast to subpatterns within such).
+ crate fn maybe_recover_colon_colon_in_pat_typo(
+ &mut self,
+ mut first_pat: P<Pat>,
+ ra: RecoverColon,
+ expected: Expected,
+ ) -> P<Pat> {
+ if RecoverColon::Yes != ra || token::Colon != self.token.kind {
+ return first_pat;
+ }
+ if !matches!(first_pat.kind, PatKind::Ident(_, _, None) | PatKind::Path(..))
+ || !self.look_ahead(1, |token| token.is_ident() && !token.is_reserved_ident())
+ {
+ return first_pat;
+ }
+ // The pattern looks like it might be a path with a `::` -> `:` typo:
+ // `match foo { bar:baz => {} }`
+ let span = self.token.span;
+ // We only emit "unexpected `:`" error here if we can successfully parse the
+ // whole pattern correctly in that case.
+ let snapshot = self.clone();
+
+ // Create error for "unexpected `:`".
+ match self.expected_one_of_not_found(&[], &[]) {
+ Err(mut err) => {
+ self.bump(); // Skip the `:`.
+ match self.parse_pat_no_top_alt(expected) {
+ Err(mut inner_err) => {
+ // Carry on as if we had not done anything, callers will emit a
+ // reasonable error.
+ inner_err.cancel();
+ err.cancel();
+ *self = snapshot;
+ }
+ Ok(mut pat) => {
+ // We've parsed the rest of the pattern.
+ let new_span = first_pat.span.to(pat.span);
+ let mut show_sugg = false;
+ // Try to construct a recovered pattern.
+ match &mut pat.kind {
+ PatKind::Struct(qself @ None, path, ..)
+ | PatKind::TupleStruct(qself @ None, path, _)
+ | PatKind::Path(qself @ None, path) => match &first_pat.kind {
+ PatKind::Ident(_, ident, _) => {
+ path.segments.insert(0, PathSegment::from_ident(ident.clone()));
+ path.span = new_span;
+ show_sugg = true;
+ first_pat = pat;
+ }
+ PatKind::Path(old_qself, old_path) => {
+ path.segments = old_path
+ .segments
+ .iter()
+ .cloned()
+ .chain(take(&mut path.segments))
+ .collect();
+ path.span = new_span;
+ *qself = old_qself.clone();
+ first_pat = pat;
+ show_sugg = true;
+ }
+ _ => {}
+ },
+ PatKind::Ident(BindingMode::ByValue(Mutability::Not), ident, None) => {
+ match &first_pat.kind {
+ PatKind::Ident(_, old_ident, _) => {
+ let path = PatKind::Path(
+ None,
+ Path {
+ span: new_span,
+ segments: vec![
+ PathSegment::from_ident(old_ident.clone()),
+ PathSegment::from_ident(ident.clone()),
+ ],
+ tokens: None,
+ },
+ );
+ first_pat = self.mk_pat(new_span, path);
+ show_sugg = true;
+ }
+ PatKind::Path(old_qself, old_path) => {
+ let mut segments = old_path.segments.clone();
+ segments.push(PathSegment::from_ident(ident.clone()));
+ let path = PatKind::Path(
+ old_qself.clone(),
+ Path { span: new_span, segments, tokens: None },
+ );
+ first_pat = self.mk_pat(new_span, path);
+ show_sugg = true;
+ }
+ _ => {}
+ }
+ }
+ _ => {}
+ }
+ if show_sugg {
+ err.span_suggestion(
+ span,
+ "maybe write a path separator here",
+ "::".to_string(),
+ Applicability::MaybeIncorrect,
+ );
+ } else {
+ first_pat = self.mk_pat(new_span, PatKind::Wild);
+ }
+ err.emit();
+ }
+ }
+ }
+ _ => {
+ // Carry on as if we had not done anything. This should be unreachable.
+ *self = snapshot;
+ }
+ };
+ first_pat
+ }
+
+ /// Some special error handling for the "top-level" patterns in a match arm,
+ /// `for` loop, `let`, &c. (in contrast to subpatterns within such).
+ crate fn maybe_recover_unexpected_comma(
+ &mut self,
+ lo: Span,
+ rc: RecoverComma,
+ ) -> PResult<'a, ()> {
+ if rc == RecoverComma::No || self.token != token::Comma {
+ return Ok(());
+ }
+
+ // An unexpected comma after a top-level pattern is a clue that the
+ // user (perhaps more accustomed to some other language) forgot the
+ // parentheses in what should have been a tuple pattern; return a
+ // suggestion-enhanced error here rather than choking on the comma later.
+ let comma_span = self.token.span;
+ self.bump();
+ if let Err(mut err) = self.skip_pat_list() {
+ // We didn't expect this to work anyway; we just wanted to advance to the
+ // end of the comma-sequence so we know the span to suggest parenthesizing.
+ err.cancel();
+ }
+ let seq_span = lo.to(self.prev_token.span);
+ let mut err = self.struct_span_err(comma_span, "unexpected `,` in pattern");
+ if let Ok(seq_snippet) = self.span_to_snippet(seq_span) {
+ const MSG: &str = "try adding parentheses to match on a tuple...";
+
+ err.span_suggestion(
+ seq_span,
+ MSG,
+ format!("({})", seq_snippet),
+ Applicability::MachineApplicable,
+ );
+ err.span_suggestion(
+ seq_span,
+ "...or a vertical bar to match on multiple alternatives",
+ seq_snippet.replace(',', " |"),
+ Applicability::MachineApplicable,
+ );
+ }
+ Err(err)
+ }
+
+ /// Parse and throw away a parenthesized comma separated
+ /// sequence of patterns until `)` is reached.
+ fn skip_pat_list(&mut self) -> PResult<'a, ()> {
+ while !self.check(&token::CloseDelim(token::Paren)) {
+ self.parse_pat_no_top_alt(None)?;
+ if !self.eat(&token::Comma) {
+ return Ok(());
+ }
+ }
+ Ok(())
+ }
}
diff --git a/compiler/rustc_parse/src/parser/expr.rs b/compiler/rustc_parse/src/parser/expr.rs
index 0c8c45410bd..ddb4f2dc25d 100644
--- a/compiler/rustc_parse/src/parser/expr.rs
+++ b/compiler/rustc_parse/src/parser/expr.rs
@@ -213,11 +213,11 @@ impl<'a> Parser<'a> {
}
}
+ // Look for JS' `===` and `!==` and recover
if (op.node == AssocOp::Equal || op.node == AssocOp::NotEqual)
&& self.token.kind == token::Eq
&& self.prev_token.span.hi() == self.token.span.lo()
{
- // Look for JS' `===` and `!==` and recover 😇
let sp = op.span.to(self.token.span);
let sugg = match op.node {
AssocOp::Equal => "==",
@@ -235,6 +235,38 @@ impl<'a> Parser<'a> {
self.bump();
}
+ // Look for PHP's `<>` and recover
+ if op.node == AssocOp::Less
+ && self.token.kind == token::Gt
+ && self.prev_token.span.hi() == self.token.span.lo()
+ {
+ let sp = op.span.to(self.token.span);
+ self.struct_span_err(sp, "invalid comparison operator `<>`")
+ .span_suggestion_short(
+ sp,
+ "`<>` is not a valid comparison operator, use `!=`",
+ "!=".to_string(),
+ Applicability::MachineApplicable,
+ )
+ .emit();
+ self.bump();
+ }
+
+ // Look for C++'s `<=>` and recover
+ if op.node == AssocOp::LessEqual
+ && self.token.kind == token::Gt
+ && self.prev_token.span.hi() == self.token.span.lo()
+ {
+ let sp = op.span.to(self.token.span);
+ self.struct_span_err(sp, "invalid comparison operator `<=>`")
+ .span_label(
+ sp,
+ "`<=>` is not a valid comparison operator, use `std::cmp::Ordering`",
+ )
+ .emit();
+ self.bump();
+ }
+
let op = op.node;
// Special cases:
if op == AssocOp::As {
@@ -1100,30 +1132,37 @@ impl<'a> Parser<'a> {
snapshot.bump(); // `(`
match snapshot.parse_struct_fields(path, false, token::Paren) {
Ok((fields, ..)) if snapshot.eat(&token::CloseDelim(token::Paren)) => {
- // We have are certain we have `Enum::Foo(a: 3, b: 4)`, suggest
+ // We are certain we have `Enum::Foo(a: 3, b: 4)`, suggest
// `Enum::Foo { a: 3, b: 4 }` or `Enum::Foo(3, 4)`.
*self = snapshot;
let close_paren = self.prev_token.span;
let span = lo.to(self.prev_token.span);
- err.cancel();
- self.struct_span_err(
- span,
- "invalid `struct` delimiters or `fn` call arguments",
- )
- .multipart_suggestion(
- &format!("if `{}` is a struct, use braces as delimiters", name),
- vec![(open_paren, " { ".to_string()), (close_paren, " }".to_string())],
- Applicability::MaybeIncorrect,
- )
- .multipart_suggestion(
- &format!("if `{}` is a function, use the arguments directly", name),
- fields
- .into_iter()
- .map(|field| (field.span.until(field.expr.span), String::new()))
- .collect(),
- Applicability::MaybeIncorrect,
- )
- .emit();
+ if !fields.is_empty() {
+ err.cancel();
+ let mut err = self.struct_span_err(
+ span,
+ "invalid `struct` delimiters or `fn` call arguments",
+ );
+ err.multipart_suggestion(
+ &format!("if `{}` is a struct, use braces as delimiters", name),
+ vec![
+ (open_paren, " { ".to_string()),
+ (close_paren, " }".to_string()),
+ ],
+ Applicability::MaybeIncorrect,
+ );
+ err.multipart_suggestion(
+ &format!("if `{}` is a function, use the arguments directly", name),
+ fields
+ .into_iter()
+ .map(|field| (field.span.until(field.expr.span), String::new()))
+ .collect(),
+ Applicability::MaybeIncorrect,
+ );
+ err.emit();
+ } else {
+ err.emit();
+ }
return Some(self.mk_expr_err(span));
}
Ok(_) => {}
@@ -1150,7 +1189,7 @@ impl<'a> Parser<'a> {
}
let fn_span_lo = self.token.span;
- let mut segment = self.parse_path_segment(PathStyle::Expr)?;
+ let mut segment = self.parse_path_segment(PathStyle::Expr, None)?;
self.check_trailing_angle_brackets(&segment, &[&token::OpenDelim(token::Paren)]);
self.check_turbofish_missing_angle_brackets(&mut segment);
@@ -1243,7 +1282,7 @@ impl<'a> Parser<'a> {
} else if self.eat_keyword(kw::Unsafe) {
self.parse_block_expr(None, lo, BlockCheckMode::Unsafe(ast::UserProvided), attrs)
} else if self.check_inline_const(0) {
- self.parse_const_block(lo.to(self.token.span))
+ self.parse_const_block(lo.to(self.token.span), false)
} else if self.is_do_catch_block() {
self.recover_do_catch(attrs)
} else if self.is_try_block() {
@@ -1258,7 +1297,6 @@ impl<'a> Parser<'a> {
} else if self.eat_keyword(kw::Let) {
self.parse_let_expr(attrs)
} else if self.eat_keyword(kw::Underscore) {
- self.sess.gated_spans.gate(sym::destructuring_assignment, self.prev_token.span);
Ok(self.mk_expr(self.prev_token.span, ExprKind::Underscore, attrs))
} else if !self.unclosed_delims.is_empty() && self.check(&token::Semi) {
// Don't complain about bare semicolons after unclosed braces
@@ -1988,25 +2026,34 @@ impl<'a> Parser<'a> {
let lo = self.prev_token.span;
let cond = self.parse_cond_expr()?;
+ let missing_then_block_binop_span = || {
+ match cond.kind {
+ ExprKind::Binary(Spanned { span: binop_span, .. }, _, ref right)
+ if let ExprKind::Block(..) = right.kind => Some(binop_span),
+ _ => None
+ }
+ };
+
// Verify that the parsed `if` condition makes sense as a condition. If it is a block, then
// verify that the last statement is either an implicit return (no `;`) or an explicit
// return. This won't catch blocks with an explicit `return`, but that would be caught by
// the dead code lint.
- let thn = if self.eat_keyword(kw::Else) || !cond.returns() {
- self.error_missing_if_cond(lo, cond.span)
+ let thn = if self.token.is_keyword(kw::Else) || !cond.returns() {
+ if let Some(binop_span) = missing_then_block_binop_span() {
+ self.error_missing_if_then_block(lo, None, Some(binop_span)).emit();
+ self.mk_block_err(cond.span)
+ } else {
+ self.error_missing_if_cond(lo, cond.span)
+ }
} else {
let attrs = self.parse_outer_attributes()?.take_for_recovery(); // For recovery.
let not_block = self.token != token::OpenDelim(token::Brace);
- let block = self.parse_block().map_err(|mut err| {
+ let block = self.parse_block().map_err(|err| {
if not_block {
- err.span_label(lo, "this `if` expression has a condition, but no block");
- if let ExprKind::Binary(_, _, ref right) = cond.kind {
- if let ExprKind::Block(_, _) = right.kind {
- err.help("maybe you forgot the right operand of the condition?");
- }
- }
+ self.error_missing_if_then_block(lo, Some(err), missing_then_block_binop_span())
+ } else {
+ err
}
- err
})?;
self.error_on_if_block_attrs(lo, false, block.span, &attrs);
block
@@ -2015,6 +2062,28 @@ impl<'a> Parser<'a> {
Ok(self.mk_expr(lo.to(self.prev_token.span), ExprKind::If(cond, thn, els), attrs))
}
+ fn error_missing_if_then_block(
+ &self,
+ if_span: Span,
+ err: Option<DiagnosticBuilder<'a>>,
+ binop_span: Option<Span>,
+ ) -> DiagnosticBuilder<'a> {
+ let msg = "this `if` expression has a condition, but no block";
+
+ let mut err = if let Some(mut err) = err {
+ err.span_label(if_span, msg);
+ err
+ } else {
+ self.struct_span_err(if_span, msg)
+ };
+
+ if let Some(binop_span) = binop_span {
+ err.span_help(binop_span, "maybe you forgot the right operand of the condition?");
+ }
+
+ err
+ }
+
fn error_missing_if_cond(&self, lo: Span, span: Span) -> P<ast::Block> {
let sp = self.sess.source_map().next_point(lo);
self.struct_span_err(sp, "missing condition for `if` expression")
@@ -2550,7 +2619,6 @@ impl<'a> Parser<'a> {
let exp_span = self.prev_token.span;
// We permit `.. }` on the left-hand side of a destructuring assignment.
if self.check(&token::CloseDelim(close_delim)) {
- self.sess.gated_spans.gate(sym::destructuring_assignment, self.prev_token.span);
base = ast::StructRest::Rest(self.prev_token.span.shrink_to_hi());
break;
}
diff --git a/compiler/rustc_parse/src/parser/generics.rs b/compiler/rustc_parse/src/parser/generics.rs
index f175c5b50b3..419ea9cced0 100644
--- a/compiler/rustc_parse/src/parser/generics.rs
+++ b/compiler/rustc_parse/src/parser/generics.rs
@@ -5,7 +5,7 @@ use rustc_ast::{
self as ast, Attribute, GenericBounds, GenericParam, GenericParamKind, WhereClause,
};
use rustc_errors::PResult;
-use rustc_span::symbol::{kw, sym};
+use rustc_span::symbol::kw;
impl<'a> Parser<'a> {
/// Parses bounds of a lifetime parameter `BOUND + BOUND + BOUND`, possibly with trailing `+`.
@@ -48,7 +48,10 @@ impl<'a> Parser<'a> {
})
}
- fn parse_const_param(&mut self, preceding_attrs: Vec<Attribute>) -> PResult<'a, GenericParam> {
+ crate fn parse_const_param(
+ &mut self,
+ preceding_attrs: Vec<Attribute>,
+ ) -> PResult<'a, GenericParam> {
let const_span = self.token.span;
self.expect_keyword(kw::Const)?;
@@ -56,19 +59,8 @@ impl<'a> Parser<'a> {
self.expect(&token::Colon)?;
let ty = self.parse_ty()?;
- // Parse optional const generics default value, taking care of feature gating the spans
- // with the unstable syntax mechanism.
- let default = if self.eat(&token::Eq) {
- // The gated span goes from the `=` to the end of the const argument that follows (and
- // which could be a block expression).
- let start = self.prev_token.span;
- let const_arg = self.parse_const_arg()?;
- let span = start.to(const_arg.value.span);
- self.sess.gated_spans.gate(sym::const_generics_defaults, span);
- Some(const_arg)
- } else {
- None
- };
+ // Parse optional const generics default value.
+ let default = if self.eat(&token::Eq) { Some(self.parse_const_arg()?) } else { None };
Ok(GenericParam {
ident,
@@ -89,6 +81,19 @@ impl<'a> Parser<'a> {
let attrs = self.parse_outer_attributes()?;
let param =
self.collect_tokens_trailing_token(attrs, ForceCollect::No, |this, attrs| {
+ if this.eat_keyword_noexpect(kw::SelfUpper) {
+ // `Self` as a generic param is invalid. Here we emit the diagnostic and continue parsing
+ // as if `Self` never existed.
+ this.struct_span_err(
+ this.prev_token.span,
+ "unexpected keyword `Self` in generic parameters",
+ )
+ .note("you cannot use `Self` as a generic parameter because it is reserved for associated items")
+ .emit();
+
+ this.eat(&token::Comma);
+ }
+
let param = if this.check_lifetime() {
let lifetime = this.expect_lifetime();
// Parse lifetime parameter.
diff --git a/compiler/rustc_parse/src/parser/item.rs b/compiler/rustc_parse/src/parser/item.rs
index 73ca809ab1d..618aa3fd002 100644
--- a/compiler/rustc_parse/src/parser/item.rs
+++ b/compiler/rustc_parse/src/parser/item.rs
@@ -15,6 +15,7 @@ use rustc_ast::{MacArgs, MacCall, MacDelimiter};
use rustc_ast_pretty::pprust;
use rustc_errors::{struct_span_err, Applicability, PResult, StashKey};
use rustc_span::edition::{Edition, LATEST_STABLE_EDITION};
+use rustc_span::lev_distance::lev_distance;
use rustc_span::source_map::{self, Span};
use rustc_span::symbol::{kw, sym, Ident, Symbol};
@@ -26,7 +27,7 @@ impl<'a> Parser<'a> {
/// Parses a source module as a crate. This is the main entry point for the parser.
pub fn parse_crate_mod(&mut self) -> PResult<'a, ast::Crate> {
let (attrs, items, span) = self.parse_mod(&token::Eof)?;
- Ok(ast::Crate { attrs, items, span })
+ Ok(ast::Crate { attrs, items, span, is_placeholder: None })
}
/// Parses a `mod <foo> { ... }` or `mod <foo>;` item.
@@ -78,16 +79,17 @@ pub(super) type ItemInfo = (Ident, ItemKind);
impl<'a> Parser<'a> {
pub fn parse_item(&mut self, force_collect: ForceCollect) -> PResult<'a, Option<P<Item>>> {
- self.parse_item_(|_| true, force_collect).map(|i| i.map(P))
+ let fn_parse_mode = FnParseMode { req_name: |_| true, req_body: true };
+ self.parse_item_(fn_parse_mode, force_collect).map(|i| i.map(P))
}
fn parse_item_(
&mut self,
- req_name: ReqName,
+ fn_parse_mode: FnParseMode,
force_collect: ForceCollect,
) -> PResult<'a, Option<Item>> {
let attrs = self.parse_outer_attributes()?;
- self.parse_item_common(attrs, true, false, req_name, force_collect)
+ self.parse_item_common(attrs, true, false, fn_parse_mode, force_collect)
}
pub(super) fn parse_item_common(
@@ -95,7 +97,7 @@ impl<'a> Parser<'a> {
attrs: AttrWrapper,
mac_allowed: bool,
attrs_allowed: bool,
- req_name: ReqName,
+ fn_parse_mode: FnParseMode,
force_collect: ForceCollect,
) -> PResult<'a, Option<Item>> {
// Don't use `maybe_whole` so that we have precise control
@@ -113,7 +115,8 @@ impl<'a> Parser<'a> {
let mut unclosed_delims = vec![];
let item =
self.collect_tokens_trailing_token(attrs, force_collect, |this: &mut Self, attrs| {
- let item = this.parse_item_common_(attrs, mac_allowed, attrs_allowed, req_name);
+ let item =
+ this.parse_item_common_(attrs, mac_allowed, attrs_allowed, fn_parse_mode);
unclosed_delims.append(&mut this.unclosed_delims);
Ok((item?, TrailingToken::None))
})?;
@@ -127,12 +130,13 @@ impl<'a> Parser<'a> {
mut attrs: Vec<Attribute>,
mac_allowed: bool,
attrs_allowed: bool,
- req_name: ReqName,
+ fn_parse_mode: FnParseMode,
) -> PResult<'a, Option<Item>> {
let lo = self.token.span;
let vis = self.parse_visibility(FollowedByType::No)?;
let mut def = self.parse_defaultness();
- let kind = self.parse_item_kind(&mut attrs, mac_allowed, lo, &vis, &mut def, req_name)?;
+ let kind =
+ self.parse_item_kind(&mut attrs, mac_allowed, lo, &vis, &mut def, fn_parse_mode)?;
if let Some((ident, kind)) = kind {
self.error_on_unconsumed_default(def, &kind);
let span = lo.to(self.prev_token.span);
@@ -192,7 +196,7 @@ impl<'a> Parser<'a> {
lo: Span,
vis: &Visibility,
def: &mut Defaultness,
- req_name: ReqName,
+ fn_parse_mode: FnParseMode,
) -> PResult<'a, Option<ItemInfo>> {
let def_final = def == &Defaultness::Final;
let mut def = || mem::replace(def, Defaultness::Final);
@@ -219,7 +223,7 @@ impl<'a> Parser<'a> {
(Ident::empty(), ItemKind::Use(tree))
} else if self.check_fn_front_matter(def_final) {
// FUNCTION ITEM
- let (ident, sig, generics, body) = self.parse_fn(attrs, req_name, lo)?;
+ let (ident, sig, generics, body) = self.parse_fn(attrs, fn_parse_mode, lo, vis)?;
(ident, ItemKind::Fn(Box::new(Fn { defaultness: def(), sig, generics, body })))
} else if self.eat_keyword(kw::Extern) {
if self.eat_keyword(kw::Crate) {
@@ -407,10 +411,30 @@ impl<'a> Parser<'a> {
fn parse_item_macro(&mut self, vis: &Visibility) -> PResult<'a, MacCall> {
let path = self.parse_path(PathStyle::Mod)?; // `foo::bar`
self.expect(&token::Not)?; // `!`
- let args = self.parse_mac_args()?; // `( .. )` or `[ .. ]` (followed by `;`), or `{ .. }`.
- self.eat_semi_for_macro_if_needed(&args);
- self.complain_if_pub_macro(vis, false);
- Ok(MacCall { path, args, prior_type_ascription: self.last_type_ascription })
+ match self.parse_mac_args() {
+ // `( .. )` or `[ .. ]` (followed by `;`), or `{ .. }`.
+ Ok(args) => {
+ self.eat_semi_for_macro_if_needed(&args);
+ self.complain_if_pub_macro(vis, false);
+ Ok(MacCall { path, args, prior_type_ascription: self.last_type_ascription })
+ }
+
+ Err(mut err) => {
+ // Maybe the user misspelled `macro_rules` (issue #91227)
+ if self.token.is_ident()
+ && path.segments.len() == 1
+ && lev_distance("macro_rules", &path.segments[0].ident.to_string()) <= 3
+ {
+ err.span_suggestion(
+ path.span,
+ "perhaps you meant to define a macro",
+ "macro_rules".to_string(),
+ Applicability::MachineApplicable,
+ );
+ }
+ Err(err)
+ }
+ }
}
/// Recover if we parsed attributes and expected an item but there was none.
@@ -514,7 +538,7 @@ impl<'a> Parser<'a> {
tokens: None,
})
} else {
- self.parse_ty()?
+ self.parse_ty_with_generics_recovery(&generics)?
};
// If `for` is missing we try to recover.
@@ -733,23 +757,26 @@ impl<'a> Parser<'a> {
&mut self,
force_collect: ForceCollect,
) -> PResult<'a, Option<Option<P<AssocItem>>>> {
- self.parse_assoc_item(|_| true, force_collect)
+ let fn_parse_mode = FnParseMode { req_name: |_| true, req_body: true };
+ self.parse_assoc_item(fn_parse_mode, force_collect)
}
pub fn parse_trait_item(
&mut self,
force_collect: ForceCollect,
) -> PResult<'a, Option<Option<P<AssocItem>>>> {
- self.parse_assoc_item(|edition| edition >= Edition::Edition2018, force_collect)
+ let fn_parse_mode =
+ FnParseMode { req_name: |edition| edition >= Edition::Edition2018, req_body: false };
+ self.parse_assoc_item(fn_parse_mode, force_collect)
}
/// Parses associated items.
fn parse_assoc_item(
&mut self,
- req_name: ReqName,
+ fn_parse_mode: FnParseMode,
force_collect: ForceCollect,
) -> PResult<'a, Option<Option<P<AssocItem>>>> {
- Ok(self.parse_item_(req_name, force_collect)?.map(
+ Ok(self.parse_item_(fn_parse_mode, force_collect)?.map(
|Item { attrs, id, span, vis, ident, kind, tokens }| {
let kind = match AssocItemKind::try_from(kind) {
Ok(kind) => kind,
@@ -944,7 +971,8 @@ impl<'a> Parser<'a> {
&mut self,
force_collect: ForceCollect,
) -> PResult<'a, Option<Option<P<ForeignItem>>>> {
- Ok(self.parse_item_(|_| true, force_collect)?.map(
+ let fn_parse_mode = FnParseMode { req_name: |_| true, req_body: false };
+ Ok(self.parse_item_(fn_parse_mode, force_collect)?.map(
|Item { attrs, id, span, vis, ident, kind, tokens }| {
let kind = match ForeignItemKind::try_from(kind) {
Ok(kind) => kind,
@@ -1483,8 +1511,16 @@ impl<'a> Parser<'a> {
let (ident, is_raw) = self.ident_or_err()?;
if !is_raw && ident.is_reserved() {
let err = if self.check_fn_front_matter(false) {
+ let inherited_vis = Visibility {
+ span: rustc_span::DUMMY_SP,
+ kind: VisibilityKind::Inherited,
+ tokens: None,
+ };
// We use `parse_fn` to get a span for the function
- if let Err(mut db) = self.parse_fn(&mut Vec::new(), |_| true, lo) {
+ let fn_parse_mode = FnParseMode { req_name: |_| true, req_body: true };
+ if let Err(mut db) =
+ self.parse_fn(&mut Vec::new(), fn_parse_mode, lo, &inherited_vis)
+ {
db.delay_as_bug();
}
let mut err = self.struct_span_err(
@@ -1698,25 +1734,83 @@ impl<'a> Parser<'a> {
/// The parsing configuration used to parse a parameter list (see `parse_fn_params`).
///
/// The function decides if, per-parameter `p`, `p` must have a pattern or just a type.
+///
+/// This function pointer accepts an edition, because in edition 2015, trait declarations
+/// were allowed to omit parameter names. In 2018, they became required.
type ReqName = fn(Edition) -> bool;
+/// Parsing configuration for functions.
+///
+/// The syntax of function items is slightly different within trait definitions,
+/// impl blocks, and modules. It is still parsed using the same code, just with
+/// different flags set, so that even when the input is wrong and produces a parse
+/// error, it still gets into the AST and the rest of the parser and
+/// type checker can run.
+#[derive(Clone, Copy)]
+pub(crate) struct FnParseMode {
+ /// A function pointer that decides if, per-parameter `p`, `p` must have a
+ /// pattern or just a type. This field affects parsing of the parameters list.
+ ///
+ /// ```text
+ /// fn foo(alef: A) -> X { X::new() }
+ /// -----^^ affects parsing this part of the function signature
+ /// |
+ /// if req_name returns false, then this name is optional
+ ///
+ /// fn bar(A) -> X;
+ /// ^
+ /// |
+ /// if req_name returns true, this is an error
+ /// ```
+ ///
+ /// Calling this function pointer should only return false if:
+ ///
+ /// * The item is being parsed inside of a trait definition.
+ /// Within an impl block or a module, it should always evaluate
+ /// to true.
+ /// * The span is from Edition 2015. In particular, you can get a
+ /// 2015 span inside a 2021 crate using macros.
+ pub req_name: ReqName,
+ /// If this flag is set to `true`, then plain, semicolon-terminated function
+ /// prototypes are not allowed here.
+ ///
+ /// ```text
+ /// fn foo(alef: A) -> X { X::new() }
+ /// ^^^^^^^^^^^^
+ /// |
+ /// this is always allowed
+ ///
+ /// fn bar(alef: A, bet: B) -> X;
+ /// ^
+ /// |
+ /// if req_body is set to true, this is an error
+ /// ```
+ ///
+ /// This field should only be set to false if the item is inside of a trait
+ /// definition or extern block. Within an impl block or a module, it should
+ /// always be set to true.
+ pub req_body: bool,
+}
+
/// Parsing of functions and methods.
impl<'a> Parser<'a> {
/// Parse a function starting from the front matter (`const ...`) to the body `{ ... }` or `;`.
fn parse_fn(
&mut self,
attrs: &mut Vec<Attribute>,
- req_name: ReqName,
+ fn_parse_mode: FnParseMode,
sig_lo: Span,
+ vis: &Visibility,
) -> PResult<'a, (Ident, FnSig, Generics, Option<P<Block>>)> {
- let header = self.parse_fn_front_matter()?; // `const ... fn`
+ let header = self.parse_fn_front_matter(vis)?; // `const ... fn`
let ident = self.parse_ident()?; // `foo`
let mut generics = self.parse_generics()?; // `<'a, T, ...>`
- let decl = self.parse_fn_decl(req_name, AllowPlus::Yes, RecoverReturnSign::Yes)?; // `(p: u8, ...)`
+ let decl =
+ self.parse_fn_decl(fn_parse_mode.req_name, AllowPlus::Yes, RecoverReturnSign::Yes)?; // `(p: u8, ...)`
generics.where_clause = self.parse_where_clause()?; // `where T: Ord`
let mut sig_hi = self.prev_token.span;
- let body = self.parse_fn_body(attrs, &ident, &mut sig_hi)?; // `;` or `{ ... }`.
+ let body = self.parse_fn_body(attrs, &ident, &mut sig_hi, fn_parse_mode.req_body)?; // `;` or `{ ... }`.
let fn_sig_span = sig_lo.to(sig_hi);
Ok((ident, FnSig { header, decl, span: fn_sig_span }, generics, body))
}
@@ -1729,9 +1823,17 @@ impl<'a> Parser<'a> {
attrs: &mut Vec<Attribute>,
ident: &Ident,
sig_hi: &mut Span,
+ req_body: bool,
) -> PResult<'a, Option<P<Block>>> {
- let (inner_attrs, body) = if self.eat(&token::Semi) {
+ let has_semi = if req_body {
+ self.token.kind == TokenKind::Semi
+ } else {
+ // Only include `;` in list of expected tokens if body is not required
+ self.check(&TokenKind::Semi)
+ };
+ let (inner_attrs, body) = if has_semi {
// Include the trailing semicolon in the span of the signature
+ self.expect_semi()?;
*sig_hi = self.prev_token.span;
(Vec::new(), None)
} else if self.check(&token::OpenDelim(token::Brace)) || self.token.is_whole_block() {
@@ -1752,9 +1854,12 @@ impl<'a> Parser<'a> {
.emit();
(Vec::new(), Some(self.mk_block_err(span)))
} else {
- if let Err(mut err) =
- self.expected_one_of_not_found(&[], &[token::Semi, token::OpenDelim(token::Brace)])
- {
+ let expected = if req_body {
+ &[token::OpenDelim(token::Brace)][..]
+ } else {
+ &[token::Semi, token::OpenDelim(token::Brace)]
+ };
+ if let Err(mut err) = self.expected_one_of_not_found(&[], &expected) {
if self.token.kind == token::CloseDelim(token::Brace) {
// The enclosing `mod`, `trait` or `impl` is being closed, so keep the `fn` in
// the AST for typechecking.
@@ -1806,12 +1911,15 @@ impl<'a> Parser<'a> {
/// Parses all the "front matter" (or "qualifiers") for a `fn` declaration,
/// up to and including the `fn` keyword. The formal grammar is:
///
- /// ```
+ /// ```text
/// Extern = "extern" StringLit? ;
/// FnQual = "const"? "async"? "unsafe"? Extern? ;
/// FnFrontMatter = FnQual "fn" ;
/// ```
- pub(super) fn parse_fn_front_matter(&mut self) -> PResult<'a, FnHeader> {
+ ///
+ /// `vis` represents the visibility that was already parsed, if any. Use
+ /// `Visibility::Inherited` when no visibility is known.
+ pub(super) fn parse_fn_front_matter(&mut self, orig_vis: &Visibility) -> PResult<'a, FnHeader> {
let sp_start = self.token.span;
let constness = self.parse_constness();
@@ -1837,51 +1945,94 @@ impl<'a> Parser<'a> {
Ok(false) => unreachable!(),
Err(mut err) => {
// Qualifier keywords ordering check
+ enum WrongKw {
+ Duplicated(Span),
+ Misplaced(Span),
+ }
- // This will allow the machine fix to directly place the keyword in the correct place
- let current_qual_sp = if self.check_keyword(kw::Const) {
- Some(async_start_sp)
+ // This will allow the machine fix to directly place the keyword in the correct place or to indicate
+ // that the keyword is already present and the second instance should be removed.
+ let wrong_kw = if self.check_keyword(kw::Const) {
+ match constness {
+ Const::Yes(sp) => Some(WrongKw::Duplicated(sp)),
+ Const::No => Some(WrongKw::Misplaced(async_start_sp)),
+ }
} else if self.check_keyword(kw::Async) {
- Some(unsafe_start_sp)
+ match asyncness {
+ Async::Yes { span, .. } => Some(WrongKw::Duplicated(span)),
+ Async::No => Some(WrongKw::Misplaced(unsafe_start_sp)),
+ }
} else if self.check_keyword(kw::Unsafe) {
- Some(ext_start_sp)
+ match unsafety {
+ Unsafe::Yes(sp) => Some(WrongKw::Duplicated(sp)),
+ Unsafe::No => Some(WrongKw::Misplaced(ext_start_sp)),
+ }
} else {
None
};
- if let Some(current_qual_sp) = current_qual_sp {
- let current_qual_sp = current_qual_sp.to(self.prev_token.span);
- if let Ok(current_qual) = self.span_to_snippet(current_qual_sp) {
- let invalid_qual_sp = self.token.uninterpolated_span();
- let invalid_qual = self.span_to_snippet(invalid_qual_sp).unwrap();
+ // The keyword is already present, suggest removal of the second instance
+ if let Some(WrongKw::Duplicated(original_sp)) = wrong_kw {
+ let original_kw = self
+ .span_to_snippet(original_sp)
+ .expect("Span extracted directly from keyword should always work");
+
+ err.span_suggestion(
+ self.token.uninterpolated_span(),
+ &format!("`{}` already used earlier, remove this one", original_kw),
+ "".to_string(),
+ Applicability::MachineApplicable,
+ )
+ .span_note(original_sp, &format!("`{}` first seen here", original_kw));
+ }
+ // The keyword has not been seen yet, suggest correct placement in the function front matter
+ else if let Some(WrongKw::Misplaced(correct_pos_sp)) = wrong_kw {
+ let correct_pos_sp = correct_pos_sp.to(self.prev_token.span);
+ if let Ok(current_qual) = self.span_to_snippet(correct_pos_sp) {
+ let misplaced_qual_sp = self.token.uninterpolated_span();
+ let misplaced_qual = self.span_to_snippet(misplaced_qual_sp).unwrap();
err.span_suggestion(
- current_qual_sp.to(invalid_qual_sp),
- &format!("`{}` must come before `{}`", invalid_qual, current_qual),
- format!("{} {}", invalid_qual, current_qual),
- Applicability::MachineApplicable,
- ).note("keyword order for functions declaration is `default`, `pub`, `const`, `async`, `unsafe`, `extern`");
+ correct_pos_sp.to(misplaced_qual_sp),
+ &format!("`{}` must come before `{}`", misplaced_qual, current_qual),
+ format!("{} {}", misplaced_qual, current_qual),
+ Applicability::MachineApplicable,
+ ).note("keyword order for functions declaration is `default`, `pub`, `const`, `async`, `unsafe`, `extern`");
}
}
- // Recover incorrect visibility order such as `async pub`.
+ // Recover incorrect visibility order such as `async pub`
else if self.check_keyword(kw::Pub) {
let sp = sp_start.to(self.prev_token.span);
if let Ok(snippet) = self.span_to_snippet(sp) {
- let vis = match self.parse_visibility(FollowedByType::No) {
+ let current_vis = match self.parse_visibility(FollowedByType::No) {
Ok(v) => v,
Err(mut d) => {
d.cancel();
return Err(err);
}
};
- let vs = pprust::vis_to_string(&vis);
+ let vs = pprust::vis_to_string(&current_vis);
let vs = vs.trim_end();
- err.span_suggestion(
- sp_start.to(self.prev_token.span),
- &format!("visibility `{}` must come before `{}`", vs, snippet),
- format!("{} {}", vs, snippet),
- Applicability::MachineApplicable,
- );
+
+ // There was no explicit visibility
+ if matches!(orig_vis.kind, VisibilityKind::Inherited) {
+ err.span_suggestion(
+ sp_start.to(self.prev_token.span),
+ &format!("visibility `{}` must come before `{}`", vs, snippet),
+ format!("{} {}", vs, snippet),
+ Applicability::MachineApplicable,
+ );
+ }
+ // There was an explicit visibility
+ else {
+ err.span_suggestion(
+ current_vis.span,
+ "there is already a visibility modifier, remove one",
+ "".to_string(),
+ Applicability::MachineApplicable,
+ )
+ .span_note(orig_vis.span, "explicit visibility first seen here");
+ }
}
}
return Err(err);
diff --git a/compiler/rustc_parse/src/parser/mod.rs b/compiler/rustc_parse/src/parser/mod.rs
index e50b983ec62..6d534bece46 100644
--- a/compiler/rustc_parse/src/parser/mod.rs
+++ b/compiler/rustc_parse/src/parser/mod.rs
@@ -14,6 +14,7 @@ use crate::lexer::UnmatchedBrace;
pub use attr_wrapper::AttrWrapper;
pub use diagnostics::AttemptLocalParseRecovery;
use diagnostics::Error;
+pub(crate) use item::FnParseMode;
pub use pat::{RecoverColon, RecoverComma};
pub use path::PathStyle;
@@ -1095,8 +1096,12 @@ impl<'a> Parser<'a> {
}
/// Parses inline const expressions.
- fn parse_const_block(&mut self, span: Span) -> PResult<'a, P<Expr>> {
- self.sess.gated_spans.gate(sym::inline_const, span);
+ fn parse_const_block(&mut self, span: Span, pat: bool) -> PResult<'a, P<Expr>> {
+ if pat {
+ self.sess.gated_spans.gate(sym::inline_const_pat, span);
+ } else {
+ self.sess.gated_spans.gate(sym::inline_const, span);
+ }
self.eat_keyword(kw::Const);
let blk = self.parse_block()?;
let anon_const = AnonConst {
diff --git a/compiler/rustc_parse/src/parser/pat.rs b/compiler/rustc_parse/src/parser/pat.rs
index 3b5a297103c..ac3123c40e3 100644
--- a/compiler/rustc_parse/src/parser/pat.rs
+++ b/compiler/rustc_parse/src/parser/pat.rs
@@ -3,14 +3,16 @@ use crate::{maybe_recover_from_interpolated_ty_qpath, maybe_whole};
use rustc_ast::mut_visit::{noop_visit_pat, MutVisitor};
use rustc_ast::ptr::P;
use rustc_ast::token;
-use rustc_ast::{self as ast, AttrVec, Attribute, MacCall, Pat, PatField, PatKind, RangeEnd};
-use rustc_ast::{BindingMode, Expr, ExprKind, Mutability, Path, QSelf, RangeSyntax};
+use rustc_ast::{
+ self as ast, AttrVec, Attribute, BindingMode, Expr, ExprKind, MacCall, Mutability, Pat,
+ PatField, PatKind, Path, QSelf, RangeEnd, RangeSyntax,
+};
use rustc_ast_pretty::pprust;
use rustc_errors::{struct_span_err, Applicability, DiagnosticBuilder, PResult};
use rustc_span::source_map::{respan, Span, Spanned};
use rustc_span::symbol::{kw, sym, Ident};
-type Expected = Option<&'static str>;
+pub(super) type Expected = Option<&'static str>;
/// `Expected` for function and lambda parameter patterns.
pub(super) const PARAM_EXPECTED: Expected = Some("parameter name");
@@ -98,55 +100,9 @@ impl<'a> Parser<'a> {
// If we parsed a leading `|` which should be gated,
// then we should really gate the leading `|`.
// This complicated procedure is done purely for diagnostics UX.
- let mut first_pat = first_pat;
-
- if let (RecoverColon::Yes, token::Colon) = (ra, &self.token.kind) {
- if matches!(
- first_pat.kind,
- PatKind::Ident(BindingMode::ByValue(Mutability::Not), _, None)
- | PatKind::Path(..)
- ) && self.look_ahead(1, |token| token.is_ident() && !token.is_reserved_ident())
- {
- // The pattern looks like it might be a path with a `::` -> `:` typo:
- // `match foo { bar:baz => {} }`
- let span = self.token.span;
- // We only emit "unexpected `:`" error here if we can successfully parse the
- // whole pattern correctly in that case.
- let snapshot = self.clone();
-
- // Create error for "unexpected `:`".
- match self.expected_one_of_not_found(&[], &[]) {
- Err(mut err) => {
- self.bump(); // Skip the `:`.
- match self.parse_pat_no_top_alt(expected) {
- Err(mut inner_err) => {
- // Carry on as if we had not done anything, callers will emit a
- // reasonable error.
- inner_err.cancel();
- err.cancel();
- *self = snapshot;
- }
- Ok(pat) => {
- // We've parsed the rest of the pattern.
- err.span_suggestion(
- span,
- "maybe write a path separator here",
- "::".to_string(),
- Applicability::MachineApplicable,
- );
- err.emit();
- first_pat =
- self.mk_pat(first_pat.span.to(pat.span), PatKind::Wild);
- }
- }
- }
- _ => {
- // Carry on as if we had not done anything. This should be unreachable.
- *self = snapshot;
- }
- };
- }
- }
+
+ // Check if the user wrote `foo:bar` instead of `foo::bar`.
+ let first_pat = self.maybe_recover_colon_colon_in_pat_typo(first_pat, ra, expected);
if let Some(leading_vert_span) = leading_vert_span {
// If there was a leading vert, treat this as an or-pattern. This improves
@@ -321,57 +277,6 @@ impl<'a> Parser<'a> {
err.emit();
}
- /// Some special error handling for the "top-level" patterns in a match arm,
- /// `for` loop, `let`, &c. (in contrast to subpatterns within such).
- fn maybe_recover_unexpected_comma(&mut self, lo: Span, rc: RecoverComma) -> PResult<'a, ()> {
- if rc == RecoverComma::No || self.token != token::Comma {
- return Ok(());
- }
-
- // An unexpected comma after a top-level pattern is a clue that the
- // user (perhaps more accustomed to some other language) forgot the
- // parentheses in what should have been a tuple pattern; return a
- // suggestion-enhanced error here rather than choking on the comma later.
- let comma_span = self.token.span;
- self.bump();
- if let Err(mut err) = self.skip_pat_list() {
- // We didn't expect this to work anyway; we just wanted to advance to the
- // end of the comma-sequence so we know the span to suggest parenthesizing.
- err.cancel();
- }
- let seq_span = lo.to(self.prev_token.span);
- let mut err = self.struct_span_err(comma_span, "unexpected `,` in pattern");
- if let Ok(seq_snippet) = self.span_to_snippet(seq_span) {
- const MSG: &str = "try adding parentheses to match on a tuple...";
-
- err.span_suggestion(
- seq_span,
- MSG,
- format!("({})", seq_snippet),
- Applicability::MachineApplicable,
- );
- err.span_suggestion(
- seq_span,
- "...or a vertical bar to match on multiple alternatives",
- seq_snippet.replace(",", " |"),
- Applicability::MachineApplicable,
- );
- }
- Err(err)
- }
-
- /// Parse and throw away a parenthesized comma separated
- /// sequence of patterns until `)` is reached.
- fn skip_pat_list(&mut self) -> PResult<'a, ()> {
- while !self.check(&token::CloseDelim(token::Paren)) {
- self.parse_pat_no_top_alt(None)?;
- if !self.eat(&token::Comma) {
- return Ok(());
- }
- }
- Ok(())
- }
-
/// A `|` or possibly `||` token shouldn't be here. Ban it.
fn ban_illegal_vert(&mut self, lo: Option<Span>, pos: &str, ctx: &str) {
let span = self.token.span;
@@ -437,7 +342,7 @@ impl<'a> Parser<'a> {
PatKind::Box(pat)
} else if self.check_inline_const(0) {
// Parse `const pat`
- let const_expr = self.parse_const_block(lo.to(self.token.span))?;
+ let const_expr = self.parse_const_block(lo.to(self.token.span), true)?;
if let Some(re) = self.parse_range_end() {
self.parse_pat_range_begin_with(const_expr, re)?
@@ -884,7 +789,7 @@ impl<'a> Parser<'a> {
fn parse_pat_range_end(&mut self) -> PResult<'a, P<Expr>> {
if self.check_inline_const(0) {
- self.parse_const_block(self.token.span)
+ self.parse_const_block(self.token.span, true)
} else if self.check_path() {
let lo = self.token.span;
let (qself, path) = if self.eat_lt() {
@@ -1168,7 +1073,7 @@ impl<'a> Parser<'a> {
self.mk_pat(span, PatKind::Ident(bm, ident, None))
}
- fn mk_pat(&self, span: Span, kind: PatKind) -> P<Pat> {
+ pub(super) fn mk_pat(&self, span: Span, kind: PatKind) -> P<Pat> {
P(Pat { kind, span, id: ast::DUMMY_NODE_ID, tokens: None })
}
}
diff --git a/compiler/rustc_parse/src/parser/path.rs b/compiler/rustc_parse/src/parser/path.rs
index c7d080a80fe..7f8fadb33bd 100644
--- a/compiler/rustc_parse/src/parser/path.rs
+++ b/compiler/rustc_parse/src/parser/path.rs
@@ -3,10 +3,11 @@ use super::{Parser, TokenType};
use crate::maybe_whole;
use rustc_ast::ptr::P;
use rustc_ast::token::{self, Token};
-use rustc_ast::{self as ast, AngleBracketedArg, AngleBracketedArgs, ParenthesizedArgs};
-use rustc_ast::{AnonConst, AssocTyConstraint, AssocTyConstraintKind, BlockCheckMode};
-use rustc_ast::{GenericArg, GenericArgs};
-use rustc_ast::{Path, PathSegment, QSelf};
+use rustc_ast::{
+ self as ast, AngleBracketedArg, AngleBracketedArgs, AnonConst, AssocTyConstraint,
+ AssocTyConstraintKind, BlockCheckMode, GenericArg, GenericArgs, Generics, ParenthesizedArgs,
+ Path, PathSegment, QSelf,
+};
use rustc_errors::{pluralize, Applicability, PResult};
use rustc_span::source_map::{BytePos, Span};
use rustc_span::symbol::{kw, sym, Ident};
@@ -78,7 +79,7 @@ impl<'a> Parser<'a> {
}
let qself = QSelf { ty, path_span, position: path.segments.len() };
- self.parse_path_segments(&mut path.segments, style)?;
+ self.parse_path_segments(&mut path.segments, style, None)?;
Ok((
qself,
@@ -119,6 +120,10 @@ impl<'a> Parser<'a> {
true
}
+ pub(super) fn parse_path(&mut self, style: PathStyle) -> PResult<'a, Path> {
+ self.parse_path_inner(style, None)
+ }
+
/// Parses simple paths.
///
/// `path = [::] segment+`
@@ -129,7 +134,11 @@ impl<'a> Parser<'a> {
/// `a::b::C::<D>` (with disambiguator)
/// `Fn(Args)` (without disambiguator)
/// `Fn::(Args)` (with disambiguator)
- pub(super) fn parse_path(&mut self, style: PathStyle) -> PResult<'a, Path> {
+ pub(super) fn parse_path_inner(
+ &mut self,
+ style: PathStyle,
+ ty_generics: Option<&Generics>,
+ ) -> PResult<'a, Path> {
maybe_whole!(self, NtPath, |path| {
if style == PathStyle::Mod && path.segments.iter().any(|segment| segment.args.is_some())
{
@@ -152,7 +161,7 @@ impl<'a> Parser<'a> {
if self.eat(&token::ModSep) {
segments.push(PathSegment::path_root(lo.shrink_to_lo().with_ctxt(mod_sep_ctxt)));
}
- self.parse_path_segments(&mut segments, style)?;
+ self.parse_path_segments(&mut segments, style, ty_generics)?;
Ok(Path { segments, span: lo.to(self.prev_token.span), tokens: None })
}
@@ -161,9 +170,10 @@ impl<'a> Parser<'a> {
&mut self,
segments: &mut Vec<PathSegment>,
style: PathStyle,
+ ty_generics: Option<&Generics>,
) -> PResult<'a, ()> {
loop {
- let segment = self.parse_path_segment(style)?;
+ let segment = self.parse_path_segment(style, ty_generics)?;
if style == PathStyle::Expr {
// In order to check for trailing angle brackets, we must have finished
// recursing (`parse_path_segment` can indirectly call this function),
@@ -191,7 +201,11 @@ impl<'a> Parser<'a> {
}
}
- pub(super) fn parse_path_segment(&mut self, style: PathStyle) -> PResult<'a, PathSegment> {
+ pub(super) fn parse_path_segment(
+ &mut self,
+ style: PathStyle,
+ ty_generics: Option<&Generics>,
+ ) -> PResult<'a, PathSegment> {
let ident = self.parse_path_segment_ident()?;
let is_args_start = |token: &Token| {
matches!(
@@ -229,8 +243,11 @@ impl<'a> Parser<'a> {
let lo = self.token.span;
let args = if self.eat_lt() {
// `<'a, T, A = U>`
- let args =
- self.parse_angle_args_with_leading_angle_bracket_recovery(style, lo)?;
+ let args = self.parse_angle_args_with_leading_angle_bracket_recovery(
+ style,
+ lo,
+ ty_generics,
+ )?;
self.expect_gt()?;
let span = lo.to(self.prev_token.span);
AngleBracketedArgs { args, span }.into()
@@ -238,9 +255,9 @@ impl<'a> Parser<'a> {
// `(T, U) -> R`
let (inputs, _) = self.parse_paren_comma_seq(|p| p.parse_ty())?;
let inputs_span = lo.to(self.prev_token.span);
- let span = ident.span.to(self.prev_token.span);
let output =
self.parse_ret_ty(AllowPlus::No, RecoverQPath::No, RecoverReturnSign::No)?;
+ let span = ident.span.to(self.prev_token.span);
ParenthesizedArgs { span, inputs, inputs_span, output }.into()
};
@@ -275,6 +292,7 @@ impl<'a> Parser<'a> {
&mut self,
style: PathStyle,
lo: Span,
+ ty_generics: Option<&Generics>,
) -> PResult<'a, Vec<AngleBracketedArg>> {
// We need to detect whether there are extra leading left angle brackets and produce an
// appropriate error and suggestion. This cannot be implemented by looking ahead at
@@ -350,7 +368,7 @@ impl<'a> Parser<'a> {
let snapshot = if is_first_invocation { Some(self.clone()) } else { None };
debug!("parse_generic_args_with_leading_angle_bracket_recovery: (snapshotting)");
- match self.parse_angle_args() {
+ match self.parse_angle_args(ty_generics) {
Ok(args) => Ok(args),
Err(mut e) if is_first_invocation && self.unmatched_angle_bracket_count > 0 => {
// Swap `self` with our backup of the parser state before attempting to parse
@@ -403,7 +421,7 @@ impl<'a> Parser<'a> {
.emit();
// Try again without unmatched angle bracket characters.
- self.parse_angle_args()
+ self.parse_angle_args(ty_generics)
}
}
Err(e) => Err(e),
@@ -412,9 +430,12 @@ impl<'a> Parser<'a> {
/// Parses (possibly empty) list of generic arguments / associated item constraints,
/// possibly including trailing comma.
- pub(super) fn parse_angle_args(&mut self) -> PResult<'a, Vec<AngleBracketedArg>> {
+ pub(super) fn parse_angle_args(
+ &mut self,
+ ty_generics: Option<&Generics>,
+ ) -> PResult<'a, Vec<AngleBracketedArg>> {
let mut args = Vec::new();
- while let Some(arg) = self.parse_angle_arg()? {
+ while let Some(arg) = self.parse_angle_arg(ty_generics)? {
args.push(arg);
if !self.eat(&token::Comma) {
if !self.token.kind.should_end_const_arg() {
@@ -431,9 +452,12 @@ impl<'a> Parser<'a> {
}
/// Parses a single argument in the angle arguments `<...>` of a path segment.
- fn parse_angle_arg(&mut self) -> PResult<'a, Option<AngleBracketedArg>> {
+ fn parse_angle_arg(
+ &mut self,
+ ty_generics: Option<&Generics>,
+ ) -> PResult<'a, Option<AngleBracketedArg>> {
let lo = self.token.span;
- let arg = self.parse_generic_arg()?;
+ let arg = self.parse_generic_arg(ty_generics)?;
match arg {
Some(arg) => {
if self.check(&token::Colon) | self.check(&token::Eq) {
@@ -476,7 +500,7 @@ impl<'a> Parser<'a> {
/// That is, parse `<term>` in `Item = <term>`.
/// Right now, this only admits types in `<term>`.
fn parse_assoc_equality_term(&mut self, ident: Ident, eq: Span) -> PResult<'a, P<ast::Ty>> {
- let arg = self.parse_generic_arg()?;
+ let arg = self.parse_generic_arg(None)?;
let span = ident.span.to(self.prev_token.span);
match arg {
Some(GenericArg::Type(ty)) => return Ok(ty),
@@ -563,7 +587,10 @@ impl<'a> Parser<'a> {
/// Parse a generic argument in a path segment.
/// This does not include constraints, e.g., `Item = u8`, which is handled in `parse_angle_arg`.
- pub(super) fn parse_generic_arg(&mut self) -> PResult<'a, Option<GenericArg>> {
+ pub(super) fn parse_generic_arg(
+ &mut self,
+ ty_generics: Option<&Generics>,
+ ) -> PResult<'a, Option<GenericArg>> {
let start = self.token.span;
let arg = if self.check_lifetime() && self.look_ahead(1, |t| !t.is_like_plus()) {
// Parse lifetime argument.
@@ -580,25 +607,8 @@ impl<'a> Parser<'a> {
return self.recover_const_arg(start, err).map(Some);
}
}
- } else if self.eat_keyword_noexpect(kw::Const) {
- // Detect and recover from the old, pre-RFC2000 syntax for const generics.
- let mut err = self.struct_span_err(
- start,
- "expected lifetime, type, or constant, found keyword `const`",
- );
- if self.check_const_arg() {
- err.span_suggestion_verbose(
- start.until(self.token.span),
- "the `const` keyword is only needed in the definition of the type",
- String::new(),
- Applicability::MaybeIncorrect,
- );
- err.emit();
- GenericArg::Const(self.parse_const_arg()?)
- } else {
- let after_kw_const = self.token.span;
- return self.recover_const_arg(after_kw_const, err).map(Some);
- }
+ } else if self.token.is_keyword(kw::Const) {
+ return self.recover_const_param_declaration(ty_generics);
} else {
return Ok(None);
};
diff --git a/compiler/rustc_parse/src/parser/stmt.rs b/compiler/rustc_parse/src/parser/stmt.rs
index 01e751ea8b5..d3e7d1690cc 100644
--- a/compiler/rustc_parse/src/parser/stmt.rs
+++ b/compiler/rustc_parse/src/parser/stmt.rs
@@ -4,7 +4,9 @@ use super::expr::LhsExpr;
use super::pat::RecoverComma;
use super::path::PathStyle;
use super::TrailingToken;
-use super::{AttrWrapper, BlockMode, ForceCollect, Parser, Restrictions, SemiColonMode};
+use super::{
+ AttrWrapper, BlockMode, FnParseMode, ForceCollect, Parser, Restrictions, SemiColonMode,
+};
use crate::maybe_whole;
use rustc_ast as ast;
@@ -79,9 +81,13 @@ impl<'a> Parser<'a> {
} else {
self.parse_stmt_path_start(lo, attrs)
}?
- } else if let Some(item) =
- self.parse_item_common(attrs.clone(), false, true, |_| true, force_collect)?
- {
+ } else if let Some(item) = self.parse_item_common(
+ attrs.clone(),
+ false,
+ true,
+ FnParseMode { req_name: |_| true, req_body: true },
+ force_collect,
+ )? {
// FIXME: Bad copy of attrs
self.mk_stmt(lo.to(item.span), StmtKind::Item(P(item)))
} else if self.eat(&token::Semi) {
diff --git a/compiler/rustc_parse/src/parser/ty.rs b/compiler/rustc_parse/src/parser/ty.rs
index c4c0c17addf..02a774ba129 100644
--- a/compiler/rustc_parse/src/parser/ty.rs
+++ b/compiler/rustc_parse/src/parser/ty.rs
@@ -4,9 +4,10 @@ use crate::{maybe_recover_from_interpolated_ty_qpath, maybe_whole};
use rustc_ast::ptr::P;
use rustc_ast::token::{self, Token, TokenKind};
-use rustc_ast::{self as ast, BareFnTy, FnRetTy, GenericParam, Lifetime, MutTy, Ty, TyKind};
-use rustc_ast::{GenericBound, GenericBounds, MacCall, Mutability};
-use rustc_ast::{PolyTraitRef, TraitBoundModifier, TraitObjectSyntax};
+use rustc_ast::{
+ self as ast, BareFnTy, FnRetTy, GenericBound, GenericBounds, GenericParam, Generics, Lifetime,
+ MacCall, MutTy, Mutability, PolyTraitRef, TraitBoundModifier, TraitObjectSyntax, Ty, TyKind,
+};
use rustc_errors::{pluralize, struct_span_err, Applicability, PResult};
use rustc_span::source_map::Span;
use rustc_span::symbol::{kw, sym};
@@ -98,6 +99,20 @@ impl<'a> Parser<'a> {
AllowCVariadic::No,
RecoverQPath::Yes,
RecoverReturnSign::Yes,
+ None,
+ )
+ }
+
+ pub(super) fn parse_ty_with_generics_recovery(
+ &mut self,
+ ty_params: &Generics,
+ ) -> PResult<'a, P<Ty>> {
+ self.parse_ty_common(
+ AllowPlus::Yes,
+ AllowCVariadic::No,
+ RecoverQPath::Yes,
+ RecoverReturnSign::Yes,
+ Some(ty_params),
)
}
@@ -110,6 +125,7 @@ impl<'a> Parser<'a> {
AllowCVariadic::Yes,
RecoverQPath::Yes,
RecoverReturnSign::Yes,
+ None,
)
}
@@ -125,6 +141,7 @@ impl<'a> Parser<'a> {
AllowCVariadic::No,
RecoverQPath::Yes,
RecoverReturnSign::Yes,
+ None,
)
}
@@ -135,6 +152,7 @@ impl<'a> Parser<'a> {
AllowCVariadic::Yes,
RecoverQPath::Yes,
RecoverReturnSign::OnlyFatArrow,
+ None,
)
}
@@ -152,6 +170,7 @@ impl<'a> Parser<'a> {
AllowCVariadic::No,
recover_qpath,
recover_return_sign,
+ None,
)?;
FnRetTy::Ty(ty)
} else if recover_return_sign.can_recover(&self.token.kind) {
@@ -171,6 +190,7 @@ impl<'a> Parser<'a> {
AllowCVariadic::No,
recover_qpath,
recover_return_sign,
+ None,
)?;
FnRetTy::Ty(ty)
} else {
@@ -184,6 +204,7 @@ impl<'a> Parser<'a> {
allow_c_variadic: AllowCVariadic,
recover_qpath: RecoverQPath,
recover_return_sign: RecoverReturnSign,
+ ty_generics: Option<&Generics>,
) -> PResult<'a, P<Ty>> {
let allow_qpath_recovery = recover_qpath == RecoverQPath::Yes;
maybe_recover_from_interpolated_ty_qpath!(self, allow_qpath_recovery);
@@ -233,7 +254,7 @@ impl<'a> Parser<'a> {
let (qself, path) = self.parse_qpath(PathStyle::Type)?;
TyKind::Path(Some(qself), path)
} else if self.check_path() {
- self.parse_path_start_ty(lo, allow_plus)?
+ self.parse_path_start_ty(lo, allow_plus, ty_generics)?
} else if self.can_begin_bound() {
self.parse_bare_trait_object(lo, allow_plus)?
} else if self.eat(&token::DotDotDot) {
@@ -453,7 +474,13 @@ impl<'a> Parser<'a> {
params: Vec<GenericParam>,
recover_return_sign: RecoverReturnSign,
) -> PResult<'a, TyKind> {
- let ast::FnHeader { ext, unsafety, constness, asyncness } = self.parse_fn_front_matter()?;
+ let inherited_vis = rustc_ast::Visibility {
+ span: rustc_span::DUMMY_SP,
+ kind: rustc_ast::VisibilityKind::Inherited,
+ tokens: None,
+ };
+ let ast::FnHeader { ext, unsafety, constness, asyncness } =
+ self.parse_fn_front_matter(&inherited_vis)?;
let decl = self.parse_fn_decl(|_| false, AllowPlus::No, recover_return_sign)?;
let whole_span = lo.to(self.prev_token.span);
if let ast::Const::Yes(span) = constness {
@@ -512,9 +539,14 @@ impl<'a> Parser<'a> {
/// 1. a type macro, `mac!(...)`,
/// 2. a bare trait object, `B0 + ... + Bn`,
/// 3. or a path, `path::to::MyType`.
- fn parse_path_start_ty(&mut self, lo: Span, allow_plus: AllowPlus) -> PResult<'a, TyKind> {
+ fn parse_path_start_ty(
+ &mut self,
+ lo: Span,
+ allow_plus: AllowPlus,
+ ty_generics: Option<&Generics>,
+ ) -> PResult<'a, TyKind> {
// Simple path
- let path = self.parse_path(PathStyle::Type)?;
+ let path = self.parse_path_inner(PathStyle::Type, ty_generics)?;
if self.eat(&token::Not) {
// Macro invocation in type position
Ok(TyKind::MacCall(MacCall {
diff --git a/compiler/rustc_passes/src/check_attr.rs b/compiler/rustc_passes/src/check_attr.rs
index 2def57cf02a..38ad8283f4d 100644
--- a/compiler/rustc_passes/src/check_attr.rs
+++ b/compiler/rustc_passes/src/check_attr.rs
@@ -32,7 +32,7 @@ pub(crate) fn target_from_impl_item<'tcx>(
match impl_item.kind {
hir::ImplItemKind::Const(..) => Target::AssocConst,
hir::ImplItemKind::Fn(..) => {
- let parent_hir_id = tcx.hir().get_parent_item(impl_item.hir_id());
+ let parent_hir_id = tcx.hir().get_parent_item(impl_item.hir_id()).expect_owner();
let containing_item = tcx.hir().expect_item(parent_hir_id);
let containing_impl_is_for_trait = match &containing_item.kind {
hir::ItemKind::Impl(impl_) => impl_.of_trait.is_some(),
@@ -58,7 +58,7 @@ struct CheckAttrVisitor<'tcx> {
tcx: TyCtxt<'tcx>,
}
-impl CheckAttrVisitor<'tcx> {
+impl CheckAttrVisitor<'_> {
/// Checks any attribute.
fn check_attributes(
&self,
@@ -382,7 +382,7 @@ impl CheckAttrVisitor<'tcx> {
&self,
hir_id: HirId,
attr_span: &Span,
- attrs: &'hir [Attribute],
+ attrs: &[Attribute],
span: &Span,
target: Target,
) -> bool {
@@ -582,7 +582,7 @@ impl CheckAttrVisitor<'tcx> {
Target::Impl => Some("implementation block"),
Target::ForeignMod => Some("extern block"),
Target::AssocTy => {
- let parent_hir_id = self.tcx.hir().get_parent_item(hir_id);
+ let parent_hir_id = self.tcx.hir().get_parent_item(hir_id).expect_owner();
let containing_item = self.tcx.hir().expect_item(parent_hir_id);
if Target::from_item(containing_item) == Target::Impl {
Some("type alias in implementation block")
@@ -591,7 +591,7 @@ impl CheckAttrVisitor<'tcx> {
}
}
Target::AssocConst => {
- let parent_hir_id = self.tcx.hir().get_parent_item(hir_id);
+ let parent_hir_id = self.tcx.hir().get_parent_item(hir_id).expect_owner();
let containing_item = self.tcx.hir().expect_item(parent_hir_id);
// We can't link to trait impl's consts.
let err = "associated constant in trait implementation block";
@@ -982,7 +982,7 @@ impl CheckAttrVisitor<'tcx> {
}
sym::primitive => {
- if !self.tcx.features().doc_primitive {
+ if !self.tcx.features().rustdoc_internals {
self.tcx.struct_span_lint_hir(
INVALID_DOC_ATTRIBUTES,
hir_id,
@@ -1481,7 +1481,7 @@ impl CheckAttrVisitor<'tcx> {
/// Checks if the `#[repr]` attributes on `item` are valid.
fn check_repr(
&self,
- attrs: &'hir [Attribute],
+ attrs: &[Attribute],
span: &Span,
target: Target,
item: Option<ItemLike<'_>>,
@@ -1663,7 +1663,7 @@ impl CheckAttrVisitor<'tcx> {
}
}
- fn check_used(&self, attrs: &'hir [Attribute], target: Target) {
+ fn check_used(&self, attrs: &[Attribute], target: Target) {
for attr in attrs {
if attr.has_name(sym::used) && target != Target::Static {
self.tcx
@@ -1842,7 +1842,7 @@ impl CheckAttrVisitor<'tcx> {
}
}
-impl Visitor<'tcx> for CheckAttrVisitor<'tcx> {
+impl<'tcx> Visitor<'tcx> for CheckAttrVisitor<'tcx> {
type Map = Map<'tcx>;
fn nested_visit_map(&mut self) -> NestedVisitorMap<Self::Map> {
@@ -1953,7 +1953,12 @@ fn is_c_like_enum(item: &Item<'_>) -> bool {
}
}
+// FIXME: Fix "Cannot determine resolution" error and remove built-in macros
+// from this check.
fn check_invalid_crate_level_attr(tcx: TyCtxt<'_>, attrs: &[Attribute]) {
+ // Check for builtin attributes at the crate level
+ // which were unsuccessfully resolved due to cannot determine
+ // resolution for the attribute macro error.
const ATTRS_TO_CHECK: &[Symbol] = &[
sym::macro_export,
sym::repr,
@@ -1961,20 +1966,39 @@ fn check_invalid_crate_level_attr(tcx: TyCtxt<'_>, attrs: &[Attribute]) {
sym::automatically_derived,
sym::start,
sym::rustc_main,
+ sym::derive,
+ sym::test,
+ sym::test_case,
+ sym::global_allocator,
+ sym::bench,
];
for attr in attrs {
- for attr_to_check in ATTRS_TO_CHECK {
- if attr.has_name(*attr_to_check) {
- tcx.sess
- .struct_span_err(
+ // This function should only be called with crate attributes
+ // which are inner attributes always but lets check to make sure
+ if attr.style == AttrStyle::Inner {
+ for attr_to_check in ATTRS_TO_CHECK {
+ if attr.has_name(*attr_to_check) {
+ let mut err = tcx.sess.struct_span_err(
attr.span,
&format!(
"`{}` attribute cannot be used at crate level",
attr_to_check.to_ident_string()
),
- )
- .emit();
+ );
+ // Only emit an error with a suggestion if we can create a
+ // string out of the attribute span
+ if let Ok(src) = tcx.sess.source_map().span_to_snippet(attr.span) {
+ let replacement = src.replace("#!", "#");
+ err.span_suggestion_verbose(
+ attr.span,
+ "perhaps you meant to use an outer attribute",
+ replacement,
+ rustc_errors::Applicability::MachineApplicable,
+ );
+ }
+ err.emit()
+ }
}
}
}
diff --git a/compiler/rustc_passes/src/check_const.rs b/compiler/rustc_passes/src/check_const.rs
index 82486a6a5f2..a5a65740707 100644
--- a/compiler/rustc_passes/src/check_const.rs
+++ b/compiler/rustc_passes/src/check_const.rs
@@ -78,7 +78,7 @@ impl<'tcx> CheckConstTraitVisitor<'tcx> {
impl<'tcx> hir::itemlikevisit::ItemLikeVisitor<'tcx> for CheckConstTraitVisitor<'tcx> {
/// check for const trait impls, and errors if the impl uses provided/default functions
/// of the trait being implemented; as those provided functions can be non-const.
- fn visit_item(&mut self, item: &'hir hir::Item<'hir>) {
+ fn visit_item<'hir>(&mut self, item: &'hir hir::Item<'hir>) {
let _: Option<_> = try {
if let hir::ItemKind::Impl(ref imp) = item.kind {
if let hir::Constness::Const = imp.constness {
@@ -134,11 +134,11 @@ impl<'tcx> hir::itemlikevisit::ItemLikeVisitor<'tcx> for CheckConstTraitVisitor<
};
}
- fn visit_trait_item(&mut self, _: &'hir hir::TraitItem<'hir>) {}
+ fn visit_trait_item<'hir>(&mut self, _: &'hir hir::TraitItem<'hir>) {}
- fn visit_impl_item(&mut self, _: &'hir hir::ImplItem<'hir>) {}
+ fn visit_impl_item<'hir>(&mut self, _: &'hir hir::ImplItem<'hir>) {}
- fn visit_foreign_item(&mut self, _: &'hir hir::ForeignItem<'hir>) {}
+ fn visit_foreign_item<'hir>(&mut self, _: &'hir hir::ForeignItem<'hir>) {}
}
#[derive(Copy, Clone)]
@@ -173,6 +173,12 @@ impl<'tcx> CheckConstVisitor<'tcx> {
None => return true,
};
+ // If the function belongs to a trait, then it must enable the const_trait_impl
+ // feature to use that trait function (with a const default body).
+ if tcx.trait_of_item(def_id).is_some() {
+ return true;
+ }
+
// If this crate is not using stability attributes, or this function is not claiming to be a
// stable `const fn`, that is all that is required.
if !tcx.features().staged_api || tcx.has_attr(def_id, sym::rustc_const_unstable) {
diff --git a/compiler/rustc_passes/src/dead.rs b/compiler/rustc_passes/src/dead.rs
index 77279132401..3b15332c678 100644
--- a/compiler/rustc_passes/src/dead.rs
+++ b/compiler/rustc_passes/src/dead.rs
@@ -150,7 +150,7 @@ impl<'tcx> MarkSymbolVisitor<'tcx> {
#[allow(dead_code)] // FIXME(81658): should be used + lint reinstated after #83171 relands.
fn check_for_self_assign(&mut self, assign: &'tcx hir::Expr<'tcx>) {
- fn check_for_self_assign_helper(
+ fn check_for_self_assign_helper<'tcx>(
tcx: TyCtxt<'tcx>,
typeck_results: &'tcx ty::TypeckResults<'tcx>,
lhs: &'tcx hir::Expr<'tcx>,
@@ -600,7 +600,7 @@ struct DeadVisitor<'tcx> {
live_symbols: FxHashSet<LocalDefId>,
}
-impl DeadVisitor<'tcx> {
+impl<'tcx> DeadVisitor<'tcx> {
fn should_warn_about_item(&mut self, item: &hir::Item<'_>) -> bool {
let should_warn = matches!(
item.kind,
@@ -672,7 +672,7 @@ impl DeadVisitor<'tcx> {
}
}
-impl Visitor<'tcx> for DeadVisitor<'tcx> {
+impl<'tcx> Visitor<'tcx> for DeadVisitor<'tcx> {
type Map = Map<'tcx>;
/// Walk nested items in place so that we don't report dead-code
diff --git a/compiler/rustc_passes/src/intrinsicck.rs b/compiler/rustc_passes/src/intrinsicck.rs
index 008b856ebf2..064c4696628 100644
--- a/compiler/rustc_passes/src/intrinsicck.rs
+++ b/compiler/rustc_passes/src/intrinsicck.rs
@@ -62,7 +62,7 @@ fn unpack_option_like<'tcx>(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>) -> Ty<'tcx> {
ty
}
-impl ExprVisitor<'tcx> {
+impl<'tcx> ExprVisitor<'tcx> {
fn def_id_is_transmute(&self, def_id: DefId) -> bool {
self.tcx.fn_sig(def_id).abi() == RustIntrinsic
&& self.tcx.item_name(def_id) == sym::transmute
@@ -487,7 +487,7 @@ impl ExprVisitor<'tcx> {
}
}
-impl Visitor<'tcx> for ItemVisitor<'tcx> {
+impl<'tcx> Visitor<'tcx> for ItemVisitor<'tcx> {
type Map = intravisit::ErasedMap<'tcx>;
fn nested_visit_map(&mut self) -> NestedVisitorMap<Self::Map> {
@@ -504,7 +504,7 @@ impl Visitor<'tcx> for ItemVisitor<'tcx> {
}
}
-impl Visitor<'tcx> for ExprVisitor<'tcx> {
+impl<'tcx> Visitor<'tcx> for ExprVisitor<'tcx> {
type Map = intravisit::ErasedMap<'tcx>;
fn nested_visit_map(&mut self) -> NestedVisitorMap<Self::Map> {
diff --git a/compiler/rustc_passes/src/lang_items.rs b/compiler/rustc_passes/src/lang_items.rs
index 388c33917c6..a808d6c8348 100644
--- a/compiler/rustc_passes/src/lang_items.rs
+++ b/compiler/rustc_passes/src/lang_items.rs
@@ -28,7 +28,7 @@ struct LanguageItemCollector<'tcx> {
tcx: TyCtxt<'tcx>,
}
-impl ItemLikeVisitor<'v> for LanguageItemCollector<'tcx> {
+impl<'v, 'tcx> ItemLikeVisitor<'v> for LanguageItemCollector<'tcx> {
fn visit_item(&mut self, item: &hir::Item<'_>) {
self.check_for_lang(Target::from_item(item), item.hir_id());
@@ -50,7 +50,7 @@ impl ItemLikeVisitor<'v> for LanguageItemCollector<'tcx> {
fn visit_foreign_item(&mut self, _: &hir::ForeignItem<'_>) {}
}
-impl LanguageItemCollector<'tcx> {
+impl<'tcx> LanguageItemCollector<'tcx> {
fn new(tcx: TyCtxt<'tcx>) -> LanguageItemCollector<'tcx> {
LanguageItemCollector { tcx, items: LanguageItems::new() }
}
diff --git a/compiler/rustc_passes/src/layout_test.rs b/compiler/rustc_passes/src/layout_test.rs
index 558d8958b13..00e8eb5eb2b 100644
--- a/compiler/rustc_passes/src/layout_test.rs
+++ b/compiler/rustc_passes/src/layout_test.rs
@@ -20,7 +20,7 @@ struct LayoutTest<'tcx> {
tcx: TyCtxt<'tcx>,
}
-impl ItemLikeVisitor<'tcx> for LayoutTest<'tcx> {
+impl<'tcx> ItemLikeVisitor<'tcx> for LayoutTest<'tcx> {
fn visit_item(&mut self, item: &'tcx hir::Item<'tcx>) {
match item.kind {
ItemKind::TyAlias(..)
@@ -42,7 +42,7 @@ impl ItemLikeVisitor<'tcx> for LayoutTest<'tcx> {
fn visit_foreign_item(&mut self, _: &'tcx hir::ForeignItem<'tcx>) {}
}
-impl LayoutTest<'tcx> {
+impl<'tcx> LayoutTest<'tcx> {
fn dump_layout_of(&self, item_def_id: LocalDefId, item: &hir::Item<'tcx>, attr: &Attribute) {
let tcx = self.tcx;
let param_env = self.tcx.param_env(item_def_id);
@@ -114,7 +114,7 @@ struct UnwrapLayoutCx<'tcx> {
param_env: ParamEnv<'tcx>,
}
-impl LayoutOfHelpers<'tcx> for UnwrapLayoutCx<'tcx> {
+impl<'tcx> LayoutOfHelpers<'tcx> for UnwrapLayoutCx<'tcx> {
type LayoutOfResult = TyAndLayout<'tcx>;
fn handle_layout_err(&self, err: LayoutError<'tcx>, span: Span, ty: Ty<'tcx>) -> ! {
@@ -127,19 +127,19 @@ impl LayoutOfHelpers<'tcx> for UnwrapLayoutCx<'tcx> {
}
}
-impl HasTyCtxt<'tcx> for UnwrapLayoutCx<'tcx> {
+impl<'tcx> HasTyCtxt<'tcx> for UnwrapLayoutCx<'tcx> {
fn tcx(&self) -> TyCtxt<'tcx> {
self.tcx
}
}
-impl HasParamEnv<'tcx> for UnwrapLayoutCx<'tcx> {
+impl<'tcx> HasParamEnv<'tcx> for UnwrapLayoutCx<'tcx> {
fn param_env(&self) -> ParamEnv<'tcx> {
self.param_env
}
}
-impl HasDataLayout for UnwrapLayoutCx<'tcx> {
+impl<'tcx> HasDataLayout for UnwrapLayoutCx<'tcx> {
fn data_layout(&self) -> &TargetDataLayout {
self.tcx.data_layout()
}
diff --git a/compiler/rustc_passes/src/lib.rs b/compiler/rustc_passes/src/lib.rs
index af1c7244100..8a411f01d6e 100644
--- a/compiler/rustc_passes/src/lib.rs
+++ b/compiler/rustc_passes/src/lib.rs
@@ -6,9 +6,6 @@
#![doc(html_root_url = "https://doc.rust-lang.org/nightly/nightly-rustc/")]
#![feature(crate_visibility_modifier)]
-#![feature(in_band_lifetimes)]
-#![cfg_attr(bootstrap, feature(format_args_capture))]
-#![feature(iter_zip)]
#![feature(map_try_insert)]
#![feature(min_specialization)]
#![feature(nll)]
diff --git a/compiler/rustc_passes/src/lib_features.rs b/compiler/rustc_passes/src/lib_features.rs
index ff8bd37238d..55ae808dc30 100644
--- a/compiler/rustc_passes/src/lib_features.rs
+++ b/compiler/rustc_passes/src/lib_features.rs
@@ -23,7 +23,7 @@ pub struct LibFeatureCollector<'tcx> {
lib_features: LibFeatures,
}
-impl LibFeatureCollector<'tcx> {
+impl<'tcx> LibFeatureCollector<'tcx> {
fn new(tcx: TyCtxt<'tcx>) -> LibFeatureCollector<'tcx> {
LibFeatureCollector { tcx, lib_features: new_lib_features() }
}
@@ -110,7 +110,7 @@ impl LibFeatureCollector<'tcx> {
}
}
-impl Visitor<'tcx> for LibFeatureCollector<'tcx> {
+impl<'tcx> Visitor<'tcx> for LibFeatureCollector<'tcx> {
type Map = Map<'tcx>;
fn nested_visit_map(&mut self) -> NestedVisitorMap<Self::Map> {
@@ -124,12 +124,12 @@ impl Visitor<'tcx> for LibFeatureCollector<'tcx> {
}
}
-fn get_lib_features(tcx: TyCtxt<'_>, (): ()) -> LibFeatures {
+fn lib_features(tcx: TyCtxt<'_>, (): ()) -> LibFeatures {
let mut collector = LibFeatureCollector::new(tcx);
tcx.hir().walk_attributes(&mut collector);
collector.lib_features
}
pub fn provide(providers: &mut Providers) {
- providers.get_lib_features = get_lib_features;
+ providers.lib_features = lib_features;
}
diff --git a/compiler/rustc_passes/src/liveness.rs b/compiler/rustc_passes/src/liveness.rs
index 3d7a215754a..3ee10431679 100644
--- a/compiler/rustc_passes/src/liveness.rs
+++ b/compiler/rustc_passes/src/liveness.rs
@@ -198,7 +198,7 @@ struct IrMaps<'tcx> {
lnks: IndexVec<LiveNode, LiveNodeKind>,
}
-impl IrMaps<'tcx> {
+impl<'tcx> IrMaps<'tcx> {
fn new(tcx: TyCtxt<'tcx>) -> IrMaps<'tcx> {
IrMaps {
tcx,
@@ -429,8 +429,8 @@ impl<'tcx> Visitor<'tcx> for IrMaps<'tcx> {
intravisit::walk_expr(self, expr);
}
- hir::ExprKind::Let(ref pat, ..) => {
- self.add_from_pat(pat);
+ hir::ExprKind::Let(let_expr) => {
+ self.add_from_pat(let_expr.pat);
intravisit::walk_expr(self, expr);
}
@@ -856,9 +856,9 @@ impl<'a, 'tcx> Liveness<'a, 'tcx> {
})
}
- hir::ExprKind::Let(ref pat, ref scrutinee, _) => {
- let succ = self.propagate_through_expr(scrutinee, succ);
- self.define_bindings_in_pat(pat, succ)
+ hir::ExprKind::Let(let_expr) => {
+ let succ = self.propagate_through_expr(let_expr.init, succ);
+ self.define_bindings_in_pat(let_expr.pat, succ)
}
// Note that labels have been resolved, so we don't need to look
@@ -1401,8 +1401,8 @@ fn check_expr<'tcx>(this: &mut Liveness<'_, 'tcx>, expr: &'tcx Expr<'tcx>) {
}
}
- hir::ExprKind::Let(ref pat, ..) => {
- this.check_unused_vars_in_pat(pat, None, |_, _, _, _| {});
+ hir::ExprKind::Let(let_expr) => {
+ this.check_unused_vars_in_pat(let_expr.pat, None, |_, _, _, _| {});
}
// no correctness conditions related to liveness
diff --git a/compiler/rustc_passes/src/naked_functions.rs b/compiler/rustc_passes/src/naked_functions.rs
index d3ecd18a93c..07cb165d796 100644
--- a/compiler/rustc_passes/src/naked_functions.rs
+++ b/compiler/rustc_passes/src/naked_functions.rs
@@ -37,7 +37,7 @@ impl<'tcx> Visitor<'tcx> for CheckNakedFunctions<'tcx> {
fn visit_fn(
&mut self,
- fk: FnKind<'v>,
+ fk: FnKind<'_>,
_fd: &'tcx hir::FnDecl<'tcx>,
body_id: hir::BodyId,
span: Span,
diff --git a/compiler/rustc_passes/src/reachable.rs b/compiler/rustc_passes/src/reachable.rs
index bd1e9520ee9..707e6b123da 100644
--- a/compiler/rustc_passes/src/reachable.rs
+++ b/compiler/rustc_passes/src/reachable.rs
@@ -22,7 +22,7 @@ use rustc_target::spec::abi::Abi;
// Returns true if the given item must be inlined because it may be
// monomorphized or it was marked with `#[inline]`. This will only return
// true for functions.
-fn item_might_be_inlined(tcx: TyCtxt<'tcx>, item: &hir::Item<'_>, attrs: &CodegenFnAttrs) -> bool {
+fn item_might_be_inlined(tcx: TyCtxt<'_>, item: &hir::Item<'_>, attrs: &CodegenFnAttrs) -> bool {
if attrs.requests_inline() {
return true;
}
@@ -173,8 +173,7 @@ impl<'tcx> ReachableContext<'tcx> {
// Check the impl. If the generics on the self
// type of the impl require inlining, this method
// does too.
- let impl_hir_id = self.tcx.hir().local_def_id_to_hir_id(impl_did);
- match self.tcx.hir().expect_item(impl_hir_id).kind {
+ match self.tcx.hir().expect_item(impl_did).kind {
hir::ItemKind::Impl { .. } => {
let generics = self.tcx.generics_of(impl_did);
generics.requires_monomorphization(self.tcx)
diff --git a/compiler/rustc_passes/src/region.rs b/compiler/rustc_passes/src/region.rs
index 6a8feb041da..8968c163987 100644
--- a/compiler/rustc_passes/src/region.rs
+++ b/compiler/rustc_passes/src/region.rs
@@ -11,7 +11,7 @@ use rustc_data_structures::fx::FxHashSet;
use rustc_hir as hir;
use rustc_hir::def_id::DefId;
use rustc_hir::intravisit::{self, NestedVisitorMap, Visitor};
-use rustc_hir::{Arm, Block, Expr, Local, Node, Pat, PatKind, Stmt};
+use rustc_hir::{Arm, Block, Expr, Local, Pat, PatKind, Stmt};
use rustc_index::vec::Idx;
use rustc_middle::middle::region::*;
use rustc_middle::ty::query::Providers;
@@ -421,11 +421,14 @@ fn resolve_expr<'tcx>(visitor: &mut RegionResolutionVisitor<'tcx>, expr: &'tcx h
// Mark this expr's scope and all parent scopes as containing `yield`.
let mut scope = Scope { id: expr.hir_id.local_id, data: ScopeData::Node };
loop {
- let data = YieldData {
- span: expr.span,
- expr_and_pat_count: visitor.expr_and_pat_count,
- source: *source,
+ let span = match expr.kind {
+ hir::ExprKind::Yield(expr, hir::YieldSource::Await { .. }) => {
+ expr.span.shrink_to_hi().to(expr.span)
+ }
+ _ => expr.span,
};
+ let data =
+ YieldData { span, expr_and_pat_count: visitor.expr_and_pat_count, source: *source };
visitor.scope_tree.yield_in_scope.insert(scope, data);
if visitor.pessimistic_yield {
debug!("resolve_expr in pessimistic_yield - marking scope {:?} for fixup", scope);
@@ -837,19 +840,7 @@ fn region_scope_tree(tcx: TyCtxt<'_>, def_id: DefId) -> &ScopeTree {
let body = tcx.hir().body(body_id);
visitor.scope_tree.root_body = Some(body.value.hir_id);
-
- // If the item is an associated const or a method,
- // record its impl/trait parent, as it can also have
- // lifetime parameters free in this body.
- match tcx.hir().get(id) {
- Node::ImplItem(_) | Node::TraitItem(_) => {
- visitor.scope_tree.root_parent = Some(tcx.hir().get_parent_item(id));
- }
- _ => {}
- }
-
visitor.visit_body(body);
-
visitor.scope_tree
} else {
ScopeTree::default()
diff --git a/compiler/rustc_passes/src/stability.rs b/compiler/rustc_passes/src/stability.rs
index 8c9f04bef13..5f19991f9c7 100644
--- a/compiler/rustc_passes/src/stability.rs
+++ b/compiler/rustc_passes/src/stability.rs
@@ -655,7 +655,7 @@ impl<'tcx> Visitor<'tcx> for MissingStabilityAnnotations<'tcx> {
// stable (assuming they have not inherited instability from their parent).
}
-fn stability_index(tcx: TyCtxt<'tcx>, (): ()) -> Index<'tcx> {
+fn stability_index<'tcx>(tcx: TyCtxt<'tcx>, (): ()) -> Index<'tcx> {
let is_staged_api =
tcx.sess.opts.debugging_opts.force_unstable_if_unmarked || tcx.features().staged_api;
let mut staged_api = FxHashMap::default();
@@ -737,7 +737,7 @@ struct Checker<'tcx> {
tcx: TyCtxt<'tcx>,
}
-impl Visitor<'tcx> for Checker<'tcx> {
+impl<'tcx> Visitor<'tcx> for Checker<'tcx> {
type Map = Map<'tcx>;
/// Because stability levels are scoped lexically, we want to walk
@@ -866,7 +866,7 @@ struct CheckTraitImplStable<'tcx> {
fully_stable: bool,
}
-impl Visitor<'tcx> for CheckTraitImplStable<'tcx> {
+impl<'tcx> Visitor<'tcx> for CheckTraitImplStable<'tcx> {
type Map = Map<'tcx>;
fn nested_visit_map(&mut self) -> NestedVisitorMap<Self::Map> {
@@ -970,7 +970,7 @@ pub fn check_unused_or_stable_features(tcx: TyCtxt<'_>) {
// We always collect the lib features declared in the current crate, even if there are
// no unknown features, because the collection also does feature attribute validation.
- let local_defined_features = tcx.lib_features().to_vec();
+ let local_defined_features = tcx.lib_features(()).to_vec();
if !remaining_lib_features.is_empty() {
check_features(&mut remaining_lib_features, &local_defined_features);
diff --git a/compiler/rustc_passes/src/upvars.rs b/compiler/rustc_passes/src/upvars.rs
index 91b8ae07637..2d84c8caada 100644
--- a/compiler/rustc_passes/src/upvars.rs
+++ b/compiler/rustc_passes/src/upvars.rs
@@ -42,7 +42,7 @@ struct LocalCollector {
locals: FxHashSet<HirId>,
}
-impl Visitor<'tcx> for LocalCollector {
+impl<'tcx> Visitor<'tcx> for LocalCollector {
type Map = intravisit::ErasedMap<'tcx>;
fn nested_visit_map(&mut self) -> NestedVisitorMap<Self::Map> {
@@ -71,7 +71,7 @@ impl CaptureCollector<'_, '_> {
}
}
-impl Visitor<'tcx> for CaptureCollector<'a, 'tcx> {
+impl<'tcx> Visitor<'tcx> for CaptureCollector<'_, 'tcx> {
type Map = intravisit::ErasedMap<'tcx>;
fn nested_visit_map(&mut self) -> NestedVisitorMap<Self::Map> {
diff --git a/compiler/rustc_passes/src/weak_lang_items.rs b/compiler/rustc_passes/src/weak_lang_items.rs
index c6c32e69aab..61c82f031dd 100644
--- a/compiler/rustc_passes/src/weak_lang_items.rs
+++ b/compiler/rustc_passes/src/weak_lang_items.rs
@@ -67,10 +67,16 @@ fn verify<'tcx>(tcx: TyCtxt<'tcx>, items: &lang_items::LanguageItems) {
} else if item == LangItem::Oom {
if !tcx.features().default_alloc_error_handler {
tcx.sess.err("`#[alloc_error_handler]` function required, but not found");
- tcx.sess.note_without_error("Use `#![feature(default_alloc_error_handler)]` for a default error handler");
+ tcx.sess.note_without_error("use `#![feature(default_alloc_error_handler)]` for a default error handler");
}
} else {
- tcx.sess.err(&format!("language item required, but not found: `{}`", name));
+ tcx
+ .sess
+ .diagnostic()
+ .struct_err(&format!("language item required, but not found: `{}`", name))
+ .note(&format!("this can occur when a binary crate with `#![no_std]` is compiled for a target where `{}` is defined in the standard library", name))
+ .help(&format!("you may be able to compile for a target that doesn't need `{}`, specify a target with `--target` or in `.cargo/config`", name))
+ .emit();
}
}
}
diff --git a/compiler/rustc_plugin_impl/Cargo.toml b/compiler/rustc_plugin_impl/Cargo.toml
index 4e666e7e93d..f5071eb6e8f 100644
--- a/compiler/rustc_plugin_impl/Cargo.toml
+++ b/compiler/rustc_plugin_impl/Cargo.toml
@@ -8,6 +8,7 @@ edition = "2021"
doctest = false
[dependencies]
+libloading = "0.7.1"
rustc_middle = { path = "../rustc_middle" }
rustc_errors = { path = "../rustc_errors" }
rustc_hir = { path = "../rustc_hir" }
diff --git a/compiler/rustc_plugin_impl/src/load.rs b/compiler/rustc_plugin_impl/src/load.rs
index c21075a443c..618682da4e5 100644
--- a/compiler/rustc_plugin_impl/src/load.rs
+++ b/compiler/rustc_plugin_impl/src/load.rs
@@ -1,6 +1,7 @@
//! Used by `rustc` when loading a plugin.
use crate::Registry;
+use libloading::Library;
use rustc_ast::Crate;
use rustc_errors::struct_span_err;
use rustc_metadata::locator;
@@ -56,37 +57,28 @@ fn load_plugin(
ident: Ident,
) {
let lib = locator::find_plugin_registrar(sess, metadata_loader, ident.span, ident.name);
- let fun = dylink_registrar(sess, ident.span, lib);
+ let fun = dylink_registrar(lib).unwrap_or_else(|err| {
+ // This is fatal: there are almost certainly macros we need inside this crate, so
+ // continuing would spew "macro undefined" errors.
+ sess.span_fatal(ident.span, &err.to_string());
+ });
plugins.push(fun);
}
-// Dynamically link a registrar function into the compiler process.
-fn dylink_registrar(sess: &Session, span: Span, path: PathBuf) -> PluginRegistrarFn {
- use rustc_metadata::dynamic_lib::DynamicLibrary;
-
+/// Dynamically link a registrar function into the compiler process.
+fn dylink_registrar(lib_path: PathBuf) -> Result<PluginRegistrarFn, libloading::Error> {
// Make sure the path contains a / or the linker will search for it.
- let path = env::current_dir().unwrap().join(&path);
+ let lib_path = env::current_dir().unwrap().join(&lib_path);
- let lib = match DynamicLibrary::open(&path) {
- Ok(lib) => lib,
- // this is fatal: there are almost certainly macros we need
- // inside this crate, so continue would spew "macro undefined"
- // errors
- Err(err) => sess.span_fatal(span, &err),
- };
+ let lib = unsafe { Library::new(&lib_path) }?;
- unsafe {
- let registrar = match lib.symbol("__rustc_plugin_registrar") {
- Ok(registrar) => mem::transmute::<*mut u8, PluginRegistrarFn>(registrar),
- // again fatal if we can't register macros
- Err(err) => sess.span_fatal(span, &err),
- };
+ let registrar_sym = unsafe { lib.get::<PluginRegistrarFn>(b"__rustc_plugin_registrar") }?;
- // Intentionally leak the dynamic library. We can't ever unload it
- // since the library can make things that will live arbitrarily long
- // (e.g., an Rc cycle or a thread).
- mem::forget(lib);
+ // Intentionally leak the dynamic library. We can't ever unload it
+ // since the library can make things that will live arbitrarily long
+ // (e.g., an Rc cycle or a thread).
+ let registrar_sym = unsafe { registrar_sym.into_raw() };
+ mem::forget(lib);
- registrar
- }
+ Ok(*registrar_sym)
}
diff --git a/compiler/rustc_privacy/src/lib.rs b/compiler/rustc_privacy/src/lib.rs
index 11668146f7b..10f6f6b1a9f 100644
--- a/compiler/rustc_privacy/src/lib.rs
+++ b/compiler/rustc_privacy/src/lib.rs
@@ -1,5 +1,4 @@
#![doc(html_root_url = "https://doc.rust-lang.org/nightly/nightly-rustc/")]
-#![feature(in_band_lifetimes)]
#![feature(nll)]
#![feature(control_flow_enum)]
#![feature(try_blocks)]
@@ -310,7 +309,7 @@ struct PubRestrictedVisitor<'tcx> {
has_pub_restricted: bool,
}
-impl Visitor<'tcx> for PubRestrictedVisitor<'tcx> {
+impl<'tcx> Visitor<'tcx> for PubRestrictedVisitor<'tcx> {
type Map = Map<'tcx>;
fn nested_visit_map(&mut self) -> NestedVisitorMap<Self::Map> {
@@ -432,7 +431,7 @@ struct ReachEverythingInTheInterfaceVisitor<'a, 'tcx> {
ev: &'a mut EmbargoVisitor<'tcx>,
}
-impl EmbargoVisitor<'tcx> {
+impl<'tcx> EmbargoVisitor<'tcx> {
fn get(&self, def_id: LocalDefId) -> Option<AccessLevel> {
self.access_levels.map.get(&def_id).copied()
}
@@ -559,8 +558,7 @@ impl EmbargoVisitor<'tcx> {
// have normal hygine, so we can treat them like other items without type
// privacy and mark them reachable.
DefKind::Macro(_) => {
- let hir_id = self.tcx.hir().local_def_id_to_hir_id(def_id);
- let item = self.tcx.hir().expect_item(hir_id);
+ let item = self.tcx.hir().expect_item(def_id);
if let hir::ItemKind::Macro(MacroDef { macro_rules: false, .. }) = item.kind {
if vis.is_accessible_from(module.to_def_id(), self.tcx) {
self.update(def_id, level);
@@ -581,8 +579,7 @@ impl EmbargoVisitor<'tcx> {
DefKind::Struct | DefKind::Union => {
// While structs and unions have type privacy, their fields do not.
if vis.is_public() {
- let item =
- self.tcx.hir().expect_item(self.tcx.hir().local_def_id_to_hir_id(def_id));
+ let item = self.tcx.hir().expect_item(def_id);
if let hir::ItemKind::Struct(ref struct_def, _)
| hir::ItemKind::Union(ref struct_def, _) = item.kind
{
@@ -653,9 +650,7 @@ impl EmbargoVisitor<'tcx> {
// If the module is `self`, i.e. the current crate,
// there will be no corresponding item.
.filter(|def_id| def_id.index != CRATE_DEF_INDEX || def_id.krate != LOCAL_CRATE)
- .and_then(|def_id| {
- def_id.as_local().map(|def_id| self.tcx.hir().local_def_id_to_hir_id(def_id))
- })
+ .and_then(|def_id| def_id.as_local())
.map(|module_hir_id| self.tcx.hir().expect_item(module_hir_id))
{
if let hir::ItemKind::Mod(m) = &item.kind {
@@ -678,7 +673,7 @@ impl EmbargoVisitor<'tcx> {
}
}
-impl Visitor<'tcx> for EmbargoVisitor<'tcx> {
+impl<'tcx> Visitor<'tcx> for EmbargoVisitor<'tcx> {
type Map = Map<'tcx>;
/// We want to visit items in the context of their containing
@@ -948,7 +943,7 @@ impl Visitor<'tcx> for EmbargoVisitor<'tcx> {
}
}
-impl ReachEverythingInTheInterfaceVisitor<'_, 'tcx> {
+impl ReachEverythingInTheInterfaceVisitor<'_, '_> {
fn generics(&mut self) -> &mut Self {
for param in &self.ev.tcx.generics_of(self.item_def_id).params {
match param.kind {
@@ -987,7 +982,7 @@ impl ReachEverythingInTheInterfaceVisitor<'_, 'tcx> {
}
}
-impl DefIdVisitor<'tcx> for ReachEverythingInTheInterfaceVisitor<'_, 'tcx> {
+impl<'tcx> DefIdVisitor<'tcx> for ReachEverythingInTheInterfaceVisitor<'_, 'tcx> {
fn tcx(&self) -> TyCtxt<'tcx> {
self.ev.tcx
}
@@ -1417,7 +1412,7 @@ impl<'tcx> Visitor<'tcx> for TypePrivacyVisitor<'tcx> {
}
}
-impl DefIdVisitor<'tcx> for TypePrivacyVisitor<'tcx> {
+impl<'tcx> DefIdVisitor<'tcx> for TypePrivacyVisitor<'tcx> {
fn tcx(&self) -> TyCtxt<'tcx> {
self.tcx
}
@@ -1804,7 +1799,7 @@ struct SearchInterfaceForPrivateItemsVisitor<'tcx> {
in_assoc_ty: bool,
}
-impl SearchInterfaceForPrivateItemsVisitor<'tcx> {
+impl SearchInterfaceForPrivateItemsVisitor<'_> {
fn generics(&mut self) -> &mut Self {
for param in &self.tcx.generics_of(self.item_def_id).params {
match param.kind {
@@ -1925,7 +1920,7 @@ impl SearchInterfaceForPrivateItemsVisitor<'tcx> {
}
}
-impl DefIdVisitor<'tcx> for SearchInterfaceForPrivateItemsVisitor<'tcx> {
+impl<'tcx> DefIdVisitor<'tcx> for SearchInterfaceForPrivateItemsVisitor<'tcx> {
fn tcx(&self) -> TyCtxt<'tcx> {
self.tcx
}
diff --git a/compiler/rustc_query_impl/src/keys.rs b/compiler/rustc_query_impl/src/keys.rs
index 34489287596..581a2bce2e5 100644
--- a/compiler/rustc_query_impl/src/keys.rs
+++ b/compiler/rustc_query_impl/src/keys.rs
@@ -151,7 +151,7 @@ impl Key for (DefId, DefId) {
}
}
-impl Key for (ty::Instance<'tcx>, LocalDefId) {
+impl<'tcx> Key for (ty::Instance<'tcx>, LocalDefId) {
#[inline(always)]
fn query_crate_is_local(&self) -> bool {
true
diff --git a/compiler/rustc_query_impl/src/lib.rs b/compiler/rustc_query_impl/src/lib.rs
index 440b6f1983e..de9d4253537 100644
--- a/compiler/rustc_query_impl/src/lib.rs
+++ b/compiler/rustc_query_impl/src/lib.rs
@@ -2,7 +2,6 @@
#![doc(html_root_url = "https://doc.rust-lang.org/nightly/nightly-rustc/")]
#![feature(crate_visibility_modifier)]
-#![feature(in_band_lifetimes)]
#![feature(nll)]
#![feature(min_specialization)]
#![feature(once_cell)]
diff --git a/compiler/rustc_query_impl/src/on_disk_cache.rs b/compiler/rustc_query_impl/src/on_disk_cache.rs
index 552906aac31..11f54ea66fa 100644
--- a/compiler/rustc_query_impl/src/on_disk_cache.rs
+++ b/compiler/rustc_query_impl/src/on_disk_cache.rs
@@ -158,7 +158,7 @@ impl<'sess> rustc_middle::ty::OnDiskCache<'sess> for OnDiskCache<'sess> {
// Wrap in a scope so we can borrow `data`.
let footer: Footer = {
- let mut decoder = opaque::Decoder::new(&data[..], start_pos);
+ let mut decoder = opaque::Decoder::new(&data, start_pos);
// Decode the *position* of the footer, which can be found in the
// last 8 bytes of the file.
@@ -212,7 +212,7 @@ impl<'sess> rustc_middle::ty::OnDiskCache<'sess> for OnDiskCache<'sess> {
/// Cache promotions require invoking queries, which needs to read the serialized data.
/// In order to serialize the new on-disk cache, the former on-disk cache file needs to be
/// deleted, hence we won't be able to refer to its memmapped data.
- fn drop_serialized_data(&self, tcx: TyCtxt<'tcx>) {
+ fn drop_serialized_data(&self, tcx: TyCtxt<'_>) {
// Load everything into memory so we can write it out to the on-disk
// cache. The vast majority of cacheable query results should already
// be in memory, so this should be a cheap operation.
diff --git a/compiler/rustc_query_impl/src/plumbing.rs b/compiler/rustc_query_impl/src/plumbing.rs
index 81a36e0d59e..6d76d09f619 100644
--- a/compiler/rustc_query_impl/src/plumbing.rs
+++ b/compiler/rustc_query_impl/src/plumbing.rs
@@ -31,7 +31,7 @@ impl<'tcx> std::ops::Deref for QueryCtxt<'tcx> {
}
}
-impl HasDepContext for QueryCtxt<'tcx> {
+impl<'tcx> HasDepContext for QueryCtxt<'tcx> {
type DepKind = rustc_middle::dep_graph::DepKind;
type DepContext = TyCtxt<'tcx>;
@@ -41,7 +41,7 @@ impl HasDepContext for QueryCtxt<'tcx> {
}
}
-impl QueryContext for QueryCtxt<'tcx> {
+impl QueryContext for QueryCtxt<'_> {
fn current_query_job(&self) -> Option<QueryJobId<Self::DepKind>> {
tls::with_related_context(**self, |icx| icx.query)
}
@@ -130,7 +130,7 @@ impl<'tcx> QueryCtxt<'tcx> {
pub(super) fn encode_query_results(
self,
- encoder: &mut on_disk_cache::CacheEncoder<'a, 'tcx, opaque::FileEncoder>,
+ encoder: &mut on_disk_cache::CacheEncoder<'_, 'tcx, opaque::FileEncoder>,
query_result_index: &mut on_disk_cache::EncodedDepNodeIndex,
) -> opaque::FileEncodeResult {
macro_rules! encode_queries {
@@ -231,6 +231,16 @@ macro_rules! get_provider {
};
}
+macro_rules! opt_remap_env_constness {
+ ([][$name:ident]) => {};
+ ([(remap_env_constness) $($rest:tt)*][$name:ident]) => {
+ let $name = $name.without_const();
+ };
+ ([$other:tt $($modifiers:tt)*][$name:ident]) => {
+ opt_remap_env_constness!([$($modifiers)*][$name])
+ };
+}
+
macro_rules! define_queries {
(<$tcx:tt>
$($(#[$attr:meta])*
@@ -247,6 +257,7 @@ macro_rules! define_queries {
// Create an eponymous constructor for each query.
$(#[allow(nonstandard_style)] $(#[$attr])*
pub fn $name<$tcx>(tcx: QueryCtxt<$tcx>, key: query_keys::$name<$tcx>) -> QueryStackFrame {
+ opt_remap_env_constness!([$($modifiers)*][key]);
let kind = dep_graph::DepKind::$name;
let name = stringify!($name);
// Disable visible paths printing for performance reasons.
@@ -500,7 +511,7 @@ macro_rules! define_queries_struct {
}
}
- impl QueryEngine<'tcx> for Queries<'tcx> {
+ impl<'tcx> QueryEngine<'tcx> for Queries<'tcx> {
fn as_any(&'tcx self) -> &'tcx dyn std::any::Any {
let this = unsafe { std::mem::transmute::<&Queries<'_>, &Queries<'_>>(self) };
this as _
@@ -521,6 +532,7 @@ macro_rules! define_queries_struct {
lookup: QueryLookup,
mode: QueryMode,
) -> Option<query_stored::$name<$tcx>> {
+ opt_remap_env_constness!([$($modifiers)*][key]);
let qcx = QueryCtxt { tcx, queries: self };
get_query::<queries::$name<$tcx>, _>(qcx, span, key, lookup, mode)
})*
diff --git a/compiler/rustc_query_impl/src/profiling_support.rs b/compiler/rustc_query_impl/src/profiling_support.rs
index 95edc1e93a5..41ee75c2432 100644
--- a/compiler/rustc_query_impl/src/profiling_support.rs
+++ b/compiler/rustc_query_impl/src/profiling_support.rs
@@ -295,7 +295,7 @@ fn alloc_self_profile_query_strings_for_query_cache<'tcx, C>(
/// If we are recording only summary data, the ids will point to
/// just the query names. If we are recording query keys too, we
/// allocate the corresponding strings here.
-pub fn alloc_self_profile_query_strings(tcx: TyCtxt<'tcx>) {
+pub fn alloc_self_profile_query_strings(tcx: TyCtxt<'_>) {
if !tcx.prof.enabled() {
return;
}
diff --git a/compiler/rustc_query_system/src/lib.rs b/compiler/rustc_query_system/src/lib.rs
index 1b992cdb0c9..0436e07e2d4 100644
--- a/compiler/rustc_query_system/src/lib.rs
+++ b/compiler/rustc_query_system/src/lib.rs
@@ -2,10 +2,9 @@
#![feature(bool_to_option)]
#![feature(core_intrinsics)]
#![feature(hash_raw_entry)]
-#![feature(iter_zip)]
#![feature(let_else)]
#![feature(min_specialization)]
-#![feature(thread_local_const_init)]
+#![feature(extern_types)]
#[macro_use]
extern crate tracing;
diff --git a/compiler/rustc_query_system/src/query/plumbing.rs b/compiler/rustc_query_system/src/query/plumbing.rs
index 9703f0c3d96..b08db39e245 100644
--- a/compiler/rustc_query_system/src/query/plumbing.rs
+++ b/compiler/rustc_query_system/src/query/plumbing.rs
@@ -18,6 +18,7 @@ use rustc_data_structures::sharded::{get_shard_index_by_hash, Sharded};
use rustc_data_structures::sync::{Lock, LockGuard};
use rustc_data_structures::thin_vec::ThinVec;
use rustc_errors::{DiagnosticBuilder, FatalError};
+use rustc_session::Session;
use rustc_span::{Span, DUMMY_SP};
use std::cell::Cell;
use std::collections::hash_map::Entry;
@@ -595,38 +596,86 @@ fn incremental_verify_ich<CTX, K, V: Debug>(
debug!("END verify_ich({:?})", dep_node);
if Some(new_hash) != old_hash {
- let run_cmd = if let Some(crate_name) = &tcx.sess().opts.crate_name {
- format!("`cargo clean -p {}` or `cargo clean`", crate_name)
- } else {
- "`cargo clean`".to_string()
- };
+ incremental_verify_ich_cold(tcx.sess(), DebugArg::from(&dep_node), DebugArg::from(&result));
+ }
+}
- // When we emit an error message and panic, we try to debug-print the `DepNode`
- // and query result. Unforunately, this can cause us to run additional queries,
- // which may result in another fingerprint mismatch while we're in the middle
- // of processing this one. To avoid a double-panic (which kills the process
- // before we can print out the query static), we print out a terse
- // but 'safe' message if we detect a re-entrant call to this method.
- thread_local! {
- static INSIDE_VERIFY_PANIC: Cell<bool> = const { Cell::new(false) };
- };
+// This DebugArg business is largely a mirror of std::fmt::ArgumentV1, which is
+// currently not exposed publicly.
+//
+// The PR which added this attempted to use `&dyn Debug` instead, but that
+// showed statistically significant worse compiler performance. It's not
+// actually clear what the cause there was -- the code should be cold. If this
+// can be replaced with `&dyn Debug` with on perf impact, then it probably
+// should be.
+extern "C" {
+ type Opaque;
+}
- let old_in_panic = INSIDE_VERIFY_PANIC.with(|in_panic| in_panic.replace(true));
+struct DebugArg<'a> {
+ value: &'a Opaque,
+ fmt: fn(&Opaque, &mut std::fmt::Formatter<'_>) -> std::fmt::Result,
+}
- if old_in_panic {
- tcx.sess().struct_err("internal compiler error: re-entrant incremental verify failure, suppressing message")
- .emit();
- } else {
- tcx.sess().struct_err(&format!("internal compiler error: encountered incremental compilation error with {:?}", dep_node))
+impl<'a, T> From<&'a T> for DebugArg<'a>
+where
+ T: std::fmt::Debug,
+{
+ fn from(value: &'a T) -> DebugArg<'a> {
+ DebugArg {
+ value: unsafe { std::mem::transmute(value) },
+ fmt: unsafe {
+ std::mem::transmute(<T as std::fmt::Debug>::fmt as fn(_, _) -> std::fmt::Result)
+ },
+ }
+ }
+}
+
+impl std::fmt::Debug for DebugArg<'_> {
+ fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
+ (self.fmt)(self.value, f)
+ }
+}
+
+// Note that this is marked #[cold] and intentionally takes the equivalent of
+// `dyn Debug` for its arguments, as we want to avoid generating a bunch of
+// different implementations for LLVM to chew on (and filling up the final
+// binary, too).
+#[cold]
+fn incremental_verify_ich_cold(sess: &Session, dep_node: DebugArg<'_>, result: DebugArg<'_>) {
+ let run_cmd = if let Some(crate_name) = &sess.opts.crate_name {
+ format!("`cargo clean -p {}` or `cargo clean`", crate_name)
+ } else {
+ "`cargo clean`".to_string()
+ };
+
+ // When we emit an error message and panic, we try to debug-print the `DepNode`
+ // and query result. Unfortunately, this can cause us to run additional queries,
+ // which may result in another fingerprint mismatch while we're in the middle
+ // of processing this one. To avoid a double-panic (which kills the process
+ // before we can print out the query static), we print out a terse
+ // but 'safe' message if we detect a re-entrant call to this method.
+ thread_local! {
+ static INSIDE_VERIFY_PANIC: Cell<bool> = const { Cell::new(false) };
+ };
+
+ let old_in_panic = INSIDE_VERIFY_PANIC.with(|in_panic| in_panic.replace(true));
+
+ if old_in_panic {
+ sess.struct_err(
+ "internal compiler error: re-entrant incremental verify failure, suppressing message",
+ )
+ .emit();
+ } else {
+ sess.struct_err(&format!("internal compiler error: encountered incremental compilation error with {:?}", dep_node))
.help(&format!("This is a known issue with the compiler. Run {} to allow your project to compile", run_cmd))
.note(&"Please follow the instructions below to create a bug report with the provided information")
.note(&"See <https://github.com/rust-lang/rust/issues/84970> for more information")
.emit();
- panic!("Found unstable fingerprints for {:?}: {:?}", dep_node, result);
- }
-
- INSIDE_VERIFY_PANIC.with(|in_panic| in_panic.set(old_in_panic));
+ panic!("Found unstable fingerprints for {:?}: {:?}", dep_node, result);
}
+
+ INSIDE_VERIFY_PANIC.with(|in_panic| in_panic.set(old_in_panic));
}
/// Ensure that either this query has all green inputs or been executed.
diff --git a/compiler/rustc_resolve/src/build_reduced_graph.rs b/compiler/rustc_resolve/src/build_reduced_graph.rs
index 3cf9d324a38..d45c064d5e3 100644
--- a/compiler/rustc_resolve/src/build_reduced_graph.rs
+++ b/compiler/rustc_resolve/src/build_reduced_graph.rs
@@ -651,11 +651,6 @@ impl<'a, 'b> BuildReducedGraphVisitor<'a, 'b> {
/// Constructs the reduced graph for one item.
fn build_reduced_graph_for_item(&mut self, item: &'b Item) {
- if matches!(item.kind, ItemKind::Mod(..)) && item.ident.name == kw::Empty {
- // Fake crate root item from expand.
- return;
- }
-
let parent_scope = &self.parent_scope;
let parent = parent_scope.module;
let expansion = parent_scope.expansion;
@@ -683,75 +678,13 @@ impl<'a, 'b> BuildReducedGraphVisitor<'a, 'b> {
}
ItemKind::ExternCrate(orig_name) => {
- let module = if orig_name.is_none() && ident.name == kw::SelfLower {
- self.r
- .session
- .struct_span_err(item.span, "`extern crate self;` requires renaming")
- .span_suggestion(
- item.span,
- "try",
- "extern crate self as name;".into(),
- Applicability::HasPlaceholders,
- )
- .emit();
- return;
- } else if orig_name == Some(kw::SelfLower) {
- self.r.graph_root
- } else {
- let crate_id = self.r.crate_loader.process_extern_crate(
- item,
- &self.r.definitions,
- local_def_id,
- );
- self.r.extern_crate_map.insert(local_def_id, crate_id);
- self.r.expect_module(crate_id.as_def_id())
- };
-
- let used = self.process_macro_use_imports(item, module);
- let binding =
- (module, ty::Visibility::Public, sp, expansion).to_name_binding(self.r.arenas);
- let import = self.r.arenas.alloc_import(Import {
- kind: ImportKind::ExternCrate { source: orig_name, target: ident },
- root_id: item.id,
- id: item.id,
- parent_scope: self.parent_scope,
- imported_module: Cell::new(Some(ModuleOrUniformRoot::Module(module))),
- has_attributes: !item.attrs.is_empty(),
- use_span_with_attributes: item.span_with_attributes(),
- use_span: item.span,
- root_span: item.span,
- span: item.span,
- module_path: Vec::new(),
- vis: Cell::new(vis),
- used: Cell::new(used),
- });
- self.r.potentially_unused_imports.push(import);
- let imported_binding = self.r.import(binding, import);
- if ptr::eq(parent, self.r.graph_root) {
- if let Some(entry) = self.r.extern_prelude.get(&ident.normalize_to_macros_2_0())
- {
- if expansion != LocalExpnId::ROOT
- && orig_name.is_some()
- && entry.extern_crate_item.is_none()
- {
- let msg = "macro-expanded `extern crate` items cannot \
- shadow names passed with `--extern`";
- self.r.session.span_err(item.span, msg);
- }
- }
- let entry =
- self.r.extern_prelude.entry(ident.normalize_to_macros_2_0()).or_insert(
- ExternPreludeEntry {
- extern_crate_item: None,
- introduced_by_item: true,
- },
- );
- entry.extern_crate_item = Some(imported_binding);
- if orig_name.is_some() {
- entry.introduced_by_item = true;
- }
- }
- self.r.define(parent, ident, TypeNS, imported_binding);
+ self.build_reduced_graph_for_extern_crate(
+ orig_name,
+ item,
+ local_def_id,
+ vis,
+ parent,
+ );
}
ItemKind::Mod(..) => {
@@ -889,6 +822,87 @@ impl<'a, 'b> BuildReducedGraphVisitor<'a, 'b> {
}
}
+ fn build_reduced_graph_for_extern_crate(
+ &mut self,
+ orig_name: Option<Symbol>,
+ item: &Item,
+ local_def_id: LocalDefId,
+ vis: ty::Visibility,
+ parent: Module<'a>,
+ ) {
+ let ident = item.ident;
+ let sp = item.span;
+ let parent_scope = self.parent_scope;
+ let expansion = parent_scope.expansion;
+
+ let (used, module, binding) = if orig_name.is_none() && ident.name == kw::SelfLower {
+ self.r
+ .session
+ .struct_span_err(item.span, "`extern crate self;` requires renaming")
+ .span_suggestion(
+ item.span,
+ "rename the `self` crate to be able to import it",
+ "extern crate self as name;".into(),
+ Applicability::HasPlaceholders,
+ )
+ .emit();
+ return;
+ } else if orig_name == Some(kw::SelfLower) {
+ Some(self.r.graph_root)
+ } else {
+ self.r.crate_loader.process_extern_crate(item, &self.r.definitions, local_def_id).map(
+ |crate_id| {
+ self.r.extern_crate_map.insert(local_def_id, crate_id);
+ self.r.expect_module(crate_id.as_def_id())
+ },
+ )
+ }
+ .map(|module| {
+ let used = self.process_macro_use_imports(item, module);
+ let binding =
+ (module, ty::Visibility::Public, sp, expansion).to_name_binding(self.r.arenas);
+ (used, Some(ModuleOrUniformRoot::Module(module)), binding)
+ })
+ .unwrap_or((true, None, self.r.dummy_binding));
+ let import = self.r.arenas.alloc_import(Import {
+ kind: ImportKind::ExternCrate { source: orig_name, target: ident },
+ root_id: item.id,
+ id: item.id,
+ parent_scope: self.parent_scope,
+ imported_module: Cell::new(module),
+ has_attributes: !item.attrs.is_empty(),
+ use_span_with_attributes: item.span_with_attributes(),
+ use_span: item.span,
+ root_span: item.span,
+ span: item.span,
+ module_path: Vec::new(),
+ vis: Cell::new(vis),
+ used: Cell::new(used),
+ });
+ self.r.potentially_unused_imports.push(import);
+ let imported_binding = self.r.import(binding, import);
+ if ptr::eq(parent, self.r.graph_root) {
+ if let Some(entry) = self.r.extern_prelude.get(&ident.normalize_to_macros_2_0()) {
+ if expansion != LocalExpnId::ROOT
+ && orig_name.is_some()
+ && entry.extern_crate_item.is_none()
+ {
+ let msg = "macro-expanded `extern crate` items cannot \
+ shadow names passed with `--extern`";
+ self.r.session.span_err(item.span, msg);
+ }
+ }
+ let entry = self.r.extern_prelude.entry(ident.normalize_to_macros_2_0()).or_insert(
+ ExternPreludeEntry { extern_crate_item: None, introduced_by_item: true },
+ );
+ entry.extern_crate_item = Some(imported_binding);
+ if orig_name.is_some() {
+ entry.introduced_by_item = true;
+ }
+ }
+ self.r.define(parent, ident, TypeNS, imported_binding);
+ }
+
/// Constructs the reduced graph for one foreign item.
fn build_reduced_graph_for_foreign_item(&mut self, item: &ForeignItem) {
let local_def_id = self.r.local_def_id(item.id);
@@ -1499,4 +1513,13 @@ impl<'a, 'b> Visitor<'b> for BuildReducedGraphVisitor<'a, 'b> {
visit::walk_variant(self, variant);
}
+
+ fn visit_crate(&mut self, krate: &'b ast::Crate) {
+ if let Some(id) = krate.is_placeholder {
+ self.visit_invoc_in_module(id);
+ } else {
+ visit::walk_crate(self, krate);
+ self.contains_macro_use(&krate.attrs);
+ }
+ }
}
diff --git a/compiler/rustc_resolve/src/def_collector.rs b/compiler/rustc_resolve/src/def_collector.rs
index 5879cb1daa5..688b7b1a8c6 100644
--- a/compiler/rustc_resolve/src/def_collector.rs
+++ b/compiler/rustc_resolve/src/def_collector.rs
@@ -7,7 +7,7 @@ use rustc_expand::expand::AstFragment;
use rustc_hir::def_id::LocalDefId;
use rustc_hir::definitions::*;
use rustc_span::hygiene::LocalExpnId;
-use rustc_span::symbol::{kw, sym};
+use rustc_span::symbol::sym;
use rustc_span::Span;
use tracing::debug;
@@ -92,10 +92,7 @@ impl<'a, 'b> visit::Visitor<'a> for DefCollector<'a, 'b> {
// information we encapsulate into, the better
let def_data = match &i.kind {
ItemKind::Impl { .. } => DefPathData::Impl,
- ItemKind::Mod(..) if i.ident.name == kw::Empty => {
- // Fake crate root item from expand.
- return visit::walk_item(self, i);
- }
+ ItemKind::ForeignMod(..) => DefPathData::ForeignMod,
ItemKind::Mod(..)
| ItemKind::Trait(..)
| ItemKind::TraitAlias(..)
@@ -103,7 +100,6 @@ impl<'a, 'b> visit::Visitor<'a> for DefCollector<'a, 'b> {
| ItemKind::Struct(..)
| ItemKind::Union(..)
| ItemKind::ExternCrate(..)
- | ItemKind::ForeignMod(..)
| ItemKind::TyAlias(..) => DefPathData::TypeNs(i.ident.name),
ItemKind::Static(..) | ItemKind::Const(..) | ItemKind::Fn(..) => {
DefPathData::ValueNs(i.ident.name)
@@ -346,4 +342,12 @@ impl<'a, 'b> visit::Visitor<'a> for DefCollector<'a, 'b> {
fn visit_field_def(&mut self, field: &'a FieldDef) {
self.collect_field(field, None);
}
+
+ fn visit_crate(&mut self, krate: &'a Crate) {
+ if let Some(id) = krate.is_placeholder {
+ self.visit_macro_invoc(id)
+ } else {
+ visit::walk_crate(self, krate)
+ }
+ }
}
diff --git a/compiler/rustc_resolve/src/diagnostics.rs b/compiler/rustc_resolve/src/diagnostics.rs
index 2e4cb4ff727..6a13627a563 100644
--- a/compiler/rustc_resolve/src/diagnostics.rs
+++ b/compiler/rustc_resolve/src/diagnostics.rs
@@ -1178,7 +1178,7 @@ impl<'a> Resolver<'a> {
fn binding_description(&self, b: &NameBinding<'_>, ident: Ident, from_prelude: bool) -> String {
let res = b.res();
- if b.span.is_dummy() {
+ if b.span.is_dummy() || self.session.source_map().span_to_snippet(b.span).is_err() {
// These already contain the "built-in" prefix or look bad with it.
let add_built_in =
!matches!(b.res(), Res::NonMacroAttr(..) | Res::PrimTy(..) | Res::ToolMod);
diff --git a/compiler/rustc_resolve/src/late.rs b/compiler/rustc_resolve/src/late.rs
index e67f7f03516..12123c946cc 100644
--- a/compiler/rustc_resolve/src/late.rs
+++ b/compiler/rustc_resolve/src/late.rs
@@ -431,6 +431,10 @@ struct LateResolutionVisitor<'a, 'b, 'ast> {
/// Walks the whole crate in DFS order, visiting each item, resolving names as it goes.
impl<'a: 'ast, 'ast> Visitor<'ast> for LateResolutionVisitor<'a, '_, 'ast> {
+ fn visit_attribute(&mut self, _: &'ast Attribute) {
+ // We do not want to resolve expressions that appear in attributes,
+ // as they do not correspond to actual code.
+ }
fn visit_item(&mut self, item: &'ast Item) {
let prev = replace(&mut self.diagnostic_metadata.current_item, Some(item));
// Always report errors in items we just entered.
diff --git a/compiler/rustc_resolve/src/late/diagnostics.rs b/compiler/rustc_resolve/src/late/diagnostics.rs
index d506931b516..3e1afdfa9a5 100644
--- a/compiler/rustc_resolve/src/late/diagnostics.rs
+++ b/compiler/rustc_resolve/src/late/diagnostics.rs
@@ -298,11 +298,16 @@ impl<'a: 'ast, 'ast> LateResolutionVisitor<'a, '_, 'ast> {
.get(0)
.map(|p| (p.span.shrink_to_lo(), "&self, "))
.unwrap_or_else(|| {
+ // Try to look for the "(" after the function name, if possible.
+ // This avoids placing the suggestion into the visibility specifier.
+ let span = fn_kind
+ .ident()
+ .map_or(*span, |ident| span.with_lo(ident.span.hi()));
(
self.r
.session
.source_map()
- .span_through_char(*span, '(')
+ .span_through_char(span, '(')
.shrink_to_hi(),
"&self",
)
@@ -1735,7 +1740,7 @@ impl<'a: 'ast, 'ast> LateResolutionVisitor<'a, '_, 'ast> {
(generics.span, format!("<{}>", ident))
};
// Do not suggest if this is coming from macro expansion.
- if !span.from_expansion() {
+ if span.can_be_used_for_suggestions() {
return Some((
span.shrink_to_hi(),
msg,
@@ -1803,7 +1808,7 @@ impl<'tcx> LifetimeContext<'_, 'tcx> {
);
err.span_label(lifetime_ref.span, "undeclared lifetime");
let mut suggests_in_band = false;
- let mut suggest_note = true;
+ let mut suggested_spans = vec![];
for missing in &self.missing_named_lifetime_spots {
match missing {
MissingLifetimeSpot::Generics(generics) => {
@@ -1821,23 +1826,17 @@ impl<'tcx> LifetimeContext<'_, 'tcx> {
suggests_in_band = true;
(generics.span, format!("<{}>", lifetime_ref))
};
- if !span.from_expansion() {
+ if suggested_spans.contains(&span) {
+ continue;
+ }
+ suggested_spans.push(span);
+ if span.can_be_used_for_suggestions() {
err.span_suggestion(
span,
&format!("consider introducing lifetime `{}` here", lifetime_ref),
sugg,
Applicability::MaybeIncorrect,
);
- } else if suggest_note {
- suggest_note = false; // Avoid displaying the same help multiple times.
- err.span_label(
- span,
- &format!(
- "lifetime `{}` is missing in item created through this procedural \
- macro",
- lifetime_ref,
- ),
- );
}
}
MissingLifetimeSpot::HigherRanked { span, span_type } => {
@@ -1871,6 +1870,117 @@ impl<'tcx> LifetimeContext<'_, 'tcx> {
err.emit();
}
+ /// Returns whether to add `'static` lifetime to the suggested lifetime list.
+ crate fn report_elision_failure(
+ &mut self,
+ db: &mut DiagnosticBuilder<'_>,
+ params: &[ElisionFailureInfo],
+ ) -> bool {
+ let mut m = String::new();
+ let len = params.len();
+
+ let elided_params: Vec<_> =
+ params.iter().cloned().filter(|info| info.lifetime_count > 0).collect();
+
+ let elided_len = elided_params.len();
+
+ for (i, info) in elided_params.into_iter().enumerate() {
+ let ElisionFailureInfo { parent, index, lifetime_count: n, have_bound_regions, span } =
+ info;
+
+ db.span_label(span, "");
+ let help_name = if let Some(ident) =
+ parent.and_then(|body| self.tcx.hir().body(body).params[index].pat.simple_ident())
+ {
+ format!("`{}`", ident)
+ } else {
+ format!("argument {}", index + 1)
+ };
+
+ m.push_str(
+ &(if n == 1 {
+ help_name
+ } else {
+ format!(
+ "one of {}'s {} {}lifetimes",
+ help_name,
+ n,
+ if have_bound_regions { "free " } else { "" }
+ )
+ })[..],
+ );
+
+ if elided_len == 2 && i == 0 {
+ m.push_str(" or ");
+ } else if i + 2 == elided_len {
+ m.push_str(", or ");
+ } else if i != elided_len - 1 {
+ m.push_str(", ");
+ }
+ }
+
+ if len == 0 {
+ db.help(
+ "this function's return type contains a borrowed value, \
+ but there is no value for it to be borrowed from",
+ );
+ true
+ } else if elided_len == 0 {
+ db.help(
+ "this function's return type contains a borrowed value with \
+ an elided lifetime, but the lifetime cannot be derived from \
+ the arguments",
+ );
+ true
+ } else if elided_len == 1 {
+ db.help(&format!(
+ "this function's return type contains a borrowed value, \
+ but the signature does not say which {} it is borrowed from",
+ m
+ ));
+ false
+ } else {
+ db.help(&format!(
+ "this function's return type contains a borrowed value, \
+ but the signature does not say whether it is borrowed from {}",
+ m
+ ));
+ false
+ }
+ }
+
+ crate fn report_elided_lifetime_in_ty(&self, lifetime_refs: &[&hir::Lifetime]) {
+ let Some(missing_lifetime) = lifetime_refs.iter().find(|lt| {
+ lt.name == hir::LifetimeName::Implicit(true)
+ }) else { return };
+
+ let mut spans: Vec<_> = lifetime_refs.iter().map(|lt| lt.span).collect();
+ spans.sort();
+ let mut spans_dedup = spans.clone();
+ spans_dedup.dedup();
+ let spans_with_counts: Vec<_> = spans_dedup
+ .into_iter()
+ .map(|sp| (sp, spans.iter().filter(|nsp| *nsp == &sp).count()))
+ .collect();
+
+ self.tcx.struct_span_lint_hir(
+ rustc_session::lint::builtin::ELIDED_LIFETIMES_IN_PATHS,
+ missing_lifetime.hir_id,
+ spans,
+ |lint| {
+ let mut db = lint.build("hidden lifetime parameters in types are deprecated");
+ self.add_missing_lifetime_specifiers_label(
+ &mut db,
+ spans_with_counts,
+ &FxHashSet::from_iter([kw::UnderscoreLifetime]),
+ Vec::new(),
+ &[],
+ );
+ db.emit()
+ },
+ );
+ }
+
// FIXME(const_generics): This patches over an ICE caused by non-'static lifetimes in const
// generics. We are disallowing this until we can decide on how we want to handle non-'static
// lifetimes in const generics. See issue #74052 for discussion.
@@ -2010,6 +2120,11 @@ impl<'tcx> LifetimeContext<'_, 'tcx> {
})
.map(|(formatter, span)| (*span, formatter(name)))
.collect();
+ if spans_suggs.is_empty() {
+ // If all the spans come from macros, we cannot extract snippets and then
+ // `formatters` only contains None and `spans_suggs` is empty.
+ return;
+ }
err.multipart_suggestion_verbose(
&format!(
"consider using the `{}` lifetime",
@@ -2297,7 +2412,9 @@ impl<'tcx> LifetimeContext<'_, 'tcx> {
);
let is_allowed_lifetime = matches!(
lifetime_ref.name,
- hir::LifetimeName::Implicit | hir::LifetimeName::Static | hir::LifetimeName::Underscore
+ hir::LifetimeName::Implicit(_)
+ | hir::LifetimeName::Static
+ | hir::LifetimeName::Underscore
);
if !self.tcx.lazy_normalization() && is_anon_const && !is_allowed_lifetime {
diff --git a/compiler/rustc_resolve/src/late/lifetimes.rs b/compiler/rustc_resolve/src/late/lifetimes.rs
index 39e710cb77f..22a74146db3 100644
--- a/compiler/rustc_resolve/src/late/lifetimes.rs
+++ b/compiler/rustc_resolve/src/late/lifetimes.rs
@@ -357,11 +357,11 @@ enum Elide {
#[derive(Clone, Debug)]
crate struct ElisionFailureInfo {
/// Where we can find the argument pattern.
- parent: Option<hir::BodyId>,
+ crate parent: Option<hir::BodyId>,
/// The index of the argument in the original definition.
- index: usize,
- lifetime_count: usize,
- have_bound_regions: bool,
+ crate index: usize,
+ crate lifetime_count: usize,
+ crate have_bound_regions: bool,
crate span: Span,
}
@@ -445,7 +445,7 @@ fn do_resolve(
trait_definition_only: bool,
with_scope_for_path: bool,
) -> NamedRegionMap {
- let item = tcx.hir().expect_item(tcx.hir().local_def_id_to_hir_id(local_def_id));
+ let item = tcx.hir().expect_item(local_def_id);
let mut named_region_map = NamedRegionMap {
defs: Default::default(),
late_bound: Default::default(),
@@ -923,7 +923,7 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> {
}
});
match lifetime.name {
- LifetimeName::Implicit => {
+ LifetimeName::Implicit(_) => {
// For types like `dyn Foo`, we should
// generate a special form of elided.
span_bug!(ty.span, "object-lifetime-default expected, not implicit",);
@@ -968,7 +968,10 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> {
let (generics, bounds) = match opaque_ty.kind {
// Named opaque `impl Trait` types are reached via `TyKind::Path`.
// This arm is for `impl Trait` in the types of statics, constants and locals.
- hir::ItemKind::OpaqueTy(hir::OpaqueTy { impl_trait_fn: None, .. }) => {
+ hir::ItemKind::OpaqueTy(hir::OpaqueTy {
+ origin: hir::OpaqueTyOrigin::TyAlias,
+ ..
+ }) => {
intravisit::walk_ty(self, ty);
// Elided lifetimes are not allowed in non-return
@@ -985,7 +988,7 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> {
}
// RPIT (return position impl trait)
hir::ItemKind::OpaqueTy(hir::OpaqueTy {
- impl_trait_fn: Some(_),
+ origin: hir::OpaqueTyOrigin::FnReturn(..) | hir::OpaqueTyOrigin::AsyncFn(..),
ref generics,
bounds,
..
@@ -1134,7 +1137,7 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> {
self.missing_named_lifetime_spots.push((&trait_item.generics).into());
let tcx = self.tcx;
self.visit_early_late(
- Some(tcx.hir().get_parent_item(trait_item.hir_id())),
+ Some(tcx.hir().get_parent_did(trait_item.hir_id())),
trait_item.hir_id(),
&sig.decl,
&trait_item.generics,
@@ -1203,7 +1206,7 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> {
self.missing_named_lifetime_spots.push((&impl_item.generics).into());
let tcx = self.tcx;
self.visit_early_late(
- Some(tcx.hir().get_parent_item(impl_item.hir_id())),
+ Some(tcx.hir().get_parent_did(impl_item.hir_id())),
impl_item.hir_id(),
&sig.decl,
&impl_item.generics,
@@ -1695,7 +1698,11 @@ fn compute_object_lifetime_defaults(
hir::ItemKind::Struct(_, ref generics)
| hir::ItemKind::Union(_, ref generics)
| hir::ItemKind::Enum(_, ref generics)
- | hir::ItemKind::OpaqueTy(hir::OpaqueTy { ref generics, impl_trait_fn: None, .. })
+ | hir::ItemKind::OpaqueTy(hir::OpaqueTy {
+ ref generics,
+ origin: hir::OpaqueTyOrigin::TyAlias,
+ ..
+ })
| hir::ItemKind::TyAlias(_, ref generics)
| hir::ItemKind::Trait(_, _, ref generics, ..) => {
let result = object_lifetime_defaults_for_item(tcx, generics);
@@ -2002,7 +2009,7 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> {
}
};
- let mut def_ids: Vec<_> = defined_by
+ let def_ids: Vec<_> = defined_by
.values()
.flat_map(|region| match region {
Region::EarlyBound(_, def_id, _)
@@ -2013,9 +2020,6 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> {
})
.collect();
- // ensure that we issue lints in a repeatable order
- def_ids.sort_by_cached_key(|&def_id| self.tcx.def_path_hash(def_id));
-
'lifetimes: for def_id in def_ids {
debug!("check_uses_for_lifetimes_defined_by_scope: def_id = {:?}", def_id);
@@ -2067,7 +2071,7 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> {
..
}) = self.tcx.hir().get(parent_hir_id)
{
- if opaque.origin != hir::OpaqueTyOrigin::AsyncFn {
+ if !matches!(opaque.origin, hir::OpaqueTyOrigin::AsyncFn(..)) {
continue 'lifetimes;
}
// We want to do this only if the liftime identifier is already defined
@@ -2176,7 +2180,7 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> {
/// ordering is not important there.
fn visit_early_late<F>(
&mut self,
- parent_id: Option<hir::HirId>,
+ parent_id: Option<LocalDefId>,
hir_id: hir::HirId,
decl: &'tcx hir::FnDecl<'tcx>,
generics: &'tcx hir::Generics<'tcx>,
@@ -2534,8 +2538,8 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> {
GenericParamDefKind::Type { object_lifetime_default, .. } => {
Some(object_lifetime_default)
}
- GenericParamDefKind::Lifetime
- | GenericParamDefKind::Const { .. } => None,
+ GenericParamDefKind::Const { .. } => Some(Set1::Empty),
+ GenericParamDefKind::Lifetime => None,
})
.collect()
})
@@ -2562,12 +2566,11 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> {
}
GenericArg::Const(ct) => {
self.visit_anon_const(&ct.value);
+ i += 1;
}
GenericArg::Infer(inf) => {
self.visit_id(inf.hir_id);
- if inf.kind.is_type() {
- i += 1;
- }
+ i += 1;
}
}
}
@@ -2758,7 +2761,7 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> {
Node::TraitItem(&hir::TraitItem { kind: hir::TraitItemKind::Fn(_, ref m), .. }) => {
if let hir::ItemKind::Trait(.., ref trait_items) =
- self.tcx.hir().expect_item(self.tcx.hir().get_parent_item(parent)).kind
+ self.tcx.hir().expect_item(self.tcx.hir().get_parent_did(parent)).kind
{
assoc_item_kind =
trait_items.iter().find(|ti| ti.id.hir_id() == parent).map(|ti| ti.kind);
@@ -2771,7 +2774,7 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> {
Node::ImplItem(&hir::ImplItem { kind: hir::ImplItemKind::Fn(_, body), .. }) => {
if let hir::ItemKind::Impl(hir::Impl { ref self_ty, ref items, .. }) =
- self.tcx.hir().expect_item(self.tcx.hir().get_parent_item(parent)).kind
+ self.tcx.hir().expect_item(self.tcx.hir().get_parent_did(parent)).kind
{
impl_self = Some(self_ty);
assoc_item_kind =
@@ -3057,9 +3060,9 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> {
let error = loop {
match *scope {
// Do not assign any resolution, it will be inferred.
- Scope::Body { .. } => return,
+ Scope::Body { .. } => break Ok(()),
- Scope::Root => break None,
+ Scope::Root => break Err(None),
Scope::Binder { s, ref lifetimes, scope_type, .. } => {
// collect named lifetimes for suggestions
@@ -3076,50 +3079,54 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> {
scope = s;
}
- Scope::Elision { ref elide, ref s, .. } => {
- let lifetime = match *elide {
- Elide::FreshLateAnon(named_late_bound_vars, ref counter) => {
- for lifetime_ref in lifetime_refs {
- let lifetime = Region::late_anon(named_late_bound_vars, counter)
- .shifted(late_depth);
+ Scope::Elision {
+ elide: Elide::FreshLateAnon(named_late_bound_vars, ref counter),
+ ..
+ } => {
+ for lifetime_ref in lifetime_refs {
+ let lifetime =
+ Region::late_anon(named_late_bound_vars, counter).shifted(late_depth);
- self.insert_lifetime(lifetime_ref, lifetime);
- }
- return;
- }
- Elide::Exact(l) => l.shifted(late_depth),
- Elide::Error(ref e) => {
- let mut scope = s;
- loop {
- match scope {
- Scope::Binder { ref lifetimes, s, .. } => {
- // Collect named lifetimes for suggestions.
- for name in lifetimes.keys() {
- if let hir::ParamName::Plain(name) = name {
- lifetime_names.insert(name.name);
- lifetime_spans.push(name.span);
- }
- }
- scope = s;
- }
- Scope::ObjectLifetimeDefault { ref s, .. }
- | Scope::Elision { ref s, .. }
- | Scope::TraitRefBoundary { ref s, .. } => {
- scope = s;
+ self.insert_lifetime(lifetime_ref, lifetime);
+ }
+ break Ok(());
+ }
+
+ Scope::Elision { elide: Elide::Exact(l), .. } => {
+ let lifetime = l.shifted(late_depth);
+ for lifetime_ref in lifetime_refs {
+ self.insert_lifetime(lifetime_ref, lifetime);
+ }
+ break Ok(());
+ }
+
+ Scope::Elision { elide: Elide::Error(ref e), ref s, .. } => {
+ let mut scope = s;
+ loop {
+ match scope {
+ Scope::Binder { ref lifetimes, s, .. } => {
+ // Collect named lifetimes for suggestions.
+ for name in lifetimes.keys() {
+ if let hir::ParamName::Plain(name) = name {
+ lifetime_names.insert(name.name);
+ lifetime_spans.push(name.span);
}
- _ => break,
}
+ scope = s;
}
- break Some(&e[..]);
+ Scope::ObjectLifetimeDefault { ref s, .. }
+ | Scope::Elision { ref s, .. }
+ | Scope::TraitRefBoundary { ref s, .. } => {
+ scope = s;
+ }
+ _ => break,
}
- Elide::Forbid => break None,
- };
- for lifetime_ref in lifetime_refs {
- self.insert_lifetime(lifetime_ref, lifetime);
}
- return;
+ break Err(Some(&e[..]));
}
+ Scope::Elision { elide: Elide::Forbid, .. } => break Err(None),
+
Scope::ObjectLifetimeDefault { s, .. }
| Scope::Supertrait { s, .. }
| Scope::TraitRefBoundary { s, .. } => {
@@ -3128,6 +3135,14 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> {
}
};
+ let error = match error {
+ Ok(()) => {
+ self.report_elided_lifetime_in_ty(lifetime_refs);
+ return;
+ }
+ Err(error) => error,
+ };
+
// If we specifically need the `scope_for_path` map, then we're in the
// diagnostic pass and we don't want to emit more errors.
if self.map.scope_for_path.is_some() {
@@ -3166,84 +3181,6 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> {
err.emit();
}
- fn report_elision_failure(
- &mut self,
- db: &mut DiagnosticBuilder<'_>,
- params: &[ElisionFailureInfo],
- ) -> bool /* add `'static` lifetime to lifetime list */ {
- let mut m = String::new();
- let len = params.len();
-
- let elided_params: Vec<_> =
- params.iter().cloned().filter(|info| info.lifetime_count > 0).collect();
-
- let elided_len = elided_params.len();
-
- for (i, info) in elided_params.into_iter().enumerate() {
- let ElisionFailureInfo { parent, index, lifetime_count: n, have_bound_regions, span } =
- info;
-
- db.span_label(span, "");
- let help_name = if let Some(ident) =
- parent.and_then(|body| self.tcx.hir().body(body).params[index].pat.simple_ident())
- {
- format!("`{}`", ident)
- } else {
- format!("argument {}", index + 1)
- };
-
- m.push_str(
- &(if n == 1 {
- help_name
- } else {
- format!(
- "one of {}'s {} {}lifetimes",
- help_name,
- n,
- if have_bound_regions { "free " } else { "" }
- )
- })[..],
- );
-
- if elided_len == 2 && i == 0 {
- m.push_str(" or ");
- } else if i + 2 == elided_len {
- m.push_str(", or ");
- } else if i != elided_len - 1 {
- m.push_str(", ");
- }
- }
-
- if len == 0 {
- db.help(
- "this function's return type contains a borrowed value, \
- but there is no value for it to be borrowed from",
- );
- true
- } else if elided_len == 0 {
- db.help(
- "this function's return type contains a borrowed value with \
- an elided lifetime, but the lifetime cannot be derived from \
- the arguments",
- );
- true
- } else if elided_len == 1 {
- db.help(&format!(
- "this function's return type contains a borrowed value, \
- but the signature does not say which {} it is borrowed from",
- m
- ));
- false
- } else {
- db.help(&format!(
- "this function's return type contains a borrowed value, \
- but the signature does not say whether it is borrowed from {}",
- m
- ));
- false
- }
- }
-
fn resolve_object_lifetime_default(&mut self, lifetime_ref: &'tcx hir::Lifetime) {
debug!("resolve_object_lifetime_default(lifetime_ref={:?})", lifetime_ref);
let mut late_depth = 0;
@@ -3348,7 +3285,7 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> {
))
.emit();
}
- hir::LifetimeName::Param(_) | hir::LifetimeName::Implicit => {
+ hir::LifetimeName::Param(_) | hir::LifetimeName::Implicit(_) => {
self.resolve_lifetime_ref(lt);
}
hir::LifetimeName::ImplicitObjectLifetimeDefault => {
diff --git a/compiler/rustc_resolve/src/lib.rs b/compiler/rustc_resolve/src/lib.rs
index d17e8875a1e..2bd65944127 100644
--- a/compiler/rustc_resolve/src/lib.rs
+++ b/compiler/rustc_resolve/src/lib.rs
@@ -13,8 +13,6 @@
#![feature(drain_filter)]
#![feature(bool_to_option)]
#![feature(crate_visibility_modifier)]
-#![cfg_attr(bootstrap, feature(format_args_capture))]
-#![feature(iter_zip)]
#![feature(let_else)]
#![feature(never_type)]
#![feature(nll)]
@@ -1430,12 +1428,9 @@ impl<'a> Resolver<'a> {
}
pub fn next_node_id(&mut self) -> NodeId {
- let next = self
- .next_node_id
- .as_usize()
- .checked_add(1)
- .expect("input too large; ran out of NodeIds");
- self.next_node_id = ast::NodeId::from_usize(next);
+ let next =
+ self.next_node_id.as_u32().checked_add(1).expect("input too large; ran out of NodeIds");
+ self.next_node_id = ast::NodeId::from_u32(next);
self.next_node_id
}
@@ -3288,7 +3283,9 @@ impl<'a> Resolver<'a> {
Some(binding)
} else {
let crate_id = if !speculative {
- self.crate_loader.process_path_extern(ident.name, ident.span)
+ let Some(crate_id) =
+ self.crate_loader.process_path_extern(ident.name, ident.span) else { return Some(self.dummy_binding); };
+ crate_id
} else {
self.crate_loader.maybe_process_path_extern(ident.name)?
};
diff --git a/compiler/rustc_resolve/src/macros.rs b/compiler/rustc_resolve/src/macros.rs
index 31fd9b989e1..28dbce0471e 100644
--- a/compiler/rustc_resolve/src/macros.rs
+++ b/compiler/rustc_resolve/src/macros.rs
@@ -1133,6 +1133,7 @@ impl<'a> Resolver<'a> {
feature,
reason,
issue,
+ None,
is_soft,
span,
soft_handler,
diff --git a/compiler/rustc_save_analysis/src/lib.rs b/compiler/rustc_save_analysis/src/lib.rs
index c7f8fe3a88a..6f86bafbe45 100644
--- a/compiler/rustc_save_analysis/src/lib.rs
+++ b/compiler/rustc_save_analysis/src/lib.rs
@@ -1036,7 +1036,7 @@ fn find_config(supplied: Option<Config>) -> Config {
// Helper function to escape quotes in a string
fn escape(s: String) -> String {
- s.replace("\"", "\"\"")
+ s.replace('\"', "\"\"")
}
// Helper function to determine if a span came from a
diff --git a/compiler/rustc_save_analysis/src/sig.rs b/compiler/rustc_save_analysis/src/sig.rs
index 7864b47ab0a..1d9c44bffa3 100644
--- a/compiler/rustc_save_analysis/src/sig.rs
+++ b/compiler/rustc_save_analysis/src/sig.rs
@@ -286,7 +286,7 @@ impl<'hir> Sig for hir::Ty<'hir> {
refs: vec![SigElement { id, start, end }],
})
}
- hir::TyKind::Path(hir::QPath::LangItem(lang_item, _)) => {
+ hir::TyKind::Path(hir::QPath::LangItem(lang_item, _, _)) => {
Ok(text_sig(format!("#[lang = \"{}\"]", lang_item.name())))
}
hir::TyKind::TraitObject(bounds, ..) => {
diff --git a/compiler/rustc_serialize/src/json.rs b/compiler/rustc_serialize/src/json.rs
index e5369b4bbfd..cb9df3c3389 100644
--- a/compiler/rustc_serialize/src/json.rs
+++ b/compiler/rustc_serialize/src/json.rs
@@ -589,6 +589,13 @@ impl<'a> crate::Encoder for Encoder<'a> {
}
}
+ fn emit_fieldless_enum_variant<const ID: usize>(
+ &mut self,
+ name: &str,
+ ) -> Result<(), Self::Error> {
+ escape_str(self.writer, name)
+ }
+
fn emit_enum_variant_arg<F>(&mut self, first: bool, f: F) -> EncodeResult
where
F: FnOnce(&mut Encoder<'a>) -> EncodeResult,
@@ -885,6 +892,13 @@ impl<'a> crate::Encoder for PrettyEncoder<'a> {
}
}
+ fn emit_fieldless_enum_variant<const ID: usize>(
+ &mut self,
+ name: &str,
+ ) -> Result<(), Self::Error> {
+ escape_str(self.writer, name)
+ }
+
fn emit_enum_variant_arg<F>(&mut self, first: bool, f: F) -> EncodeResult
where
F: FnOnce(&mut PrettyEncoder<'a>) -> EncodeResult,
@@ -2306,12 +2320,12 @@ impl crate::Decoder for Decoder {
let name = match self.pop() {
Json::String(s) => s,
Json::Object(mut o) => {
- let n = match o.remove(&"variant".to_owned()) {
+ let n = match o.remove("variant") {
Some(Json::String(s)) => s,
Some(val) => return Err(ExpectedError("String".to_owned(), val.to_string())),
None => return Err(MissingFieldError("variant".to_owned())),
};
- match o.remove(&"fields".to_string()) {
+ match o.remove("fields") {
Some(Json::Array(l)) => {
self.stack.extend(l.into_iter().rev());
}
@@ -2351,7 +2365,7 @@ impl crate::Decoder for Decoder {
{
let mut obj = expect!(self.pop(), Object)?;
- let value = match obj.remove(&name.to_string()) {
+ let value = match obj.remove(name) {
None => {
// Add a Null and try to parse it as an Option<_>
// to get None as a default value.
diff --git a/compiler/rustc_serialize/src/opaque.rs b/compiler/rustc_serialize/src/opaque.rs
index 6e36184aff0..cc1216418ae 100644
--- a/compiler/rustc_serialize/src/opaque.rs
+++ b/compiler/rustc_serialize/src/opaque.rs
@@ -55,6 +55,13 @@ macro_rules! write_leb128 {
}};
}
+/// A byte that [cannot occur in UTF8 sequences][utf8]. Used to mark the end of a string.
+/// This way we can skip validation and still be relatively sure that deserialization
+/// did not desynchronize.
+///
+/// [utf8]: https://en.wikipedia.org/w/index.php?title=UTF-8&oldid=1058865525#Codepage_layout
+const STR_SENTINEL: u8 = 0xC1;
+
impl serialize::Encoder for Encoder {
type Error = !;
@@ -150,7 +157,8 @@ impl serialize::Encoder for Encoder {
#[inline]
fn emit_str(&mut self, v: &str) -> EncodeResult {
self.emit_usize(v.len())?;
- self.emit_raw_bytes(v.as_bytes())
+ self.emit_raw_bytes(v.as_bytes())?;
+ self.emit_u8(STR_SENTINEL)
}
#[inline]
@@ -502,7 +510,8 @@ impl serialize::Encoder for FileEncoder {
#[inline]
fn emit_str(&mut self, v: &str) -> FileEncodeResult {
self.emit_usize(v.len())?;
- self.emit_raw_bytes(v.as_bytes())
+ self.emit_raw_bytes(v.as_bytes())?;
+ self.emit_u8(STR_SENTINEL)
}
#[inline]
@@ -656,8 +665,12 @@ impl<'a> serialize::Decoder for Decoder<'a> {
#[inline]
fn read_str(&mut self) -> Result<Cow<'_, str>, Self::Error> {
let len = self.read_usize()?;
- let s = std::str::from_utf8(&self.data[self.position..self.position + len]).unwrap();
- self.position += len;
+ let sentinel = self.data[self.position + len];
+ assert!(sentinel == STR_SENTINEL);
+ let s = unsafe {
+ std::str::from_utf8_unchecked(&self.data[self.position..self.position + len])
+ };
+ self.position += len + 1;
Ok(Cow::Borrowed(s))
}
diff --git a/compiler/rustc_serialize/src/serialize.rs b/compiler/rustc_serialize/src/serialize.rs
index e32e4493726..96a2231b590 100644
--- a/compiler/rustc_serialize/src/serialize.rs
+++ b/compiler/rustc_serialize/src/serialize.rs
@@ -58,6 +58,20 @@ pub trait Encoder {
f(self)
}
+ // We put the field index in a const generic to allow the emit_usize to be
+ // compiled into a more efficient form. In practice, the variant index is
+ // known at compile-time, and that knowledge allows much more efficient
+ // codegen than we'd otherwise get. LLVM isn't always able to make the
+ // optimization that would otherwise be necessary here, likely due to the
+ // multiple levels of inlining and const-prop that are needed.
+ #[inline]
+ fn emit_fieldless_enum_variant<const ID: usize>(
+ &mut self,
+ _v_name: &str,
+ ) -> Result<(), Self::Error> {
+ self.emit_usize(ID)
+ }
+
#[inline]
fn emit_enum_variant_arg<F>(&mut self, _first: bool, f: F) -> Result<(), Self::Error>
where
diff --git a/compiler/rustc_session/src/config.rs b/compiler/rustc_session/src/config.rs
index 3f0a6b0e2f6..50a8f033672 100644
--- a/compiler/rustc_session/src/config.rs
+++ b/compiler/rustc_session/src/config.rs
@@ -335,9 +335,10 @@ impl Default for ErrorOutputType {
}
/// Parameter to control path trimming.
-#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
+#[derive(Clone, Copy, Debug, Default, PartialEq, Eq, Hash)]
pub enum TrimmedDefPaths {
/// `try_print_trimmed_def_path` never prints a trimmed path and never calls the expensive query
+ #[default]
Never,
/// `try_print_trimmed_def_path` calls the expensive query, the query doesn't call `delay_good_path_bug`
Always,
@@ -345,12 +346,6 @@ pub enum TrimmedDefPaths {
GoodPath,
}
-impl Default for TrimmedDefPaths {
- fn default() -> Self {
- Self::Never
- }
-}
-
/// Use tree-based collections to cheaply get a deterministic `Hash` implementation.
/// *Do not* switch `BTreeMap` out for an unsorted container type! That would break
/// dependency tracking for command-line arguments. Also only hash keys, since tracking
@@ -538,6 +533,7 @@ pub enum PrintRequest {
TlsModels,
TargetSpec,
NativeStaticLibs,
+ StackProtectorStrategies,
}
#[derive(Copy, Clone)]
@@ -750,6 +746,7 @@ impl Default for Options {
edition: DEFAULT_EDITION,
json_artifact_notifications: false,
json_unused_externs: false,
+ json_future_incompat: false,
pretty: None,
working_dir: RealFileName::LocalPath(std::env::current_dir().unwrap()),
}
@@ -837,6 +834,13 @@ impl Passes {
Passes::All => false,
}
}
+
+ pub fn extend(&mut self, passes: impl IntoIterator<Item = String>) {
+ match *self {
+ Passes::Some(ref mut v) => v.extend(passes),
+ Passes::All => {}
+ }
+ }
}
pub const fn default_lib_output() -> CrateType {
@@ -1110,8 +1114,8 @@ pub fn rustc_short_optgroups() -> Vec<RustcOptGroup> {
"print",
"Compiler information to print on stdout",
"[crate-name|file-names|sysroot|target-libdir|cfg|target-list|\
- target-cpus|target-features|relocation-models|\
- code-models|tls-models|target-spec-json|native-static-libs]",
+ target-cpus|target-features|relocation-models|code-models|\
+ tls-models|target-spec-json|native-static-libs|stack-protector-strategies]",
),
opt::flagmulti_s("g", "", "Equivalent to -C debuginfo=2"),
opt::flagmulti_s("O", "", "Equivalent to -C opt-level=2"),
@@ -1209,7 +1213,7 @@ pub fn get_cmd_lint_options(
if lint_name == "help" {
describe_lints = true;
} else {
- lint_opts_with_position.push((arg_pos, lint_name.replace("-", "_"), level));
+ lint_opts_with_position.push((arg_pos, lint_name.replace('-', "_"), level));
}
}
}
@@ -1254,6 +1258,7 @@ pub struct JsonConfig {
pub json_rendered: HumanReadableErrorType,
pub json_artifact_notifications: bool,
pub json_unused_externs: bool,
+ pub json_future_incompat: bool,
}
/// Parse the `--json` flag.
@@ -1266,6 +1271,7 @@ pub fn parse_json(matches: &getopts::Matches) -> JsonConfig {
let mut json_color = ColorConfig::Never;
let mut json_artifact_notifications = false;
let mut json_unused_externs = false;
+ let mut json_future_incompat = false;
for option in matches.opt_strs("json") {
// For now conservatively forbid `--color` with `--json` since `--json`
// won't actually be emitting any colors and anything colorized is
@@ -1283,6 +1289,7 @@ pub fn parse_json(matches: &getopts::Matches) -> JsonConfig {
"diagnostic-rendered-ansi" => json_color = ColorConfig::Always,
"artifacts" => json_artifact_notifications = true,
"unused-externs" => json_unused_externs = true,
+ "future-incompat" => json_future_incompat = true,
s => early_error(
ErrorOutputType::default(),
&format!("unknown `--json` option `{}`", s),
@@ -1295,6 +1302,7 @@ pub fn parse_json(matches: &getopts::Matches) -> JsonConfig {
json_rendered: json_rendered(json_color),
json_artifact_notifications,
json_unused_externs,
+ json_future_incompat,
}
}
@@ -1527,6 +1535,7 @@ fn collect_print_requests(
"code-models" => PrintRequest::CodeModels,
"tls-models" => PrintRequest::TlsModels,
"native-static-libs" => PrintRequest::NativeStaticLibs,
+ "stack-protector-strategies" => PrintRequest::StackProtectorStrategies,
"target-spec-json" => {
if dopts.unstable_options {
PrintRequest::TargetSpec
@@ -1726,7 +1735,7 @@ fn parse_native_lib_modifiers(
) -> (NativeLibKind, Option<bool>) {
let mut verbatim = None;
for modifier in modifiers.split(',') {
- let (modifier, value) = match modifier.strip_prefix(&['+', '-'][..]) {
+ let (modifier, value) = match modifier.strip_prefix(&['+', '-']) {
Some(m) => (m, modifier.starts_with('+')),
None => early_error(
error_format,
@@ -2007,14 +2016,18 @@ pub fn build_session_options(matches: &getopts::Matches) -> Options {
let edition = parse_crate_edition(matches);
- let JsonConfig { json_rendered, json_artifact_notifications, json_unused_externs } =
- parse_json(matches);
+ let JsonConfig {
+ json_rendered,
+ json_artifact_notifications,
+ json_unused_externs,
+ json_future_incompat,
+ } = parse_json(matches);
let error_format = parse_error_format(matches, color, json_rendered);
let unparsed_crate_types = matches.opt_strs("crate-type");
let crate_types = parse_crate_types_from_list(unparsed_crate_types)
- .unwrap_or_else(|e| early_error(error_format, &e[..]));
+ .unwrap_or_else(|e| early_error(error_format, &e));
let mut debugging_opts = DebuggingOptions::build(matches, error_format);
let (lint_opts, describe_lints, lint_cap) = get_cmd_lint_options(matches, error_format);
@@ -2138,7 +2151,7 @@ pub fn build_session_options(matches: &getopts::Matches) -> Options {
let mut search_paths = vec![];
for s in &matches.opt_strs("L") {
- search_paths.push(SearchPath::from_cli_opt(&s[..], error_format));
+ search_paths.push(SearchPath::from_cli_opt(&s, error_format));
}
let libs = parse_libs(matches, error_format);
@@ -2244,6 +2257,7 @@ pub fn build_session_options(matches: &getopts::Matches) -> Options {
edition,
json_artifact_notifications,
json_unused_externs,
+ json_future_incompat,
pretty,
working_dir,
}
@@ -2494,7 +2508,9 @@ crate mod dep_tracking {
use rustc_span::edition::Edition;
use rustc_span::RealFileName;
use rustc_target::spec::{CodeModel, MergeFunctions, PanicStrategy, RelocModel};
- use rustc_target::spec::{RelroLevel, SanitizerSet, SplitDebuginfo, TargetTriple, TlsModel};
+ use rustc_target::spec::{
+ RelroLevel, SanitizerSet, SplitDebuginfo, StackProtector, TargetTriple, TlsModel,
+ };
use std::collections::hash_map::DefaultHasher;
use std::collections::BTreeMap;
use std::hash::Hash;
@@ -2568,6 +2584,7 @@ crate mod dep_tracking {
Edition,
LinkerPluginLto,
SplitDebuginfo,
+ StackProtector,
SwitchWithOptPath,
SymbolManglingVersion,
SourceFileHashAlgorithm,
diff --git a/compiler/rustc_session/src/filesearch.rs b/compiler/rustc_session/src/filesearch.rs
index 9359a55e55a..357190178ce 100644
--- a/compiler/rustc_session/src/filesearch.rs
+++ b/compiler/rustc_session/src/filesearch.rs
@@ -4,6 +4,7 @@ pub use self::FileMatch::*;
use std::env;
use std::fs;
+use std::iter::FromIterator;
use std::path::{Path, PathBuf};
use crate::search_paths::{PathKind, SearchPath, SearchPathFile};
@@ -91,8 +92,7 @@ impl<'a> FileSearch<'a> {
pub fn make_target_lib_path(sysroot: &Path, target_triple: &str) -> PathBuf {
let rustlib_path = rustc_target::target_rustlib_path(sysroot, target_triple);
- std::array::IntoIter::new([sysroot, Path::new(&rustlib_path), Path::new("lib")])
- .collect::<PathBuf>()
+ PathBuf::from_iter([sysroot, Path::new(&rustlib_path), Path::new("lib")])
}
/// This function checks if sysroot is found using env::args().next(), and if it
diff --git a/compiler/rustc_session/src/lib.rs b/compiler/rustc_session/src/lib.rs
index 6c86f86ecd9..399b616915e 100644
--- a/compiler/rustc_session/src/lib.rs
+++ b/compiler/rustc_session/src/lib.rs
@@ -1,4 +1,5 @@
#![feature(crate_visibility_modifier)]
+#![feature(derive_default_enum)]
#![feature(min_specialization)]
#![feature(once_cell)]
#![recursion_limit = "256"]
diff --git a/compiler/rustc_session/src/options.rs b/compiler/rustc_session/src/options.rs
index cba05f6aa59..9090524c933 100644
--- a/compiler/rustc_session/src/options.rs
+++ b/compiler/rustc_session/src/options.rs
@@ -5,7 +5,9 @@ use crate::lint;
use crate::search_paths::SearchPath;
use crate::utils::NativeLib;
use rustc_target::spec::{CodeModel, LinkerFlavor, MergeFunctions, PanicStrategy, SanitizerSet};
-use rustc_target::spec::{RelocModel, RelroLevel, SplitDebuginfo, TargetTriple, TlsModel};
+use rustc_target::spec::{
+ RelocModel, RelroLevel, SplitDebuginfo, StackProtector, TargetTriple, TlsModel,
+};
use rustc_feature::UnstableFeatures;
use rustc_span::edition::Edition;
@@ -99,6 +101,29 @@ macro_rules! top_level_options {
);
}
+impl Options {
+ pub fn mir_opt_level(&self) -> usize {
+ self.debugging_opts
+ .mir_opt_level
+ .unwrap_or_else(|| if self.optimize != OptLevel::No { 2 } else { 1 })
+ }
+
+ pub fn instrument_coverage(&self) -> bool {
+ self.debugging_opts.instrument_coverage.unwrap_or(InstrumentCoverage::Off)
+ != InstrumentCoverage::Off
+ }
+
+ pub fn instrument_coverage_except_unused_generics(&self) -> bool {
+ self.debugging_opts.instrument_coverage.unwrap_or(InstrumentCoverage::Off)
+ == InstrumentCoverage::ExceptUnusedGenerics
+ }
+
+ pub fn instrument_coverage_except_unused_functions(&self) -> bool {
+ self.debugging_opts.instrument_coverage.unwrap_or(InstrumentCoverage::Off)
+ == InstrumentCoverage::ExceptUnusedFunctions
+ }
+}
+
top_level_options!(
/// The top-level command-line options struct.
///
@@ -203,6 +228,9 @@ top_level_options!(
/// `true` if we're emitting a JSON blob containing the unused externs
json_unused_externs: bool [UNTRACKED],
+ /// `true` if we're emitting a JSON job containg a future-incompat report for lints
+ json_future_incompat: bool [TRACKED],
+
pretty: Option<PpMode> [UNTRACKED],
/// The (potentially remapped) working directory
@@ -307,7 +335,7 @@ fn build_options<O: Default>(
Some((k, v)) => (k.to_string(), Some(v)),
};
- let option_to_lookup = key.replace("-", "_");
+ let option_to_lookup = key.replace('-', "_");
match descrs.iter().find(|(name, ..)| *name == option_to_lookup) {
Some((_, setter, type_desc, _)) => {
if !setter(&mut op, value) {
@@ -385,6 +413,8 @@ mod desc {
pub const parse_split_debuginfo: &str =
"one of supported split-debuginfo modes (`off`, `packed`, or `unpacked`)";
pub const parse_gcc_ld: &str = "one of: no value, `lld`";
+ pub const parse_stack_protector: &str =
+ "one of (`none` (default), `basic`, `strong`, or `all`)";
}
mod parse {
@@ -563,7 +593,7 @@ mod parse {
v => {
let mut passes = vec![];
if parse_list(&mut passes, v) {
- *slot = Passes::Some(passes);
+ slot.extend(passes);
true
} else {
false
@@ -917,6 +947,14 @@ mod parse {
}
true
}
+
+ crate fn parse_stack_protector(slot: &mut StackProtector, v: Option<&str>) -> bool {
+ match v.and_then(|s| StackProtector::from_str(s).ok()) {
+ Some(ssp) => *slot = ssp,
+ _ => return false,
+ }
+ true
+ }
}
options! {
@@ -1112,15 +1150,11 @@ options! {
computed `block` spans (one span encompassing a block's terminator and \
all statements). If `-Z instrument-coverage` is also enabled, create \
an additional `.html` file showing the computed coverage spans."),
- emit_future_incompat_report: bool = (false, parse_bool, [UNTRACKED],
- "emits a future-incompatibility report for lints (RFC 2834)"),
emit_stack_sizes: bool = (false, parse_bool, [UNTRACKED],
"emit a section containing stack size metadata (default: no)"),
fewer_names: Option<bool> = (None, parse_opt_bool, [TRACKED],
"reduce memory use by retaining fewer names within compilation artifacts (LLVM-IR) \
(default: no)"),
- force_overflow_checks: Option<bool> = (None, parse_opt_bool, [TRACKED],
- "force overflow checks on or off"),
force_unstable_if_unmarked: bool = (false, parse_bool, [TRACKED],
"force all crates to be `rustc_private` unstable (default: no)"),
fuel: Option<(String, u64)> = (None, parse_optimization_fuel, [TRACKED],
@@ -1287,6 +1321,8 @@ options! {
"print some statistics about the query system (default: no)"),
randomize_layout: bool = (false, parse_bool, [TRACKED],
"randomize the layout of types (default: no)"),
+ layout_seed: Option<u64> = (None, parse_opt_number, [TRACKED],
+ "seed layout randomization"),
relax_elf_relocations: Option<bool> = (None, parse_opt_bool, [TRACKED],
"whether ELF relocations can be relaxed"),
relro_level: Option<RelroLevel> = (None, parse_relro_level, [TRACKED],
@@ -1330,6 +1366,8 @@ options! {
"exclude spans when debug-printing compiler state (default: no)"),
src_hash_algorithm: Option<SourceFileHashAlgorithm> = (None, parse_src_file_hash, [TRACKED],
"hash algorithm of source files in debug info (`md5`, `sha1`, or `sha256`)"),
+ stack_protector: StackProtector = (StackProtector::None, parse_stack_protector, [TRACKED],
+ "control stack smash protection strategy (`rustc --print stack-protector-strategies` for details)"),
strip: Strip = (Strip::None, parse_strip, [UNTRACKED],
"tell the linker which information to strip (`none` (default), `debuginfo` or `symbols`)"),
split_dwarf_inlining: bool = (true, parse_bool, [UNTRACKED],
diff --git a/compiler/rustc_session/src/output.rs b/compiler/rustc_session/src/output.rs
index cc1e4bb198a..5689b723ad6 100644
--- a/compiler/rustc_session/src/output.rs
+++ b/compiler/rustc_session/src/output.rs
@@ -85,7 +85,7 @@ pub fn find_crate_name(sess: &Session, attrs: &[ast::Attribute], input: &Input)
);
sess.err(&msg);
} else {
- return validate(s.replace("-", "_"), None);
+ return validate(s.replace('-', "_"), None);
}
}
}
diff --git a/compiler/rustc_session/src/parse.rs b/compiler/rustc_session/src/parse.rs
index f7246641dca..d5b520325e5 100644
--- a/compiler/rustc_session/src/parse.rs
+++ b/compiler/rustc_session/src/parse.rs
@@ -119,8 +119,13 @@ pub struct ParseSess {
pub config: CrateConfig,
pub edition: Edition,
pub missing_fragment_specifiers: Lock<FxHashMap<Span, NodeId>>,
- /// Places where raw identifiers were used. This is used for feature-gating raw identifiers.
+ /// Places where raw identifiers were used. This is used to avoid complaining about idents
+ /// clashing with keywords in new editions.
pub raw_identifier_spans: Lock<Vec<Span>>,
+ /// Places where identifiers that contain invalid Unicode codepoints but that look like they
+ /// should be. Useful to avoid bad tokenization when encountering emoji. We group them to
+ /// provide a single error per unique incorrect identifier.
+ pub bad_unicode_identifiers: Lock<FxHashMap<Symbol, Vec<Span>>>,
source_map: Lrc<SourceMap>,
pub buffered_lints: Lock<Vec<BufferedEarlyLint>>,
/// Contains the spans of block expressions that could have been incomplete based on the
@@ -160,6 +165,7 @@ impl ParseSess {
edition: ExpnId::root().expn_data().edition,
missing_fragment_specifiers: Default::default(),
raw_identifier_spans: Lock::new(Vec::new()),
+ bad_unicode_identifiers: Lock::new(Default::default()),
source_map,
buffered_lints: Lock::new(vec![]),
ambiguous_block_expr_parse: Lock::new(FxHashMap::default()),
diff --git a/compiler/rustc_session/src/session.rs b/compiler/rustc_session/src/session.rs
index 74b3cfa44c3..730e79a5647 100644
--- a/compiler/rustc_session/src/session.rs
+++ b/compiler/rustc_session/src/session.rs
@@ -27,7 +27,9 @@ use rustc_span::source_map::{FileLoader, MultiSpan, RealFileLoader, SourceMap, S
use rustc_span::{sym, SourceFileHashAlgorithm, Symbol};
use rustc_target::asm::InlineAsmArch;
use rustc_target::spec::{CodeModel, PanicStrategy, RelocModel, RelroLevel};
-use rustc_target::spec::{SanitizerSet, SplitDebuginfo, Target, TargetTriple, TlsModel};
+use rustc_target::spec::{
+ SanitizerSet, SplitDebuginfo, StackProtector, Target, TargetTriple, TlsModel,
+};
use std::cell::{self, RefCell};
use std::env;
@@ -278,7 +280,7 @@ impl Session {
}
fn emit_future_breakage(&self) {
- if !self.opts.debugging_opts.emit_future_incompat_report {
+ if !self.opts.json_future_incompat {
return;
}
@@ -560,10 +562,7 @@ impl Session {
self.opts.debugging_opts.binary_dep_depinfo
}
pub fn mir_opt_level(&self) -> usize {
- self.opts
- .debugging_opts
- .mir_opt_level
- .unwrap_or_else(|| if self.opts.optimize != config::OptLevel::No { 2 } else { 1 })
+ self.opts.mir_opt_level()
}
/// Gets the features enabled for the current compilation session.
@@ -676,11 +675,7 @@ impl Session {
self.opts.debugging_opts.sanitizer.contains(SanitizerSet::CFI)
}
pub fn overflow_checks(&self) -> bool {
- self.opts
- .cg
- .overflow_checks
- .or(self.opts.debugging_opts.force_overflow_checks)
- .unwrap_or(self.opts.debug_assertions)
+ self.opts.cg.overflow_checks.unwrap_or(self.opts.debug_assertions)
}
/// Check whether this compile session and crate type use static crt.
@@ -732,6 +727,14 @@ impl Session {
self.opts.cg.split_debuginfo.unwrap_or(self.target.split_debuginfo)
}
+ pub fn stack_protector(&self) -> StackProtector {
+ if self.target.options.supports_stack_protector {
+ self.opts.debugging_opts.stack_protector
+ } else {
+ StackProtector::None
+ }
+ }
+
pub fn target_can_use_split_dwarf(&self) -> bool {
!self.target.is_like_windows && !self.target.is_like_osx
}
@@ -789,12 +792,11 @@ impl Session {
/// Returns a list of directories where target-specific tool binaries are located.
pub fn get_tools_search_paths(&self, self_contained: bool) -> Vec<PathBuf> {
let rustlib_path = rustc_target::target_rustlib_path(&self.sysroot, &config::host_triple());
- let p = std::array::IntoIter::new([
+ let p = PathBuf::from_iter([
Path::new(&self.sysroot),
Path::new(&rustlib_path),
Path::new("bin"),
- ])
- .collect::<PathBuf>();
+ ]);
if self_contained { vec![p.clone(), p.join("self-contained")] } else { vec![p] }
}
@@ -1041,18 +1043,15 @@ impl Session {
}
pub fn instrument_coverage(&self) -> bool {
- self.opts.debugging_opts.instrument_coverage.unwrap_or(config::InstrumentCoverage::Off)
- != config::InstrumentCoverage::Off
+ self.opts.instrument_coverage()
}
pub fn instrument_coverage_except_unused_generics(&self) -> bool {
- self.opts.debugging_opts.instrument_coverage.unwrap_or(config::InstrumentCoverage::Off)
- == config::InstrumentCoverage::ExceptUnusedGenerics
+ self.opts.instrument_coverage_except_unused_generics()
}
pub fn instrument_coverage_except_unused_functions(&self) -> bool {
- self.opts.debugging_opts.instrument_coverage.unwrap_or(config::InstrumentCoverage::Off)
- == config::InstrumentCoverage::ExceptUnusedFunctions
+ self.opts.instrument_coverage_except_unused_functions()
}
pub fn is_proc_macro_attr(&self, attr: &Attribute) -> bool {
@@ -1411,6 +1410,15 @@ fn validate_commandline_args_with_session_available(sess: &Session) {
sess.err("`-Zsanitizer=cfi` requires `-Clto`");
}
}
+
+ if sess.opts.debugging_opts.stack_protector != StackProtector::None {
+ if !sess.target.options.supports_stack_protector {
+ sess.warn(&format!(
+ "`-Z stack-protector={}` is not supported for target {} and will be ignored",
+ sess.opts.debugging_opts.stack_protector, sess.opts.target_triple
+ ))
+ }
+ }
}
/// Holds data on the current incremental compilation session, if there is one.
diff --git a/compiler/rustc_span/src/def_id.rs b/compiler/rustc_span/src/def_id.rs
index 64baf94cc00..64c2ef30b4d 100644
--- a/compiler/rustc_span/src/def_id.rs
+++ b/compiler/rustc_span/src/def_id.rs
@@ -7,6 +7,7 @@ use rustc_macros::HashStable_Generic;
use rustc_serialize::{Decodable, Decoder, Encodable, Encoder};
use std::borrow::Borrow;
use std::fmt;
+use std::hash::{Hash, Hasher};
rustc_index::newtype_index! {
pub struct CrateNum {
@@ -126,14 +127,17 @@ impl Borrow<Fingerprint> for DefPathHash {
}
}
-/// A [StableCrateId] is a 64 bit hash of the crate name combined with all
-/// `-Cmetadata` arguments. It is to [CrateNum] what [DefPathHash] is to
-/// [DefId]. It is stable across compilation sessions.
+/// A [`StableCrateId`] is a 64-bit hash of a crate name, together with all
+/// `-Cmetadata` arguments, and some other data. It is to [`CrateNum`] what [`DefPathHash`] is to
+/// [`DefId`]. It is stable across compilation sessions.
///
-/// Since the ID is a hash value there is a (very small) chance that two crates
-/// end up with the same [StableCrateId]. The compiler will check for such
+/// Since the ID is a hash value, there is a small chance that two crates
+/// end up with the same [`StableCrateId`]. The compiler will check for such
/// collisions when loading crates and abort compilation in order to avoid
/// further trouble.
+///
+/// See the discussion in [`DefId`] for more information
+/// on the possibility of hash collisions in rustc,
#[derive(Copy, Clone, Hash, PartialEq, Eq, PartialOrd, Ord, Debug)]
#[derive(HashStable_Generic, Encodable, Decodable)]
pub struct StableCrateId(pub(crate) u64);
@@ -146,13 +150,10 @@ impl StableCrateId {
/// Computes the stable ID for a crate with the given name and
/// `-Cmetadata` arguments.
pub fn new(crate_name: &str, is_exe: bool, mut metadata: Vec<String>) -> StableCrateId {
- use std::hash::Hash;
- use std::hash::Hasher;
-
let mut hasher = StableHasher::new();
crate_name.hash(&mut hasher);
- // We don't want the stable crate id to dependent on the order
+ // We don't want the stable crate ID to depend on the order of
// -C metadata arguments, so sort them:
metadata.sort();
// Every distinct -C metadata value is only incorporated once:
@@ -171,6 +172,18 @@ impl StableCrateId {
// linking against a library of the same name, if this is an executable.
hasher.write(if is_exe { b"exe" } else { b"lib" });
+ // Also incorporate the rustc version. Otherwise, with -Zsymbol-mangling-version=v0
+ // and no -Cmetadata, symbols from the same crate compiled with different versions of
+ // rustc are named the same.
+ //
+ // RUSTC_FORCE_INCR_COMP_ARTIFACT_HEADER is used to inject rustc version information
+ // during testing.
+ if let Some(val) = std::env::var_os("RUSTC_FORCE_INCR_COMP_ARTIFACT_HEADER") {
+ hasher.write(val.to_string_lossy().into_owned().as_bytes())
+ } else {
+ hasher.write(option_env!("CFG_VERSION").unwrap_or("unknown version").as_bytes());
+ }
+
StableCrateId(hasher.finish())
}
}
@@ -205,10 +218,38 @@ impl<D: Decoder> Decodable<D> for DefIndex {
/// index and a def index.
///
/// You can create a `DefId` from a `LocalDefId` using `local_def_id.to_def_id()`.
-#[derive(Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Copy)]
+#[derive(Clone, PartialEq, Eq, PartialOrd, Ord, Copy)]
+// On below-64 bit systems we can simply use the derived `Hash` impl
+#[cfg_attr(not(target_pointer_width = "64"), derive(Hash))]
+// Note that the order is essential here, see below why
pub struct DefId {
- pub krate: CrateNum,
pub index: DefIndex,
+ pub krate: CrateNum,
+}
+
+// On 64-bit systems, we can hash the whole `DefId` as one `u64` instead of two `u32`s. This
+// improves performance without impairing `FxHash` quality. So the below code gets compiled to a
+// noop on little endian systems because the memory layout of `DefId` is as follows:
+//
+// ```
+// +-1--------------31-+-32-------------63-+
+// ! index ! krate !
+// +-------------------+-------------------+
+// ```
+//
+// The order here has direct impact on `FxHash` quality because we have far more `DefIndex` per
+// crate than we have `Crate`s within one compilation. Or in other words, this arrangement puts
+// more entropy in the low bits than the high bits. The reason this matters is that `FxHash`, which
+// is used throughout rustc, has problems distributing the entropy from the high bits, so reversing
+// the order would lead to a large number of collisions and thus far worse performance.
+//
+// On 64-bit big-endian systems, this compiles to a 64-bit rotation by 32 bits, which is still
+// faster than another `FxHash` round.
+#[cfg(target_pointer_width = "64")]
+impl Hash for DefId {
+ fn hash<H: Hasher>(&self, h: &mut H) {
+ (((self.krate.as_u32() as u64) << 32) | (self.index.as_u32() as u64)).hash(h)
+ }
}
impl DefId {
diff --git a/compiler/rustc_span/src/hygiene.rs b/compiler/rustc_span/src/hygiene.rs
index d590776676b..315b706fbc4 100644
--- a/compiler/rustc_span/src/hygiene.rs
+++ b/compiler/rustc_span/src/hygiene.rs
@@ -264,7 +264,15 @@ impl ExpnId {
HygieneData::with(|data| data.expn_data(self).clone())
}
+ #[inline]
pub fn is_descendant_of(self, ancestor: ExpnId) -> bool {
+ // a few "fast path" cases to avoid locking HygieneData
+ if ancestor == ExpnId::root() || ancestor == self {
+ return true;
+ }
+ if ancestor.krate != self.krate {
+ return false;
+ }
HygieneData::with(|data| data.is_descendant_of(self, ancestor))
}
@@ -376,13 +384,22 @@ impl HygieneData {
}
fn is_descendant_of(&self, mut expn_id: ExpnId, ancestor: ExpnId) -> bool {
- while expn_id != ancestor {
+ // a couple "fast path" cases to avoid traversing parents in the loop below
+ if ancestor == ExpnId::root() {
+ return true;
+ }
+ if expn_id.krate != ancestor.krate {
+ return false;
+ }
+ loop {
+ if expn_id == ancestor {
+ return true;
+ }
if expn_id == ExpnId::root() {
return false;
}
expn_id = self.expn_data(expn_id).parent;
}
- true
}
fn normalize_to_macros_2_0(&self, ctxt: SyntaxContext) -> SyntaxContext {
@@ -1223,6 +1240,7 @@ pub fn register_expn_id(
data: ExpnData,
hash: ExpnHash,
) -> ExpnId {
+ debug_assert!(data.parent == ExpnId::root() || krate == data.parent.krate);
let expn_id = ExpnId { krate, local_id };
HygieneData::with(|hygiene_data| {
let _old_data = hygiene_data.foreign_expn_data.insert(expn_id, data);
diff --git a/compiler/rustc_span/src/lib.rs b/compiler/rustc_span/src/lib.rs
index 66c01140abc..2934368dfeb 100644
--- a/compiler/rustc_span/src/lib.rs
+++ b/compiler/rustc_span/src/lib.rs
@@ -20,7 +20,6 @@
#![feature(negative_impls)]
#![feature(nll)]
#![feature(min_specialization)]
-#![feature(thread_local_const_init)]
#[macro_use]
extern crate rustc_macros;
@@ -551,6 +550,16 @@ impl Span {
matches!(self.ctxt().outer_expn_data().kind, ExpnKind::Macro(MacroKind::Derive, _))
}
+ /// Gate suggestions that would not be appropriate in a context the user didn't write.
+ pub fn can_be_used_for_suggestions(self) -> bool {
+ !self.from_expansion()
+ // FIXME: If this span comes from a `derive` macro but it points at code the user wrote,
+ // the callsite span and the span will be pointing at different places. It also means that
+ // we can safely provide suggestions on this span.
+ || (matches!(self.ctxt().outer_expn_data().kind, ExpnKind::Macro(MacroKind::Derive, _))
+ && self.parent_callsite().map(|p| (p.lo(), p.hi())) != Some((self.lo(), self.hi())))
+ }
+
#[inline]
pub fn with_root_ctxt(lo: BytePos, hi: BytePos) -> Span {
Span::new(lo, hi, SyntaxContext::root(), None)
@@ -1374,7 +1383,7 @@ impl<S: Encoder> Encodable<S> for SourceFile {
// Encode the first element.
lines[0].encode(s)?;
- let diff_iter = lines[..].array_windows().map(|&[fst, snd]| snd - fst);
+ let diff_iter = lines.array_windows().map(|&[fst, snd]| snd - fst);
match bytes_per_diff {
1 => {
@@ -1497,7 +1506,7 @@ impl SourceFile {
assert!(end_pos <= u32::MAX as usize);
let (lines, multibyte_chars, non_narrow_chars) =
- analyze_source_file::analyze_source_file(&src[..], start_pos);
+ analyze_source_file::analyze_source_file(&src, start_pos);
SourceFile {
name,
diff --git a/compiler/rustc_span/src/symbol.rs b/compiler/rustc_span/src/symbol.rs
index 0d556b5eda6..eb6063d7612 100644
--- a/compiler/rustc_span/src/symbol.rs
+++ b/compiler/rustc_span/src/symbol.rs
@@ -196,6 +196,7 @@ symbols! {
Implied,
Input,
Into,
+ IntoFuture,
IntoIterator,
IoRead,
IoWrite,
@@ -307,6 +308,7 @@ symbols! {
alloc_layout,
alloc_zeroed,
allocator,
+ allocator_api,
allocator_internals,
allow,
allow_fail,
@@ -330,6 +332,7 @@ symbols! {
asm_const,
asm_experimental_arch,
asm_sym,
+ asm_unwind,
assert,
assert_inhabited,
assert_macro,
@@ -436,6 +439,7 @@ symbols! {
compiler_builtins,
compiler_fence,
concat,
+ concat_bytes,
concat_idents,
conservative_impl_trait,
console,
@@ -496,6 +500,7 @@ symbols! {
core_panic_macro,
cosf32,
cosf64,
+ count,
cr,
crate_id,
crate_in_paths,
@@ -626,6 +631,7 @@ symbols! {
fdiv_fast,
feature,
fence,
+ ferris: "🦀",
fetch_update,
ffi,
ffi_const,
@@ -678,6 +684,7 @@ symbols! {
gen_future,
gen_kill,
generator,
+ generator_return,
generator_state,
generators,
generic_arg_infer,
@@ -731,9 +738,11 @@ symbols! {
inlateout,
inline,
inline_const,
+ inline_const_pat,
inout,
instruction_set,
intel,
+ into_future,
into_iter,
intra_doc_pointers,
intrinsics,
@@ -812,6 +821,7 @@ symbols! {
maxnumf32,
maxnumf64,
may_dangle,
+ may_unwind,
maybe_uninit,
maybe_uninit_uninit,
maybe_uninit_zeroed,
@@ -1045,8 +1055,11 @@ symbols! {
reg64,
reg_abcd,
reg_byte,
+ reg_iw,
reg_nonzero,
- reg_thumb,
+ reg_pair,
+ reg_ptr,
+ reg_upper,
register_attr,
register_tool,
relaxed_adts,
@@ -1153,6 +1166,7 @@ symbols! {
rustc_unsafe_specialization_marker,
rustc_variance,
rustdoc,
+ rustdoc_internals,
rustfmt,
rvalue_static_promotion,
s,
@@ -1712,8 +1726,9 @@ pub(crate) struct Interner(Lock<InternerInner>);
// found that to regress performance up to 2% in some cases. This might be
// revisited after further improvements to `indexmap`.
//
-// This type is private to prevent accidentally constructing more than one `Interner` on the same
-// thread, which makes it easy to mixup `Symbol`s between `Interner`s.
+// This type is private to prevent accidentally constructing more than one
+// `Interner` on the same thread, which makes it easy to mixup `Symbol`s
+// between `Interner`s.
#[derive(Default)]
struct InternerInner {
arena: DroplessArena,
@@ -1739,14 +1754,20 @@ impl Interner {
let name = Symbol::new(inner.strings.len() as u32);
- // `from_utf8_unchecked` is safe since we just allocated a `&str` which is known to be
- // UTF-8.
+ // SAFETY: we convert from `&str` to `&[u8]`, clone it into the arena,
+ // and immediately convert the clone back to `&[u8], all because there
+ // is no `inner.arena.alloc_str()` method. This is clearly safe.
let string: &str =
unsafe { str::from_utf8_unchecked(inner.arena.alloc_slice(string.as_bytes())) };
- // It is safe to extend the arena allocation to `'static` because we only access
- // these while the arena is still alive.
+
+ // SAFETY: we can extend the arena allocation to `'static` because we
+ // only access these while the arena is still alive.
let string: &'static str = unsafe { &*(string as *const str) };
inner.strings.push(string);
+
+ // This second hash table lookup can be avoided by using `RawEntryMut`,
+ // but this code path isn't hot enough for it to be worth it. See
+ // #91445 for details.
inner.names.insert(string, name);
name
}
diff --git a/compiler/rustc_symbol_mangling/src/legacy.rs b/compiler/rustc_symbol_mangling/src/legacy.rs
index de18614360e..0232aace6d7 100644
--- a/compiler/rustc_symbol_mangling/src/legacy.rs
+++ b/compiler/rustc_symbol_mangling/src/legacy.rs
@@ -13,7 +13,7 @@ use tracing::debug;
use std::fmt::{self, Write};
use std::mem::{self, discriminant};
-pub(super) fn mangle(
+pub(super) fn mangle<'tcx>(
tcx: TyCtxt<'tcx>,
instance: Instance<'tcx>,
instantiating_crate: Option<CrateNum>,
@@ -199,7 +199,7 @@ struct SymbolPrinter<'tcx> {
// `PrettyPrinter` aka pretty printing of e.g. types in paths,
// symbol names should have their own printing machinery.
-impl Printer<'tcx> for &mut SymbolPrinter<'tcx> {
+impl<'tcx> Printer<'tcx> for &mut SymbolPrinter<'tcx> {
type Error = fmt::Error;
type Path = Self;
@@ -311,8 +311,8 @@ impl Printer<'tcx> for &mut SymbolPrinter<'tcx> {
) -> Result<Self::Path, Self::Error> {
self = print_prefix(self)?;
- // Skip `::{{constructor}}` on tuple/unit structs.
- if let DefPathData::Ctor = disambiguated_data.data {
+ // Skip `::{{extern}}` blocks and `::{{constructor}}` on tuple/unit structs.
+ if let DefPathData::ForeignMod | DefPathData::Ctor = disambiguated_data.data {
return Ok(self);
}
@@ -345,7 +345,7 @@ impl Printer<'tcx> for &mut SymbolPrinter<'tcx> {
}
}
-impl PrettyPrinter<'tcx> for &mut SymbolPrinter<'tcx> {
+impl<'tcx> PrettyPrinter<'tcx> for &mut SymbolPrinter<'tcx> {
fn region_should_not_be_omitted(&self, _region: ty::Region<'_>) -> bool {
false
}
diff --git a/compiler/rustc_symbol_mangling/src/lib.rs b/compiler/rustc_symbol_mangling/src/lib.rs
index bb7b4529556..65b5852bc39 100644
--- a/compiler/rustc_symbol_mangling/src/lib.rs
+++ b/compiler/rustc_symbol_mangling/src/lib.rs
@@ -90,8 +90,6 @@
#![doc(html_root_url = "https://doc.rust-lang.org/nightly/nightly-rustc/")]
#![feature(never_type)]
#![feature(nll)]
-#![feature(in_band_lifetimes)]
-#![feature(iter_zip)]
#![recursion_limit = "256"]
#[macro_use]
@@ -117,7 +115,7 @@ pub mod test;
/// This function computes the symbol name for the given `instance` and the
/// given instantiating crate. That is, if you know that instance X is
/// instantiated in crate Y, this is the symbol name this instance would have.
-pub fn symbol_name_for_instance_in_crate(
+pub fn symbol_name_for_instance_in_crate<'tcx>(
tcx: TyCtxt<'tcx>,
instance: Instance<'tcx>,
instantiating_crate: CrateNum,
@@ -132,7 +130,7 @@ pub fn provide(providers: &mut Providers) {
// The `symbol_name` query provides the symbol name for calling a given
// instance from the local crate. In particular, it will also look up the
// correct symbol name of instances from upstream crates.
-fn symbol_name_provider(tcx: TyCtxt<'tcx>, instance: Instance<'tcx>) -> ty::SymbolName<'tcx> {
+fn symbol_name_provider<'tcx>(tcx: TyCtxt<'tcx>, instance: Instance<'tcx>) -> ty::SymbolName<'tcx> {
let symbol_name = compute_symbol_name(tcx, instance, || {
// This closure determines the instantiating crate for instances that
// need an instantiating-crate-suffix for their symbol name, in order
@@ -152,14 +150,14 @@ fn symbol_name_provider(tcx: TyCtxt<'tcx>, instance: Instance<'tcx>) -> ty::Symb
}
/// This function computes the typeid for the given function ABI.
-pub fn typeid_for_fnabi(tcx: TyCtxt<'tcx>, fn_abi: &FnAbi<'tcx, Ty<'tcx>>) -> String {
+pub fn typeid_for_fnabi<'tcx>(tcx: TyCtxt<'tcx>, fn_abi: &FnAbi<'tcx, Ty<'tcx>>) -> String {
v0::mangle_typeid_for_fnabi(tcx, fn_abi)
}
/// Computes the symbol name for the given instance. This function will call
/// `compute_instantiating_crate` if it needs to factor the instantiating crate
/// into the symbol name.
-fn compute_symbol_name(
+fn compute_symbol_name<'tcx>(
tcx: TyCtxt<'tcx>,
instance: Instance<'tcx>,
compute_instantiating_crate: impl FnOnce() -> CrateNum,
diff --git a/compiler/rustc_symbol_mangling/src/test.rs b/compiler/rustc_symbol_mangling/src/test.rs
index f7d68b5cc70..700765a351c 100644
--- a/compiler/rustc_symbol_mangling/src/test.rs
+++ b/compiler/rustc_symbol_mangling/src/test.rs
@@ -31,7 +31,7 @@ struct SymbolNamesTest<'tcx> {
tcx: TyCtxt<'tcx>,
}
-impl SymbolNamesTest<'tcx> {
+impl SymbolNamesTest<'_> {
fn process_attrs(&mut self, def_id: LocalDefId) {
let tcx = self.tcx;
for attr in tcx.get_attrs(def_id.to_def_id()).iter() {
@@ -59,7 +59,7 @@ impl SymbolNamesTest<'tcx> {
}
}
-impl hir::itemlikevisit::ItemLikeVisitor<'tcx> for SymbolNamesTest<'tcx> {
+impl<'tcx> hir::itemlikevisit::ItemLikeVisitor<'tcx> for SymbolNamesTest<'tcx> {
fn visit_item(&mut self, item: &'tcx hir::Item<'tcx>) {
self.process_attrs(item.def_id);
}
diff --git a/compiler/rustc_symbol_mangling/src/v0.rs b/compiler/rustc_symbol_mangling/src/v0.rs
index 0363ddb0e6e..ea6366c407e 100644
--- a/compiler/rustc_symbol_mangling/src/v0.rs
+++ b/compiler/rustc_symbol_mangling/src/v0.rs
@@ -17,7 +17,7 @@ use std::fmt::Write;
use std::iter;
use std::ops::Range;
-pub(super) fn mangle(
+pub(super) fn mangle<'tcx>(
tcx: TyCtxt<'tcx>,
instance: Instance<'tcx>,
instantiating_crate: Option<CrateNum>,
@@ -56,7 +56,7 @@ pub(super) fn mangle(
std::mem::take(&mut cx.out)
}
-pub(super) fn mangle_typeid_for_fnabi(
+pub(super) fn mangle_typeid_for_fnabi<'tcx>(
_tcx: TyCtxt<'tcx>,
fn_abi: &FnAbi<'tcx, Ty<'tcx>>,
) -> String {
@@ -118,7 +118,7 @@ struct SymbolMangler<'tcx> {
consts: FxHashMap<&'tcx ty::Const<'tcx>, usize>,
}
-impl SymbolMangler<'tcx> {
+impl<'tcx> SymbolMangler<'tcx> {
fn push(&mut self, s: &str) {
self.out.push_str(s);
}
@@ -250,7 +250,7 @@ impl SymbolMangler<'tcx> {
}
}
-impl Printer<'tcx> for &mut SymbolMangler<'tcx> {
+impl<'tcx> Printer<'tcx> for &mut SymbolMangler<'tcx> {
type Error = !;
type Path = Self;
@@ -771,6 +771,10 @@ impl Printer<'tcx> for &mut SymbolMangler<'tcx> {
disambiguated_data: &DisambiguatedDefPathData,
) -> Result<Self::Path, Self::Error> {
let ns = match disambiguated_data.data {
+ // FIXME: It shouldn't be necessary to add anything for extern block segments,
+ // but we add 't' for backward compatibility.
+ DefPathData::ForeignMod => 't',
+
// Uppercase categories are more stable than lowercase ones.
DefPathData::TypeNs(_) => 't',
DefPathData::ValueNs(_) => 'v',
diff --git a/compiler/rustc_target/src/abi/call/mips64.rs b/compiler/rustc_target/src/abi/call/mips64.rs
index 2e00ffc7e14..1ac454be5e9 100644
--- a/compiler/rustc_target/src/abi/call/mips64.rs
+++ b/compiler/rustc_target/src/abi/call/mips64.rs
@@ -1,4 +1,6 @@
-use crate::abi::call::{ArgAbi, ArgExtension, CastTarget, FnAbi, PassMode, Reg, RegKind, Uniform};
+use crate::abi::call::{
+ ArgAbi, ArgAttribute, ArgAttributes, ArgExtension, CastTarget, FnAbi, PassMode, Reg, Uniform,
+};
use crate::abi::{self, HasDataLayout, Size, TyAbiInterface};
fn extend_integer_width_mips<Ty>(arg: &mut ArgAbi<'_, Ty>, bits: u64) {
@@ -115,7 +117,7 @@ where
for _ in 0..((offset - last_offset).bits() / 64)
.min((prefix.len() - prefix_index) as u64)
{
- prefix[prefix_index] = Some(RegKind::Integer);
+ prefix[prefix_index] = Some(Reg::i64());
prefix_index += 1;
}
@@ -123,7 +125,7 @@ where
break;
}
- prefix[prefix_index] = Some(RegKind::Float);
+ prefix[prefix_index] = Some(Reg::f64());
prefix_index += 1;
last_offset = offset + Reg::f64().size;
}
@@ -137,8 +139,13 @@ where
let rest_size = size - Size::from_bytes(8) * prefix_index as u64;
arg.cast_to(CastTarget {
prefix,
- prefix_chunk_size: Size::from_bytes(8),
rest: Uniform { unit: Reg::i64(), total: rest_size },
+ attrs: ArgAttributes {
+ regular: ArgAttribute::default(),
+ arg_ext: ArgExtension::None,
+ pointee_size: Size::ZERO,
+ pointee_align: None,
+ },
});
}
diff --git a/compiler/rustc_target/src/abi/call/mod.rs b/compiler/rustc_target/src/abi/call/mod.rs
index 4768c9e2db5..735b7e76e38 100644
--- a/compiler/rustc_target/src/abi/call/mod.rs
+++ b/compiler/rustc_target/src/abi/call/mod.rs
@@ -214,9 +214,9 @@ impl Uniform {
#[derive(Clone, Copy, PartialEq, Eq, Hash, Debug, HashStable_Generic)]
pub struct CastTarget {
- pub prefix: [Option<RegKind>; 8],
- pub prefix_chunk_size: Size,
+ pub prefix: [Option<Reg>; 8],
pub rest: Uniform,
+ pub attrs: ArgAttributes,
}
impl From<Reg> for CastTarget {
@@ -227,29 +227,48 @@ impl From<Reg> for CastTarget {
impl From<Uniform> for CastTarget {
fn from(uniform: Uniform) -> CastTarget {
- CastTarget { prefix: [None; 8], prefix_chunk_size: Size::ZERO, rest: uniform }
+ CastTarget {
+ prefix: [None; 8],
+ rest: uniform,
+ attrs: ArgAttributes {
+ regular: ArgAttribute::default(),
+ arg_ext: ArgExtension::None,
+ pointee_size: Size::ZERO,
+ pointee_align: None,
+ },
+ }
}
}
impl CastTarget {
pub fn pair(a: Reg, b: Reg) -> CastTarget {
CastTarget {
- prefix: [Some(a.kind), None, None, None, None, None, None, None],
- prefix_chunk_size: a.size,
+ prefix: [Some(a), None, None, None, None, None, None, None],
rest: Uniform::from(b),
+ attrs: ArgAttributes {
+ regular: ArgAttribute::default(),
+ arg_ext: ArgExtension::None,
+ pointee_size: Size::ZERO,
+ pointee_align: None,
+ },
}
}
- pub fn size<C: HasDataLayout>(&self, cx: &C) -> Size {
- (self.prefix_chunk_size * self.prefix.iter().filter(|x| x.is_some()).count() as u64)
- .align_to(self.rest.align(cx))
- + self.rest.total
+ pub fn size<C: HasDataLayout>(&self, _cx: &C) -> Size {
+ let mut size = self.rest.total;
+ for i in 0..self.prefix.iter().count() {
+ match self.prefix[i] {
+ Some(v) => size += Size { raw: v.size.bytes() },
+ None => {}
+ }
+ }
+ return size;
}
pub fn align<C: HasDataLayout>(&self, cx: &C) -> Align {
self.prefix
.iter()
- .filter_map(|x| x.map(|kind| Reg { kind, size: self.prefix_chunk_size }.align(cx)))
+ .filter_map(|x| x.map(|reg| reg.align(cx)))
.fold(cx.data_layout().aggregate_align.abi.max(self.rest.align(cx)), |acc, align| {
acc.max(align)
})
diff --git a/compiler/rustc_target/src/abi/call/sparc64.rs b/compiler/rustc_target/src/abi/call/sparc64.rs
index 5d74c94e2c6..39d80c4c7e7 100644
--- a/compiler/rustc_target/src/abi/call/sparc64.rs
+++ b/compiler/rustc_target/src/abi/call/sparc64.rs
@@ -1,7 +1,9 @@
// FIXME: This needs an audit for correctness and completeness.
-use crate::abi::call::{ArgAbi, FnAbi, Reg, RegKind, Uniform};
-use crate::abi::{HasDataLayout, TyAbiInterface};
+use crate::abi::call::{
+ ArgAbi, ArgAttribute, ArgAttributes, ArgExtension, CastTarget, FnAbi, Reg, RegKind, Uniform,
+};
+use crate::abi::{self, HasDataLayout, Size, TyAbiInterface};
fn is_homogeneous_aggregate<'a, Ty, C>(cx: &C, arg: &mut ArgAbi<'a, Ty>) -> Option<Uniform>
where
@@ -16,7 +18,7 @@ where
let valid_unit = match unit.kind {
RegKind::Integer => false,
- RegKind::Float => true,
+ RegKind::Float => false,
RegKind::Vector => arg.layout.size.bits() == 128,
};
@@ -24,33 +26,7 @@ where
})
}
-fn classify_ret<'a, Ty, C>(cx: &C, ret: &mut ArgAbi<'a, Ty>)
-where
- Ty: TyAbiInterface<'a, C> + Copy,
- C: HasDataLayout,
-{
- if !ret.layout.is_aggregate() {
- ret.extend_integer_width_to(64);
- return;
- }
-
- if let Some(uniform) = is_homogeneous_aggregate(cx, ret) {
- ret.cast_to(uniform);
- return;
- }
- let size = ret.layout.size;
- let bits = size.bits();
- if bits <= 256 {
- let unit = Reg::i64();
- ret.cast_to(Uniform { unit, total: size });
- return;
- }
-
- // don't return aggregates in registers
- ret.make_indirect();
-}
-
-fn classify_arg<'a, Ty, C>(cx: &C, arg: &mut ArgAbi<'a, Ty>)
+fn classify_arg<'a, Ty, C>(cx: &C, arg: &mut ArgAbi<'a, Ty>, in_registers_max: Size)
where
Ty: TyAbiInterface<'a, C> + Copy,
C: HasDataLayout,
@@ -60,13 +36,97 @@ where
return;
}
+ // This doesn't intentionally handle structures with floats which needs
+ // special care below.
if let Some(uniform) = is_homogeneous_aggregate(cx, arg) {
arg.cast_to(uniform);
return;
}
+ if let abi::FieldsShape::Arbitrary { .. } = arg.layout.fields {
+ let dl = cx.data_layout();
+ let size = arg.layout.size;
+ let mut prefix = [None; 8];
+ let mut prefix_index = 0;
+ let mut last_offset = Size::ZERO;
+ let mut has_float = false;
+ let mut arg_attribute = ArgAttribute::default();
+
+ for i in 0..arg.layout.fields.count() {
+ let field = arg.layout.field(cx, i);
+ let offset = arg.layout.fields.offset(i);
+
+ if let abi::Abi::Scalar(scalar) = &field.abi {
+ if scalar.value == abi::F32 || scalar.value == abi::F64 {
+ has_float = true;
+
+ if !last_offset.is_aligned(dl.f64_align.abi) && last_offset < offset {
+ if prefix_index == prefix.len() {
+ break;
+ }
+ prefix[prefix_index] = Some(Reg::i32());
+ prefix_index += 1;
+ last_offset = last_offset + Reg::i32().size;
+ }
+
+ for _ in 0..((offset - last_offset).bits() / 64)
+ .min((prefix.len() - prefix_index) as u64)
+ {
+ prefix[prefix_index] = Some(Reg::i64());
+ prefix_index += 1;
+ last_offset = last_offset + Reg::i64().size;
+ }
+
+ if last_offset < offset {
+ if prefix_index == prefix.len() {
+ break;
+ }
+ prefix[prefix_index] = Some(Reg::i32());
+ prefix_index += 1;
+ last_offset = last_offset + Reg::i32().size;
+ }
+
+ if prefix_index == prefix.len() {
+ break;
+ }
+
+ if scalar.value == abi::F32 {
+ arg_attribute = ArgAttribute::InReg;
+ prefix[prefix_index] = Some(Reg::f32());
+ last_offset = offset + Reg::f32().size;
+ } else {
+ prefix[prefix_index] = Some(Reg::f64());
+ last_offset = offset + Reg::f64().size;
+ }
+ prefix_index += 1;
+ }
+ }
+ }
+
+ if has_float && arg.layout.size <= in_registers_max {
+ let mut rest_size = size - last_offset;
+
+ if (rest_size.raw % 8) != 0 && prefix_index < prefix.len() {
+ prefix[prefix_index] = Some(Reg::i32());
+ rest_size = rest_size - Reg::i32().size;
+ }
+
+ arg.cast_to(CastTarget {
+ prefix,
+ rest: Uniform { unit: Reg::i64(), total: rest_size },
+ attrs: ArgAttributes {
+ regular: arg_attribute,
+ arg_ext: ArgExtension::None,
+ pointee_size: Size::ZERO,
+ pointee_align: None,
+ },
+ });
+ return;
+ }
+ }
+
let total = arg.layout.size;
- if total.bits() > 128 {
+ if total > in_registers_max {
arg.make_indirect();
return;
}
@@ -80,13 +140,13 @@ where
C: HasDataLayout,
{
if !fn_abi.ret.is_ignore() {
- classify_ret(cx, &mut fn_abi.ret);
+ classify_arg(cx, &mut fn_abi.ret, Size { raw: 32 });
}
for arg in &mut fn_abi.args {
if arg.is_ignore() {
continue;
}
- classify_arg(cx, arg);
+ classify_arg(cx, arg, Size { raw: 16 });
}
}
diff --git a/compiler/rustc_target/src/asm/aarch64.rs b/compiler/rustc_target/src/asm/aarch64.rs
index 76e50678314..4bf909ce46d 100644
--- a/compiler/rustc_target/src/asm/aarch64.rs
+++ b/compiler/rustc_target/src/asm/aarch64.rs
@@ -1,4 +1,5 @@
use super::{InlineAsmArch, InlineAsmType};
+use crate::spec::Target;
use rustc_macros::HashStable_Generic;
use std::fmt;
@@ -70,6 +71,22 @@ impl AArch64InlineAsmRegClass {
}
}
+pub fn reserved_x18(
+ _arch: InlineAsmArch,
+ _has_feature: impl FnMut(&str) -> bool,
+ target: &Target,
+) -> Result<(), &'static str> {
+ if target.os == "android"
+ || target.is_like_fuchsia
+ || target.is_like_osx
+ || target.is_like_windows
+ {
+ Err("x18 is a reserved register on this target")
+ } else {
+ Ok(())
+ }
+}
+
def_regs! {
AArch64 AArch64InlineAsmReg AArch64InlineAsmRegClass {
x0: reg = ["x0", "w0"],
@@ -90,6 +107,7 @@ def_regs! {
x15: reg = ["x15", "w15"],
x16: reg = ["x16", "w16"],
x17: reg = ["x17", "w17"],
+ x18: reg = ["x18", "w18"] % reserved_x18,
x20: reg = ["x20", "w20"],
x21: reg = ["x21", "w21"],
x22: reg = ["x22", "w22"],
@@ -149,8 +167,6 @@ def_regs! {
p14: preg = ["p14"],
p15: preg = ["p15"],
ffr: preg = ["ffr"],
- #error = ["x18", "w18"] =>
- "x18 is used as a reserved register on some targets and cannot be used as an operand for inline asm",
#error = ["x19", "w19"] =>
"x19 is used internally by LLVM and cannot be used as an operand for inline asm",
#error = ["x29", "w29", "fp", "wfp"] =>
diff --git a/compiler/rustc_target/src/asm/arm.rs b/compiler/rustc_target/src/asm/arm.rs
index 4c323fc35d6..b03594b3151 100644
--- a/compiler/rustc_target/src/asm/arm.rs
+++ b/compiler/rustc_target/src/asm/arm.rs
@@ -6,7 +6,6 @@ use std::fmt;
def_reg_class! {
Arm ArmInlineAsmRegClass {
reg,
- reg_thumb,
sreg,
sreg_low16,
dreg,
@@ -47,7 +46,7 @@ impl ArmInlineAsmRegClass {
_arch: InlineAsmArch,
) -> &'static [(InlineAsmType, Option<&'static str>)] {
match self {
- Self::reg | Self::reg_thumb => types! { _: I8, I16, I32, F32; },
+ Self::reg => types! { _: I8, I16, I32, F32; },
Self::sreg | Self::sreg_low16 => types! { "vfp2": I32, F32; },
Self::dreg | Self::dreg_low16 | Self::dreg_low8 => types! {
"vfp2": I64, F64, VecI8(8), VecI16(4), VecI32(2), VecI64(1), VecF32(2);
@@ -88,20 +87,49 @@ fn frame_pointer_r7(
}
}
+fn not_thumb1(
+ _arch: InlineAsmArch,
+ mut has_feature: impl FnMut(&str) -> bool,
+ _target: &Target,
+) -> Result<(), &'static str> {
+ if has_feature("thumb-mode") && !has_feature("thumb2") {
+ Err("high registers (r8+) cannot be used in Thumb-1 code")
+ } else {
+ Ok(())
+ }
+}
+
+fn reserved_r9(
+ arch: InlineAsmArch,
+ mut has_feature: impl FnMut(&str) -> bool,
+ target: &Target,
+) -> Result<(), &'static str> {
+ not_thumb1(arch, &mut has_feature, target)?;
+
+ // We detect this using the reserved-r9 feature instead of using the target
+ // because the relocation model can be changed with compiler options.
+ if has_feature("reserved-r9") {
+ Err("the RWPI static base register (r9) cannot be used as an operand for inline asm")
+ } else {
+ Ok(())
+ }
+}
+
def_regs! {
Arm ArmInlineAsmReg ArmInlineAsmRegClass {
- r0: reg, reg_thumb = ["r0", "a1"],
- r1: reg, reg_thumb = ["r1", "a2"],
- r2: reg, reg_thumb = ["r2", "a3"],
- r3: reg, reg_thumb = ["r3", "a4"],
- r4: reg, reg_thumb = ["r4", "v1"],
- r5: reg, reg_thumb = ["r5", "v2"],
- r7: reg, reg_thumb = ["r7", "v4"] % frame_pointer_r7,
- r8: reg = ["r8", "v5"],
- r10: reg = ["r10", "sl"],
+ r0: reg = ["r0", "a1"],
+ r1: reg = ["r1", "a2"],
+ r2: reg = ["r2", "a3"],
+ r3: reg = ["r3", "a4"],
+ r4: reg = ["r4", "v1"],
+ r5: reg = ["r5", "v2"],
+ r7: reg = ["r7", "v4"] % frame_pointer_r7,
+ r8: reg = ["r8", "v5"] % not_thumb1,
+ r9: reg = ["r9", "v6", "rfp"] % reserved_r9,
+ r10: reg = ["r10", "sl"] % not_thumb1,
r11: reg = ["r11", "fp"] % frame_pointer_r11,
- r12: reg = ["r12", "ip"],
- r14: reg = ["r14", "lr"],
+ r12: reg = ["r12", "ip"] % not_thumb1,
+ r14: reg = ["r14", "lr"] % not_thumb1,
s0: sreg, sreg_low16 = ["s0"],
s1: sreg, sreg_low16 = ["s1"],
s2: sreg, sreg_low16 = ["s2"],
@@ -184,8 +212,6 @@ def_regs! {
q15: qreg = ["q15"],
#error = ["r6", "v3"] =>
"r6 is used internally by LLVM and cannot be used as an operand for inline asm",
- #error = ["r9", "v6", "rfp"] =>
- "r9 is used internally by LLVM and cannot be used as an operand for inline asm",
#error = ["r13", "sp"] =>
"the stack pointer cannot be used as an operand for inline asm",
#error = ["r15", "pc"] =>
diff --git a/compiler/rustc_target/src/asm/avr.rs b/compiler/rustc_target/src/asm/avr.rs
new file mode 100644
index 00000000000..82a4f8bacb3
--- /dev/null
+++ b/compiler/rustc_target/src/asm/avr.rs
@@ -0,0 +1,196 @@
+use super::{InlineAsmArch, InlineAsmType};
+use rustc_macros::HashStable_Generic;
+use std::fmt;
+
+def_reg_class! {
+ Avr AvrInlineAsmRegClass {
+ reg,
+ reg_upper,
+ reg_pair,
+ reg_iw,
+ reg_ptr,
+ }
+}
+
+impl AvrInlineAsmRegClass {
+ pub fn valid_modifiers(self, _arch: InlineAsmArch) -> &'static [char] {
+ match self {
+ Self::reg_pair | Self::reg_iw | Self::reg_ptr => &['h', 'l'],
+ _ => &[],
+ }
+ }
+
+ pub fn suggest_class(self, _arch: InlineAsmArch, _ty: InlineAsmType) -> Option<Self> {
+ None
+ }
+
+ pub fn suggest_modifier(
+ self,
+ _arch: InlineAsmArch,
+ _ty: InlineAsmType,
+ ) -> Option<(char, &'static str)> {
+ None
+ }
+
+ pub fn default_modifier(self, _arch: InlineAsmArch) -> Option<(char, &'static str)> {
+ None
+ }
+
+ pub fn supported_types(
+ self,
+ _arch: InlineAsmArch,
+ ) -> &'static [(InlineAsmType, Option<&'static str>)] {
+ match self {
+ Self::reg => types! { _: I8; },
+ Self::reg_upper => types! { _: I8; },
+ Self::reg_pair => types! { _: I16; },
+ Self::reg_iw => types! { _: I16; },
+ Self::reg_ptr => types! { _: I16; },
+ }
+ }
+}
+
+def_regs! {
+ Avr AvrInlineAsmReg AvrInlineAsmRegClass {
+ r2: reg = ["r2"],
+ r3: reg = ["r3"],
+ r4: reg = ["r4"],
+ r5: reg = ["r5"],
+ r6: reg = ["r6"],
+ r7: reg = ["r7"],
+ r8: reg = ["r8"],
+ r9: reg = ["r9"],
+ r10: reg = ["r10"],
+ r11: reg = ["r11"],
+ r12: reg = ["r12"],
+ r13: reg = ["r13"],
+ r14: reg = ["r14"],
+ r15: reg = ["r15"],
+ r16: reg, reg_upper = ["r16"],
+ r17: reg, reg_upper = ["r17"],
+ r18: reg, reg_upper = ["r18"],
+ r19: reg, reg_upper = ["r19"],
+ r20: reg, reg_upper = ["r20"],
+ r21: reg, reg_upper = ["r21"],
+ r22: reg, reg_upper = ["r22"],
+ r23: reg, reg_upper = ["r23"],
+ r24: reg, reg_upper = ["r24"],
+ r25: reg, reg_upper = ["r25"],
+ r26: reg, reg_upper = ["r26", "XL"],
+ r27: reg, reg_upper = ["r27", "XH"],
+ r30: reg, reg_upper = ["r30", "ZL"],
+ r31: reg, reg_upper = ["r31", "ZH"],
+
+ r3r2: reg_pair = ["r3r2"],
+ r5r4: reg_pair = ["r5r4"],
+ r7r6: reg_pair = ["r7r6"],
+ r9r8: reg_pair = ["r9r8"],
+ r11r10: reg_pair = ["r11r10"],
+ r13r12: reg_pair = ["r13r12"],
+ r15r14: reg_pair = ["r15r14"],
+ r17r16: reg_pair = ["r17r16"],
+ r19r18: reg_pair = ["r19r18"],
+ r21r20: reg_pair = ["r21r20"],
+ r23r22: reg_pair = ["r23r22"],
+
+ r25r24: reg_iw, reg_pair = ["r25r24"],
+
+ X: reg_ptr, reg_iw, reg_pair = ["r27r26", "X"],
+ Z: reg_ptr, reg_iw, reg_pair = ["r31r30", "Z"],
+
+ #error = ["Y", "YL", "YH"] =>
+ "the frame pointer cannot be used as an operand for inline asm",
+ #error = ["SP", "SPL", "SPH"] =>
+ "the stack pointer cannot be used as an operand for inline asm",
+ #error = ["r0", "r1", "r1r0"] =>
+ "r0 and r1 are not available due to an issue in LLVM",
+ }
+}
+
+macro_rules! emit_pairs {
+ (
+ $self:ident $modifier:ident,
+ $($pair:ident $name:literal $hi:literal $lo:literal,)*
+ ) => {
+ match ($self, $modifier) {
+ $(
+ (AvrInlineAsmReg::$pair, Some('h')) => $hi,
+ (AvrInlineAsmReg::$pair, Some('l')) => $lo,
+ (AvrInlineAsmReg::$pair, _) => $name,
+ )*
+ _ => $self.name(),
+ }
+ };
+}
+
+impl AvrInlineAsmReg {
+ pub fn emit(
+ self,
+ out: &mut dyn fmt::Write,
+ _arch: InlineAsmArch,
+ modifier: Option<char>,
+ ) -> fmt::Result {
+ let name = emit_pairs! {
+ self modifier,
+ Z "Z" "ZH" "ZL",
+ X "X" "XH" "XL",
+ r25r24 "r25:r24" "r25" "r24",
+ r23r22 "r23:r22" "r23" "r22",
+ r21r20 "r21:r20" "r21" "r20",
+ r19r18 "r19:r18" "r19" "r18",
+ r17r16 "r17:r16" "r17" "r16",
+ r15r14 "r15:r14" "r15" "r14",
+ r13r12 "r13:r12" "r13" "r12",
+ r11r10 "r11:r10" "r11" "r10",
+ r9r8 "r9:r8" "r9" "r8",
+ r7r6 "r7:r6" "r7" "r6",
+ r5r4 "r5:r4" "r5" "r4",
+ r3r2 "r3:r2" "r3" "r2",
+ };
+ out.write_str(name)
+ }
+
+ pub fn overlapping_regs(self, mut cb: impl FnMut(AvrInlineAsmReg)) {
+ cb(self);
+
+ macro_rules! reg_conflicts {
+ (
+ $(
+ $pair:ident : $hi:ident $lo:ident,
+ )*
+ ) => {
+ match self {
+ $(
+ Self::$pair => {
+ cb(Self::$hi);
+ cb(Self::$lo);
+ }
+ Self::$hi => {
+ cb(Self::$pair);
+ }
+ Self::$lo => {
+ cb(Self::$pair);
+ }
+ )*
+ }
+ };
+ }
+
+ reg_conflicts! {
+ Z : r31 r30,
+ X : r27 r26,
+ r25r24 : r25 r24,
+ r23r22 : r23 r22,
+ r21r20 : r21 r20,
+ r19r18 : r19 r18,
+ r17r16 : r17 r16,
+ r15r14 : r15 r14,
+ r13r12 : r13 r12,
+ r11r10 : r11 r10,
+ r9r8 : r9 r8,
+ r7r6 : r7 r6,
+ r5r4 : r5 r4,
+ r3r2 : r3 r2,
+ }
+ }
+}
diff --git a/compiler/rustc_target/src/asm/mod.rs b/compiler/rustc_target/src/asm/mod.rs
index bff13246521..f1f5f4389e3 100644
--- a/compiler/rustc_target/src/asm/mod.rs
+++ b/compiler/rustc_target/src/asm/mod.rs
@@ -148,6 +148,7 @@ macro_rules! types {
mod aarch64;
mod arm;
+mod avr;
mod bpf;
mod hexagon;
mod mips;
@@ -161,6 +162,7 @@ mod x86;
pub use aarch64::{AArch64InlineAsmReg, AArch64InlineAsmRegClass};
pub use arm::{ArmInlineAsmReg, ArmInlineAsmRegClass};
+pub use avr::{AvrInlineAsmReg, AvrInlineAsmRegClass};
pub use bpf::{BpfInlineAsmReg, BpfInlineAsmRegClass};
pub use hexagon::{HexagonInlineAsmReg, HexagonInlineAsmRegClass};
pub use mips::{MipsInlineAsmReg, MipsInlineAsmRegClass};
@@ -191,6 +193,7 @@ pub enum InlineAsmArch {
Wasm32,
Wasm64,
Bpf,
+ Avr,
}
impl FromStr for InlineAsmArch {
@@ -215,6 +218,7 @@ impl FromStr for InlineAsmArch {
"wasm32" => Ok(Self::Wasm32),
"wasm64" => Ok(Self::Wasm64),
"bpf" => Ok(Self::Bpf),
+ "avr" => Ok(Self::Avr),
_ => Err(()),
}
}
@@ -245,6 +249,7 @@ pub enum InlineAsmReg {
SpirV(SpirVInlineAsmReg),
Wasm(WasmInlineAsmReg),
Bpf(BpfInlineAsmReg),
+ Avr(AvrInlineAsmReg),
// Placeholder for invalid register constraints for the current target
Err,
}
@@ -261,6 +266,7 @@ impl InlineAsmReg {
Self::Mips(r) => r.name(),
Self::S390x(r) => r.name(),
Self::Bpf(r) => r.name(),
+ Self::Avr(r) => r.name(),
Self::Err => "<reg>",
}
}
@@ -276,6 +282,7 @@ impl InlineAsmReg {
Self::Mips(r) => InlineAsmRegClass::Mips(r.reg_class()),
Self::S390x(r) => InlineAsmRegClass::S390x(r.reg_class()),
Self::Bpf(r) => InlineAsmRegClass::Bpf(r.reg_class()),
+ Self::Avr(r) => InlineAsmRegClass::Avr(r.reg_class()),
Self::Err => InlineAsmRegClass::Err,
}
}
@@ -326,6 +333,9 @@ impl InlineAsmReg {
InlineAsmArch::Bpf => {
Self::Bpf(BpfInlineAsmReg::parse(arch, has_feature, target, &name)?)
}
+ InlineAsmArch::Avr => {
+ Self::Avr(AvrInlineAsmReg::parse(arch, has_feature, target, &name)?)
+ }
})
}
@@ -347,6 +357,7 @@ impl InlineAsmReg {
Self::Mips(r) => r.emit(out, arch, modifier),
Self::S390x(r) => r.emit(out, arch, modifier),
Self::Bpf(r) => r.emit(out, arch, modifier),
+ Self::Avr(r) => r.emit(out, arch, modifier),
Self::Err => unreachable!("Use of InlineAsmReg::Err"),
}
}
@@ -362,6 +373,7 @@ impl InlineAsmReg {
Self::Mips(_) => cb(self),
Self::S390x(_) => cb(self),
Self::Bpf(r) => r.overlapping_regs(|r| cb(Self::Bpf(r))),
+ Self::Avr(r) => r.overlapping_regs(|r| cb(Self::Avr(r))),
Self::Err => unreachable!("Use of InlineAsmReg::Err"),
}
}
@@ -392,6 +404,7 @@ pub enum InlineAsmRegClass {
SpirV(SpirVInlineAsmRegClass),
Wasm(WasmInlineAsmRegClass),
Bpf(BpfInlineAsmRegClass),
+ Avr(AvrInlineAsmRegClass),
// Placeholder for invalid register constraints for the current target
Err,
}
@@ -411,6 +424,7 @@ impl InlineAsmRegClass {
Self::SpirV(r) => r.name(),
Self::Wasm(r) => r.name(),
Self::Bpf(r) => r.name(),
+ Self::Avr(r) => r.name(),
Self::Err => rustc_span::symbol::sym::reg,
}
}
@@ -432,6 +446,7 @@ impl InlineAsmRegClass {
Self::SpirV(r) => r.suggest_class(arch, ty).map(InlineAsmRegClass::SpirV),
Self::Wasm(r) => r.suggest_class(arch, ty).map(InlineAsmRegClass::Wasm),
Self::Bpf(r) => r.suggest_class(arch, ty).map(InlineAsmRegClass::Bpf),
+ Self::Avr(r) => r.suggest_class(arch, ty).map(InlineAsmRegClass::Avr),
Self::Err => unreachable!("Use of InlineAsmRegClass::Err"),
}
}
@@ -460,6 +475,7 @@ impl InlineAsmRegClass {
Self::SpirV(r) => r.suggest_modifier(arch, ty),
Self::Wasm(r) => r.suggest_modifier(arch, ty),
Self::Bpf(r) => r.suggest_modifier(arch, ty),
+ Self::Avr(r) => r.suggest_modifier(arch, ty),
Self::Err => unreachable!("Use of InlineAsmRegClass::Err"),
}
}
@@ -484,6 +500,7 @@ impl InlineAsmRegClass {
Self::SpirV(r) => r.default_modifier(arch),
Self::Wasm(r) => r.default_modifier(arch),
Self::Bpf(r) => r.default_modifier(arch),
+ Self::Avr(r) => r.default_modifier(arch),
Self::Err => unreachable!("Use of InlineAsmRegClass::Err"),
}
}
@@ -507,6 +524,7 @@ impl InlineAsmRegClass {
Self::SpirV(r) => r.supported_types(arch),
Self::Wasm(r) => r.supported_types(arch),
Self::Bpf(r) => r.supported_types(arch),
+ Self::Avr(r) => r.supported_types(arch),
Self::Err => unreachable!("Use of InlineAsmRegClass::Err"),
}
}
@@ -535,6 +553,7 @@ impl InlineAsmRegClass {
Self::Wasm(WasmInlineAsmRegClass::parse(arch, name)?)
}
InlineAsmArch::Bpf => Self::Bpf(BpfInlineAsmRegClass::parse(arch, name)?),
+ InlineAsmArch::Avr => Self::Avr(AvrInlineAsmRegClass::parse(arch, name)?),
})
}
@@ -554,6 +573,7 @@ impl InlineAsmRegClass {
Self::SpirV(r) => r.valid_modifiers(arch),
Self::Wasm(r) => r.valid_modifiers(arch),
Self::Bpf(r) => r.valid_modifiers(arch),
+ Self::Avr(r) => r.valid_modifiers(arch),
Self::Err => unreachable!("Use of InlineAsmRegClass::Err"),
}
}
@@ -739,6 +759,11 @@ pub fn allocatable_registers(
bpf::fill_reg_map(arch, has_feature, target, &mut map);
map
}
+ InlineAsmArch::Avr => {
+ let mut map = avr::regclass_map();
+ avr::fill_reg_map(arch, has_feature, target, &mut map);
+ map
+ }
}
}
@@ -760,6 +785,7 @@ pub enum InlineAsmClobberAbi {
X86_64SysV,
Arm,
AArch64,
+ AArch64NoX18,
RiscV,
}
@@ -768,6 +794,7 @@ impl InlineAsmClobberAbi {
/// clobber ABIs for the target.
pub fn parse(
arch: InlineAsmArch,
+ has_feature: impl FnMut(&str) -> bool,
target: &Target,
name: Symbol,
) -> Result<Self, &'static [&'static str]> {
@@ -791,7 +818,13 @@ impl InlineAsmClobberAbi {
_ => Err(&["C", "system", "efiapi", "aapcs"]),
},
InlineAsmArch::AArch64 => match name {
- "C" | "system" | "efiapi" => Ok(InlineAsmClobberAbi::AArch64),
+ "C" | "system" | "efiapi" => {
+ Ok(if aarch64::reserved_x18(arch, has_feature, target).is_err() {
+ InlineAsmClobberAbi::AArch64NoX18
+ } else {
+ InlineAsmClobberAbi::AArch64
+ })
+ }
_ => Err(&["C", "system", "efiapi"]),
},
InlineAsmArch::RiscV32 | InlineAsmArch::RiscV64 => match name {
@@ -866,8 +899,25 @@ impl InlineAsmClobberAbi {
AArch64 AArch64InlineAsmReg {
x0, x1, x2, x3, x4, x5, x6, x7,
x8, x9, x10, x11, x12, x13, x14, x15,
- // x18 is platform-reserved or temporary, but we exclude it
- // here since it is a reserved register.
+ x16, x17, x18, x30,
+
+ // Technically the low 64 bits of v8-v15 are preserved, but
+ // we have no way of expressing this using clobbers.
+ v0, v1, v2, v3, v4, v5, v6, v7,
+ v8, v9, v10, v11, v12, v13, v14, v15,
+ v16, v17, v18, v19, v20, v21, v22, v23,
+ v24, v25, v26, v27, v28, v29, v30, v31,
+
+ p0, p1, p2, p3, p4, p5, p6, p7,
+ p8, p9, p10, p11, p12, p13, p14, p15,
+ ffr,
+
+ }
+ },
+ InlineAsmClobberAbi::AArch64NoX18 => clobbered_regs! {
+ AArch64 AArch64InlineAsmReg {
+ x0, x1, x2, x3, x4, x5, x6, x7,
+ x8, x9, x10, x11, x12, x13, x14, x15,
x16, x17, x30,
// Technically the low 64 bits of v8-v15 are preserved, but
@@ -885,7 +935,8 @@ impl InlineAsmClobberAbi {
},
InlineAsmClobberAbi::Arm => clobbered_regs! {
Arm ArmInlineAsmReg {
- // r9 is platform-reserved and is treated as callee-saved.
+ // r9 is either platform-reserved or callee-saved. Either
+ // way we don't need to clobber it.
r0, r1, r2, r3, r12, r14,
// The finest-grained register variant is used here so that
diff --git a/compiler/rustc_target/src/lib.rs b/compiler/rustc_target/src/lib.rs
index 23d5d575d94..b18d17c1b7d 100644
--- a/compiler/rustc_target/src/lib.rs
+++ b/compiler/rustc_target/src/lib.rs
@@ -16,6 +16,7 @@
#![feature(min_specialization)]
#![feature(step_trait)]
+use std::iter::FromIterator;
use std::path::{Path, PathBuf};
#[macro_use]
@@ -47,12 +48,11 @@ const RUST_LIB_DIR: &str = "rustlib";
/// `"lib*/rustlib/x86_64-unknown-linux-gnu"`.
pub fn target_rustlib_path(sysroot: &Path, target_triple: &str) -> PathBuf {
let libdir = find_libdir(sysroot);
- std::array::IntoIter::new([
+ PathBuf::from_iter([
Path::new(libdir.as_ref()),
Path::new(RUST_LIB_DIR),
Path::new(target_triple),
])
- .collect::<PathBuf>()
}
/// The name of the directory rustc expects libraries to be located.
diff --git a/compiler/rustc_target/src/spec/aarch64_apple_darwin.rs b/compiler/rustc_target/src/spec/aarch64_apple_darwin.rs
index ca3550e9278..f01ff02da07 100644
--- a/compiler/rustc_target/src/spec/aarch64_apple_darwin.rs
+++ b/compiler/rustc_target/src/spec/aarch64_apple_darwin.rs
@@ -14,14 +14,13 @@ pub fn target() -> Target {
// Clang automatically chooses a more specific target based on
// MACOSX_DEPLOYMENT_TARGET. To enable cross-language LTO to work
// correctly, we do too.
- let arch = "aarch64";
- let llvm_target = super::apple_base::macos_llvm_target(&arch);
+ let llvm_target = super::apple_base::macos_llvm_target("arm64");
Target {
llvm_target,
pointer_width: 64,
data_layout: "e-m:o-i64:64-i128:128-n32:64-S128".to_string(),
- arch: arch.to_string(),
+ arch: "aarch64".to_string(),
options: TargetOptions {
mcount: "\u{1}mcount".to_string(),
frame_pointer: FramePointer::NonLeaf,
diff --git a/compiler/rustc_target/src/spec/aarch64_unknown_linux_musl.rs b/compiler/rustc_target/src/spec/aarch64_unknown_linux_musl.rs
index 0770f3496c2..6a16b4ce419 100644
--- a/compiler/rustc_target/src/spec/aarch64_unknown_linux_musl.rs
+++ b/compiler/rustc_target/src/spec/aarch64_unknown_linux_musl.rs
@@ -9,10 +9,6 @@ pub fn target() -> Target {
pointer_width: 64,
data_layout: "e-m:e-i8:8:32-i16:16:32-i64:64-i128:128-n32:64-S128".to_string(),
arch: "aarch64".to_string(),
- options: TargetOptions {
- features: "+outline-atomics".to_string(),
- mcount: "\u{1}_mcount".to_string(),
- ..base
- },
+ options: TargetOptions { mcount: "\u{1}_mcount".to_string(), ..base },
}
}
diff --git a/compiler/rustc_target/src/spec/apple_base.rs b/compiler/rustc_target/src/spec/apple_base.rs
index a21b784e11b..db6aee59a5d 100644
--- a/compiler/rustc_target/src/spec/apple_base.rs
+++ b/compiler/rustc_target/src/spec/apple_base.rs
@@ -13,8 +13,10 @@ pub fn opts(os: &str) -> TargetOptions {
// warnings about the usage of ELF TLS.
//
// Here we detect what version is being requested, defaulting to 10.7. ELF
- // TLS is flagged as enabled if it looks to be supported.
- let version = macos_deployment_target();
+ // TLS is flagged as enabled if it looks to be supported. The architecture
+ // only matters for default deployment target which is 11.0 for ARM64 and
+ // 10.7 for everything else.
+ let has_elf_tls = macos_deployment_target("x86_64") >= (10, 7);
TargetOptions {
os: os.to_string(),
@@ -31,7 +33,7 @@ pub fn opts(os: &str) -> TargetOptions {
has_rpath: true,
dll_suffix: ".dylib".to_string(),
archive_format: "darwin".to_string(),
- has_elf_tls: version >= (10, 7),
+ has_elf_tls,
abi_return_struct_as_int: true,
emit_debug_gdb_scripts: false,
eh_frame_header: false,
@@ -63,12 +65,17 @@ fn deployment_target(var_name: &str) -> Option<(u32, u32)> {
.and_then(|(a, b)| a.parse::<u32>().and_then(|a| b.parse::<u32>().map(|b| (a, b))).ok())
}
-fn macos_deployment_target() -> (u32, u32) {
- deployment_target("MACOSX_DEPLOYMENT_TARGET").unwrap_or((10, 7))
+fn macos_default_deployment_target(arch: &str) -> (u32, u32) {
+ if arch == "arm64" { (11, 0) } else { (10, 7) }
+}
+
+fn macos_deployment_target(arch: &str) -> (u32, u32) {
+ deployment_target("MACOSX_DEPLOYMENT_TARGET")
+ .unwrap_or_else(|| macos_default_deployment_target(arch))
}
pub fn macos_llvm_target(arch: &str) -> String {
- let (major, minor) = macos_deployment_target();
+ let (major, minor) = macos_deployment_target(arch);
format!("{}-apple-macosx{}.{}.0", arch, major, minor)
}
diff --git a/compiler/rustc_target/src/spec/m68k_unknown_linux_gnu.rs b/compiler/rustc_target/src/spec/m68k_unknown_linux_gnu.rs
index fff7b25a349..5671b59c63f 100644
--- a/compiler/rustc_target/src/spec/m68k_unknown_linux_gnu.rs
+++ b/compiler/rustc_target/src/spec/m68k_unknown_linux_gnu.rs
@@ -2,7 +2,7 @@ use crate::abi::Endian;
use crate::spec::{Target, TargetOptions};
pub fn target() -> Target {
- let mut base = super::linux_base::opts();
+ let mut base = super::linux_gnu_base::opts();
base.max_atomic_width = Some(32);
Target {
diff --git a/compiler/rustc_target/src/spec/mod.rs b/compiler/rustc_target/src/spec/mod.rs
index 0771f998535..ece704d7700 100644
--- a/compiler/rustc_target/src/spec/mod.rs
+++ b/compiler/rustc_target/src/spec/mod.rs
@@ -42,6 +42,7 @@ use rustc_serialize::json::{Json, ToJson};
use rustc_span::symbol::{sym, Symbol};
use std::collections::BTreeMap;
use std::convert::TryFrom;
+use std::iter::FromIterator;
use std::ops::{Deref, DerefMut};
use std::path::{Path, PathBuf};
use std::str::FromStr;
@@ -712,6 +713,59 @@ impl ToJson for FramePointer {
}
}
+/// Controls use of stack canaries.
+#[derive(Clone, Copy, Debug, PartialEq, Hash, Eq)]
+pub enum StackProtector {
+ /// Disable stack canary generation.
+ None,
+
+ /// On LLVM, mark all generated LLVM functions with the `ssp` attribute (see
+ /// llvm/docs/LangRef.rst). This triggers stack canary generation in
+ /// functions which contain an array of a byte-sized type with more than
+ /// eight elements.
+ Basic,
+
+ /// On LLVM, mark all generated LLVM functions with the `sspstrong`
+ /// attribute (see llvm/docs/LangRef.rst). This triggers stack canary
+ /// generation in functions which either contain an array, or which take
+ /// the address of a local variable.
+ Strong,
+
+ /// Generate stack canaries in all functions.
+ All,
+}
+
+impl StackProtector {
+ fn as_str(&self) -> &'static str {
+ match self {
+ StackProtector::None => "none",
+ StackProtector::Basic => "basic",
+ StackProtector::Strong => "strong",
+ StackProtector::All => "all",
+ }
+ }
+}
+
+impl FromStr for StackProtector {
+ type Err = ();
+
+ fn from_str(s: &str) -> Result<StackProtector, ()> {
+ Ok(match s {
+ "none" => StackProtector::None,
+ "basic" => StackProtector::Basic,
+ "strong" => StackProtector::Strong,
+ "all" => StackProtector::All,
+ _ => return Err(()),
+ })
+ }
+}
+
+impl fmt::Display for StackProtector {
+ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ f.write_str(self.as_str())
+ }
+}
+
macro_rules! supported_targets {
( $(($( $triple:literal, )+ $module:ident ),)+ ) => {
$(mod $module;)+
@@ -813,6 +867,7 @@ supported_targets! {
("powerpc-unknown-freebsd", powerpc_unknown_freebsd),
("powerpc64-unknown-freebsd", powerpc64_unknown_freebsd),
("powerpc64le-unknown-freebsd", powerpc64le_unknown_freebsd),
+ ("riscv64gc-unknown-freebsd", riscv64gc_unknown_freebsd),
("x86_64-unknown-freebsd", x86_64_unknown_freebsd),
("x86_64-unknown-dragonfly", x86_64_unknown_dragonfly),
@@ -1360,6 +1415,10 @@ pub struct TargetOptions {
/// Whether or not the DWARF `.debug_aranges` section should be generated.
pub generate_arange_section: bool,
+
+ /// Whether the target supports stack canary checks. `true` by default,
+ /// since this is most common among tier 1 and tier 2 targets.
+ pub supports_stack_protector: bool,
}
impl Default for TargetOptions {
@@ -1466,6 +1525,7 @@ impl Default for TargetOptions {
default_adjusted_cabi: None,
c_enum_min_bits: 32,
generate_arange_section: true,
+ supports_stack_protector: true,
}
}
}
@@ -2052,6 +2112,7 @@ impl Target {
key!(default_adjusted_cabi, Option<Abi>)?;
key!(c_enum_min_bits, u64);
key!(generate_arange_section, bool);
+ key!(supports_stack_protector, bool);
if base.is_builtin {
// This can cause unfortunate ICEs later down the line.
@@ -2114,12 +2175,11 @@ impl Target {
// Additionally look in the sysroot under `lib/rustlib/<triple>/target.json`
// as a fallback.
let rustlib_path = crate::target_rustlib_path(&sysroot, &target_triple);
- let p = std::array::IntoIter::new([
+ let p = PathBuf::from_iter([
Path::new(sysroot),
Path::new(&rustlib_path),
Path::new("target.json"),
- ])
- .collect::<PathBuf>();
+ ]);
if p.is_file() {
return load_file(&p);
}
@@ -2292,6 +2352,7 @@ impl ToJson for Target {
target_option_val!(supported_sanitizers);
target_option_val!(c_enum_min_bits);
target_option_val!(generate_arange_section);
+ target_option_val!(supports_stack_protector);
if let Some(abi) = self.default_adjusted_cabi {
d.insert("default-adjusted-cabi".to_string(), Abi::name(abi).to_json());
diff --git a/compiler/rustc_target/src/spec/nvptx64_nvidia_cuda.rs b/compiler/rustc_target/src/spec/nvptx64_nvidia_cuda.rs
index 083262cf351..ba32a312910 100644
--- a/compiler/rustc_target/src/spec/nvptx64_nvidia_cuda.rs
+++ b/compiler/rustc_target/src/spec/nvptx64_nvidia_cuda.rs
@@ -44,6 +44,10 @@ pub fn target() -> Target {
// produce kernel functions that call other kernel functions.
// This behavior is not supported by PTX ISA.
merge_functions: MergeFunctions::Disabled,
+
+ // The LLVM backend does not support stack canaries for this target
+ supports_stack_protector: false,
+
..Default::default()
},
}
diff --git a/compiler/rustc_target/src/spec/riscv64gc_unknown_freebsd.rs b/compiler/rustc_target/src/spec/riscv64gc_unknown_freebsd.rs
new file mode 100644
index 00000000000..1ea1b9bea2e
--- /dev/null
+++ b/compiler/rustc_target/src/spec/riscv64gc_unknown_freebsd.rs
@@ -0,0 +1,18 @@
+use crate::spec::{CodeModel, Target, TargetOptions};
+
+pub fn target() -> Target {
+ Target {
+ llvm_target: "riscv64-unknown-freebsd".to_string(),
+ pointer_width: 64,
+ data_layout: "e-m:e-p:64:64-i64:64-i128:128-n64-S128".to_string(),
+ arch: "riscv64".to_string(),
+ options: TargetOptions {
+ code_model: Some(CodeModel::Medium),
+ cpu: "generic-rv64".to_string(),
+ features: "+m,+a,+f,+d,+c".to_string(),
+ llvm_abiname: "lp64d".to_string(),
+ max_atomic_width: Some(64),
+ ..super::freebsd_base::opts()
+ },
+ }
+}
diff --git a/compiler/rustc_trait_selection/src/autoderef.rs b/compiler/rustc_trait_selection/src/autoderef.rs
index 4c80483fc1f..46c74660f86 100644
--- a/compiler/rustc_trait_selection/src/autoderef.rs
+++ b/compiler/rustc_trait_selection/src/autoderef.rs
@@ -3,7 +3,7 @@ use crate::traits::{self, TraitEngine};
use rustc_errors::struct_span_err;
use rustc_hir as hir;
use rustc_infer::infer::InferCtxt;
-use rustc_middle::ty::{self, TraitRef, Ty, TyCtxt, WithConstness};
+use rustc_middle::ty::{self, TraitRef, Ty, TyCtxt};
use rustc_middle::ty::{ToPredicate, TypeFoldable};
use rustc_session::{DiagnosticMessageId, Limit};
use rustc_span::def_id::LOCAL_CRATE;
diff --git a/compiler/rustc_trait_selection/src/infer.rs b/compiler/rustc_trait_selection/src/infer.rs
index 70816b5722b..f135f0c1b13 100644
--- a/compiler/rustc_trait_selection/src/infer.rs
+++ b/compiler/rustc_trait_selection/src/infer.rs
@@ -9,7 +9,6 @@ use rustc_middle::infer::canonical::{Canonical, CanonicalizedQueryResponse, Quer
use rustc_middle::traits::query::Fallible;
use rustc_middle::ty::subst::SubstsRef;
use rustc_middle::ty::ToPredicate;
-use rustc_middle::ty::WithConstness;
use rustc_middle::ty::{self, Ty, TypeFoldable};
use rustc_span::{Span, DUMMY_SP};
diff --git a/compiler/rustc_trait_selection/src/lib.rs b/compiler/rustc_trait_selection/src/lib.rs
index 1a049e6ec64..17e7b481890 100644
--- a/compiler/rustc_trait_selection/src/lib.rs
+++ b/compiler/rustc_trait_selection/src/lib.rs
@@ -14,9 +14,9 @@
#![feature(bool_to_option)]
#![feature(box_patterns)]
#![feature(drain_filter)]
+#![feature(derive_default_enum)]
#![feature(hash_drain_filter)]
-#![feature(in_band_lifetimes)]
-#![feature(iter_zip)]
+#![feature(label_break_value)]
#![feature(let_else)]
#![feature(never_type)]
#![feature(crate_visibility_modifier)]
diff --git a/compiler/rustc_trait_selection/src/opaque_types.rs b/compiler/rustc_trait_selection/src/opaque_types.rs
index 75d57d78e3b..ea0ac6318bc 100644
--- a/compiler/rustc_trait_selection/src/opaque_types.rs
+++ b/compiler/rustc_trait_selection/src/opaque_types.rs
@@ -97,7 +97,7 @@ struct ReverseMapper<'tcx> {
span: Span,
}
-impl ReverseMapper<'tcx> {
+impl<'tcx> ReverseMapper<'tcx> {
fn new(
tcx: TyCtxt<'tcx>,
tainted_by_errors: bool,
@@ -134,7 +134,7 @@ impl ReverseMapper<'tcx> {
}
}
-impl TypeFolder<'tcx> for ReverseMapper<'tcx> {
+impl<'tcx> TypeFolder<'tcx> for ReverseMapper<'tcx> {
fn tcx(&self) -> TyCtxt<'tcx> {
self.tcx
}
@@ -338,7 +338,7 @@ impl TypeFolder<'tcx> for ReverseMapper<'tcx> {
/// Requires that trait definitions have been processed so that we can
/// elaborate predicates and walk supertraits.
#[instrument(skip(tcx, predicates), level = "debug")]
-crate fn required_region_bounds(
+crate fn required_region_bounds<'tcx>(
tcx: TyCtxt<'tcx>,
erased_self_ty: Ty<'tcx>,
predicates: impl Iterator<Item = ty::Predicate<'tcx>>,
diff --git a/compiler/rustc_trait_selection/src/traits/auto_trait.rs b/compiler/rustc_trait_selection/src/traits/auto_trait.rs
index 54f7b91080d..53ff911ea0c 100644
--- a/compiler/rustc_trait_selection/src/traits/auto_trait.rs
+++ b/compiler/rustc_trait_selection/src/traits/auto_trait.rs
@@ -219,7 +219,7 @@ impl<'tcx> AutoTraitFinder<'tcx> {
}
}
-impl AutoTraitFinder<'tcx> {
+impl<'tcx> AutoTraitFinder<'tcx> {
/// The core logic responsible for computing the bounds for our synthesized impl.
///
/// To calculate the bounds, we call `SelectionContext.select` in a loop. Like
@@ -370,12 +370,17 @@ impl AutoTraitFinder<'tcx> {
computed_preds.clone().chain(user_computed_preds.iter().cloned()),
)
.map(|o| o.predicate);
- new_env = ty::ParamEnv::new(tcx.mk_predicates(normalized_preds), param_env.reveal());
+ new_env = ty::ParamEnv::new(
+ tcx.mk_predicates(normalized_preds),
+ param_env.reveal(),
+ param_env.constness(),
+ );
}
let final_user_env = ty::ParamEnv::new(
tcx.mk_predicates(user_computed_preds.into_iter()),
user_env.reveal(),
+ user_env.constness(),
);
debug!(
"evaluate_nested_obligations(ty={:?}, trait_did={:?}): succeeded with '{:?}' \
diff --git a/compiler/rustc_trait_selection/src/traits/chalk_fulfill.rs b/compiler/rustc_trait_selection/src/traits/chalk_fulfill.rs
index 2ccb2534917..34fc4ca8fea 100644
--- a/compiler/rustc_trait_selection/src/traits/chalk_fulfill.rs
+++ b/compiler/rustc_trait_selection/src/traits/chalk_fulfill.rs
@@ -16,7 +16,7 @@ pub struct FulfillmentContext<'tcx> {
relationships: FxHashMap<ty::TyVid, ty::FoundRelationships>,
}
-impl FulfillmentContext<'tcx> {
+impl FulfillmentContext<'_> {
crate fn new() -> Self {
FulfillmentContext {
obligations: FxIndexSet::default(),
@@ -25,7 +25,7 @@ impl FulfillmentContext<'tcx> {
}
}
-impl TraitEngine<'tcx> for FulfillmentContext<'tcx> {
+impl<'tcx> TraitEngine<'tcx> for FulfillmentContext<'tcx> {
fn normalize_projection_type(
&mut self,
infcx: &InferCtxt<'_, 'tcx>,
diff --git a/compiler/rustc_trait_selection/src/traits/codegen.rs b/compiler/rustc_trait_selection/src/traits/codegen.rs
index bdd4fdd4043..848aba7c912 100644
--- a/compiler/rustc_trait_selection/src/traits/codegen.rs
+++ b/compiler/rustc_trait_selection/src/traits/codegen.rs
@@ -107,7 +107,7 @@ pub fn codegen_fulfill_obligation<'tcx>(
/// type inference variables that appear in `result` to be
/// unified, and hence we need to process those obligations to get
/// the complete picture of the type.
-fn drain_fulfillment_cx_or_panic<T>(
+fn drain_fulfillment_cx_or_panic<'tcx, T>(
infcx: &InferCtxt<'_, 'tcx>,
fulfill_cx: &mut FulfillmentContext<'tcx>,
result: T,
diff --git a/compiler/rustc_trait_selection/src/traits/coherence.rs b/compiler/rustc_trait_selection/src/traits/coherence.rs
index 42d3194aed4..290426aa827 100644
--- a/compiler/rustc_trait_selection/src/traits/coherence.rs
+++ b/compiler/rustc_trait_selection/src/traits/coherence.rs
@@ -12,9 +12,10 @@ use crate::traits::{
self, Normalized, Obligation, ObligationCause, PredicateObligation, SelectionContext,
};
use rustc_hir::def_id::{DefId, LOCAL_CRATE};
+use rustc_middle::ty::fast_reject::{self, SimplifyParams, StripReferences};
use rustc_middle::ty::fold::TypeFoldable;
use rustc_middle::ty::subst::Subst;
-use rustc_middle::ty::{self, fast_reject, Ty, TyCtxt};
+use rustc_middle::ty::{self, Ty, TyCtxt};
use rustc_span::symbol::sym;
use rustc_span::DUMMY_SP;
use std::iter;
@@ -82,12 +83,11 @@ where
impl2_ref.iter().flat_map(|tref| tref.substs.types()),
)
.any(|(ty1, ty2)| {
- let t1 = fast_reject::simplify_type(tcx, ty1, false);
- let t2 = fast_reject::simplify_type(tcx, ty2, false);
+ let t1 = fast_reject::simplify_type(tcx, ty1, SimplifyParams::No, StripReferences::No);
+ let t2 = fast_reject::simplify_type(tcx, ty2, SimplifyParams::No, StripReferences::No);
if let (Some(t1), Some(t2)) = (t1, t2) {
// Simplified successfully
- // Types cannot unify if they differ in their reference mutability or simplify to different types
- t1 != t2 || ty1.ref_mutability() != ty2.ref_mutability()
+ t1 != t2
} else {
// Types might unify
false
@@ -154,18 +154,24 @@ fn overlap<'cx, 'tcx>(
})
}
-fn overlap_within_probe(
+fn overlap_within_probe<'cx, 'tcx>(
selcx: &mut SelectionContext<'cx, 'tcx>,
skip_leak_check: SkipLeakCheck,
a_def_id: DefId,
b_def_id: DefId,
snapshot: &CombinedSnapshot<'_, 'tcx>,
) -> Option<OverlapResult<'tcx>> {
- fn loose_check(selcx: &mut SelectionContext<'cx, 'tcx>, o: &PredicateObligation<'tcx>) -> bool {
+ fn loose_check<'cx, 'tcx>(
+ selcx: &mut SelectionContext<'cx, 'tcx>,
+ o: &PredicateObligation<'tcx>,
+ ) -> bool {
!selcx.predicate_may_hold_fatal(o)
}
- fn strict_check(selcx: &SelectionContext<'cx, 'tcx>, o: &PredicateObligation<'tcx>) -> bool {
+ fn strict_check<'cx, 'tcx>(
+ selcx: &SelectionContext<'cx, 'tcx>,
+ o: &PredicateObligation<'tcx>,
+ ) -> bool {
let infcx = selcx.infcx();
let tcx = infcx.tcx;
o.flip_polarity(tcx)
@@ -498,9 +504,7 @@ fn orphan_check_trait_ref<'tcx>(
return Err(OrphanCheckErr::UncoveredTy(input_ty, local_type));
}
- for input_ty in non_local_tys {
- non_local_spans.push((input_ty, i == 0));
- }
+ non_local_spans.extend(non_local_tys.into_iter().map(|input_ty| (input_ty, i == 0)));
}
// If we exit above loop, never found a local type.
debug!("orphan_check_trait_ref: no local type");
@@ -520,7 +524,11 @@ fn orphan_check_trait_ref<'tcx>(
/// - for `Foo<u32>`, where `Foo` is a local type, this returns `[]`.
/// - `&mut u32` returns `[u32]`, as `&mut` is a fundamental type, similar to `Box`.
/// - `Box<Foo<u32>>` returns `[]`, as `Box` is a fundamental type and `Foo` is local.
-fn contained_non_local_types(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>, in_crate: InCrate) -> Vec<Ty<'tcx>> {
+fn contained_non_local_types<'tcx>(
+ tcx: TyCtxt<'tcx>,
+ ty: Ty<'tcx>,
+ in_crate: InCrate,
+) -> Vec<Ty<'tcx>> {
if ty_is_local_constructor(ty, in_crate) {
Vec::new()
} else {
@@ -536,7 +544,7 @@ fn contained_non_local_types(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>, in_crate: InCrate)
/// For `#[fundamental]` ADTs and `&T` / `&mut T`, returns `Some` with the
/// type parameters of the ADT, or `T`, respectively. For non-fundamental
/// types, returns `None`.
-fn fundamental_ty_inner_tys(
+fn fundamental_ty_inner_tys<'tcx>(
tcx: TyCtxt<'tcx>,
ty: Ty<'tcx>,
) -> Option<impl Iterator<Item = Ty<'tcx>>> {
diff --git a/compiler/rustc_trait_selection/src/traits/const_evaluatable.rs b/compiler/rustc_trait_selection/src/traits/const_evaluatable.rs
index 6b5d37c0f43..0ea3a18ca34 100644
--- a/compiler/rustc_trait_selection/src/traits/const_evaluatable.rs
+++ b/compiler/rustc_trait_selection/src/traits/const_evaluatable.rs
@@ -399,13 +399,25 @@ impl<'a, 'tcx> AbstractConstBuilder<'a, 'tcx> {
let arg = self.recurse_build(source)?;
self.nodes.push(Node::Cast(abstract_const::CastKind::As, arg, node.ty))
}
-
+ ExprKind::Borrow{ arg, ..} => {
+ let arg_node = &self.body.exprs[*arg];
+
+ // Skip reborrows for now until we allow Deref/Borrow/AddressOf
+ // expressions.
+ // FIXME(generic_const_exprs): Verify/explain why this is sound
+ if let ExprKind::Deref {arg} = arg_node.kind {
+ self.recurse_build(arg)?
+ } else {
+ self.maybe_supported_error(
+ node.span,
+ "borrowing is not supported in generic constants",
+ )?
+ }
+ }
// FIXME(generic_const_exprs): We may want to support these.
- ExprKind::AddressOf { .. }
- | ExprKind::Borrow { .. }
- | ExprKind::Deref { .. } => self.maybe_supported_error(
+ ExprKind::AddressOf { .. } | ExprKind::Deref {..}=> self.maybe_supported_error(
node.span,
- "dereferencing is not supported in generic constants",
+ "dereferencing or taking the address is not supported in generic constants",
)?,
ExprKind::Repeat { .. } | ExprKind::Array { .. } => self.maybe_supported_error(
node.span,
diff --git a/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs b/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs
index f8df0e25959..8833805d35c 100644
--- a/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs
+++ b/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs
@@ -21,10 +21,10 @@ use rustc_hir::Item;
use rustc_hir::Node;
use rustc_middle::thir::abstract_const::NotConstEvaluatable;
use rustc_middle::ty::error::ExpectedFound;
+use rustc_middle::ty::fast_reject::{self, SimplifyParams, StripReferences};
use rustc_middle::ty::fold::TypeFolder;
use rustc_middle::ty::{
- self, fast_reject, AdtKind, SubtypePredicate, ToPolyTraitRef, ToPredicate, Ty, TyCtxt,
- TypeFoldable, WithConstness,
+ self, AdtKind, SubtypePredicate, ToPolyTraitRef, ToPredicate, Ty, TyCtxt, TypeFoldable,
};
use rustc_session::DiagnosticMessageId;
use rustc_span::symbol::{kw, sym};
@@ -439,6 +439,7 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> {
self.suggest_remove_reference(&obligation, &mut err, trait_ref);
self.suggest_semicolon_removal(&obligation, &mut err, span, trait_ref);
self.note_version_mismatch(&mut err, &trait_ref);
+ self.suggest_remove_await(&obligation, &mut err);
if Some(trait_ref.def_id()) == tcx.lang_items().try_trait() {
self.suggest_await_before_try(&mut err, &obligation, trait_ref, span);
@@ -539,11 +540,6 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> {
// is otherwise overwhelming and unhelpful (see #85844 for an
// example).
- let trait_is_debug =
- self.tcx.is_diagnostic_item(sym::Debug, trait_ref.def_id());
- let trait_is_display =
- self.tcx.is_diagnostic_item(sym::Display, trait_ref.def_id());
-
let in_std_macro =
match obligation.cause.span.ctxt().outer_expn_data().macro_def_id {
Some(macro_def_id) => {
@@ -553,7 +549,12 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> {
None => false,
};
- if in_std_macro && (trait_is_debug || trait_is_display) {
+ if in_std_macro
+ && matches!(
+ self.tcx.get_diagnostic_name(trait_ref.def_id()),
+ Some(sym::Debug | sym::Display)
+ )
+ {
err.emit();
return;
}
@@ -1062,7 +1063,7 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> {
}
}
-trait InferCtxtPrivExt<'tcx> {
+trait InferCtxtPrivExt<'hir, 'tcx> {
// returns if `cond` not occurring implies that `error` does not occur - i.e., that
// `error` occurring implies that `cond` occurs.
fn error_implies(&self, cond: ty::Predicate<'tcx>, error: ty::Predicate<'tcx>) -> bool;
@@ -1173,7 +1174,7 @@ trait InferCtxtPrivExt<'tcx> {
) -> bool;
}
-impl<'a, 'tcx> InferCtxtPrivExt<'tcx> for InferCtxt<'a, 'tcx> {
+impl<'a, 'tcx> InferCtxtPrivExt<'a, 'tcx> for InferCtxt<'a, 'tcx> {
// returns if `cond` not occurring implies that `error` does not occur - i.e., that
// `error` occurring implies that `cond` occurs.
fn error_implies(&self, cond: ty::Predicate<'tcx>, error: ty::Predicate<'tcx>) -> bool {
@@ -1338,7 +1339,46 @@ impl<'a, 'tcx> InferCtxtPrivExt<'tcx> for InferCtxt<'a, 'tcx> {
"type mismatch resolving `{}`",
predicate
);
- self.note_type_err(&mut diag, &obligation.cause, None, values, err);
+ let secondary_span = match predicate.kind().skip_binder() {
+ ty::PredicateKind::Projection(proj) => self
+ .tcx
+ .opt_associated_item(proj.projection_ty.item_def_id)
+ .and_then(|trait_assoc_item| {
+ self.tcx
+ .trait_of_item(proj.projection_ty.item_def_id)
+ .map(|id| (trait_assoc_item, id))
+ })
+ .and_then(|(trait_assoc_item, id)| {
+ self.tcx.find_map_relevant_impl(
+ id,
+ proj.projection_ty.self_ty(),
+ |did| {
+ self.tcx
+ .associated_items(did)
+ .in_definition_order()
+ .filter(|assoc| assoc.ident == trait_assoc_item.ident)
+ .next()
+ },
+ )
+ })
+ .and_then(|item| match self.tcx.hir().get_if_local(item.def_id) {
+ Some(
+ hir::Node::TraitItem(hir::TraitItem {
+ kind: hir::TraitItemKind::Type(_, Some(ty)),
+ ..
+ })
+ | hir::Node::ImplItem(hir::ImplItem {
+ kind: hir::ImplItemKind::TyAlias(ty),
+ ..
+ }),
+ ) => {
+ Some((ty.span, format!("type mismatch resolving `{}`", predicate)))
+ }
+ _ => None,
+ }),
+ _ => None,
+ };
+ self.note_type_err(&mut diag, &obligation.cause, secondary_span, values, err, true);
self.note_obligation_cause(&mut diag, obligation);
diag.emit();
}
@@ -1400,14 +1440,32 @@ impl<'a, 'tcx> InferCtxtPrivExt<'tcx> for InferCtxt<'a, 'tcx> {
&self,
trait_ref: ty::PolyTraitRef<'tcx>,
) -> Vec<ty::TraitRef<'tcx>> {
- let simp = fast_reject::simplify_type(self.tcx, trait_ref.skip_binder().self_ty(), true);
+ // We simplify params and strip references here.
+ //
+ // This both removes a lot of unhelpful suggestions, e.g.
+ // when searching for `&Foo: Trait` it doesn't suggestion `impl Trait for &Bar`,
+ // while also suggesting impls for `&Foo` when we're looking for `Foo: Trait`.
+ //
+ // The second thing isn't necessarily always a good thing, but
+ // any other simple setup results in a far worse output, so 🤷
+ let simp = fast_reject::simplify_type(
+ self.tcx,
+ trait_ref.skip_binder().self_ty(),
+ SimplifyParams::Yes,
+ StripReferences::Yes,
+ );
let all_impls = self.tcx.all_impls(trait_ref.def_id());
match simp {
Some(simp) => all_impls
.filter_map(|def_id| {
let imp = self.tcx.impl_trait_ref(def_id).unwrap();
- let imp_simp = fast_reject::simplify_type(self.tcx, imp.self_ty(), true);
+ let imp_simp = fast_reject::simplify_type(
+ self.tcx,
+ imp.self_ty(),
+ SimplifyParams::Yes,
+ StripReferences::Yes,
+ );
if let Some(imp_simp) = imp_simp {
if simp != imp_simp {
return None;
@@ -1984,7 +2042,7 @@ impl<'a, 'tcx> InferCtxtPrivExt<'tcx> for InferCtxt<'a, 'tcx> {
self.maybe_suggest_unsized_generics(err, span, node);
}
- fn maybe_suggest_unsized_generics(
+ fn maybe_suggest_unsized_generics<'hir>(
&self,
err: &mut DiagnosticBuilder<'tcx>,
span: Span,
@@ -2025,9 +2083,7 @@ impl<'a, 'tcx> InferCtxtPrivExt<'tcx> for InferCtxt<'a, 'tcx> {
debug!("maybe_suggest_unsized_generics: param={:?}", param);
match node {
hir::Node::Item(
- item
- @
- hir::Item {
+ item @ hir::Item {
// Only suggest indirection for uses of type parameters in ADTs.
kind:
hir::ItemKind::Enum(..) | hir::ItemKind::Struct(..) | hir::ItemKind::Union(..),
@@ -2053,7 +2109,7 @@ impl<'a, 'tcx> InferCtxtPrivExt<'tcx> for InferCtxt<'a, 'tcx> {
);
}
- fn maybe_indirection_for_unsized(
+ fn maybe_indirection_for_unsized<'hir>(
&self,
err: &mut DiagnosticBuilder<'tcx>,
item: &'hir Item<'hir>,
@@ -2097,10 +2153,21 @@ impl<'a, 'tcx> InferCtxtPrivExt<'tcx> for InferCtxt<'a, 'tcx> {
) -> bool {
if let ObligationCauseCode::BuiltinDerivedObligation(ref data) = cause_code {
let parent_trait_ref = self.resolve_vars_if_possible(data.parent_trait_ref);
-
- if obligated_types.iter().any(|ot| ot == &parent_trait_ref.skip_binder().self_ty()) {
+ let self_ty = parent_trait_ref.skip_binder().self_ty();
+ if obligated_types.iter().any(|ot| ot == &self_ty) {
return true;
}
+ if let ty::Adt(def, substs) = self_ty.kind() {
+ if let [arg] = &substs[..] {
+ if let ty::subst::GenericArgKind::Type(ty) = arg.unpack() {
+ if let ty::Adt(inner_def, _) = ty.kind() {
+ if inner_def == def {
+ return true;
+ }
+ }
+ }
+ }
+ }
}
false
}
@@ -2156,7 +2223,7 @@ impl<'v> Visitor<'v> for FindTypeParam {
}
pub fn recursive_type_with_infinite_size_error(
- tcx: TyCtxt<'tcx>,
+ tcx: TyCtxt<'_>,
type_def_id: DefId,
spans: Vec<Span>,
) {
diff --git a/compiler/rustc_trait_selection/src/traits/error_reporting/on_unimplemented.rs b/compiler/rustc_trait_selection/src/traits/error_reporting/on_unimplemented.rs
index 6128c119b6b..d9a5aea4d95 100644
--- a/compiler/rustc_trait_selection/src/traits/error_reporting/on_unimplemented.rs
+++ b/compiler/rustc_trait_selection/src/traits/error_reporting/on_unimplemented.rs
@@ -231,7 +231,7 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> {
if let Ok(Some(command)) =
OnUnimplementedDirective::of_item(self.tcx, trait_ref.def_id, def_id)
{
- command.evaluate(self.tcx, trait_ref, &flags[..])
+ command.evaluate(self.tcx, trait_ref, &flags)
} else {
OnUnimplementedNote::default()
}
diff --git a/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs b/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs
index a90140a9b50..9c10823a844 100644
--- a/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs
+++ b/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs
@@ -21,7 +21,7 @@ use rustc_hir::lang_items::LangItem;
use rustc_hir::{AsyncGeneratorKind, GeneratorKind, Node};
use rustc_middle::ty::{
self, suggest_arbitrary_trait_bound, suggest_constraining_type_param, AdtKind, DefIdTree,
- Infer, InferTy, ToPredicate, Ty, TyCtxt, TypeFoldable, WithConstness,
+ Infer, InferTy, ToPredicate, Ty, TyCtxt, TypeFoldable,
};
use rustc_middle::ty::{TypeAndMut, TypeckResults};
use rustc_session::Limit;
@@ -89,6 +89,12 @@ pub trait InferCtxtExt<'tcx> {
trait_ref: ty::Binder<'tcx, ty::TraitRef<'tcx>>,
);
+ fn suggest_remove_await(
+ &self,
+ obligation: &PredicateObligation<'tcx>,
+ err: &mut DiagnosticBuilder<'_>,
+ );
+
fn suggest_change_mut(
&self,
obligation: &PredicateObligation<'tcx>,
@@ -192,7 +198,7 @@ fn predicate_constraint(generics: &hir::Generics<'_>, pred: String) -> (Span, St
/// Type parameter needs more bounds. The trivial case is `T` `where T: Bound`, but
/// it can also be an `impl Trait` param that needs to be decomposed to a type
/// param for cleaner code.
-fn suggest_restriction(
+fn suggest_restriction<'tcx>(
tcx: TyCtxt<'tcx>,
generics: &hir::Generics<'tcx>,
msg: &str,
@@ -262,8 +268,8 @@ fn suggest_restriction(
match generics
.params
.iter()
- .map(|p| p.bounds_span().unwrap_or(p.span))
- .filter(|&span| generics.span.contains(span) && span.desugaring_kind().is_none())
+ .map(|p| p.bounds_span_for_suggestions().unwrap_or(p.span.shrink_to_hi()))
+ .filter(|&span| generics.span.contains(span) && span.can_be_used_for_suggestions())
.max_by_key(|span| span.hi())
{
// `fn foo(t: impl Trait)`
@@ -271,7 +277,7 @@ fn suggest_restriction(
None => (generics.span, format!("<{}>", type_param)),
// `fn foo<A>(t: impl Trait)`
// ^^^ suggest `<A, T: Trait>` here
- Some(span) => (span.shrink_to_hi(), format!(", {}", type_param)),
+ Some(span) => (span, format!(", {}", type_param)),
},
// `fn foo(t: impl Trait)`
// ^ suggest `where <T as Trait>::A: Bound`
@@ -741,7 +747,7 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> {
let msg = format!(
"the trait bound `{}: {}` is not satisfied",
- orig_ty.to_string(),
+ orig_ty,
old_ref.print_only_trait_path(),
);
if has_custom_message {
@@ -804,7 +810,7 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> {
} else if let ObligationCauseCode::BindingObligation(_, _)
| ObligationCauseCode::ItemObligation(_) = &*code
{
- try_borrowing(*poly_trait_ref, &never_suggest_borrow[..])
+ try_borrowing(*poly_trait_ref, &never_suggest_borrow)
} else {
false
}
@@ -873,6 +879,63 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> {
}
}
+ fn suggest_remove_await(
+ &self,
+ obligation: &PredicateObligation<'tcx>,
+ err: &mut DiagnosticBuilder<'_>,
+ ) {
+ let span = obligation.cause.span;
+
+ if let ObligationCauseCode::AwaitableExpr(hir_id) = obligation.cause.code.peel_derives() {
+ let hir = self.tcx.hir();
+ if let Some(node) = hir_id.and_then(|hir_id| hir.find(hir_id)) {
+ if let hir::Node::Expr(expr) = node {
+ // FIXME: use `obligation.predicate.kind()...trait_ref.self_ty()` to see if we have `()`
+ // and if not maybe suggest doing something else? If we kept the expression around we
+ // could also check if it is an fn call (very likely) and suggest changing *that*, if
+ // it is from the local crate.
+ err.span_suggestion_verbose(
+ expr.span.shrink_to_hi().with_hi(span.hi()),
+ "remove the `.await`",
+ String::new(),
+ Applicability::MachineApplicable,
+ );
+ // FIXME: account for associated `async fn`s.
+ if let hir::Expr { span, kind: hir::ExprKind::Call(base, _), .. } = expr {
+ if let ty::PredicateKind::Trait(pred) =
+ obligation.predicate.kind().skip_binder()
+ {
+ err.span_label(
+ *span,
+ &format!("this call returns `{}`", pred.self_ty()),
+ );
+ }
+ if let Some(typeck_results) =
+ self.in_progress_typeck_results.map(|t| t.borrow())
+ {
+ let ty = typeck_results.expr_ty_adjusted(base);
+ if let ty::FnDef(def_id, _substs) = ty.kind() {
+ if let Some(hir::Node::Item(hir::Item { span, ident, .. })) =
+ hir.get_if_local(*def_id)
+ {
+ err.span_suggestion_verbose(
+ span.shrink_to_lo(),
+ &format!(
+ "alternatively, consider making `fn {}` asynchronous",
+ ident
+ ),
+ "async ".to_string(),
+ Applicability::MaybeIncorrect,
+ );
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+
/// Check if the trait bound is implemented for a different mutability and note it in the
/// final error.
fn suggest_change_mut(
@@ -1132,7 +1195,7 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> {
<https://doc.rust-lang.org/book/ch17-02-trait-objects.html\
#using-trait-objects-that-allow-for-values-of-different-types>";
let has_dyn = snippet.split_whitespace().next().map_or(false, |s| s == "dyn");
- let trait_obj = if has_dyn { &snippet[4..] } else { &snippet[..] };
+ let trait_obj = if has_dyn { &snippet[4..] } else { &snippet };
if only_never_return {
// No return paths, probably using `panic!()` or similar.
// Suggest `-> T`, `-> impl Trait`, and if `Trait` is object safe, `-> Box<dyn Trait>`.
@@ -1654,130 +1717,63 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> {
format!("does not implement `{}`", trait_ref.print_only_trait_path())
};
- let mut explain_yield =
- |interior_span: Span, yield_span: Span, scope_span: Option<Span>| {
- let mut span = MultiSpan::from_span(yield_span);
- if let Ok(snippet) = source_map.span_to_snippet(interior_span) {
- // #70935: If snippet contains newlines, display "the value" instead
- // so that we do not emit complex diagnostics.
- let snippet = &format!("`{}`", snippet);
- let snippet = if snippet.contains('\n') { "the value" } else { snippet };
- // The multispan can be complex here, like:
- // note: future is not `Send` as this value is used across an await
- // --> $DIR/issue-70935-complex-spans.rs:13:9
- // |
- // LL | baz(|| async{
- // | __________^___-
- // | | _________|
- // | ||
- // LL | || foo(tx.clone());
- // LL | || }).await;
- // | || - ^- value is later dropped here
- // | ||_________|______|
- // | |__________| await occurs here, with value maybe used later
- // | has type `closure` which is not `Send`
- //
- // So, detect it and separate into some notes, like:
- //
- // note: future is not `Send` as this value is used across an await
- // --> $DIR/issue-70935-complex-spans.rs:13:9
- // |
- // LL | / baz(|| async{
- // LL | | foo(tx.clone());
- // LL | | }).await;
- // | |________________^ first, await occurs here, with the value maybe used later...
- // note: the value is later dropped here
- // --> $DIR/issue-70935-complex-spans.rs:15:17
- // |
- // LL | }).await;
- // | ^
- //
- // If available, use the scope span to annotate the drop location.
- if let Some(scope_span) = scope_span {
- let scope_span = source_map.end_point(scope_span);
- let is_overlapped =
- yield_span.overlaps(scope_span) || yield_span.overlaps(interior_span);
- if is_overlapped {
- span.push_span_label(
- yield_span,
- format!(
- "first, {} occurs here, with {} maybe used later...",
- await_or_yield, snippet
- ),
- );
- err.span_note(
- span,
- &format!(
- "{} {} as this value is used across {}",
- future_or_generator, trait_explanation, an_await_or_yield
- ),
- );
- if source_map.is_multiline(interior_span) {
- err.span_note(
- scope_span,
- &format!("{} is later dropped here", snippet),
- );
- err.span_note(
- interior_span,
- &format!(
- "this has type `{}` which {}",
- target_ty, trait_explanation
- ),
- );
- } else {
- let mut span = MultiSpan::from_span(scope_span);
- span.push_span_label(
- interior_span,
- format!("has type `{}` which {}", target_ty, trait_explanation),
- );
- err.span_note(span, &format!("{} is later dropped here", snippet));
- }
- } else {
- span.push_span_label(
- yield_span,
- format!(
- "{} occurs here, with {} maybe used later",
- await_or_yield, snippet
- ),
- );
- span.push_span_label(
- scope_span,
- format!("{} is later dropped here", snippet),
- );
- span.push_span_label(
- interior_span,
- format!("has type `{}` which {}", target_ty, trait_explanation),
- );
- err.span_note(
- span,
- &format!(
- "{} {} as this value is used across {}",
- future_or_generator, trait_explanation, an_await_or_yield
- ),
- );
- }
+ let mut explain_yield = |interior_span: Span,
+ yield_span: Span,
+ scope_span: Option<Span>| {
+ let mut span = MultiSpan::from_span(yield_span);
+ if let Ok(snippet) = source_map.span_to_snippet(interior_span) {
+ // #70935: If snippet contains newlines, display "the value" instead
+ // so that we do not emit complex diagnostics.
+ let snippet = &format!("`{}`", snippet);
+ let snippet = if snippet.contains('\n') { "the value" } else { snippet };
+ // note: future is not `Send` as this value is used across an await
+ // --> $DIR/issue-70935-complex-spans.rs:13:9
+ // |
+ // LL | baz(|| async {
+ // | ______________-
+ // | |
+ // | |
+ // LL | | foo(tx.clone());
+ // LL | | }).await;
+ // | | - ^^^^^^ await occurs here, with value maybe used later
+ // | |__________|
+ // | has type `closure` which is not `Send`
+ // note: value is later dropped here
+ // LL | | }).await;
+ // | | ^
+ //
+ span.push_span_label(
+ yield_span,
+ format!("{} occurs here, with {} maybe used later", await_or_yield, snippet),
+ );
+ span.push_span_label(
+ interior_span,
+ format!("has type `{}` which {}", target_ty, trait_explanation),
+ );
+ // If available, use the scope span to annotate the drop location.
+ let mut scope_note = None;
+ if let Some(scope_span) = scope_span {
+ let scope_span = source_map.end_point(scope_span);
+
+ let msg = format!("{} is later dropped here", snippet);
+ if source_map.is_multiline(yield_span.between(scope_span)) {
+ span.push_span_label(scope_span, msg);
} else {
- span.push_span_label(
- yield_span,
- format!(
- "{} occurs here, with {} maybe used later",
- await_or_yield, snippet
- ),
- );
- span.push_span_label(
- interior_span,
- format!("has type `{}` which {}", target_ty, trait_explanation),
- );
- err.span_note(
- span,
- &format!(
- "{} {} as this value is used across {}",
- future_or_generator, trait_explanation, an_await_or_yield
- ),
- );
+ scope_note = Some((scope_span, msg));
}
}
- };
+ err.span_note(
+ span,
+ &format!(
+ "{} {} as this value is used across {}",
+ future_or_generator, trait_explanation, an_await_or_yield
+ ),
+ );
+ if let Some((span, msg)) = scope_note {
+ err.span_note(span, &msg);
+ }
+ }
+ };
match interior_or_upvar_span {
GeneratorInteriorOrUpvar::Interior(interior_span) => {
if let Some((scope_span, yield_span, expr, from_awaited_ty)) = interior_extra_info {
@@ -1935,6 +1931,9 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> {
| ObligationCauseCode::ReturnType
| ObligationCauseCode::ReturnValue(_)
| ObligationCauseCode::BlockTailExpression(_)
+ | ObligationCauseCode::AwaitableExpr(_)
+ | ObligationCauseCode::ForLoopIterator
+ | ObligationCauseCode::QuestionMark
| ObligationCauseCode::LetElse => {}
ObligationCauseCode::SliceOrArrayElem => {
err.note("slice and array elements must have `Sized` type");
@@ -2186,6 +2185,16 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> {
seen_requirements,
)
});
+ } else {
+ ensure_sufficient_stack(|| {
+ self.note_obligation_cause_code(
+ err,
+ &parent_predicate,
+ &cause_code.peel_derives(),
+ obligated_types,
+ seen_requirements,
+ )
+ });
}
}
ObligationCauseCode::ImplDerivedObligation(ref data) => {
diff --git a/compiler/rustc_trait_selection/src/traits/fulfill.rs b/compiler/rustc_trait_selection/src/traits/fulfill.rs
index e121837c987..35bb7d6f06c 100644
--- a/compiler/rustc_trait_selection/src/traits/fulfill.rs
+++ b/compiler/rustc_trait_selection/src/traits/fulfill.rs
@@ -4,7 +4,7 @@ use rustc_data_structures::obligation_forest::ProcessResult;
use rustc_data_structures::obligation_forest::{Error, ForestObligation, Outcome};
use rustc_data_structures::obligation_forest::{ObligationForest, ObligationProcessor};
use rustc_errors::ErrorReported;
-use rustc_hir as hir;
+use rustc_infer::traits::ProjectionCacheKey;
use rustc_infer::traits::{SelectionError, TraitEngine, TraitEngineExt as _, TraitObligation};
use rustc_middle::mir::interpret::ErrorHandled;
use rustc_middle::thir::abstract_const::NotConstEvaluatable;
@@ -21,12 +21,14 @@ use super::wf;
use super::CodeAmbiguity;
use super::CodeProjectionError;
use super::CodeSelectionError;
+use super::EvaluationResult;
use super::Unimplemented;
use super::{FulfillmentError, FulfillmentErrorCode};
use super::{ObligationCause, PredicateObligation};
use crate::traits::error_reporting::InferCtxtExt as _;
use crate::traits::project::PolyProjectionObligation;
+use crate::traits::project::ProjectionCacheKeyExt as _;
use crate::traits::query::evaluate_obligation::InferCtxtExt as _;
impl<'tcx> ForestObligation for PendingPredicateObligation<'tcx> {
@@ -231,21 +233,6 @@ impl<'tcx> TraitEngine<'tcx> for FulfillmentContext<'tcx> {
self.predicates.to_errors(CodeAmbiguity).into_iter().map(to_fulfillment_error).collect()
}
- fn select_all_with_constness_or_error(
- &mut self,
- infcx: &InferCtxt<'_, 'tcx>,
- constness: rustc_hir::Constness,
- ) -> Vec<FulfillmentError<'tcx>> {
- {
- let errors = self.select_with_constness_where_possible(infcx, constness);
- if !errors.is_empty() {
- return errors;
- }
- }
-
- self.predicates.to_errors(CodeAmbiguity).into_iter().map(to_fulfillment_error).collect()
- }
-
fn select_where_possible(
&mut self,
infcx: &InferCtxt<'_, 'tcx>,
@@ -254,15 +241,6 @@ impl<'tcx> TraitEngine<'tcx> for FulfillmentContext<'tcx> {
self.select(&mut selcx)
}
- fn select_with_constness_where_possible(
- &mut self,
- infcx: &InferCtxt<'_, 'tcx>,
- constness: hir::Constness,
- ) -> Vec<FulfillmentError<'tcx>> {
- let mut selcx = SelectionContext::with_constness(infcx, constness);
- self.select(&mut selcx)
- }
-
fn pending_obligations(&self) -> Vec<PredicateObligation<'tcx>> {
self.predicates.map_pending_obligations(|o| o.obligation.clone())
}
@@ -277,7 +255,7 @@ struct FulfillProcessor<'a, 'b, 'tcx> {
register_region_obligations: bool,
}
-fn mk_pending(os: Vec<PredicateObligation<'tcx>>) -> Vec<PendingPredicateObligation<'tcx>> {
+fn mk_pending(os: Vec<PredicateObligation<'_>>) -> Vec<PendingPredicateObligation<'_>> {
os.into_iter()
.map(|o| PendingPredicateObligation { obligation: o, stalled_on: vec![] })
.collect()
@@ -679,12 +657,7 @@ impl<'a, 'b, 'tcx> FulfillProcessor<'a, 'b, 'tcx> {
if obligation.predicate.is_known_global() {
// no type variables present, can use evaluation for better caching.
// FIXME: consider caching errors too.
- //
- // If the predicate is considered const, then we cannot use this because
- // it will cause false negatives in the ui tests.
- if !self.selcx.is_predicate_const(obligation.predicate)
- && infcx.predicate_must_hold_considering_regions(obligation)
- {
+ if infcx.predicate_must_hold_considering_regions(obligation) {
debug!(
"selecting trait at depth {} evaluated to holds",
obligation.recursion_depth
@@ -738,12 +711,21 @@ impl<'a, 'b, 'tcx> FulfillProcessor<'a, 'b, 'tcx> {
if obligation.predicate.is_global(tcx) {
// no type variables present, can use evaluation for better caching.
// FIXME: consider caching errors too.
- //
- // If the predicate is considered const, then we cannot use this because
- // it will cause false negatives in the ui tests.
- if !self.selcx.is_predicate_const(obligation.predicate)
- && self.selcx.infcx().predicate_must_hold_considering_regions(obligation)
- {
+ if self.selcx.infcx().predicate_must_hold_considering_regions(obligation) {
+ if let Some(key) = ProjectionCacheKey::from_poly_projection_predicate(
+ &mut self.selcx,
+ project_obligation.predicate,
+ ) {
+ // If `predicate_must_hold_considering_regions` succeeds, then we've
+ // evaluated all sub-obligations. We can therefore mark the 'root'
+ // obligation as complete, and skip evaluating sub-obligations.
+ self.selcx
+ .infcx()
+ .inner
+ .borrow_mut()
+ .projection_cache()
+ .complete(key, EvaluationResult::EvaluatedToOk);
+ }
return ProcessResult::Changed(vec![]);
} else {
tracing::debug!("Does NOT hold: {:?}", obligation);
diff --git a/compiler/rustc_trait_selection/src/traits/misc.rs b/compiler/rustc_trait_selection/src/traits/misc.rs
index fa8890fc352..b23dce8a581 100644
--- a/compiler/rustc_trait_selection/src/traits/misc.rs
+++ b/compiler/rustc_trait_selection/src/traits/misc.rs
@@ -16,7 +16,7 @@ pub enum CopyImplementationError<'tcx> {
HasDestructor,
}
-pub fn can_type_implement_copy(
+pub fn can_type_implement_copy<'tcx>(
tcx: TyCtxt<'tcx>,
param_env: ty::ParamEnv<'tcx>,
self_type: Ty<'tcx>,
diff --git a/compiler/rustc_trait_selection/src/traits/mod.rs b/compiler/rustc_trait_selection/src/traits/mod.rs
index 91671994c5a..a8f26982d2e 100644
--- a/compiler/rustc_trait_selection/src/traits/mod.rs
+++ b/compiler/rustc_trait_selection/src/traits/mod.rs
@@ -33,8 +33,7 @@ use rustc_hir::lang_items::LangItem;
use rustc_middle::ty::fold::TypeFoldable;
use rustc_middle::ty::subst::{InternalSubsts, SubstsRef};
use rustc_middle::ty::{
- self, GenericParamDefKind, ToPredicate, Ty, TyCtxt, VtblEntry, WithConstness,
- COMMON_VTABLE_ENTRIES,
+ self, GenericParamDefKind, ToPredicate, Ty, TyCtxt, VtblEntry, COMMON_VTABLE_ENTRIES,
};
use rustc_span::{sym, Span};
use smallvec::SmallVec;
@@ -82,9 +81,14 @@ pub use self::chalk_fulfill::FulfillmentContext as ChalkFulfillmentContext;
pub use rustc_infer::traits::*;
/// Whether to skip the leak check, as part of a future compatibility warning step.
-#[derive(Copy, Clone, PartialEq, Eq, Debug)]
+///
+/// The "default" for skip-leak-check corresponds to the current
+/// behavior (do not skip the leak check) -- not the behavior we are
+/// transitioning into.
+#[derive(Copy, Clone, PartialEq, Eq, Debug, Default)]
pub enum SkipLeakCheck {
Yes,
+ #[default]
No,
}
@@ -94,15 +98,6 @@ impl SkipLeakCheck {
}
}
-/// The "default" for skip-leak-check corresponds to the current
-/// behavior (do not skip the leak check) -- not the behavior we are
-/// transitioning into.
-impl Default for SkipLeakCheck {
- fn default() -> Self {
- SkipLeakCheck::No
- }
-}
-
/// The mode that trait queries run in.
#[derive(Copy, Clone, PartialEq, Eq, Debug)]
pub enum TraitQueryMode {
@@ -311,8 +306,11 @@ pub fn normalize_param_env_or_error<'tcx>(
debug!("normalize_param_env_or_error: elaborated-predicates={:?}", predicates);
- let elaborated_env =
- ty::ParamEnv::new(tcx.intern_predicates(&predicates), unnormalized_env.reveal());
+ let elaborated_env = ty::ParamEnv::new(
+ tcx.intern_predicates(&predicates),
+ unnormalized_env.reveal(),
+ unnormalized_env.constness(),
+ );
// HACK: we are trying to normalize the param-env inside *itself*. The problem is that
// normalization expects its param-env to be already normalized, which means we have
@@ -364,8 +362,11 @@ pub fn normalize_param_env_or_error<'tcx>(
// predicates here anyway. Keeping them here anyway because it seems safer.
let outlives_env: Vec<_> =
non_outlives_predicates.iter().chain(&outlives_predicates).cloned().collect();
- let outlives_env =
- ty::ParamEnv::new(tcx.intern_predicates(&outlives_env), unnormalized_env.reveal());
+ let outlives_env = ty::ParamEnv::new(
+ tcx.intern_predicates(&outlives_env),
+ unnormalized_env.reveal(),
+ unnormalized_env.constness(),
+ );
let outlives_predicates = match do_normalize_predicates(
tcx,
region_context,
@@ -385,7 +386,11 @@ pub fn normalize_param_env_or_error<'tcx>(
let mut predicates = non_outlives_predicates;
predicates.extend(outlives_predicates);
debug!("normalize_param_env_or_error: final predicates={:?}", predicates);
- ty::ParamEnv::new(tcx.intern_predicates(&predicates), unnormalized_env.reveal())
+ ty::ParamEnv::new(
+ tcx.intern_predicates(&predicates),
+ unnormalized_env.reveal(),
+ unnormalized_env.constness(),
+ )
}
pub fn fully_normalize<'a, 'tcx, T>(
@@ -568,14 +573,17 @@ fn prepare_vtable_segments<'tcx, T>(
.predicates
.into_iter()
.filter_map(move |(pred, _)| {
- pred.subst_supertrait(tcx, &inner_most_trait_ref).to_opt_poly_trait_ref()
+ pred.subst_supertrait(tcx, &inner_most_trait_ref).to_opt_poly_trait_pred()
});
'diving_in_skip_visited_traits: loop {
if let Some(next_super_trait) = direct_super_traits_iter.next() {
if visited.insert(next_super_trait.to_predicate(tcx)) {
+ // We're throwing away potential constness of super traits here.
+ // FIXME: handle ~const super traits
+ let next_super_trait = next_super_trait.map_bound(|t| t.trait_ref);
stack.push((
- next_super_trait.value,
+ next_super_trait,
emit_vptr_on_new_entry,
Some(direct_super_traits_iter),
));
@@ -607,7 +615,11 @@ fn prepare_vtable_segments<'tcx, T>(
if let Some(siblings) = siblings_opt {
if let Some(next_inner_most_trait_ref) = siblings.next() {
if visited.insert(next_inner_most_trait_ref.to_predicate(tcx)) {
- *inner_most_trait_ref = next_inner_most_trait_ref.value;
+ // We're throwing away potential constness of super traits here.
+ // FIXME: handle ~const super traits
+ let next_inner_most_trait_ref =
+ next_inner_most_trait_ref.map_bound(|t| t.trait_ref);
+ *inner_most_trait_ref = next_inner_most_trait_ref;
*emit_vptr = emit_vptr_on_new_entry;
break 'exiting_out;
} else {
@@ -789,7 +801,7 @@ fn vtable_trait_first_method_offset<'tcx>(
}
/// Find slot offset for trait vptr within vtable entries of another trait
-pub fn vtable_trait_upcasting_coercion_new_vptr_slot(
+pub fn vtable_trait_upcasting_coercion_new_vptr_slot<'tcx>(
tcx: TyCtxt<'tcx>,
key: (
Ty<'tcx>, // trait object type whose trait owning vtable
diff --git a/compiler/rustc_trait_selection/src/traits/object_safety.rs b/compiler/rustc_trait_selection/src/traits/object_safety.rs
index afc546540d2..4e84849bc1e 100644
--- a/compiler/rustc_trait_selection/src/traits/object_safety.rs
+++ b/compiler/rustc_trait_selection/src/traits/object_safety.rs
@@ -18,14 +18,13 @@ use rustc_errors::FatalError;
use rustc_hir as hir;
use rustc_hir::def_id::DefId;
use rustc_middle::ty::subst::{GenericArg, InternalSubsts, Subst};
-use rustc_middle::ty::{self, Ty, TyCtxt, TypeFoldable, TypeVisitor, WithConstness};
+use rustc_middle::ty::{self, Ty, TyCtxt, TypeFoldable, TypeVisitor};
use rustc_middle::ty::{Predicate, ToPredicate};
use rustc_session::lint::builtin::WHERE_CLAUSES_OBJECT_SAFETY;
use rustc_span::symbol::Symbol;
use rustc_span::{MultiSpan, Span};
use smallvec::SmallVec;
-use std::array;
use std::iter;
use std::ops::ControlFlow;
@@ -51,10 +50,7 @@ pub fn astconv_object_safety_violations(
violations
}
-fn object_safety_violations(
- tcx: TyCtxt<'tcx>,
- trait_def_id: DefId,
-) -> &'tcx [ObjectSafetyViolation] {
+fn object_safety_violations(tcx: TyCtxt<'_>, trait_def_id: DefId) -> &'_ [ObjectSafetyViolation] {
debug_assert!(tcx.generics_of(trait_def_id).has_self);
debug!("object_safety_violations: {:?}", trait_def_id);
@@ -273,7 +269,7 @@ fn bounds_reference_self(tcx: TyCtxt<'_>, trait_def_id: DefId) -> SmallVec<[Span
.collect()
}
-fn predicate_references_self(
+fn predicate_references_self<'tcx>(
tcx: TyCtxt<'tcx>,
(predicate, sp): (ty::Predicate<'tcx>, Span),
) -> Option<Span> {
@@ -692,13 +688,14 @@ fn receiver_is_dispatchable<'tcx>(
.to_predicate(tcx)
};
- let caller_bounds: Vec<Predicate<'tcx>> = param_env
- .caller_bounds()
- .iter()
- .chain(array::IntoIter::new([unsize_predicate, trait_predicate]))
- .collect();
+ let caller_bounds: Vec<Predicate<'tcx>> =
+ param_env.caller_bounds().iter().chain([unsize_predicate, trait_predicate]).collect();
- ty::ParamEnv::new(tcx.intern_predicates(&caller_bounds), param_env.reveal())
+ ty::ParamEnv::new(
+ tcx.intern_predicates(&caller_bounds),
+ param_env.reveal(),
+ param_env.constness(),
+ )
};
// Receiver: DispatchFromDyn<Receiver[Self => U]>
diff --git a/compiler/rustc_trait_selection/src/traits/project.rs b/compiler/rustc_trait_selection/src/traits/project.rs
index b8c66931cbe..490e35d34f2 100644
--- a/compiler/rustc_trait_selection/src/traits/project.rs
+++ b/compiler/rustc_trait_selection/src/traits/project.rs
@@ -20,6 +20,7 @@ use super::{Normalized, NormalizedTy, ProjectionCacheEntry, ProjectionCacheKey};
use crate::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind};
use crate::infer::{InferCtxt, InferOk, LateBoundRegionConversionTime};
use crate::traits::error_reporting::InferCtxtExt as _;
+use rustc_data_structures::sso::SsoHashSet;
use rustc_data_structures::stack::ensure_sufficient_stack;
use rustc_errors::ErrorReported;
use rustc_hir::def_id::DefId;
@@ -27,7 +28,7 @@ use rustc_hir::lang_items::LangItem;
use rustc_infer::infer::resolve::OpportunisticRegionResolver;
use rustc_middle::ty::fold::{TypeFoldable, TypeFolder};
use rustc_middle::ty::subst::Subst;
-use rustc_middle::ty::{self, ToPredicate, Ty, TyCtxt, WithConstness};
+use rustc_middle::ty::{self, ToPredicate, Ty, TyCtxt};
use rustc_span::symbol::sym;
use std::collections::BTreeMap;
@@ -569,7 +570,7 @@ impl<'me, 'tcx> BoundVarReplacer<'me, 'tcx> {
}
}
-impl TypeFolder<'tcx> for BoundVarReplacer<'_, 'tcx> {
+impl<'tcx> TypeFolder<'tcx> for BoundVarReplacer<'_, 'tcx> {
fn tcx<'b>(&'b self) -> TyCtxt<'tcx> {
self.infcx.tcx
}
@@ -677,7 +678,7 @@ impl<'me, 'tcx> PlaceholderReplacer<'me, 'tcx> {
}
}
-impl TypeFolder<'tcx> for PlaceholderReplacer<'_, 'tcx> {
+impl<'tcx> TypeFolder<'tcx> for PlaceholderReplacer<'_, 'tcx> {
fn tcx<'b>(&'b self) -> TyCtxt<'tcx> {
self.infcx.tcx
}
@@ -888,7 +889,7 @@ fn opt_normalize_projection_type<'a, 'b, 'tcx>(
debug!("recur cache");
return Err(InProgress);
}
- Err(ProjectionCacheEntry::NormalizedTy(ty)) => {
+ Err(ProjectionCacheEntry::NormalizedTy { ty, complete: _ }) => {
// This is the hottest path in this function.
//
// If we find the value in the cache, then return it along
@@ -944,9 +945,14 @@ fn opt_normalize_projection_type<'a, 'b, 'tcx>(
Normalized { value: projected_ty, obligations: projected_obligations }
};
+ let mut deduped: SsoHashSet<_> = Default::default();
let mut canonical =
SelectionContext::with_query_mode(selcx.infcx(), TraitQueryMode::Canonical);
+
result.obligations.drain_filter(|projected_obligation| {
+ if !deduped.insert(projected_obligation.clone()) {
+ return true;
+ }
// If any global obligations always apply, considering regions, then we don't
// need to include them. The `is_global` check rules out inference variables,
// so there's no need for the caller of `opt_normalize_projection_type`
@@ -1931,14 +1937,14 @@ fn assoc_ty_def(
}
}
-crate trait ProjectionCacheKeyExt<'tcx>: Sized {
+crate trait ProjectionCacheKeyExt<'cx, 'tcx>: Sized {
fn from_poly_projection_predicate(
selcx: &mut SelectionContext<'cx, 'tcx>,
predicate: ty::PolyProjectionPredicate<'tcx>,
) -> Option<Self>;
}
-impl<'tcx> ProjectionCacheKeyExt<'tcx> for ProjectionCacheKey<'tcx> {
+impl<'cx, 'tcx> ProjectionCacheKeyExt<'cx, 'tcx> for ProjectionCacheKey<'tcx> {
fn from_poly_projection_predicate(
selcx: &mut SelectionContext<'cx, 'tcx>,
predicate: ty::PolyProjectionPredicate<'tcx>,
diff --git a/compiler/rustc_trait_selection/src/traits/query/evaluate_obligation.rs b/compiler/rustc_trait_selection/src/traits/query/evaluate_obligation.rs
index 2fa6c0c0259..4874ba6f58c 100644
--- a/compiler/rustc_trait_selection/src/traits/query/evaluate_obligation.rs
+++ b/compiler/rustc_trait_selection/src/traits/query/evaluate_obligation.rs
@@ -1,3 +1,5 @@
+use rustc_middle::ty;
+
use crate::infer::canonical::OriginalQueryValues;
use crate::infer::InferCtxt;
use crate::traits::{
@@ -64,10 +66,21 @@ impl<'cx, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'cx, 'tcx> {
obligation: &PredicateObligation<'tcx>,
) -> Result<EvaluationResult, OverflowError> {
let mut _orig_values = OriginalQueryValues::default();
- let c_pred = self.canonicalize_query_keep_static(
- obligation.param_env.and(obligation.predicate),
- &mut _orig_values,
- );
+
+ let param_env = match obligation.predicate.kind().skip_binder() {
+ ty::PredicateKind::Trait(pred) => {
+ // we ignore the value set to it.
+ let mut _constness = pred.constness;
+ obligation
+ .param_env
+ .with_constness(_constness.and(obligation.param_env.constness()))
+ }
+ // constness has no effect on the given predicate.
+ _ => obligation.param_env.without_const(),
+ };
+
+ let c_pred = self
+ .canonicalize_query_keep_static(param_env.and(obligation.predicate), &mut _orig_values);
// Run canonical query. If overflow occurs, rerun from scratch but this time
// in standard trait query mode so that overflow is handled appropriately
// within `SelectionContext`.
diff --git a/compiler/rustc_trait_selection/src/traits/query/normalize.rs b/compiler/rustc_trait_selection/src/traits/query/normalize.rs
index 1364cf1c995..26bacf787e2 100644
--- a/compiler/rustc_trait_selection/src/traits/query/normalize.rs
+++ b/compiler/rustc_trait_selection/src/traits/query/normalize.rs
@@ -12,7 +12,7 @@ use rustc_data_structures::sso::SsoHashMap;
use rustc_data_structures::stack::ensure_sufficient_stack;
use rustc_infer::traits::Normalized;
use rustc_middle::mir;
-use rustc_middle::ty::fold::{TypeFoldable, TypeFolder};
+use rustc_middle::ty::fold::{FallibleTypeFolder, TypeFoldable, TypeFolder};
use rustc_middle::ty::subst::Subst;
use rustc_middle::ty::{self, Ty, TyCtxt, TypeVisitor};
@@ -61,7 +61,6 @@ impl<'cx, 'tcx> AtExt<'tcx> for At<'cx, 'tcx> {
cause: self.cause,
param_env: self.param_env,
obligations: vec![],
- error: false,
cache: SsoHashMap::new(),
anon_depth: 0,
universes: vec![],
@@ -88,7 +87,7 @@ impl<'cx, 'tcx> AtExt<'tcx> for At<'cx, 'tcx> {
normalizer.universes.extend((0..max_visitor.escaping).map(|_| None));
}
}
- let result = value.fold_with(&mut normalizer);
+ let result = value.try_fold_with(&mut normalizer);
info!(
"normalize::<{}>: result={:?} with {} obligations",
std::any::type_name::<T>(),
@@ -100,11 +99,7 @@ impl<'cx, 'tcx> AtExt<'tcx> for At<'cx, 'tcx> {
std::any::type_name::<T>(),
normalizer.obligations,
);
- if normalizer.error {
- Err(NoSolution)
- } else {
- Ok(Normalized { value: result, obligations: normalizer.obligations })
- }
+ result.map(|value| Normalized { value, obligations: normalizer.obligations })
}
}
@@ -171,34 +166,37 @@ struct QueryNormalizer<'cx, 'tcx> {
param_env: ty::ParamEnv<'tcx>,
obligations: Vec<PredicateObligation<'tcx>>,
cache: SsoHashMap<Ty<'tcx>, Ty<'tcx>>,
- error: bool,
anon_depth: usize,
universes: Vec<Option<ty::UniverseIndex>>,
}
impl<'cx, 'tcx> TypeFolder<'tcx> for QueryNormalizer<'cx, 'tcx> {
+ type Error = NoSolution;
+
fn tcx<'c>(&'c self) -> TyCtxt<'tcx> {
self.infcx.tcx
}
+}
- fn fold_binder<T: TypeFoldable<'tcx>>(
+impl<'cx, 'tcx> FallibleTypeFolder<'tcx> for QueryNormalizer<'cx, 'tcx> {
+ fn try_fold_binder<T: TypeFoldable<'tcx>>(
&mut self,
t: ty::Binder<'tcx, T>,
- ) -> ty::Binder<'tcx, T> {
+ ) -> Result<ty::Binder<'tcx, T>, Self::Error> {
self.universes.push(None);
- let t = t.super_fold_with(self);
+ let t = t.try_super_fold_with(self);
self.universes.pop();
t
}
#[instrument(level = "debug", skip(self))]
- fn fold_ty(&mut self, ty: Ty<'tcx>) -> Ty<'tcx> {
+ fn try_fold_ty(&mut self, ty: Ty<'tcx>) -> Result<Ty<'tcx>, Self::Error> {
if !needs_normalization(&ty, self.param_env.reveal()) {
- return ty;
+ return Ok(ty);
}
if let Some(ty) = self.cache.get(&ty) {
- return ty;
+ return Ok(ty);
}
// See note in `rustc_trait_selection::traits::project` about why we
@@ -212,10 +210,10 @@ impl<'cx, 'tcx> TypeFolder<'tcx> for QueryNormalizer<'cx, 'tcx> {
ty::Opaque(def_id, substs) if !substs.has_escaping_bound_vars() => {
// Only normalize `impl Trait` after type-checking, usually in codegen.
match self.param_env.reveal() {
- Reveal::UserFacing => ty.super_fold_with(self),
+ Reveal::UserFacing => ty.try_super_fold_with(self),
Reveal::All => {
- let substs = substs.super_fold_with(self);
+ let substs = substs.try_super_fold_with(self)?;
let recursion_limit = self.tcx().recursion_limit();
if !recursion_limit.value_within_limit(self.anon_depth) {
let obligation = Obligation::with_depth(
@@ -240,7 +238,7 @@ impl<'cx, 'tcx> TypeFolder<'tcx> for QueryNormalizer<'cx, 'tcx> {
ty
);
}
- let folded_ty = ensure_sufficient_stack(|| self.fold_ty(concrete_ty));
+ let folded_ty = ensure_sufficient_stack(|| self.try_fold_ty(concrete_ty));
self.anon_depth -= 1;
folded_ty
}
@@ -252,7 +250,7 @@ impl<'cx, 'tcx> TypeFolder<'tcx> for QueryNormalizer<'cx, 'tcx> {
// we don't need to replace them with placeholders (see branch below).
let tcx = self.infcx.tcx;
- let data = data.super_fold_with(self);
+ let data = data.try_super_fold_with(self)?;
let mut orig_values = OriginalQueryValues::default();
// HACK(matthewjasper) `'static` is special-cased in selection,
@@ -262,39 +260,22 @@ impl<'cx, 'tcx> TypeFolder<'tcx> for QueryNormalizer<'cx, 'tcx> {
.canonicalize_query_keep_static(self.param_env.and(data), &mut orig_values);
debug!("QueryNormalizer: c_data = {:#?}", c_data);
debug!("QueryNormalizer: orig_values = {:#?}", orig_values);
- match tcx.normalize_projection_ty(c_data) {
- Ok(result) => {
- // We don't expect ambiguity.
- if result.is_ambiguous() {
- self.error = true;
- return ty.super_fold_with(self);
- }
-
- match self.infcx.instantiate_query_response_and_region_obligations(
- self.cause,
- self.param_env,
- &orig_values,
- result,
- ) {
- Ok(InferOk { value: result, obligations }) => {
- debug!("QueryNormalizer: result = {:#?}", result);
- debug!("QueryNormalizer: obligations = {:#?}", obligations);
- self.obligations.extend(obligations);
- result.normalized_ty
- }
-
- Err(_) => {
- self.error = true;
- ty.super_fold_with(self)
- }
- }
- }
-
- Err(NoSolution) => {
- self.error = true;
- ty.super_fold_with(self)
- }
+ let result = tcx.normalize_projection_ty(c_data)?;
+ // We don't expect ambiguity.
+ if result.is_ambiguous() {
+ return Err(NoSolution);
}
+ let InferOk { value: result, obligations } =
+ self.infcx.instantiate_query_response_and_region_obligations(
+ self.cause,
+ self.param_env,
+ &orig_values,
+ result,
+ )?;
+ debug!("QueryNormalizer: result = {:#?}", result);
+ debug!("QueryNormalizer: obligations = {:#?}", obligations);
+ self.obligations.extend(obligations);
+ Ok(result.normalized_ty)
}
ty::Projection(data) => {
@@ -308,7 +289,7 @@ impl<'cx, 'tcx> TypeFolder<'tcx> for QueryNormalizer<'cx, 'tcx> {
&mut self.universes,
data,
);
- let data = data.super_fold_with(self);
+ let data = data.try_super_fold_with(self)?;
let mut orig_values = OriginalQueryValues::default();
// HACK(matthewjasper) `'static` is special-cased in selection,
@@ -318,57 +299,49 @@ impl<'cx, 'tcx> TypeFolder<'tcx> for QueryNormalizer<'cx, 'tcx> {
.canonicalize_query_keep_static(self.param_env.and(data), &mut orig_values);
debug!("QueryNormalizer: c_data = {:#?}", c_data);
debug!("QueryNormalizer: orig_values = {:#?}", orig_values);
- match tcx.normalize_projection_ty(c_data) {
- Ok(result) => {
- // We don't expect ambiguity.
- if result.is_ambiguous() {
- self.error = true;
- return ty.super_fold_with(self);
- }
- match self.infcx.instantiate_query_response_and_region_obligations(
- self.cause,
- self.param_env,
- &orig_values,
- result,
- ) {
- Ok(InferOk { value: result, obligations }) => {
- debug!("QueryNormalizer: result = {:#?}", result);
- debug!("QueryNormalizer: obligations = {:#?}", obligations);
- self.obligations.extend(obligations);
- crate::traits::project::PlaceholderReplacer::replace_placeholders(
- infcx,
- mapped_regions,
- mapped_types,
- mapped_consts,
- &self.universes,
- result.normalized_ty,
- )
- }
- Err(_) => {
- self.error = true;
- ty.super_fold_with(self)
- }
- }
- }
- Err(NoSolution) => {
- self.error = true;
- ty.super_fold_with(self)
- }
+ let result = tcx.normalize_projection_ty(c_data)?;
+ // We don't expect ambiguity.
+ if result.is_ambiguous() {
+ return Err(NoSolution);
}
+ let InferOk { value: result, obligations } =
+ self.infcx.instantiate_query_response_and_region_obligations(
+ self.cause,
+ self.param_env,
+ &orig_values,
+ result,
+ )?;
+ debug!("QueryNormalizer: result = {:#?}", result);
+ debug!("QueryNormalizer: obligations = {:#?}", obligations);
+ self.obligations.extend(obligations);
+ Ok(crate::traits::project::PlaceholderReplacer::replace_placeholders(
+ infcx,
+ mapped_regions,
+ mapped_types,
+ mapped_consts,
+ &self.universes,
+ result.normalized_ty,
+ ))
}
- _ => ty.super_fold_with(self),
- })();
+ _ => ty.try_super_fold_with(self),
+ })()?;
self.cache.insert(ty, res);
- res
+ Ok(res)
}
- fn fold_const(&mut self, constant: &'tcx ty::Const<'tcx>) -> &'tcx ty::Const<'tcx> {
- let constant = constant.super_fold_with(self);
- constant.eval(self.infcx.tcx, self.param_env)
+ fn try_fold_const(
+ &mut self,
+ constant: &'tcx ty::Const<'tcx>,
+ ) -> Result<&'tcx ty::Const<'tcx>, Self::Error> {
+ let constant = constant.try_super_fold_with(self)?;
+ Ok(constant.eval(self.infcx.tcx, self.param_env))
}
- fn fold_mir_const(&mut self, constant: mir::ConstantKind<'tcx>) -> mir::ConstantKind<'tcx> {
- constant.super_fold_with(self)
+ fn try_fold_mir_const(
+ &mut self,
+ constant: mir::ConstantKind<'tcx>,
+ ) -> Result<mir::ConstantKind<'tcx>, Self::Error> {
+ constant.try_super_fold_with(self)
}
}
diff --git a/compiler/rustc_trait_selection/src/traits/query/type_op/normalize.rs b/compiler/rustc_trait_selection/src/traits/query/type_op/normalize.rs
index 729b66ac21c..e92ca7325d3 100644
--- a/compiler/rustc_trait_selection/src/traits/query/type_op/normalize.rs
+++ b/compiler/rustc_trait_selection/src/traits/query/type_op/normalize.rs
@@ -31,7 +31,7 @@ pub trait Normalizable<'tcx>: fmt::Debug + TypeFoldable<'tcx> + Lift<'tcx> + Cop
) -> Fallible<CanonicalizedQueryResponse<'tcx, Self>>;
}
-impl Normalizable<'tcx> for Ty<'tcx> {
+impl<'tcx> Normalizable<'tcx> for Ty<'tcx> {
fn type_op_method(
tcx: TyCtxt<'tcx>,
canonicalized: Canonicalized<'tcx, ParamEnvAnd<'tcx, Normalize<Self>>>,
@@ -40,7 +40,7 @@ impl Normalizable<'tcx> for Ty<'tcx> {
}
}
-impl Normalizable<'tcx> for ty::Predicate<'tcx> {
+impl<'tcx> Normalizable<'tcx> for ty::Predicate<'tcx> {
fn type_op_method(
tcx: TyCtxt<'tcx>,
canonicalized: Canonicalized<'tcx, ParamEnvAnd<'tcx, Normalize<Self>>>,
@@ -49,7 +49,7 @@ impl Normalizable<'tcx> for ty::Predicate<'tcx> {
}
}
-impl Normalizable<'tcx> for ty::PolyFnSig<'tcx> {
+impl<'tcx> Normalizable<'tcx> for ty::PolyFnSig<'tcx> {
fn type_op_method(
tcx: TyCtxt<'tcx>,
canonicalized: Canonicalized<'tcx, ParamEnvAnd<'tcx, Normalize<Self>>>,
@@ -58,7 +58,7 @@ impl Normalizable<'tcx> for ty::PolyFnSig<'tcx> {
}
}
-impl Normalizable<'tcx> for ty::FnSig<'tcx> {
+impl<'tcx> Normalizable<'tcx> for ty::FnSig<'tcx> {
fn type_op_method(
tcx: TyCtxt<'tcx>,
canonicalized: Canonicalized<'tcx, ParamEnvAnd<'tcx, Normalize<Self>>>,
diff --git a/compiler/rustc_trait_selection/src/traits/query/type_op/outlives.rs b/compiler/rustc_trait_selection/src/traits/query/type_op/outlives.rs
index 5a27e57860e..82f147f8143 100644
--- a/compiler/rustc_trait_selection/src/traits/query/type_op/outlives.rs
+++ b/compiler/rustc_trait_selection/src/traits/query/type_op/outlives.rs
@@ -14,7 +14,7 @@ impl<'tcx> DropckOutlives<'tcx> {
}
}
-impl super::QueryTypeOp<'tcx> for DropckOutlives<'tcx> {
+impl<'tcx> super::QueryTypeOp<'tcx> for DropckOutlives<'tcx> {
type QueryResponse = DropckOutlivesResult<'tcx>;
fn try_fast_path(
diff --git a/compiler/rustc_trait_selection/src/traits/query/type_op/prove_predicate.rs b/compiler/rustc_trait_selection/src/traits/query/type_op/prove_predicate.rs
index 02e9b4d0f0e..081308ac73e 100644
--- a/compiler/rustc_trait_selection/src/traits/query/type_op/prove_predicate.rs
+++ b/compiler/rustc_trait_selection/src/traits/query/type_op/prove_predicate.rs
@@ -30,8 +30,14 @@ impl<'tcx> super::QueryTypeOp<'tcx> for ProvePredicate<'tcx> {
fn perform_query(
tcx: TyCtxt<'tcx>,
- canonicalized: Canonicalized<'tcx, ParamEnvAnd<'tcx, Self>>,
+ mut canonicalized: Canonicalized<'tcx, ParamEnvAnd<'tcx, Self>>,
) -> Fallible<CanonicalizedQueryResponse<'tcx, ()>> {
+ match canonicalized.value.value.predicate.kind().skip_binder() {
+ ty::PredicateKind::Trait(pred) => {
+ canonicalized.value.param_env.remap_constness_with(pred.constness);
+ }
+ _ => canonicalized.value.param_env = canonicalized.value.param_env.without_const(),
+ }
tcx.type_op_prove_predicate(canonicalized)
}
}
diff --git a/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs b/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs
index 1d0c54f86de..017f47d4357 100644
--- a/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs
+++ b/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs
@@ -11,7 +11,7 @@ use rustc_infer::traits::TraitEngine;
use rustc_infer::traits::{Obligation, SelectionError, TraitObligation};
use rustc_lint_defs::builtin::DEREF_INTO_DYN_SUPERTRAIT;
use rustc_middle::ty::print::with_no_trimmed_paths;
-use rustc_middle::ty::{self, ToPredicate, Ty, TypeFoldable, WithConstness};
+use rustc_middle::ty::{self, ToPredicate, Ty, TypeFoldable};
use rustc_target::spec::abi::Abi;
use crate::traits;
@@ -303,8 +303,8 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
} else if lang_items.drop_trait() == Some(def_id)
&& obligation.predicate.skip_binder().constness == ty::BoundConstness::ConstIfConst
{
- if self.is_in_const_context {
- self.assemble_const_drop_candidates(obligation, &mut candidates)?;
+ if obligation.param_env.constness() == hir::Constness::Const {
+ self.assemble_const_drop_candidates(obligation, stack, &mut candidates)?;
} else {
debug!("passing ~const Drop bound; in non-const context");
// `~const Drop` when we are not in a const context has no effect.
@@ -362,9 +362,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
.infcx
.probe(|_| self.match_projection_obligation_against_definition_bounds(obligation));
- for predicate_index in result {
- candidates.vec.push(ProjectionCandidate(predicate_index));
- }
+ candidates.vec.extend(result.into_iter().map(ProjectionCandidate));
}
/// Given an obligation like `<SomeTrait for T>`, searches the obligations that the caller
@@ -383,17 +381,19 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
.param_env
.caller_bounds()
.iter()
- .filter_map(|o| o.to_opt_poly_trait_ref());
+ .filter_map(|o| o.to_opt_poly_trait_pred());
// Micro-optimization: filter out predicates relating to different traits.
let matching_bounds =
- all_bounds.filter(|p| p.value.def_id() == stack.obligation.predicate.def_id());
+ all_bounds.filter(|p| p.def_id() == stack.obligation.predicate.def_id());
// Keep only those bounds which may apply, and propagate overflow if it occurs.
for bound in matching_bounds {
- let wc = self.evaluate_where_clause(stack, bound.value)?;
+ // FIXME(oli-obk): it is suspicious that we are dropping the constness and
+ // polarity here.
+ let wc = self.evaluate_where_clause(stack, bound.map_bound(|t| t.trait_ref))?;
if wc.may_apply() {
- candidates.vec.push(ParamCandidate((bound, stack.obligation.polarity())));
+ candidates.vec.push(ParamCandidate(bound));
}
}
@@ -536,7 +536,10 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
// This helps us avoid overflow: see issue #72839
// Since compilation is already guaranteed to fail, this is just
// to try to show the 'nicest' possible errors to the user.
- if obligation.references_error() {
+ // We don't check for errors in the `ParamEnv` - in practice,
+ // it seems to cause us to be overly aggressive in deciding
+ // to give up searching for candidates, leading to spurious errors.
+ if obligation.predicate.references_error() {
return;
}
@@ -911,9 +914,10 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
}
}
- fn assemble_const_drop_candidates(
+ fn assemble_const_drop_candidates<'a>(
&mut self,
obligation: &TraitObligation<'tcx>,
+ obligation_stack: &TraitObligationStack<'a, 'tcx>,
candidates: &mut SelectionCandidateSet<'tcx>,
) -> Result<(), SelectionError<'tcx>> {
let mut stack: Vec<(Ty<'tcx>, usize)> = vec![(obligation.self_ty().skip_binder(), 0)];
@@ -922,7 +926,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
let mut noreturn = false;
self.check_recursion_depth(depth, obligation)?;
- let mut copy_candidates = SelectionCandidateSet { vec: Vec::new(), ambiguous: false };
+ let mut new_candidates = SelectionCandidateSet { vec: Vec::new(), ambiguous: false };
let mut copy_obligation =
obligation.with(obligation.predicate.rebind(ty::TraitPredicate {
trait_ref: ty::TraitRef {
@@ -933,13 +937,29 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
polarity: ty::ImplPolarity::Positive,
}));
copy_obligation.recursion_depth = depth + 1;
- self.assemble_candidates_from_impls(&copy_obligation, &mut copy_candidates);
+ self.assemble_candidates_from_impls(&copy_obligation, &mut new_candidates);
let copy_conditions = self.copy_clone_conditions(&copy_obligation);
- self.assemble_builtin_bound_candidates(copy_conditions, &mut copy_candidates);
- if !copy_candidates.vec.is_empty() {
+ self.assemble_builtin_bound_candidates(copy_conditions, &mut new_candidates);
+ let copy_stack = self.push_stack(obligation_stack.list(), &copy_obligation);
+ self.assemble_candidates_from_caller_bounds(&copy_stack, &mut new_candidates)?;
+
+ let const_drop_obligation =
+ obligation.with(obligation.predicate.rebind(ty::TraitPredicate {
+ trait_ref: ty::TraitRef {
+ def_id: self.tcx().require_lang_item(hir::LangItem::Drop, None),
+ substs: self.tcx().mk_substs_trait(ty, &[]),
+ },
+ constness: ty::BoundConstness::ConstIfConst,
+ polarity: ty::ImplPolarity::Positive,
+ }));
+
+ let const_drop_stack = self.push_stack(obligation_stack.list(), &const_drop_obligation);
+ self.assemble_candidates_from_caller_bounds(&const_drop_stack, &mut new_candidates)?;
+
+ if !new_candidates.vec.is_empty() {
noreturn = true;
}
- debug!(?copy_candidates.vec, "assemble_const_drop_candidates - copy");
+ debug!(?new_candidates.vec, "assemble_const_drop_candidates");
match ty.kind() {
ty::Int(_)
diff --git a/compiler/rustc_trait_selection/src/traits/select/confirmation.rs b/compiler/rustc_trait_selection/src/traits/select/confirmation.rs
index 2f1f7971a79..e9b368f683e 100644
--- a/compiler/rustc_trait_selection/src/traits/select/confirmation.rs
+++ b/compiler/rustc_trait_selection/src/traits/select/confirmation.rs
@@ -13,7 +13,7 @@ use rustc_infer::infer::InferOk;
use rustc_infer::infer::LateBoundRegionConversionTime::HigherRankedType;
use rustc_middle::ty::subst::{GenericArg, GenericArgKind, Subst, SubstsRef};
use rustc_middle::ty::{self, Ty};
-use rustc_middle::ty::{ToPolyTraitRef, ToPredicate, WithConstness};
+use rustc_middle::ty::{ToPolyTraitRef, ToPredicate};
use rustc_span::def_id::DefId;
use crate::traits::project::{normalize_with_depth, normalize_with_depth_to};
@@ -58,8 +58,9 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
}
ParamCandidate(param) => {
- let obligations = self.confirm_param_candidate(obligation, param.0.value);
- Ok(ImplSource::Param(obligations, param.0.constness))
+ let obligations =
+ self.confirm_param_candidate(obligation, param.map_bound(|t| t.trait_ref));
+ Ok(ImplSource::Param(obligations, param.skip_binder().constness))
}
ImplCandidate(impl_def_id) => {
@@ -139,7 +140,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
let trait_predicate = self.infcx.shallow_resolve(obligation.predicate);
let placeholder_trait_predicate =
- self.infcx().replace_bound_vars_with_placeholders(trait_predicate);
+ self.infcx().replace_bound_vars_with_placeholders(trait_predicate).trait_ref;
let placeholder_self_ty = placeholder_trait_predicate.self_ty();
let placeholder_trait_predicate = ty::Binder::dummy(placeholder_trait_predicate);
let (def_id, substs) = match *placeholder_self_ty.kind() {
@@ -150,8 +151,9 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
let candidate_predicate = tcx.item_bounds(def_id)[idx].subst(tcx, substs);
let candidate = candidate_predicate
- .to_opt_poly_trait_ref()
- .expect("projection candidate is not a trait predicate");
+ .to_opt_poly_trait_pred()
+ .expect("projection candidate is not a trait predicate")
+ .map_bound(|t| t.trait_ref);
let mut obligations = Vec::new();
let candidate = normalize_with_depth_to(
self,
@@ -165,7 +167,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
obligations.extend(self.infcx.commit_if_ok(|_| {
self.infcx
.at(&obligation.cause, obligation.param_env)
- .sup(placeholder_trait_predicate.to_poly_trait_ref(), candidate.value)
+ .sup(placeholder_trait_predicate, candidate)
.map(|InferOk { obligations, .. }| obligations)
.map_err(|_| Unimplemented)
})?);
diff --git a/compiler/rustc_trait_selection/src/traits/select/mod.rs b/compiler/rustc_trait_selection/src/traits/select/mod.rs
index 2aa214694cb..77b8fc49a15 100644
--- a/compiler/rustc_trait_selection/src/traits/select/mod.rs
+++ b/compiler/rustc_trait_selection/src/traits/select/mod.rs
@@ -25,6 +25,8 @@ use super::{ObligationCause, PredicateObligation, TraitObligation};
use crate::infer::{InferCtxt, InferOk, TypeFreshener};
use crate::traits::error_reporting::InferCtxtExt;
+use crate::traits::project::ProjectionCacheKeyExt;
+use crate::traits::ProjectionCacheKey;
use rustc_data_structures::fx::{FxHashMap, FxHashSet};
use rustc_data_structures::stack::ensure_sufficient_stack;
use rustc_data_structures::sync::Lrc;
@@ -35,11 +37,10 @@ use rustc_infer::infer::LateBoundRegionConversionTime;
use rustc_middle::dep_graph::{DepKind, DepNodeIndex};
use rustc_middle::mir::interpret::ErrorHandled;
use rustc_middle::thir::abstract_const::NotConstEvaluatable;
-use rustc_middle::ty::fast_reject;
+use rustc_middle::ty::fast_reject::{self, SimplifyParams, StripReferences};
use rustc_middle::ty::print::with_no_trimmed_paths;
use rustc_middle::ty::relate::TypeRelation;
use rustc_middle::ty::subst::{GenericArgKind, Subst, SubstsRef};
-use rustc_middle::ty::WithConstness;
use rustc_middle::ty::{self, PolyProjectionPredicate, ToPolyTraitRef, ToPredicate};
use rustc_middle::ty::{Ty, TyCtxt, TypeFoldable};
use rustc_span::symbol::sym;
@@ -128,9 +129,6 @@ pub struct SelectionContext<'cx, 'tcx> {
/// and a negative impl
allow_negative_impls: bool,
- /// Are we in a const context that needs `~const` bounds to be const?
- is_in_const_context: bool,
-
/// The mode that trait queries run in, which informs our error handling
/// policy. In essence, canonicalized queries need their errors propagated
/// rather than immediately reported because we do not have accurate spans.
@@ -141,9 +139,9 @@ pub struct SelectionContext<'cx, 'tcx> {
struct TraitObligationStack<'prev, 'tcx> {
obligation: &'prev TraitObligation<'tcx>,
- /// The trait ref from `obligation` but "freshened" with the
+ /// The trait predicate from `obligation` but "freshened" with the
/// selection-context's freshener. Used to check for recursion.
- fresh_trait_ref: ty::ConstnessAnd<ty::PolyTraitRef<'tcx>>,
+ fresh_trait_pred: ty::PolyTraitPredicate<'tcx>,
/// Starts out equal to `depth` -- if, during evaluation, we
/// encounter a cycle, then we will set this flag to the minimum
@@ -222,7 +220,6 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
intercrate: false,
intercrate_ambiguity_causes: None,
allow_negative_impls: false,
- is_in_const_context: false,
query_mode: TraitQueryMode::Standard,
}
}
@@ -234,7 +231,6 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
intercrate: true,
intercrate_ambiguity_causes: None,
allow_negative_impls: false,
- is_in_const_context: false,
query_mode: TraitQueryMode::Standard,
}
}
@@ -250,7 +246,6 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
intercrate: false,
intercrate_ambiguity_causes: None,
allow_negative_impls,
- is_in_const_context: false,
query_mode: TraitQueryMode::Standard,
}
}
@@ -266,26 +261,10 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
intercrate: false,
intercrate_ambiguity_causes: None,
allow_negative_impls: false,
- is_in_const_context: false,
query_mode,
}
}
- pub fn with_constness(
- infcx: &'cx InferCtxt<'cx, 'tcx>,
- constness: hir::Constness,
- ) -> SelectionContext<'cx, 'tcx> {
- SelectionContext {
- infcx,
- freshener: infcx.freshener_keep_static(),
- intercrate: false,
- intercrate_ambiguity_causes: None,
- allow_negative_impls: false,
- is_in_const_context: matches!(constness, hir::Constness::Const),
- query_mode: TraitQueryMode::Standard,
- }
- }
-
/// Enables tracking of intercrate ambiguity causes. These are
/// used in coherence to give improved diagnostics. We don't do
/// this until we detect a coherence error because it can lead to
@@ -318,20 +297,6 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
self.intercrate
}
- /// Returns `true` if the trait predicate is considerd `const` to this selection context.
- pub fn is_trait_predicate_const(&self, pred: ty::TraitPredicate<'_>) -> bool {
- matches!(pred.constness, ty::BoundConstness::ConstIfConst) && self.is_in_const_context
- }
-
- /// Returns `true` if the predicate is considered `const` to
- /// this selection context.
- pub fn is_predicate_const(&self, pred: ty::Predicate<'_>) -> bool {
- match pred.kind().skip_binder() {
- ty::PredicateKind::Trait(pred) => self.is_trait_predicate_const(pred),
- _ => false,
- }
- }
-
///////////////////////////////////////////////////////////////////////////
// Selection
//
@@ -558,7 +523,11 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
},
ty::PredicateKind::TypeOutlives(pred) => {
- if pred.0.is_known_global() {
+ // A global type with no late-bound regions can only
+ // contain the "'static" lifetime (any other lifetime
+ // would either be late-bound or local), so it is guaranteed
+ // to outlive any other lifetime
+ if pred.0.is_global(self.infcx.tcx) && !pred.0.has_late_bound_regions() {
Ok(EvaluatedToOk)
} else {
Ok(EvaluatedToOkModuloRegions)
@@ -583,8 +552,54 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
let project_obligation = obligation.with(data);
match project::poly_project_and_unify_type(self, &project_obligation) {
Ok(Ok(Some(mut subobligations))) => {
- self.add_depth(subobligations.iter_mut(), obligation.recursion_depth);
- self.evaluate_predicates_recursively(previous_stack, subobligations)
+ 'compute_res: {
+ // If we've previously marked this projection as 'complete', thne
+ // use the final cached result (either `EvaluatedToOk` or
+ // `EvaluatedToOkModuloRegions`), and skip re-evaluating the
+ // sub-obligations.
+ if let Some(key) =
+ ProjectionCacheKey::from_poly_projection_predicate(self, data)
+ {
+ if let Some(cached_res) = self
+ .infcx
+ .inner
+ .borrow_mut()
+ .projection_cache()
+ .is_complete(key)
+ {
+ break 'compute_res Ok(cached_res);
+ }
+ }
+
+ self.add_depth(
+ subobligations.iter_mut(),
+ obligation.recursion_depth,
+ );
+ let res = self.evaluate_predicates_recursively(
+ previous_stack,
+ subobligations,
+ );
+ if let Ok(res) = res {
+ if res == EvaluatedToOk || res == EvaluatedToOkModuloRegions {
+ if let Some(key) =
+ ProjectionCacheKey::from_poly_projection_predicate(
+ self, data,
+ )
+ {
+ // If the result is something that we can cache, then mark this
+ // entry as 'complete'. This will allow us to skip evaluating the
+ // suboligations at all the next time we evaluate the projection
+ // predicate.
+ self.infcx
+ .inner
+ .borrow_mut()
+ .projection_cache()
+ .complete(key, res);
+ }
+ }
+ }
+ res
+ }
}
Ok(Ok(None)) => Ok(EvaluatedToAmbig),
Ok(Err(project::InProgress)) => Ok(EvaluatedToRecur),
@@ -712,20 +727,22 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
}
let stack = self.push_stack(previous_stack, &obligation);
- let fresh_trait_ref = stack.fresh_trait_ref;
+ let mut fresh_trait_pred = stack.fresh_trait_pred;
+ let mut param_env = obligation.param_env;
- debug!(?fresh_trait_ref);
+ fresh_trait_pred = fresh_trait_pred.map_bound(|mut pred| {
+ param_env = param_env.with_constness(pred.constness.and(param_env.constness()));
+ pred
+ });
- if let Some(result) = self.check_evaluation_cache(
- obligation.param_env,
- fresh_trait_ref,
- obligation.polarity(),
- ) {
+ debug!(?fresh_trait_pred);
+
+ if let Some(result) = self.check_evaluation_cache(param_env, fresh_trait_pred) {
debug!(?result, "CACHE HIT");
return Ok(result);
}
- if let Some(result) = stack.cache().get_provisional(fresh_trait_ref) {
+ if let Some(result) = stack.cache().get_provisional(fresh_trait_pred) {
debug!(?result, "PROVISIONAL CACHE HIT");
stack.update_reached_depth(result.reached_depth);
return Ok(result.result);
@@ -750,19 +767,12 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
let reached_depth = stack.reached_depth.get();
if reached_depth >= stack.depth {
debug!(?result, "CACHE MISS");
- self.insert_evaluation_cache(
- obligation.param_env,
- fresh_trait_ref,
- obligation.polarity(),
- dep_node,
- result,
- );
+ self.insert_evaluation_cache(param_env, fresh_trait_pred, dep_node, result);
- stack.cache().on_completion(stack.dfn, |fresh_trait_ref, provisional_result| {
+ stack.cache().on_completion(stack.dfn, |fresh_trait_pred, provisional_result| {
self.insert_evaluation_cache(
- obligation.param_env,
- fresh_trait_ref,
- obligation.polarity(),
+ param_env,
+ fresh_trait_pred,
dep_node,
provisional_result.max(result),
);
@@ -772,10 +782,10 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
debug!(
"caching provisionally because {:?} \
is a cycle participant (at depth {}, reached depth {})",
- fresh_trait_ref, stack.depth, reached_depth,
+ fresh_trait_pred, stack.depth, reached_depth,
);
- stack.cache().insert_provisional(stack.dfn, reached_depth, fresh_trait_ref, result);
+ stack.cache().insert_provisional(stack.dfn, reached_depth, fresh_trait_pred, result);
}
Ok(result)
@@ -809,7 +819,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
.skip(1) // Skip top-most frame.
.find(|prev| {
stack.obligation.param_env == prev.obligation.param_env
- && stack.fresh_trait_ref == prev.fresh_trait_ref
+ && stack.fresh_trait_pred == prev.fresh_trait_pred
})
.map(|stack| stack.depth)
{
@@ -872,7 +882,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
// terms of `Fn` etc, but we could probably make this more
// precise still.
let unbound_input_types =
- stack.fresh_trait_ref.value.skip_binder().substs.types().any(|ty| ty.is_fresh());
+ stack.fresh_trait_pred.skip_binder().trait_ref.substs.types().any(|ty| ty.is_fresh());
if stack.obligation.polarity() != ty::ImplPolarity::Negative {
// This check was an imperfect workaround for a bug in the old
@@ -910,8 +920,8 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
&& stack.iter().skip(1).any(|prev| {
stack.obligation.param_env == prev.obligation.param_env
&& self.match_fresh_trait_refs(
- stack.fresh_trait_ref,
- prev.fresh_trait_ref,
+ stack.fresh_trait_pred,
+ prev.fresh_trait_pred,
prev.obligation.param_env,
)
})
@@ -989,7 +999,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
// not just the lifetime choice for this particular (non-erased)
// predicate.
// See issue #80691
- if stack.fresh_trait_ref.has_erased_regions() {
+ if stack.fresh_trait_pred.has_erased_regions() {
result = result.max(EvaluatedToOkModuloRegions);
}
@@ -1000,8 +1010,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
fn check_evaluation_cache(
&self,
param_env: ty::ParamEnv<'tcx>,
- trait_ref: ty::ConstnessAnd<ty::PolyTraitRef<'tcx>>,
- polarity: ty::ImplPolarity,
+ trait_pred: ty::PolyTraitPredicate<'tcx>,
) -> Option<EvaluationResult> {
// Neither the global nor local cache is aware of intercrate
// mode, so don't do any caching. In particular, we might
@@ -1013,19 +1022,17 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
let tcx = self.tcx();
if self.can_use_global_caches(param_env) {
- if let Some(res) = tcx.evaluation_cache.get(&(param_env.and(trait_ref), polarity), tcx)
- {
+ if let Some(res) = tcx.evaluation_cache.get(&param_env.and(trait_pred), tcx) {
return Some(res);
}
}
- self.infcx.evaluation_cache.get(&(param_env.and(trait_ref), polarity), tcx)
+ self.infcx.evaluation_cache.get(&param_env.and(trait_pred), tcx)
}
fn insert_evaluation_cache(
&mut self,
param_env: ty::ParamEnv<'tcx>,
- trait_ref: ty::ConstnessAnd<ty::PolyTraitRef<'tcx>>,
- polarity: ty::ImplPolarity,
+ trait_pred: ty::PolyTraitPredicate<'tcx>,
dep_node: DepNodeIndex,
result: EvaluationResult,
) {
@@ -1044,23 +1051,19 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
}
if self.can_use_global_caches(param_env) {
- if !trait_ref.needs_infer() {
- debug!(?trait_ref, ?result, "insert_evaluation_cache global");
+ if !trait_pred.needs_infer() {
+ debug!(?trait_pred, ?result, "insert_evaluation_cache global");
// This may overwrite the cache with the same value
// FIXME: Due to #50507 this overwrites the different values
// This should be changed to use HashMapExt::insert_same
// when that is fixed
- self.tcx().evaluation_cache.insert(
- (param_env.and(trait_ref), polarity),
- dep_node,
- result,
- );
+ self.tcx().evaluation_cache.insert(param_env.and(trait_pred), dep_node, result);
return;
}
}
- debug!(?trait_ref, ?result, "insert_evaluation_cache");
- self.infcx.evaluation_cache.insert((param_env.and(trait_ref), polarity), dep_node, result);
+ debug!(?trait_pred, ?result, "insert_evaluation_cache");
+ self.infcx.evaluation_cache.insert(param_env.and(trait_pred), dep_node, result);
}
/// For various reasons, it's possible for a subobligation
@@ -1138,16 +1141,15 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
for candidate in candidates {
// Respect const trait obligations
- if self.is_trait_predicate_const(obligation.predicate.skip_binder()) {
+ if obligation.is_const() {
match candidate {
// const impl
ImplCandidate(def_id)
if tcx.impl_constness(def_id) == hir::Constness::Const => {}
// const param
- ParamCandidate((
- ty::ConstnessAnd { constness: ty::BoundConstness::ConstIfConst, .. },
- _,
- )) => {}
+ ParamCandidate(trait_pred)
+ if trait_pred.skip_binder().constness
+ == ty::BoundConstness::ConstIfConst => {}
// auto trait impl
AutoImplCandidate(..) => {}
// generator, this will raise error in other places
@@ -1256,7 +1258,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
fn check_candidate_cache(
&mut self,
- param_env: ty::ParamEnv<'tcx>,
+ mut param_env: ty::ParamEnv<'tcx>,
cache_fresh_trait_pred: ty::PolyTraitPredicate<'tcx>,
) -> Option<SelectionResult<'tcx, SelectionCandidate<'tcx>>> {
// Neither the global nor local cache is aware of intercrate
@@ -1267,19 +1269,15 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
return None;
}
let tcx = self.tcx();
- let pred = &cache_fresh_trait_pred.skip_binder();
- let trait_ref = pred.trait_ref;
+ let mut pred = cache_fresh_trait_pred.skip_binder();
+ param_env = param_env.with_constness(pred.constness.and(param_env.constness()));
+
if self.can_use_global_caches(param_env) {
- if let Some(res) = tcx
- .selection_cache
- .get(&(param_env.and(trait_ref).with_constness(pred.constness), pred.polarity), tcx)
- {
+ if let Some(res) = tcx.selection_cache.get(&param_env.and(pred), tcx) {
return Some(res);
}
}
- self.infcx
- .selection_cache
- .get(&(param_env.and(trait_ref).with_constness(pred.constness), pred.polarity), tcx)
+ self.infcx.selection_cache.get(&param_env.and(pred), tcx)
}
/// Determines whether can we safely cache the result
@@ -1317,43 +1315,36 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
fn insert_candidate_cache(
&mut self,
- param_env: ty::ParamEnv<'tcx>,
+ mut param_env: ty::ParamEnv<'tcx>,
cache_fresh_trait_pred: ty::PolyTraitPredicate<'tcx>,
dep_node: DepNodeIndex,
candidate: SelectionResult<'tcx, SelectionCandidate<'tcx>>,
) {
let tcx = self.tcx();
- let pred = cache_fresh_trait_pred.skip_binder();
- let trait_ref = pred.trait_ref;
+ let mut pred = cache_fresh_trait_pred.skip_binder();
+
+ param_env = param_env.with_constness(pred.constness.and(param_env.constness()));
if !self.can_cache_candidate(&candidate) {
- debug!(?trait_ref, ?candidate, "insert_candidate_cache - candidate is not cacheable");
+ debug!(?pred, ?candidate, "insert_candidate_cache - candidate is not cacheable");
return;
}
if self.can_use_global_caches(param_env) {
if let Err(Overflow) = candidate {
// Don't cache overflow globally; we only produce this in certain modes.
- } else if !trait_ref.needs_infer() {
+ } else if !pred.needs_infer() {
if !candidate.needs_infer() {
- debug!(?trait_ref, ?candidate, "insert_candidate_cache global");
+ debug!(?pred, ?candidate, "insert_candidate_cache global");
// This may overwrite the cache with the same value.
- tcx.selection_cache.insert(
- (param_env.and(trait_ref).with_constness(pred.constness), pred.polarity),
- dep_node,
- candidate,
- );
+ tcx.selection_cache.insert(param_env.and(pred), dep_node, candidate);
return;
}
}
}
- debug!(?trait_ref, ?candidate, "insert_candidate_cache local");
- self.infcx.selection_cache.insert(
- (param_env.and(trait_ref).with_constness(pred.constness), pred.polarity),
- dep_node,
- candidate,
- );
+ debug!(?pred, ?candidate, "insert_candidate_cache local");
+ self.infcx.selection_cache.insert(param_env.and(pred), dep_node, candidate);
}
/// Matches a predicate against the bounds of its self type.
@@ -1544,7 +1535,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
// Check if a bound would previously have been removed when normalizing
// the param_env so that it can be given the lowest priority. See
// #50825 for the motivation for this.
- let is_global = |cand: &ty::PolyTraitRef<'tcx>| {
+ let is_global = |cand: &ty::PolyTraitPredicate<'tcx>| {
cand.is_global(self.infcx.tcx) && !cand.has_late_bound_regions()
};
@@ -1577,25 +1568,22 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
| ConstDropCandidate,
) => false,
- (
- ParamCandidate((other, other_polarity)),
- ParamCandidate((victim, victim_polarity)),
- ) => {
- let same_except_bound_vars = other.value.skip_binder()
- == victim.value.skip_binder()
- && other.constness == victim.constness
- && other_polarity == victim_polarity
- && !other.value.skip_binder().has_escaping_bound_vars();
+ (ParamCandidate(other), ParamCandidate(victim)) => {
+ let same_except_bound_vars = other.skip_binder().trait_ref
+ == victim.skip_binder().trait_ref
+ && other.skip_binder().constness == victim.skip_binder().constness
+ && other.skip_binder().polarity == victim.skip_binder().polarity
+ && !other.skip_binder().trait_ref.has_escaping_bound_vars();
if same_except_bound_vars {
// See issue #84398. In short, we can generate multiple ParamCandidates which are
// the same except for unused bound vars. Just pick the one with the fewest bound vars
// or the current one if tied (they should both evaluate to the same answer). This is
// probably best characterized as a "hack", since we might prefer to just do our
// best to *not* create essentially duplicate candidates in the first place.
- other.value.bound_vars().len() <= victim.value.bound_vars().len()
- } else if other.value == victim.value
- && victim.constness == ty::BoundConstness::NotConst
- && other_polarity == victim_polarity
+ other.bound_vars().len() <= victim.bound_vars().len()
+ } else if other.skip_binder().trait_ref == victim.skip_binder().trait_ref
+ && victim.skip_binder().constness == ty::BoundConstness::NotConst
+ && other.skip_binder().polarity == victim.skip_binder().polarity
{
// Drop otherwise equivalent non-const candidates in favor of const candidates.
true
@@ -1625,11 +1613,11 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
| TraitAliasCandidate(..)
| ObjectCandidate(_)
| ProjectionCandidate(_),
- ) => !is_global(&cand.0.value),
+ ) => !is_global(cand),
(ObjectCandidate(_) | ProjectionCandidate(_), ParamCandidate(ref cand)) => {
// Prefer these to a global where-clause bound
// (see issue #50825).
- is_global(&cand.0.value)
+ is_global(cand)
}
(
ImplCandidate(_)
@@ -1645,7 +1633,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
) => {
// Prefer these to a global where-clause bound
// (see issue #50825).
- is_global(&cand.0.value) && other.evaluation.must_apply_modulo_regions()
+ is_global(cand) && other.evaluation.must_apply_modulo_regions()
}
(ProjectionCandidate(i), ProjectionCandidate(j))
@@ -2149,10 +2137,21 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
|(obligation_arg, impl_arg)| {
match (obligation_arg.unpack(), impl_arg.unpack()) {
(GenericArgKind::Type(obligation_ty), GenericArgKind::Type(impl_ty)) => {
- let simplified_obligation_ty =
- fast_reject::simplify_type(self.tcx(), obligation_ty, true);
- let simplified_impl_ty =
- fast_reject::simplify_type(self.tcx(), impl_ty, false);
+ // Note, we simplify parameters for the obligation but not the
+ // impl so that we do not reject a blanket impl but do reject
+ // more concrete impls if we're searching for `T: Trait`.
+ let simplified_obligation_ty = fast_reject::simplify_type(
+ self.tcx(),
+ obligation_ty,
+ SimplifyParams::Yes,
+ StripReferences::No,
+ );
+ let simplified_impl_ty = fast_reject::simplify_type(
+ self.tcx(),
+ impl_ty,
+ SimplifyParams::No,
+ StripReferences::No,
+ );
simplified_obligation_ty.is_some()
&& simplified_impl_ty.is_some()
@@ -2205,8 +2204,8 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
fn match_fresh_trait_refs(
&self,
- previous: ty::ConstnessAnd<ty::PolyTraitRef<'tcx>>,
- current: ty::ConstnessAnd<ty::PolyTraitRef<'tcx>>,
+ previous: ty::PolyTraitPredicate<'tcx>,
+ current: ty::PolyTraitPredicate<'tcx>,
param_env: ty::ParamEnv<'tcx>,
) -> bool {
let mut matcher = ty::_match::Match::new(self.tcx(), param_env);
@@ -2218,17 +2217,13 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
previous_stack: TraitObligationStackList<'o, 'tcx>,
obligation: &'o TraitObligation<'tcx>,
) -> TraitObligationStack<'o, 'tcx> {
- let fresh_trait_ref = obligation
- .predicate
- .to_poly_trait_ref()
- .fold_with(&mut self.freshener)
- .with_constness(obligation.predicate.skip_binder().constness);
+ let fresh_trait_pred = obligation.predicate.fold_with(&mut self.freshener);
let dfn = previous_stack.cache.next_dfn();
let depth = previous_stack.depth() + 1;
TraitObligationStack {
obligation,
- fresh_trait_ref,
+ fresh_trait_pred,
reached_depth: Cell::new(depth),
previous: previous_stack,
dfn,
@@ -2422,7 +2417,7 @@ impl<'o, 'tcx> TraitObligationStack<'o, 'tcx> {
debug!(reached_depth, "update_reached_depth");
let mut p = self;
while reached_depth < p.depth {
- debug!(?p.fresh_trait_ref, "update_reached_depth: marking as cycle participant");
+ debug!(?p.fresh_trait_pred, "update_reached_depth: marking as cycle participant");
p.reached_depth.set(p.reached_depth.get().min(reached_depth));
p = p.previous.head.unwrap();
}
@@ -2501,7 +2496,7 @@ struct ProvisionalEvaluationCache<'tcx> {
/// - then we determine that `E` is in error -- we will then clear
/// all cache values whose DFN is >= 4 -- in this case, that
/// means the cached value for `F`.
- map: RefCell<FxHashMap<ty::ConstnessAnd<ty::PolyTraitRef<'tcx>>, ProvisionalEvaluation>>,
+ map: RefCell<FxHashMap<ty::PolyTraitPredicate<'tcx>, ProvisionalEvaluation>>,
}
/// A cache value for the provisional cache: contains the depth-first
@@ -2533,28 +2528,28 @@ impl<'tcx> ProvisionalEvaluationCache<'tcx> {
/// `reached_depth` (from the returned value).
fn get_provisional(
&self,
- fresh_trait_ref: ty::ConstnessAnd<ty::PolyTraitRef<'tcx>>,
+ fresh_trait_pred: ty::PolyTraitPredicate<'tcx>,
) -> Option<ProvisionalEvaluation> {
debug!(
- ?fresh_trait_ref,
+ ?fresh_trait_pred,
"get_provisional = {:#?}",
- self.map.borrow().get(&fresh_trait_ref),
+ self.map.borrow().get(&fresh_trait_pred),
);
- Some(*self.map.borrow().get(&fresh_trait_ref)?)
+ Some(*self.map.borrow().get(&fresh_trait_pred)?)
}
/// Insert a provisional result into the cache. The result came
/// from the node with the given DFN. It accessed a minimum depth
- /// of `reached_depth` to compute. It evaluated `fresh_trait_ref`
+ /// of `reached_depth` to compute. It evaluated `fresh_trait_pred`
/// and resulted in `result`.
fn insert_provisional(
&self,
from_dfn: usize,
reached_depth: usize,
- fresh_trait_ref: ty::ConstnessAnd<ty::PolyTraitRef<'tcx>>,
+ fresh_trait_pred: ty::PolyTraitPredicate<'tcx>,
result: EvaluationResult,
) {
- debug!(?from_dfn, ?fresh_trait_ref, ?result, "insert_provisional");
+ debug!(?from_dfn, ?fresh_trait_pred, ?result, "insert_provisional");
let mut map = self.map.borrow_mut();
@@ -2578,7 +2573,7 @@ impl<'tcx> ProvisionalEvaluationCache<'tcx> {
}
}
- map.insert(fresh_trait_ref, ProvisionalEvaluation { from_dfn, reached_depth, result });
+ map.insert(fresh_trait_pred, ProvisionalEvaluation { from_dfn, reached_depth, result });
}
/// Invoked when the node with dfn `dfn` does not get a successful
@@ -2629,16 +2624,16 @@ impl<'tcx> ProvisionalEvaluationCache<'tcx> {
fn on_completion(
&self,
dfn: usize,
- mut op: impl FnMut(ty::ConstnessAnd<ty::PolyTraitRef<'tcx>>, EvaluationResult),
+ mut op: impl FnMut(ty::PolyTraitPredicate<'tcx>, EvaluationResult),
) {
debug!(?dfn, "on_completion");
- for (fresh_trait_ref, eval) in
+ for (fresh_trait_pred, eval) in
self.map.borrow_mut().drain_filter(|_k, eval| eval.from_dfn >= dfn)
{
- debug!(?fresh_trait_ref, ?eval, "on_completion");
+ debug!(?fresh_trait_pred, ?eval, "on_completion");
- op(fresh_trait_ref, eval.result);
+ op(fresh_trait_pred, eval.result);
}
}
}
diff --git a/compiler/rustc_trait_selection/src/traits/specialize/mod.rs b/compiler/rustc_trait_selection/src/traits/specialize/mod.rs
index b64c5559227..ab732f510ff 100644
--- a/compiler/rustc_trait_selection/src/traits/specialize/mod.rs
+++ b/compiler/rustc_trait_selection/src/traits/specialize/mod.rs
@@ -508,9 +508,9 @@ crate fn to_pretty_impl_header(tcx: TyCtxt<'_>, impl_def_id: DefId) -> Option<St
Vec::with_capacity(predicates.len() + types_without_default_bounds.len());
for (p, _) in predicates {
- if let Some(poly_trait_ref) = p.to_opt_poly_trait_ref() {
- if Some(poly_trait_ref.value.def_id()) == sized_trait {
- types_without_default_bounds.remove(poly_trait_ref.value.self_ty().skip_binder());
+ if let Some(poly_trait_ref) = p.to_opt_poly_trait_pred() {
+ if Some(poly_trait_ref.def_id()) == sized_trait {
+ types_without_default_bounds.remove(poly_trait_ref.self_ty().skip_binder());
continue;
}
}
diff --git a/compiler/rustc_trait_selection/src/traits/specialize/specialization_graph.rs b/compiler/rustc_trait_selection/src/traits/specialize/specialization_graph.rs
index ec7dcd4a419..3ac273fd19b 100644
--- a/compiler/rustc_trait_selection/src/traits/specialize/specialization_graph.rs
+++ b/compiler/rustc_trait_selection/src/traits/specialize/specialization_graph.rs
@@ -2,7 +2,7 @@ use super::OverlapError;
use crate::traits;
use rustc_hir::def_id::DefId;
-use rustc_middle::ty::fast_reject::{self, SimplifiedType};
+use rustc_middle::ty::fast_reject::{self, SimplifiedType, SimplifyParams, StripReferences};
use rustc_middle::ty::print::with_no_trimmed_paths;
use rustc_middle::ty::{self, TyCtxt, TypeFoldable};
@@ -32,7 +32,7 @@ enum Inserted {
ShouldRecurseOn(DefId),
}
-trait ChildrenExt {
+trait ChildrenExt<'tcx> {
fn insert_blindly(&mut self, tcx: TyCtxt<'tcx>, impl_def_id: DefId);
fn remove_existing(&mut self, tcx: TyCtxt<'tcx>, impl_def_id: DefId);
@@ -44,11 +44,16 @@ trait ChildrenExt {
) -> Result<Inserted, OverlapError>;
}
-impl ChildrenExt for Children {
+impl ChildrenExt<'_> for Children {
/// Insert an impl into this set of children without comparing to any existing impls.
- fn insert_blindly(&mut self, tcx: TyCtxt<'tcx>, impl_def_id: DefId) {
+ fn insert_blindly(&mut self, tcx: TyCtxt<'_>, impl_def_id: DefId) {
let trait_ref = tcx.impl_trait_ref(impl_def_id).unwrap();
- if let Some(st) = fast_reject::simplify_type(tcx, trait_ref.self_ty(), false) {
+ if let Some(st) = fast_reject::simplify_type(
+ tcx,
+ trait_ref.self_ty(),
+ SimplifyParams::No,
+ StripReferences::No,
+ ) {
debug!("insert_blindly: impl_def_id={:?} st={:?}", impl_def_id, st);
self.non_blanket_impls.entry(st).or_default().push(impl_def_id)
} else {
@@ -60,10 +65,15 @@ impl ChildrenExt for Children {
/// Removes an impl from this set of children. Used when replacing
/// an impl with a parent. The impl must be present in the list of
/// children already.
- fn remove_existing(&mut self, tcx: TyCtxt<'tcx>, impl_def_id: DefId) {
+ fn remove_existing(&mut self, tcx: TyCtxt<'_>, impl_def_id: DefId) {
let trait_ref = tcx.impl_trait_ref(impl_def_id).unwrap();
let vec: &mut Vec<DefId>;
- if let Some(st) = fast_reject::simplify_type(tcx, trait_ref.self_ty(), false) {
+ if let Some(st) = fast_reject::simplify_type(
+ tcx,
+ trait_ref.self_ty(),
+ SimplifyParams::No,
+ StripReferences::No,
+ ) {
debug!("remove_existing: impl_def_id={:?} st={:?}", impl_def_id, st);
vec = self.non_blanket_impls.get_mut(&st).unwrap();
} else {
@@ -79,7 +89,7 @@ impl ChildrenExt for Children {
/// specialization relationships.
fn insert(
&mut self,
- tcx: TyCtxt<'tcx>,
+ tcx: TyCtxt<'_>,
impl_def_id: DefId,
simplified_self: Option<SimplifiedType>,
) -> Result<Inserted, OverlapError> {
@@ -261,12 +271,12 @@ pub trait GraphExt {
/// information about the area of overlap is returned in the `Err`.
fn insert(
&mut self,
- tcx: TyCtxt<'tcx>,
+ tcx: TyCtxt<'_>,
impl_def_id: DefId,
) -> Result<Option<FutureCompatOverlapError>, OverlapError>;
/// Insert cached metadata mapping from a child impl back to its parent.
- fn record_impl_from_cstore(&mut self, tcx: TyCtxt<'tcx>, parent: DefId, child: DefId);
+ fn record_impl_from_cstore(&mut self, tcx: TyCtxt<'_>, parent: DefId, child: DefId);
}
impl GraphExt for Graph {
@@ -275,7 +285,7 @@ impl GraphExt for Graph {
/// information about the area of overlap is returned in the `Err`.
fn insert(
&mut self,
- tcx: TyCtxt<'tcx>,
+ tcx: TyCtxt<'_>,
impl_def_id: DefId,
) -> Result<Option<FutureCompatOverlapError>, OverlapError> {
assert!(impl_def_id.is_local());
@@ -306,7 +316,12 @@ impl GraphExt for Graph {
let mut parent = trait_def_id;
let mut last_lint = None;
- let simplified = fast_reject::simplify_type(tcx, trait_ref.self_ty(), false);
+ let simplified = fast_reject::simplify_type(
+ tcx,
+ trait_ref.self_ty(),
+ SimplifyParams::No,
+ StripReferences::No,
+ );
// Descend the specialization tree, where `parent` is the current parent node.
loop {
@@ -370,7 +385,7 @@ impl GraphExt for Graph {
}
/// Insert cached metadata mapping from a child impl back to its parent.
- fn record_impl_from_cstore(&mut self, tcx: TyCtxt<'tcx>, parent: DefId, child: DefId) {
+ fn record_impl_from_cstore(&mut self, tcx: TyCtxt<'_>, parent: DefId, child: DefId) {
if self.parent.insert(child, parent).is_some() {
bug!(
"When recording an impl from the crate store, information about its parent \
diff --git a/compiler/rustc_trait_selection/src/traits/structural_match.rs b/compiler/rustc_trait_selection/src/traits/structural_match.rs
index 3d713822278..55feb3c1de1 100644
--- a/compiler/rustc_trait_selection/src/traits/structural_match.rs
+++ b/compiler/rustc_trait_selection/src/traits/structural_match.rs
@@ -66,7 +66,7 @@ pub fn search_for_structural_match_violation<'tcx>(
///
/// Note that this does *not* recursively check if the substructure of `adt_ty`
/// implements the traits.
-fn type_marked_structural(
+fn type_marked_structural<'tcx>(
infcx: &InferCtxt<'_, 'tcx>,
adt_ty: Ty<'tcx>,
cause: ObligationCause<'tcx>,
@@ -119,7 +119,7 @@ struct Search<'a, 'tcx> {
seen: FxHashSet<hir::def_id::DefId>,
}
-impl Search<'a, 'tcx> {
+impl<'a, 'tcx> Search<'a, 'tcx> {
fn tcx(&self) -> TyCtxt<'tcx> {
self.infcx.tcx
}
diff --git a/compiler/rustc_trait_selection/src/traits/util.rs b/compiler/rustc_trait_selection/src/traits/util.rs
index 6d2323abba4..3090e8a0428 100644
--- a/compiler/rustc_trait_selection/src/traits/util.rs
+++ b/compiler/rustc_trait_selection/src/traits/util.rs
@@ -6,7 +6,7 @@ use smallvec::SmallVec;
use rustc_data_structures::fx::FxHashSet;
use rustc_hir::def_id::DefId;
use rustc_middle::ty::subst::{GenericArg, Subst, SubstsRef};
-use rustc_middle::ty::{self, ToPredicate, Ty, TyCtxt, TypeFoldable, WithConstness};
+use rustc_middle::ty::{self, ToPredicate, Ty, TyCtxt, TypeFoldable};
use super::{Normalized, Obligation, ObligationCause, PredicateObligation, SelectionContext};
pub use rustc_infer::traits::{self, util::*};
@@ -126,8 +126,8 @@ impl<'tcx> TraitAliasExpander<'tcx> {
let items = predicates.predicates.iter().rev().filter_map(|(pred, span)| {
pred.subst_supertrait(tcx, &trait_ref)
- .to_opt_poly_trait_ref()
- .map(|trait_ref| item.clone_and_push(trait_ref.value, *span))
+ .to_opt_poly_trait_pred()
+ .map(|trait_ref| item.clone_and_push(trait_ref.map_bound(|t| t.trait_ref), *span))
});
debug!("expand_trait_aliases: items={:?}", items.clone());
@@ -172,7 +172,7 @@ pub fn supertrait_def_ids(tcx: TyCtxt<'_>, trait_def_id: DefId) -> SupertraitDef
}
}
-impl Iterator for SupertraitDefIds<'tcx> {
+impl Iterator for SupertraitDefIds<'_> {
type Item = DefId;
fn next(&mut self) -> Option<DefId> {
@@ -183,8 +183,8 @@ impl Iterator for SupertraitDefIds<'tcx> {
predicates
.predicates
.iter()
- .filter_map(|(pred, _)| pred.to_opt_poly_trait_ref())
- .map(|trait_ref| trait_ref.value.def_id())
+ .filter_map(|(pred, _)| pred.to_opt_poly_trait_pred())
+ .map(|trait_ref| trait_ref.def_id())
.filter(|&super_def_id| visited.insert(super_def_id)),
);
Some(def_id)
@@ -259,7 +259,7 @@ pub fn predicate_for_trait_ref<'tcx>(
}
}
-pub fn predicate_for_trait_def(
+pub fn predicate_for_trait_def<'tcx>(
tcx: TyCtxt<'tcx>,
param_env: ty::ParamEnv<'tcx>,
cause: ObligationCause<'tcx>,
@@ -276,7 +276,7 @@ pub fn predicate_for_trait_def(
/// Casts a trait reference into a reference to one of its super
/// traits; returns `None` if `target_trait_def_id` is not a
/// supertrait.
-pub fn upcast_choices(
+pub fn upcast_choices<'tcx>(
tcx: TyCtxt<'tcx>,
source_trait_ref: ty::PolyTraitRef<'tcx>,
target_trait_def_id: DefId,
@@ -291,7 +291,10 @@ pub fn upcast_choices(
/// Given a trait `trait_ref`, returns the number of vtable entries
/// that come from `trait_ref`, excluding its supertraits. Used in
/// computing the vtable base for an upcast trait of a trait object.
-pub fn count_own_vtable_entries(tcx: TyCtxt<'tcx>, trait_ref: ty::PolyTraitRef<'tcx>) -> usize {
+pub fn count_own_vtable_entries<'tcx>(
+ tcx: TyCtxt<'tcx>,
+ trait_ref: ty::PolyTraitRef<'tcx>,
+) -> usize {
let existential_trait_ref =
trait_ref.map_bound(|trait_ref| ty::ExistentialTraitRef::erase_self_ty(tcx, trait_ref));
let existential_trait_ref = tcx.erase_regions(existential_trait_ref);
@@ -301,7 +304,7 @@ pub fn count_own_vtable_entries(tcx: TyCtxt<'tcx>, trait_ref: ty::PolyTraitRef<'
/// Given an upcast trait object described by `object`, returns the
/// index of the method `method_def_id` (which should be part of
/// `object.upcast_trait_ref`) within the vtable for `object`.
-pub fn get_vtable_index_of_object_method<N>(
+pub fn get_vtable_index_of_object_method<'tcx, N>(
tcx: TyCtxt<'tcx>,
object: &super::ImplSourceObjectData<'tcx, N>,
method_def_id: DefId,
@@ -323,7 +326,7 @@ pub fn get_vtable_index_of_object_method<N>(
object.vtable_base + index
}
-pub fn closure_trait_ref_and_return_type(
+pub fn closure_trait_ref_and_return_type<'tcx>(
tcx: TyCtxt<'tcx>,
fn_trait_def_id: DefId,
self_ty: Ty<'tcx>,
@@ -342,7 +345,7 @@ pub fn closure_trait_ref_and_return_type(
sig.map_bound(|sig| (trait_ref, sig.output()))
}
-pub fn generator_trait_ref_and_outputs(
+pub fn generator_trait_ref_and_outputs<'tcx>(
tcx: TyCtxt<'tcx>,
fn_trait_def_id: DefId,
self_ty: Ty<'tcx>,
diff --git a/compiler/rustc_trait_selection/src/traits/wf.rs b/compiler/rustc_trait_selection/src/traits/wf.rs
index 2a66684e2a2..5875b764e9f 100644
--- a/compiler/rustc_trait_selection/src/traits/wf.rs
+++ b/compiler/rustc_trait_selection/src/traits/wf.rs
@@ -6,7 +6,7 @@ use rustc_hir as hir;
use rustc_hir::def_id::DefId;
use rustc_hir::lang_items::LangItem;
use rustc_middle::ty::subst::{GenericArg, GenericArgKind, SubstsRef};
-use rustc_middle::ty::{self, ToPredicate, Ty, TyCtxt, TypeFoldable, WithConstness};
+use rustc_middle::ty::{self, ToPredicate, Ty, TyCtxt, TypeFoldable};
use rustc_span::Span;
use std::iter;
@@ -298,9 +298,10 @@ impl<'a, 'tcx> WfPredicates<'a, 'tcx> {
let extend = |obligation: traits::PredicateObligation<'tcx>| {
let mut cause = cause.clone();
- if let Some(parent_trait_ref) = obligation.predicate.to_opt_poly_trait_ref() {
+ if let Some(parent_trait_ref) = obligation.predicate.to_opt_poly_trait_pred() {
let derived_cause = traits::DerivedObligationCause {
- parent_trait_ref: parent_trait_ref.value,
+ // FIXME(fee1-dead): when improving error messages, change this to PolyTraitPredicate
+ parent_trait_ref: parent_trait_ref.map_bound(|t| t.trait_ref),
parent_code: Lrc::new(obligation.cause.code.clone()),
};
cause.make_mut().code =
diff --git a/compiler/rustc_traits/src/normalize_erasing_regions.rs b/compiler/rustc_traits/src/normalize_erasing_regions.rs
index 61ab5e28b67..87530cf9961 100644
--- a/compiler/rustc_traits/src/normalize_erasing_regions.rs
+++ b/compiler/rustc_traits/src/normalize_erasing_regions.rs
@@ -8,27 +8,28 @@ use std::sync::atomic::Ordering;
crate fn provide(p: &mut Providers) {
*p = Providers {
- normalize_generic_arg_after_erasing_regions: |tcx, goal| {
- debug!("normalize_generic_arg_after_erasing_regions(goal={:#?})", goal);
+ try_normalize_generic_arg_after_erasing_regions: |tcx, goal| {
+ debug!("try_normalize_generic_arg_after_erasing_regions(goal={:#?}", goal);
tcx.sess
.perf_stats
.normalize_generic_arg_after_erasing_regions
.fetch_add(1, Ordering::Relaxed);
- normalize_after_erasing_regions(tcx, goal)
+
+ try_normalize_after_erasing_regions(tcx, goal)
},
- normalize_mir_const_after_erasing_regions: |tcx, goal| {
- normalize_after_erasing_regions(tcx, goal)
+ try_normalize_mir_const_after_erasing_regions: |tcx, goal| {
+ try_normalize_after_erasing_regions(tcx, goal)
},
..*p
};
}
#[instrument(level = "debug", skip(tcx))]
-fn normalize_after_erasing_regions<'tcx, T: TypeFoldable<'tcx> + PartialEq + Copy>(
+fn try_normalize_after_erasing_regions<'tcx, T: TypeFoldable<'tcx> + PartialEq + Copy>(
tcx: TyCtxt<'tcx>,
goal: ParamEnvAnd<'tcx, T>,
-) -> T {
+) -> Result<T, NoSolution> {
let ParamEnvAnd { param_env, value } = goal;
tcx.infer_ctxt().enter(|infcx| {
let cause = ObligationCause::dummy();
@@ -49,9 +50,9 @@ fn normalize_after_erasing_regions<'tcx, T: TypeFoldable<'tcx> + PartialEq + Cop
debug_assert_eq!(normalized_value, resolved_value);
let erased = infcx.tcx.erase_regions(resolved_value);
debug_assert!(!erased.needs_infer(), "{:?}", erased);
- erased
+ Ok(erased)
}
- Err(NoSolution) => bug!("could not fully normalize `{:?}`", value),
+ Err(NoSolution) => Err(NoSolution),
}
})
}
diff --git a/compiler/rustc_ty_utils/src/needs_drop.rs b/compiler/rustc_ty_utils/src/needs_drop.rs
index 595b623b020..fc309aa848c 100644
--- a/compiler/rustc_ty_utils/src/needs_drop.rs
+++ b/compiler/rustc_ty_utils/src/needs_drop.rs
@@ -147,8 +147,10 @@ where
Ok(tys) => tys,
};
for required_ty in tys {
- let required =
- tcx.normalize_erasing_regions(self.param_env, required_ty);
+ let required = tcx
+ .try_normalize_erasing_regions(self.param_env, required_ty)
+ .unwrap_or(required_ty);
+
queue_type(self, required);
}
}
diff --git a/compiler/rustc_ty_utils/src/ty.rs b/compiler/rustc_ty_utils/src/ty.rs
index af3706f886e..6c2657bd64b 100644
--- a/compiler/rustc_ty_utils/src/ty.rs
+++ b/compiler/rustc_ty_utils/src/ty.rs
@@ -2,10 +2,8 @@ use rustc_data_structures::fx::FxIndexSet;
use rustc_hir as hir;
use rustc_hir::def_id::{DefId, LocalDefId};
use rustc_middle::ty::subst::Subst;
-use rustc_middle::ty::{
- self, Binder, Predicate, PredicateKind, ToPredicate, Ty, TyCtxt, WithConstness,
-};
-use rustc_span::Span;
+use rustc_middle::ty::{self, Binder, Predicate, PredicateKind, ToPredicate, Ty, TyCtxt};
+use rustc_span::{sym, Span};
use rustc_trait_selection::traits;
fn sized_constraint_for_ty<'tcx>(
@@ -123,7 +121,7 @@ fn associated_item(tcx: TyCtxt<'_>, def_id: DefId) -> ty::AssocItem {
let id = tcx.hir().local_def_id_to_hir_id(def_id.expect_local());
let parent_id = tcx.hir().get_parent_item(id);
let parent_def_id = tcx.hir().local_def_id(parent_id);
- let parent_item = tcx.hir().expect_item(parent_id);
+ let parent_item = tcx.hir().expect_item(parent_def_id);
match parent_item.kind {
hir::ItemKind::Impl(ref impl_) => {
if let Some(impl_item_ref) =
@@ -158,8 +156,7 @@ fn associated_item(tcx: TyCtxt<'_>, def_id: DefId) -> ty::AssocItem {
}
fn impl_defaultness(tcx: TyCtxt<'_>, def_id: DefId) -> hir::Defaultness {
- let hir_id = tcx.hir().local_def_id_to_hir_id(def_id.expect_local());
- let item = tcx.hir().expect_item(hir_id);
+ let item = tcx.hir().expect_item(def_id.expect_local());
if let hir::ItemKind::Impl(impl_) = &item.kind {
impl_.defaultness
} else {
@@ -168,8 +165,7 @@ fn impl_defaultness(tcx: TyCtxt<'_>, def_id: DefId) -> hir::Defaultness {
}
fn impl_constness(tcx: TyCtxt<'_>, def_id: DefId) -> hir::Constness {
- let hir_id = tcx.hir().local_def_id_to_hir_id(def_id.expect_local());
- let item = tcx.hir().expect_item(hir_id);
+ let item = tcx.hir().expect_item(def_id.expect_local());
if let hir::ItemKind::Impl(impl_) = &item.kind {
impl_.constness
} else {
@@ -202,8 +198,7 @@ fn adt_sized_constraint(tcx: TyCtxt<'_>, def_id: DefId) -> ty::AdtSizedConstrain
}
fn associated_item_def_ids(tcx: TyCtxt<'_>, def_id: DefId) -> &[DefId] {
- let id = tcx.hir().local_def_id_to_hir_id(def_id.expect_local());
- let item = tcx.hir().expect_item(id);
+ let item = tcx.hir().expect_item(def_id.expect_local());
match item.kind {
hir::ItemKind::Trait(.., ref trait_item_refs) => tcx.arena.alloc_from_iter(
trait_item_refs.iter().map(|trait_item_ref| trait_item_ref.id.def_id.to_def_id()),
@@ -251,7 +246,7 @@ fn trait_of_item(tcx: TyCtxt<'_>, def_id: DefId) -> Option<DefId> {
fn param_env(tcx: TyCtxt<'_>, def_id: DefId) -> ty::ParamEnv<'_> {
// The param_env of an impl Trait type is its defining function's param_env
if let Some(parent) = ty::is_impl_trait_defn(tcx, def_id) {
- return param_env(tcx, parent);
+ return param_env(tcx, parent.to_def_id());
}
// Compute the bounds on Self and the type parameters.
@@ -285,16 +280,85 @@ fn param_env(tcx: TyCtxt<'_>, def_id: DefId) -> ty::ParamEnv<'_> {
// issue #89334
predicates = tcx.expose_default_const_substs(predicates);
- let unnormalized_env =
- ty::ParamEnv::new(tcx.intern_predicates(&predicates), traits::Reveal::UserFacing);
+ let local_did = def_id.as_local();
+ let hir_id = local_did.map(|def_id| tcx.hir().local_def_id_to_hir_id(def_id));
+
+ let constness = match hir_id {
+ Some(hir_id) => match tcx.hir().get(hir_id) {
+ hir::Node::TraitItem(hir::TraitItem { kind: hir::TraitItemKind::Fn(..), .. })
+ if tcx.has_attr(def_id, sym::default_method_body_is_const) =>
+ {
+ hir::Constness::Const
+ }
+
+ hir::Node::Item(hir::Item { kind: hir::ItemKind::Const(..), .. })
+ | hir::Node::Item(hir::Item { kind: hir::ItemKind::Static(..), .. })
+ | hir::Node::TraitItem(hir::TraitItem {
+ kind: hir::TraitItemKind::Const(..), ..
+ })
+ | hir::Node::AnonConst(_)
+ | hir::Node::ImplItem(hir::ImplItem { kind: hir::ImplItemKind::Const(..), .. })
+ | hir::Node::ImplItem(hir::ImplItem {
+ kind:
+ hir::ImplItemKind::Fn(
+ hir::FnSig {
+ header: hir::FnHeader { constness: hir::Constness::Const, .. },
+ ..
+ },
+ ..,
+ ),
+ ..
+ }) => hir::Constness::Const,
+
+ hir::Node::ImplItem(hir::ImplItem {
+ kind: hir::ImplItemKind::TyAlias(..) | hir::ImplItemKind::Fn(..),
+ ..
+ }) => {
+ let parent_hir_id = tcx.hir().get_parent_node(hir_id);
+ match tcx.hir().get(parent_hir_id) {
+ hir::Node::Item(hir::Item {
+ kind: hir::ItemKind::Impl(hir::Impl { constness, .. }),
+ ..
+ }) => *constness,
+ _ => span_bug!(
+ tcx.def_span(parent_hir_id.owner),
+ "impl item's parent node is not an impl",
+ ),
+ }
+ }
+
+ hir::Node::Item(hir::Item {
+ kind:
+ hir::ItemKind::Fn(hir::FnSig { header: hir::FnHeader { constness, .. }, .. }, ..),
+ ..
+ })
+ | hir::Node::TraitItem(hir::TraitItem {
+ kind:
+ hir::TraitItemKind::Fn(
+ hir::FnSig { header: hir::FnHeader { constness, .. }, .. },
+ ..,
+ ),
+ ..
+ })
+ | hir::Node::Item(hir::Item {
+ kind: hir::ItemKind::Impl(hir::Impl { constness, .. }),
+ ..
+ }) => *constness,
- debug!("unnormalized_env caller bounds: {:?}", unnormalized_env.caller_bounds());
- let body_id = def_id
- .as_local()
- .map(|def_id| tcx.hir().local_def_id_to_hir_id(def_id))
- .map_or(hir::CRATE_HIR_ID, |id| {
- tcx.hir().maybe_body_owned_by(id).map_or(id, |body| body.hir_id)
- });
+ _ => hir::Constness::NotConst,
+ },
+ None => hir::Constness::NotConst,
+ };
+
+ let unnormalized_env = ty::ParamEnv::new(
+ tcx.intern_predicates(&predicates),
+ traits::Reveal::UserFacing,
+ constness,
+ );
+
+ let body_id = hir_id.map_or(hir::CRATE_HIR_ID, |id| {
+ tcx.hir().maybe_body_owned_by(id).map_or(id, |body| body.hir_id)
+ });
let cause = traits::ObligationCause::misc(tcx.def_span(def_id), body_id);
traits::normalize_param_env_or_error(tcx, def_id, unnormalized_env, cause)
}
@@ -316,7 +380,7 @@ fn well_formed_types_in_env<'tcx>(
// The environment of an impl Trait type is its defining function's environment.
if let Some(parent) = ty::is_impl_trait_defn(tcx, def_id) {
- return well_formed_types_in_env(tcx, parent);
+ return well_formed_types_in_env(tcx, parent.to_def_id());
}
// Compute the bounds on `Self` and the type parameters.
diff --git a/compiler/rustc_type_ir/src/lib.rs b/compiler/rustc_type_ir/src/lib.rs
index 91dbbec782f..f11c93e9339 100644
--- a/compiler/rustc_type_ir/src/lib.rs
+++ b/compiler/rustc_type_ir/src/lib.rs
@@ -559,6 +559,7 @@ impl<CTX> HashStable<CTX> for FloatTy {
impl<CTX> HashStable<CTX> for InferTy {
fn hash_stable(&self, ctx: &mut CTX, hasher: &mut StableHasher) {
use InferTy::*;
+ discriminant(self).hash_stable(ctx, hasher);
match self {
TyVar(v) => v.as_u32().hash_stable(ctx, hasher),
IntVar(v) => v.index.hash_stable(ctx, hasher),
diff --git a/compiler/rustc_typeck/src/astconv/errors.rs b/compiler/rustc_typeck/src/astconv/errors.rs
index ec75e4a55d4..ea54b85b2f2 100644
--- a/compiler/rustc_typeck/src/astconv/errors.rs
+++ b/compiler/rustc_typeck/src/astconv/errors.rs
@@ -92,7 +92,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
&self,
span: Span,
trait_def_id: DefId,
- trait_segment: &'a hir::PathSegment<'a>,
+ trait_segment: &'_ hir::PathSegment<'_>,
) {
let trait_def = self.tcx().trait_def(trait_def_id);
diff --git a/compiler/rustc_typeck/src/astconv/generics.rs b/compiler/rustc_typeck/src/astconv/generics.rs
index e8bd038fed7..caa5c71e21c 100644
--- a/compiler/rustc_typeck/src/astconv/generics.rs
+++ b/compiler/rustc_typeck/src/astconv/generics.rs
@@ -131,8 +131,8 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
_ => {}
}
- let kind_ord = param.kind.to_ord(tcx);
- let arg_ord = arg.to_ord(tcx.features());
+ let kind_ord = param.kind.to_ord();
+ let arg_ord = arg.to_ord();
// This note is only true when generic parameters are strictly ordered by their kind.
if possible_ordering_error && kind_ord.cmp(&arg_ord) != core::cmp::Ordering::Equal {
@@ -298,26 +298,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
.params
.clone()
.into_iter()
- .map(|param| {
- (
- match param.kind {
- GenericParamDefKind::Lifetime => {
- ParamKindOrd::Lifetime
- }
- GenericParamDefKind::Type { .. } => {
- ParamKindOrd::Type
- }
- GenericParamDefKind::Const { .. } => {
- ParamKindOrd::Const {
- unordered: tcx
- .features()
- .unordered_const_ty_params(),
- }
- }
- },
- param,
- )
- })
+ .map(|param| (param.kind.to_ord(), param))
.collect::<Vec<(ParamKindOrd, GenericParamDef)>>();
param_types_present.sort_by_key(|(ord, _)| *ord);
let (mut param_types_present, ordered_params): (
@@ -330,16 +311,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
tcx,
arg,
param,
- !args_iter.clone().is_sorted_by_key(|arg| match arg {
- GenericArg::Lifetime(_) => ParamKindOrd::Lifetime,
- GenericArg::Type(_) => ParamKindOrd::Type,
- GenericArg::Const(_) => ParamKindOrd::Const {
- unordered: tcx
- .features()
- .unordered_const_ty_params(),
- },
- GenericArg::Infer(_) => ParamKindOrd::Infer,
- }),
+ !args_iter.clone().is_sorted_by_key(|arg| arg.to_ord()),
Some(&format!(
"reorder the arguments: {}: `<{}>`",
param_types_present
diff --git a/compiler/rustc_typeck/src/astconv/mod.rs b/compiler/rustc_typeck/src/astconv/mod.rs
index da751f20753..8db706c3709 100644
--- a/compiler/rustc_typeck/src/astconv/mod.rs
+++ b/compiler/rustc_typeck/src/astconv/mod.rs
@@ -13,6 +13,7 @@ use crate::errors::{
};
use crate::middle::resolve_lifetime as rl;
use crate::require_c_abi_if_c_variadic;
+use rustc_ast::TraitObjectSyntax;
use rustc_data_structures::fx::{FxHashMap, FxHashSet};
use rustc_errors::{struct_span_err, Applicability, ErrorReported, FatalError};
use rustc_hir as hir;
@@ -24,7 +25,8 @@ use rustc_hir::{GenericArg, GenericArgs};
use rustc_middle::ty::subst::{self, GenericArgKind, InternalSubsts, Subst, SubstsRef};
use rustc_middle::ty::GenericParamDefKind;
use rustc_middle::ty::{self, Const, DefIdTree, Ty, TyCtxt, TypeFoldable};
-use rustc_session::lint::builtin::AMBIGUOUS_ASSOCIATED_ITEMS;
+use rustc_session::lint::builtin::{AMBIGUOUS_ASSOCIATED_ITEMS, BARE_TRAIT_OBJECTS};
+use rustc_span::edition::Edition;
use rustc_span::lev_distance::find_best_match_for_name;
use rustc_span::symbol::{Ident, Symbol};
use rustc_span::{Span, DUMMY_SP};
@@ -35,7 +37,6 @@ use rustc_trait_selection::traits::error_reporting::report_object_safety_error;
use rustc_trait_selection::traits::wf::object_region_bounds;
use smallvec::SmallVec;
-use std::array;
use std::collections::BTreeSet;
use std::slice;
@@ -415,34 +416,40 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
arg: &GenericArg<'_>,
) -> subst::GenericArg<'tcx> {
let tcx = self.astconv.tcx();
+
+ let mut handle_ty_args = |has_default, ty: &hir::Ty<'_>| {
+ if has_default {
+ tcx.check_optional_stability(
+ param.def_id,
+ Some(arg.id()),
+ arg.span(),
+ None,
+ |_, _| {
+ // Default generic parameters may not be marked
+ // with stability attributes, i.e. when the
+ // default parameter was defined at the same time
+ // as the rest of the type. As such, we ignore missing
+ // stability attributes.
+ },
+ )
+ }
+ if let (hir::TyKind::Infer, false) = (&ty.kind, self.astconv.allow_ty_infer()) {
+ self.inferred_params.push(ty.span);
+ tcx.ty_error().into()
+ } else {
+ self.astconv.ast_ty_to_ty(ty).into()
+ }
+ };
+
match (&param.kind, arg) {
(GenericParamDefKind::Lifetime, GenericArg::Lifetime(lt)) => {
self.astconv.ast_region_to_region(lt, Some(param)).into()
}
(&GenericParamDefKind::Type { has_default, .. }, GenericArg::Type(ty)) => {
- if has_default {
- tcx.check_optional_stability(
- param.def_id,
- Some(arg.id()),
- arg.span(),
- None,
- |_, _| {
- // Default generic parameters may not be marked
- // with stability attributes, i.e. when the
- // default parameter was defined at the same time
- // as the rest of the type. As such, we ignore missing
- // stability attributes.
- },
- )
- }
- if let (hir::TyKind::Infer, false) =
- (&ty.kind, self.astconv.allow_ty_infer())
- {
- self.inferred_params.push(ty.span);
- tcx.ty_error().into()
- } else {
- self.astconv.ast_ty_to_ty(ty).into()
- }
+ handle_ty_args(has_default, ty)
+ }
+ (&GenericParamDefKind::Type { has_default, .. }, GenericArg::Infer(inf)) => {
+ handle_ty_args(has_default, &inf.to_ty())
}
(GenericParamDefKind::Const { .. }, GenericArg::Const(ct)) => {
ty::Const::from_opt_const_arg_anon_const(
@@ -454,41 +461,13 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
)
.into()
}
- (&GenericParamDefKind::Const { has_default }, hir::GenericArg::Infer(inf)) => {
- if has_default {
- tcx.const_param_default(param.def_id).into()
- } else if self.astconv.allow_ty_infer() {
- // FIXME(const_generics): Actually infer parameter here?
- todo!()
- } else {
- self.inferred_params.push(inf.span);
- tcx.ty_error().into()
- }
- }
- (
- &GenericParamDefKind::Type { has_default, .. },
- hir::GenericArg::Infer(inf),
- ) => {
- if has_default {
- tcx.check_optional_stability(
- param.def_id,
- Some(arg.id()),
- arg.span(),
- None,
- |_, _| {
- // Default generic parameters may not be marked
- // with stability attributes, i.e. when the
- // default parameter was defined at the same time
- // as the rest of the type. As such, we ignore missing
- // stability attributes.
- },
- );
- }
+ (&GenericParamDefKind::Const { .. }, hir::GenericArg::Infer(inf)) => {
+ let ty = tcx.at(self.span).type_of(param.def_id);
if self.astconv.allow_ty_infer() {
- self.astconv.ast_ty_to_ty(&inf.to_ty()).into()
+ self.astconv.ct_infer(ty, Some(param), inf.span).into()
} else {
self.inferred_params.push(inf.span);
- tcx.ty_error().into()
+ tcx.const_error(ty).into()
}
}
_ => unreachable!(),
@@ -1351,7 +1330,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
tcx,
span,
item.trait_ref().def_id(),
- &object_safety_violations[..],
+ &object_safety_violations,
)
.emit();
return tcx.ty_error();
@@ -1588,7 +1567,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
traits::transitive_bounds_that_define_assoc_type(
tcx,
predicates.iter().filter_map(|(p, _)| {
- p.to_opt_poly_trait_ref().map(|trait_ref| trait_ref.value)
+ Some(p.to_opt_poly_trait_pred()?.map_bound(|t| t.trait_ref))
}),
assoc_name,
)
@@ -1635,7 +1614,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
debug!("one_bound_for_assoc_type: bound2 = {:?}", bound2);
let is_equality = is_equality();
- let bounds = array::IntoIter::new([bound, bound2]).chain(matching_candidates);
+ let bounds = IntoIterator::into_iter([bound, bound2]).chain(matching_candidates);
let mut err = if is_equality.is_some() {
// More specific Error Index entry.
struct_span_err!(
@@ -2289,13 +2268,19 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
/// Parses the programmer's textual representation of a type into our
/// internal notion of a type.
pub fn ast_ty_to_ty(&self, ast_ty: &hir::Ty<'_>) -> Ty<'tcx> {
- self.ast_ty_to_ty_inner(ast_ty, false)
+ self.ast_ty_to_ty_inner(ast_ty, false, false)
+ }
+
+ /// Parses the programmer's textual representation of a type into our
+ /// internal notion of a type. This is meant to be used within a path.
+ pub fn ast_ty_to_ty_in_path(&self, ast_ty: &hir::Ty<'_>) -> Ty<'tcx> {
+ self.ast_ty_to_ty_inner(ast_ty, false, true)
}
/// Turns a `hir::Ty` into a `Ty`. For diagnostics' purposes we keep track of whether trait
/// objects are borrowed like `&dyn Trait` to avoid emitting redundant errors.
#[tracing::instrument(level = "debug", skip(self))]
- fn ast_ty_to_ty_inner(&self, ast_ty: &hir::Ty<'_>, borrowed: bool) -> Ty<'tcx> {
+ fn ast_ty_to_ty_inner(&self, ast_ty: &hir::Ty<'_>, borrowed: bool, in_path: bool) -> Ty<'tcx> {
let tcx = self.tcx();
let result_ty = match ast_ty.kind {
@@ -2306,7 +2291,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
hir::TyKind::Rptr(ref region, ref mt) => {
let r = self.ast_region_to_region(region, None);
debug!(?r);
- let t = self.ast_ty_to_ty_inner(mt.ty, true);
+ let t = self.ast_ty_to_ty_inner(mt.ty, true, false);
tcx.mk_ref(r, ty::TypeAndMut { ty: t, mutbl: mt.mutbl })
}
hir::TyKind::Never => tcx.types.never,
@@ -2325,6 +2310,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
))
}
hir::TyKind::TraitObject(bounds, ref lifetime, _) => {
+ self.maybe_lint_bare_trait(ast_ty, in_path);
self.conv_object_ty_poly_trait_ref(ast_ty.span, bounds, lifetime, borrowed)
}
hir::TyKind::Path(hir::QPath::Resolved(ref maybe_qself, ref path)) => {
@@ -2337,15 +2323,22 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
let def_id = item_id.def_id.to_def_id();
match opaque_ty.kind {
- hir::ItemKind::OpaqueTy(hir::OpaqueTy { impl_trait_fn, .. }) => {
- self.impl_trait_ty_to_ty(def_id, lifetimes, impl_trait_fn.is_some())
- }
+ hir::ItemKind::OpaqueTy(hir::OpaqueTy { origin, .. }) => self
+ .impl_trait_ty_to_ty(
+ def_id,
+ lifetimes,
+ matches!(
+ origin,
+ hir::OpaqueTyOrigin::FnReturn(..)
+ | hir::OpaqueTyOrigin::AsyncFn(..)
+ ),
+ ),
ref i => bug!("`impl Trait` pointed to non-opaque type?? {:#?}", i),
}
}
hir::TyKind::Path(hir::QPath::TypeRelative(ref qself, ref segment)) => {
debug!(?qself, ?segment);
- let ty = self.ast_ty_to_ty(qself);
+ let ty = self.ast_ty_to_ty_inner(qself, false, true);
let res = if let hir::TyKind::Path(hir::QPath::Resolved(_, path)) = qself.kind {
path.res
@@ -2356,7 +2349,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
.map(|(ty, _, _)| ty)
.unwrap_or_else(|_| tcx.ty_error())
}
- hir::TyKind::Path(hir::QPath::LangItem(lang_item, span)) => {
+ hir::TyKind::Path(hir::QPath::LangItem(lang_item, span, _)) => {
let def_id = tcx.require_lang_item(lang_item, Some(span));
let (substs, _) = self.create_substs_for_ast_path(
span,
@@ -2602,4 +2595,62 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
}
Some(r)
}
+
+ fn maybe_lint_bare_trait(&self, self_ty: &hir::Ty<'_>, in_path: bool) {
+ let tcx = self.tcx();
+ if let hir::TyKind::TraitObject([poly_trait_ref, ..], _, TraitObjectSyntax::None) =
+ self_ty.kind
+ {
+ let needs_bracket = in_path
+ && !tcx
+ .sess
+ .source_map()
+ .span_to_prev_source(self_ty.span)
+ .ok()
+ .map_or(false, |s| s.trim_end().ends_with('<'));
+
+ let is_global = poly_trait_ref.trait_ref.path.is_global();
+ let sugg = Vec::from_iter([
+ (
+ self_ty.span.shrink_to_lo(),
+ format!(
+ "{}dyn {}",
+ if needs_bracket { "<" } else { "" },
+ if is_global { "(" } else { "" },
+ ),
+ ),
+ (
+ self_ty.span.shrink_to_hi(),
+ format!(
+ "{}{}",
+ if is_global { ")" } else { "" },
+ if needs_bracket { ">" } else { "" },
+ ),
+ ),
+ ]);
+ if self_ty.span.edition() >= Edition::Edition2021 {
+ let msg = "trait objects must include the `dyn` keyword";
+ let label = "add `dyn` keyword before this trait";
+ rustc_errors::struct_span_err!(tcx.sess, self_ty.span, E0782, "{}", msg)
+ .multipart_suggestion_verbose(label, sugg, Applicability::MachineApplicable)
+ .emit();
+ } else {
+ let msg = "trait objects without an explicit `dyn` are deprecated";
+ tcx.struct_span_lint_hir(
+ BARE_TRAIT_OBJECTS,
+ self_ty.hir_id,
+ self_ty.span,
+ |lint| {
+ lint.build(msg)
+ .multipart_suggestion_verbose(
+ "use `dyn`",
+ sugg,
+ Applicability::MachineApplicable,
+ )
+ .emit()
+ },
+ );
+ }
+ }
+ }
}
diff --git a/compiler/rustc_typeck/src/bounds.rs b/compiler/rustc_typeck/src/bounds.rs
index 24474e163b9..8bc3a48e5b5 100644
--- a/compiler/rustc_typeck/src/bounds.rs
+++ b/compiler/rustc_typeck/src/bounds.rs
@@ -1,7 +1,7 @@
//! Bounds are restrictions applied to some types after they've been converted into the
//! `ty` form from the HIR.
-use rustc_middle::ty::{self, ToPredicate, Ty, TyCtxt, WithConstness};
+use rustc_middle::ty::{self, ToPredicate, Ty, TyCtxt};
use rustc_span::Span;
/// Collects together a list of type bounds. These lists of bounds occur in many places
diff --git a/compiler/rustc_typeck/src/check/_match.rs b/compiler/rustc_typeck/src/check/_match.rs
index a8160313228..405e4e8594a 100644
--- a/compiler/rustc_typeck/src/check/_match.rs
+++ b/compiler/rustc_typeck/src/check/_match.rs
@@ -557,7 +557,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
}
}
-fn arms_contain_ref_bindings(arms: &'tcx [hir::Arm<'tcx>]) -> Option<hir::Mutability> {
+fn arms_contain_ref_bindings<'tcx>(arms: &'tcx [hir::Arm<'tcx>]) -> Option<hir::Mutability> {
arms.iter().filter_map(|a| a.pat.contains_explicit_ref_binding()).max_by_key(|m| match *m {
hir::Mutability::Mut => 1,
hir::Mutability::Not => 0,
diff --git a/compiler/rustc_typeck/src/check/callee.rs b/compiler/rustc_typeck/src/check/callee.rs
index 635ed938193..e67ee1cab3d 100644
--- a/compiler/rustc_typeck/src/check/callee.rs
+++ b/compiler/rustc_typeck/src/check/callee.rs
@@ -496,7 +496,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
call_expr.span,
call_expr,
fn_sig.inputs(),
- &expected_arg_tys[..],
+ &expected_arg_tys,
arg_exprs,
fn_sig.c_variadic,
TupleArgumentsFlag::DontTupleArguments,
diff --git a/compiler/rustc_typeck/src/check/cast.rs b/compiler/rustc_typeck/src/check/cast.rs
index 511a2d7ddac..a397ee771af 100644
--- a/compiler/rustc_typeck/src/check/cast.rs
+++ b/compiler/rustc_typeck/src/check/cast.rs
@@ -638,7 +638,11 @@ impl<'a, 'tcx> CastCheck<'tcx> {
self.expr_ty = fcx.structurally_resolved_type(self.expr.span, self.expr_ty);
self.cast_ty = fcx.structurally_resolved_type(self.cast_span, self.cast_ty);
- if !fcx.type_is_known_to_be_sized_modulo_regions(self.cast_ty, self.span) {
+ debug!("check_cast({}, {:?} as {:?})", self.expr.hir_id, self.expr_ty, self.cast_ty);
+
+ if !fcx.type_is_known_to_be_sized_modulo_regions(self.cast_ty, self.span)
+ && !self.cast_ty.has_infer_types()
+ {
self.report_cast_to_unsized_type(fcx);
} else if self.expr_ty.references_error() || self.cast_ty.references_error() {
// No sense in giving duplicate error messages
diff --git a/compiler/rustc_typeck/src/check/check.rs b/compiler/rustc_typeck/src/check/check.rs
index bb1d9744e66..fd7b3a55dfb 100644
--- a/compiler/rustc_typeck/src/check/check.rs
+++ b/compiler/rustc_typeck/src/check/check.rs
@@ -453,12 +453,12 @@ pub(super) fn check_opaque<'tcx>(
/// Checks that an opaque type does not use `Self` or `T::Foo` projections that would result
/// in "inheriting lifetimes".
#[instrument(level = "debug", skip(tcx, span))]
-pub(super) fn check_opaque_for_inheriting_lifetimes(
+pub(super) fn check_opaque_for_inheriting_lifetimes<'tcx>(
tcx: TyCtxt<'tcx>,
def_id: LocalDefId,
span: Span,
) {
- let item = tcx.hir().expect_item(tcx.hir().local_def_id_to_hir_id(def_id));
+ let item = tcx.hir().expect_item(def_id);
debug!(?item, ?span);
struct FoundParentLifetime;
@@ -517,7 +517,7 @@ pub(super) fn check_opaque_for_inheriting_lifetimes(
}
}
- impl Visitor<'tcx> for ProhibitOpaqueVisitor<'tcx> {
+ impl<'tcx> Visitor<'tcx> for ProhibitOpaqueVisitor<'tcx> {
type Map = rustc_middle::hir::map::Map<'tcx>;
fn nested_visit_map(&mut self) -> hir::intravisit::NestedVisitorMap<Self::Map> {
@@ -541,7 +541,7 @@ pub(super) fn check_opaque_for_inheriting_lifetimes(
}
if let ItemKind::OpaqueTy(hir::OpaqueTy {
- origin: hir::OpaqueTyOrigin::AsyncFn | hir::OpaqueTyOrigin::FnReturn,
+ origin: hir::OpaqueTyOrigin::AsyncFn(..) | hir::OpaqueTyOrigin::FnReturn(..),
..
}) = item.kind
{
@@ -567,7 +567,7 @@ pub(super) fn check_opaque_for_inheriting_lifetimes(
visitor.visit_item(&item);
let is_async = match item.kind {
ItemKind::OpaqueTy(hir::OpaqueTy { origin, .. }) => {
- matches!(origin, hir::OpaqueTyOrigin::AsyncFn)
+ matches!(origin, hir::OpaqueTyOrigin::AsyncFn(..))
}
_ => unreachable!(),
};
@@ -604,7 +604,7 @@ pub(super) fn check_opaque_for_cycles<'tcx>(
) -> Result<(), ErrorReported> {
if tcx.try_expand_impl_trait_type(def_id.to_def_id(), substs).is_err() {
match origin {
- hir::OpaqueTyOrigin::AsyncFn => async_opaque_type_cycle_error(tcx, span),
+ hir::OpaqueTyOrigin::AsyncFn(..) => async_opaque_type_cycle_error(tcx, span),
_ => opaque_type_cycle_error(tcx, def_id, span),
}
Err(ErrorReported)
@@ -635,7 +635,7 @@ fn check_opaque_meets_bounds<'tcx>(
) {
match origin {
// Checked when type checking the function containing them.
- hir::OpaqueTyOrigin::FnReturn | hir::OpaqueTyOrigin::AsyncFn => return,
+ hir::OpaqueTyOrigin::FnReturn(..) | hir::OpaqueTyOrigin::AsyncFn(..) => return,
// Can have different predicates to their defining use
hir::OpaqueTyOrigin::TyAlias => {}
}
@@ -730,7 +730,7 @@ pub fn check_item_type<'tcx>(tcx: TyCtxt<'tcx>, it: &'tcx hir::Item<'tcx>) {
let abi = sig.header.abi;
fn_maybe_err(tcx, item.ident.span, abi);
}
- hir::TraitItemKind::Type(.., Some(_default)) => {
+ hir::TraitItemKind::Type(.., Some(default)) => {
let assoc_item = tcx.associated_item(item.def_id);
let trait_substs =
InternalSubsts::identity_for_item(tcx, it.def_id.to_def_id());
@@ -738,7 +738,7 @@ pub fn check_item_type<'tcx>(tcx: TyCtxt<'tcx>, it: &'tcx hir::Item<'tcx>) {
tcx,
assoc_item,
assoc_item,
- item.span,
+ default.span,
ty::TraitRef { def_id: it.def_id.to_def_id(), substs: trait_substs },
);
}
@@ -987,12 +987,12 @@ pub(super) fn check_impl_items_against_trait<'tcx>(
opt_trait_span,
);
}
- hir::ImplItemKind::TyAlias(_) => {
+ hir::ImplItemKind::TyAlias(impl_ty) => {
let opt_trait_span = tcx.hir().span_if_local(ty_trait_item.def_id);
compare_ty_impl(
tcx,
&ty_impl_item,
- impl_item.span,
+ impl_ty.span,
&ty_trait_item,
impl_trait_ref,
opt_trait_span,
@@ -1506,19 +1506,13 @@ pub(super) fn check_mod_item_types(tcx: TyCtxt<'_>, module_def_id: LocalDefId) {
tcx.hir().visit_item_likes_in_module(module_def_id, &mut CheckItemTypesVisitor { tcx });
}
-pub(super) fn check_item_well_formed(tcx: TyCtxt<'_>, def_id: LocalDefId) {
- wfcheck::check_item_well_formed(tcx, def_id);
-}
+pub(super) use wfcheck::check_item_well_formed;
-pub(super) fn check_trait_item_well_formed(tcx: TyCtxt<'_>, def_id: LocalDefId) {
- wfcheck::check_trait_item(tcx, def_id);
-}
+pub(super) use wfcheck::check_trait_item as check_trait_item_well_formed;
-pub(super) fn check_impl_item_well_formed(tcx: TyCtxt<'_>, def_id: LocalDefId) {
- wfcheck::check_impl_item(tcx, def_id);
-}
+pub(super) use wfcheck::check_impl_item as check_impl_item_well_formed;
-fn async_opaque_type_cycle_error(tcx: TyCtxt<'tcx>, span: Span) {
+fn async_opaque_type_cycle_error(tcx: TyCtxt<'_>, span: Span) {
struct_span_err!(tcx.sess, span, E0733, "recursion in an `async fn` requires boxing")
.span_label(span, "recursive `async fn`")
.note("a recursive `async fn` must be rewritten to return a boxed `dyn Future`")
@@ -1536,7 +1530,7 @@ fn async_opaque_type_cycle_error(tcx: TyCtxt<'tcx>, span: Span) {
///
/// If all the return expressions evaluate to `!`, then we explain that the error will go away
/// after changing it. This can happen when a user uses `panic!()` or similar as a placeholder.
-fn opaque_type_cycle_error(tcx: TyCtxt<'tcx>, def_id: LocalDefId, span: Span) {
+fn opaque_type_cycle_error(tcx: TyCtxt<'_>, def_id: LocalDefId, span: Span) {
let mut err = struct_span_err!(tcx.sess, span, E0720, "cannot resolve opaque type");
let mut label = false;
diff --git a/compiler/rustc_typeck/src/check/closure.rs b/compiler/rustc_typeck/src/check/closure.rs
index 4a41552a5fb..c87ab0d410c 100644
--- a/compiler/rustc_typeck/src/check/closure.rs
+++ b/compiler/rustc_typeck/src/check/closure.rs
@@ -80,7 +80,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
let generator_types = check_fn(
self,
- self.param_env,
+ self.param_env.without_const(),
liberated_sig,
decl,
expr.hir_id,
diff --git a/compiler/rustc_typeck/src/check/coercion.rs b/compiler/rustc_typeck/src/check/coercion.rs
index 28712e06582..ac18908e95b 100644
--- a/compiler/rustc_typeck/src/check/coercion.rs
+++ b/compiler/rustc_typeck/src/check/coercion.rs
@@ -102,7 +102,7 @@ fn identity(_: Ty<'_>) -> Vec<Adjustment<'_>> {
vec![]
}
-fn simple(kind: Adjust<'tcx>) -> impl FnOnce(Ty<'tcx>) -> Vec<Adjustment<'tcx>> {
+fn simple<'tcx>(kind: Adjust<'tcx>) -> impl FnOnce(Ty<'tcx>) -> Vec<Adjustment<'tcx>> {
move |target| vec![Adjustment { kind, target }]
}
@@ -1126,8 +1126,10 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
for expr in exprs {
let expr = expr.as_coercion_site();
let noop = match self.typeck_results.borrow().expr_adjustments(expr) {
- &[Adjustment { kind: Adjust::Deref(_), .. }, Adjustment { kind: Adjust::Borrow(AutoBorrow::Ref(_, mutbl_adj)), .. }] =>
- {
+ &[
+ Adjustment { kind: Adjust::Deref(_), .. },
+ Adjustment { kind: Adjust::Borrow(AutoBorrow::Ref(_, mutbl_adj)), .. },
+ ] => {
match *self.node_ty(expr.hir_id).kind() {
ty::Ref(_, _, mt_orig) => {
let mutbl_adj: hir::Mutability = mutbl_adj.into();
@@ -1458,7 +1460,7 @@ impl<'tcx, 'exprs, E: AsCoercionSite> CoerceMany<'tcx, 'exprs, E> {
cause,
expected,
found,
- coercion_error,
+ coercion_error.clone(),
fcx,
parent_id,
expression.map(|expr| (expr, blk_id)),
@@ -1472,7 +1474,7 @@ impl<'tcx, 'exprs, E: AsCoercionSite> CoerceMany<'tcx, 'exprs, E> {
cause,
expected,
found,
- coercion_error,
+ coercion_error.clone(),
fcx,
id,
None,
@@ -1483,7 +1485,12 @@ impl<'tcx, 'exprs, E: AsCoercionSite> CoerceMany<'tcx, 'exprs, E> {
}
}
_ => {
- err = fcx.report_mismatched_types(cause, expected, found, coercion_error);
+ err = fcx.report_mismatched_types(
+ cause,
+ expected,
+ found,
+ coercion_error.clone(),
+ );
}
}
@@ -1492,7 +1499,14 @@ impl<'tcx, 'exprs, E: AsCoercionSite> CoerceMany<'tcx, 'exprs, E> {
}
if let Some(expr) = expression {
- fcx.emit_coerce_suggestions(&mut err, expr, found, expected, None);
+ fcx.emit_coerce_suggestions(
+ &mut err,
+ expr,
+ found,
+ expected,
+ None,
+ coercion_error,
+ );
}
err.emit_unless(unsized_return);
@@ -1625,11 +1639,10 @@ impl<'tcx, 'exprs, E: AsCoercionSite> CoerceMany<'tcx, 'exprs, E> {
let ty = <dyn AstConv<'_>>::ast_ty_to_ty(fcx, ty);
// Get the `impl Trait`'s `DefId`.
if let ty::Opaque(def_id, _) = ty.kind() {
- let hir_id = fcx.tcx.hir().local_def_id_to_hir_id(def_id.expect_local());
// Get the `impl Trait`'s `Item` so that we can get its trait bounds and
// get the `Trait`'s `DefId`.
if let hir::ItemKind::OpaqueTy(hir::OpaqueTy { bounds, .. }) =
- fcx.tcx.hir().expect_item(hir_id).kind
+ fcx.tcx.hir().expect_item(def_id.expect_local()).kind
{
// Are of this `impl Trait`'s traits object safe?
is_object_safe = bounds.iter().all(|bound| {
@@ -1681,7 +1694,7 @@ impl<'tcx, 'exprs, E: AsCoercionSite> CoerceMany<'tcx, 'exprs, E> {
err.help("you could instead create a new `enum` with a variant for each returned type");
}
- fn is_return_ty_unsized(&self, fcx: &FnCtxt<'a, 'tcx>, blk_id: hir::HirId) -> bool {
+ fn is_return_ty_unsized<'a>(&self, fcx: &FnCtxt<'a, 'tcx>, blk_id: hir::HirId) -> bool {
if let Some((fn_decl, _)) = fcx.get_fn_decl(blk_id) {
if let hir::FnRetTy::Return(ty) = fn_decl.output {
let ty = <dyn AstConv<'_>>::ast_ty_to_ty(fcx, ty);
diff --git a/compiler/rustc_typeck/src/check/compare_method.rs b/compiler/rustc_typeck/src/check/compare_method.rs
index 4d4662f73a9..11560f51822 100644
--- a/compiler/rustc_typeck/src/check/compare_method.rs
+++ b/compiler/rustc_typeck/src/check/compare_method.rs
@@ -208,8 +208,11 @@ fn compare_predicate_entailment<'tcx>(
// The key step here is to update the caller_bounds's predicates to be
// the new hybrid bounds we computed.
let normalize_cause = traits::ObligationCause::misc(impl_m_span, impl_m_hir_id);
- let param_env =
- ty::ParamEnv::new(tcx.intern_predicates(&hybrid_preds.predicates), Reveal::UserFacing);
+ let param_env = ty::ParamEnv::new(
+ tcx.intern_predicates(&hybrid_preds.predicates),
+ Reveal::UserFacing,
+ hir::Constness::NotConst,
+ );
let param_env =
traits::normalize_param_env_or_error(tcx, impl_m.def_id, param_env, normalize_cause);
@@ -264,14 +267,9 @@ fn compare_predicate_entailment<'tcx>(
// First liberate late bound regions and subst placeholders
let trait_sig = tcx.liberate_late_bound_regions(impl_m.def_id, tcx.fn_sig(trait_m.def_id));
let trait_sig = trait_sig.subst(tcx, trait_to_placeholder_substs);
- // Next, add all inputs and output as well-formed tys. Importantly,
- // we have to do this before normalization, since the normalized ty may
- // not contain the input parameters. See issue #87748.
- wf_tys.extend(trait_sig.inputs_and_output.iter());
let trait_sig =
inh.normalize_associated_types_in(impl_m_span, impl_m_hir_id, param_env, trait_sig);
- // Also add the resulting inputs and output as well-formed.
- // This probably isn't strictly necessary.
+ // Add the resulting inputs and output as well-formed.
wf_tys.extend(trait_sig.inputs_and_output.iter());
let trait_fty = tcx.mk_fn_ptr(ty::Binder::dummy(trait_sig));
@@ -322,9 +320,7 @@ fn compare_predicate_entailment<'tcx>(
// When the `impl` receiver is an arbitrary self type, like `self: Box<Self>`, the
// span points only at the type `Box<Self`>, but we want to cover the whole
// argument pattern and type.
- let impl_m_hir_id =
- tcx.hir().local_def_id_to_hir_id(impl_m.def_id.expect_local());
- let span = match tcx.hir().expect_impl_item(impl_m_hir_id).kind {
+ let span = match tcx.hir().expect_impl_item(impl_m.def_id.expect_local()).kind {
ImplItemKind::Fn(ref sig, body) => tcx
.hir()
.body_param_names(body)
@@ -346,9 +342,7 @@ fn compare_predicate_entailment<'tcx>(
if trait_sig.inputs().len() == *i {
// Suggestion to change output type. We do not suggest in `async` functions
// to avoid complex logic or incorrect output.
- let impl_m_hir_id =
- tcx.hir().local_def_id_to_hir_id(impl_m.def_id.expect_local());
- match tcx.hir().expect_impl_item(impl_m_hir_id).kind {
+ match tcx.hir().expect_impl_item(impl_m.def_id.expect_local()).kind {
ImplItemKind::Fn(ref sig, _)
if sig.header.asyncness == hir::IsAsync::NotAsync =>
{
@@ -388,6 +382,7 @@ fn compare_predicate_entailment<'tcx>(
found: impl_fty,
})),
&terr,
+ false,
);
diag.emit();
return Err(ErrorReported);
@@ -467,22 +462,19 @@ fn extract_spans_for_error_reporting<'a, 'tcx>(
trait_m: &ty::AssocItem,
) -> (Span, Option<Span>) {
let tcx = infcx.tcx;
- let impl_m_hir_id = tcx.hir().local_def_id_to_hir_id(impl_m.def_id.expect_local());
- let mut impl_args = match tcx.hir().expect_impl_item(impl_m_hir_id).kind {
+ let mut impl_args = match tcx.hir().expect_impl_item(impl_m.def_id.expect_local()).kind {
ImplItemKind::Fn(ref sig, _) => {
sig.decl.inputs.iter().map(|t| t.span).chain(iter::once(sig.decl.output.span()))
}
_ => bug!("{:?} is not a method", impl_m),
};
- let trait_args = trait_m.def_id.as_local().map(|def_id| {
- let trait_m_hir_id = tcx.hir().local_def_id_to_hir_id(def_id);
- match tcx.hir().expect_trait_item(trait_m_hir_id).kind {
+ let trait_args =
+ trait_m.def_id.as_local().map(|def_id| match tcx.hir().expect_trait_item(def_id).kind {
TraitItemKind::Fn(ref sig, _) => {
sig.decl.inputs.iter().map(|t| t.span).chain(iter::once(sig.decl.output.span()))
}
_ => bug!("{:?} is not a TraitItemKind::Fn", trait_m),
- }
- });
+ });
match *terr {
TypeError::ArgumentMutability(i) => {
@@ -600,8 +592,7 @@ fn compare_number_of_generics<'tcx>(
err_occurred = true;
let (trait_spans, impl_trait_spans) = if let Some(def_id) = trait_.def_id.as_local() {
- let trait_hir_id = tcx.hir().local_def_id_to_hir_id(def_id);
- let trait_item = tcx.hir().expect_trait_item(trait_hir_id);
+ let trait_item = tcx.hir().expect_trait_item(def_id);
if trait_item.generics.params.is_empty() {
(Some(vec![trait_item.generics.span]), vec![])
} else {
@@ -622,8 +613,7 @@ fn compare_number_of_generics<'tcx>(
(trait_span.map(|s| vec![s]), vec![])
};
- let impl_hir_id = tcx.hir().local_def_id_to_hir_id(impl_.def_id.expect_local());
- let impl_item = tcx.hir().expect_impl_item(impl_hir_id);
+ let impl_item = tcx.hir().expect_impl_item(impl_.def_id.expect_local());
let impl_item_impl_trait_spans: Vec<Span> = impl_item
.generics
.params
@@ -711,8 +701,7 @@ fn compare_number_of_method_arguments<'tcx>(
let impl_number_args = impl_m_fty.inputs().skip_binder().len();
if trait_number_args != impl_number_args {
let trait_span = if let Some(def_id) = trait_m.def_id.as_local() {
- let trait_id = tcx.hir().local_def_id_to_hir_id(def_id);
- match tcx.hir().expect_trait_item(trait_id).kind {
+ match tcx.hir().expect_trait_item(def_id).kind {
TraitItemKind::Fn(ref trait_m_sig, _) => {
let pos = if trait_number_args > 0 { trait_number_args - 1 } else { 0 };
if let Some(arg) = trait_m_sig.decl.inputs.get(pos) {
@@ -730,8 +719,7 @@ fn compare_number_of_method_arguments<'tcx>(
} else {
trait_item_span
};
- let impl_m_hir_id = tcx.hir().local_def_id_to_hir_id(impl_m.def_id.expect_local());
- let impl_span = match tcx.hir().expect_impl_item(impl_m_hir_id).kind {
+ let impl_span = match tcx.hir().expect_impl_item(impl_m.def_id.expect_local()).kind {
ImplItemKind::Fn(ref impl_m_sig, _) => {
let pos = if impl_number_args > 0 { impl_number_args - 1 } else { 0 };
if let Some(arg) = impl_m_sig.decl.inputs.get(pos) {
@@ -750,8 +738,7 @@ fn compare_number_of_method_arguments<'tcx>(
tcx.sess,
impl_span,
E0050,
- "method `{}` has {} but the declaration in \
- trait `{}` has {}",
+ "method `{}` has {} but the declaration in trait `{}` has {}",
trait_m.ident,
potentially_plural_count(impl_number_args, "parameter"),
tcx.def_path_str(trait_m.def_id),
@@ -1055,7 +1042,7 @@ crate fn compare_const_impl<'tcx>(
);
// Locate the Span containing just the type of the offending impl
- match tcx.hir().expect_impl_item(impl_c_hir_id).kind {
+ match tcx.hir().expect_impl_item(impl_c.def_id.expect_local()).kind {
ImplItemKind::Const(ref ty, _) => cause.make_mut().span = ty.span,
_ => bug!("{:?} is not a impl const", impl_c),
}
@@ -1068,11 +1055,9 @@ crate fn compare_const_impl<'tcx>(
trait_c.ident
);
- let trait_c_hir_id =
- trait_c.def_id.as_local().map(|def_id| tcx.hir().local_def_id_to_hir_id(def_id));
- let trait_c_span = trait_c_hir_id.map(|trait_c_hir_id| {
+ let trait_c_span = trait_c.def_id.as_local().map(|trait_c_def_id| {
// Add a label to the Span containing just the type of the const
- match tcx.hir().expect_trait_item(trait_c_hir_id).kind {
+ match tcx.hir().expect_trait_item(trait_c_def_id).kind {
TraitItemKind::Const(ref ty, _) => ty.span,
_ => bug!("{:?} is not a trait const", trait_c),
}
@@ -1087,6 +1072,7 @@ crate fn compare_const_impl<'tcx>(
found: impl_ty,
})),
&terr,
+ false,
);
diag.emit();
}
@@ -1117,7 +1103,8 @@ crate fn compare_ty_impl<'tcx>(
let _: Result<(), ErrorReported> = (|| {
compare_number_of_generics(tcx, impl_ty, impl_ty_span, trait_ty, trait_item_span)?;
- compare_type_predicate_entailment(tcx, impl_ty, impl_ty_span, trait_ty, impl_trait_ref)?;
+ let sp = tcx.def_span(impl_ty.def_id);
+ compare_type_predicate_entailment(tcx, impl_ty, sp, trait_ty, impl_trait_ref)?;
check_type_bounds(tcx, trait_ty, impl_ty, impl_ty_span, impl_trait_ref)
})();
@@ -1183,8 +1170,11 @@ fn compare_type_predicate_entailment<'tcx>(
debug!("compare_type_predicate_entailment: bounds={:?}", hybrid_preds);
let normalize_cause = traits::ObligationCause::misc(impl_ty_span, impl_ty_hir_id);
- let param_env =
- ty::ParamEnv::new(tcx.intern_predicates(&hybrid_preds.predicates), Reveal::UserFacing);
+ let param_env = ty::ParamEnv::new(
+ tcx.intern_predicates(&hybrid_preds.predicates),
+ Reveal::UserFacing,
+ hir::Constness::NotConst,
+ );
let param_env = traits::normalize_param_env_or_error(
tcx,
impl_ty.def_id,
@@ -1369,7 +1359,11 @@ pub fn check_type_bounds<'tcx>(
.to_predicate(tcx),
),
};
- ty::ParamEnv::new(tcx.intern_predicates(&predicates), Reveal::UserFacing)
+ ty::ParamEnv::new(
+ tcx.intern_predicates(&predicates),
+ Reveal::UserFacing,
+ param_env.constness(),
+ )
};
debug!(?normalize_param_env);
@@ -1378,13 +1372,7 @@ pub fn check_type_bounds<'tcx>(
impl_ty_substs.rebase_onto(tcx, impl_ty.container.id(), impl_trait_ref.substs);
tcx.infer_ctxt().enter(move |infcx| {
- let constness = impl_ty
- .container
- .impl_def_id()
- .map(|did| tcx.impl_constness(did))
- .unwrap_or(hir::Constness::NotConst);
-
- let inh = Inherited::with_constness(infcx, impl_ty.def_id.expect_local(), constness);
+ let inh = Inherited::new(infcx, impl_ty.def_id.expect_local());
let infcx = &inh.infcx;
let mut selcx = traits::SelectionContext::new(&infcx);
@@ -1428,8 +1416,7 @@ pub fn check_type_bounds<'tcx>(
// Check that all obligations are satisfied by the implementation's
// version.
- let errors =
- inh.fulfillment_cx.borrow_mut().select_all_with_constness_or_error(&infcx, constness);
+ let errors = inh.fulfillment_cx.borrow_mut().select_all_or_error(&infcx);
if !errors.is_empty() {
infcx.report_fulfillment_errors(&errors, None, false);
return Err(ErrorReported);
diff --git a/compiler/rustc_typeck/src/check/demand.rs b/compiler/rustc_typeck/src/check/demand.rs
index ece2d7b4f37..b7e276b6965 100644
--- a/compiler/rustc_typeck/src/check/demand.rs
+++ b/compiler/rustc_typeck/src/check/demand.rs
@@ -10,6 +10,7 @@ use rustc_hir::lang_items::LangItem;
use rustc_hir::{is_range_literal, Node};
use rustc_middle::lint::in_external_macro;
use rustc_middle::ty::adjustment::AllowTwoPhase;
+use rustc_middle::ty::error::{ExpectedFound, TypeError};
use rustc_middle::ty::print::with_no_trimmed_paths;
use rustc_middle::ty::{self, AssocItem, Ty, TypeAndMut};
use rustc_span::symbol::sym;
@@ -27,8 +28,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
expr_ty: Ty<'tcx>,
expected: Ty<'tcx>,
expected_ty_expr: Option<&'tcx hir::Expr<'tcx>>,
+ error: TypeError<'tcx>,
) {
- self.annotate_expected_due_to_let_ty(err, expr);
+ self.annotate_expected_due_to_let_ty(err, expr, error);
self.suggest_box_deref(err, expr, expected, expr_ty);
self.suggest_compatible_variants(err, expr, expected, expr_ty);
self.suggest_deref_ref_or_into(err, expr, expected, expr_ty, expected_ty_expr);
@@ -145,9 +147,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
let expr = expr.peel_drop_temps();
let cause = self.misc(expr.span);
let expr_ty = self.resolve_vars_with_obligations(checked_ty);
- let mut err = self.report_mismatched_types(&cause, expected, expr_ty, e);
+ let mut err = self.report_mismatched_types(&cause, expected, expr_ty, e.clone());
- self.emit_coerce_suggestions(&mut err, expr, expr_ty, expected, expected_ty_expr);
+ self.emit_coerce_suggestions(&mut err, expr, expr_ty, expected, expected_ty_expr, e);
(expected, Some(err))
}
@@ -156,15 +158,104 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
&self,
err: &mut DiagnosticBuilder<'_>,
expr: &hir::Expr<'_>,
+ error: TypeError<'_>,
) {
let parent = self.tcx.hir().get_parent_node(expr.hir_id);
- if let Some(hir::Node::Local(hir::Local { ty: Some(ty), init: Some(init), .. })) =
- self.tcx.hir().find(parent)
- {
- if init.hir_id == expr.hir_id {
+ match (self.tcx.hir().find(parent), error) {
+ (Some(hir::Node::Local(hir::Local { ty: Some(ty), init: Some(init), .. })), _)
+ if init.hir_id == expr.hir_id =>
+ {
// Point at `let` assignment type.
err.span_label(ty.span, "expected due to this");
}
+ (
+ Some(hir::Node::Expr(hir::Expr {
+ kind: hir::ExprKind::Assign(lhs, rhs, _), ..
+ })),
+ TypeError::Sorts(ExpectedFound { expected, .. }),
+ ) if rhs.hir_id == expr.hir_id && !expected.is_closure() => {
+ // We ignore closures explicitly because we already point at them elsewhere.
+ // Point at the assigned-to binding.
+ let mut primary_span = lhs.span;
+ let mut secondary_span = lhs.span;
+ let mut post_message = "";
+ match lhs.kind {
+ hir::ExprKind::Path(hir::QPath::Resolved(
+ None,
+ hir::Path {
+ res:
+ hir::def::Res::Def(
+ hir::def::DefKind::Static | hir::def::DefKind::Const,
+ def_id,
+ ),
+ ..
+ },
+ )) => {
+ if let Some(hir::Node::Item(hir::Item {
+ ident,
+ kind: hir::ItemKind::Static(ty, ..) | hir::ItemKind::Const(ty, ..),
+ ..
+ })) = self.tcx.hir().get_if_local(*def_id)
+ {
+ primary_span = ty.span;
+ secondary_span = ident.span;
+ post_message = " type";
+ }
+ }
+ hir::ExprKind::Path(hir::QPath::Resolved(
+ None,
+ hir::Path { res: hir::def::Res::Local(hir_id), .. },
+ )) => {
+ if let Some(hir::Node::Binding(pat)) = self.tcx.hir().find(*hir_id) {
+ let parent = self.tcx.hir().get_parent_node(pat.hir_id);
+ primary_span = pat.span;
+ secondary_span = pat.span;
+ match self.tcx.hir().find(parent) {
+ Some(hir::Node::Local(hir::Local { ty: Some(ty), .. })) => {
+ primary_span = ty.span;
+ post_message = " type";
+ }
+ Some(hir::Node::Local(hir::Local { init: Some(init), .. })) => {
+ primary_span = init.span;
+ post_message = " value";
+ }
+ Some(hir::Node::Param(hir::Param { ty_span, .. })) => {
+ primary_span = *ty_span;
+ post_message = " parameter type";
+ }
+ _ => {}
+ }
+ }
+ }
+ _ => {}
+ }
+
+ if primary_span != secondary_span
+ && self
+ .tcx
+ .sess
+ .source_map()
+ .is_multiline(secondary_span.shrink_to_hi().until(primary_span))
+ {
+ // We are pointing at the binding's type or initializer value, but it's pattern
+ // is in a different line, so we point at both.
+ err.span_label(secondary_span, "expected due to the type of this binding");
+ err.span_label(primary_span, &format!("expected due to this{}", post_message));
+ } else if post_message == "" {
+ // We are pointing at either the assignment lhs or the binding def pattern.
+ err.span_label(primary_span, "expected due to the type of this binding");
+ } else {
+ // We are pointing at the binding's type or initializer value.
+ err.span_label(primary_span, &format!("expected due to this{}", post_message));
+ }
+
+ if !lhs.is_syntactic_place_expr() {
+ // We already emitted E0070 "invalid left-hand side of assignment", so we
+ // silence this.
+ err.delay_as_bug();
+ }
+ }
+ _ => {}
}
}
@@ -1132,7 +1223,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
// Missing try_into implementation for `{integer}` to `{float}`
err.multipart_suggestion_verbose(
&format!(
- "{}, producing the floating point representation of the integer,
+ "{}, producing the floating point representation of the integer, \
rounded if necessary",
cast_msg,
),
@@ -1173,6 +1264,18 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
}
true
}
+ (
+ &ty::Uint(ty::UintTy::U32 | ty::UintTy::U64 | ty::UintTy::U128)
+ | &ty::Int(ty::IntTy::I32 | ty::IntTy::I64 | ty::IntTy::I128),
+ &ty::Char,
+ ) => {
+ err.multipart_suggestion_verbose(
+ &format!("{}, since a `char` always occupies 4 bytes", cast_msg,),
+ cast_suggestion,
+ Applicability::MachineApplicable,
+ );
+ true
+ }
_ => false,
}
}
diff --git a/compiler/rustc_typeck/src/check/dropck.rs b/compiler/rustc_typeck/src/check/dropck.rs
index 4b4d29307ff..3cc66aaf0d7 100644
--- a/compiler/rustc_typeck/src/check/dropck.rs
+++ b/compiler/rustc_typeck/src/check/dropck.rs
@@ -302,7 +302,7 @@ impl<'tcx> SimpleEqRelation<'tcx> {
}
}
-impl TypeRelation<'tcx> for SimpleEqRelation<'tcx> {
+impl<'tcx> TypeRelation<'tcx> for SimpleEqRelation<'tcx> {
fn tcx(&self) -> TyCtxt<'tcx> {
self.tcx
}
diff --git a/compiler/rustc_typeck/src/check/expr.rs b/compiler/rustc_typeck/src/check/expr.rs
index c9fa0fd72fc..096c4fcf472 100644
--- a/compiler/rustc_typeck/src/check/expr.rs
+++ b/compiler/rustc_typeck/src/check/expr.rs
@@ -36,8 +36,8 @@ use rustc_infer::infer;
use rustc_infer::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind};
use rustc_infer::infer::InferOk;
use rustc_middle::ty::adjustment::{Adjust, Adjustment, AllowTwoPhase};
+use rustc_middle::ty::error::ExpectedFound;
use rustc_middle::ty::error::TypeError::{FieldMisMatch, Sorts};
-use rustc_middle::ty::relate::expected_found_bool;
use rustc_middle::ty::subst::SubstsRef;
use rustc_middle::ty::{self, AdtKind, Ty, TypeFoldable};
use rustc_session::parse::feature_err;
@@ -46,6 +46,7 @@ use rustc_span::hygiene::DesugaringKind;
use rustc_span::lev_distance::find_best_match_for_name;
use rustc_span::source_map::Span;
use rustc_span::symbol::{kw, sym, Ident, Symbol};
+use rustc_span::{BytePos, Pos};
use rustc_trait_selection::traits::{self, ObligationCauseCode};
impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
@@ -276,8 +277,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
ExprKind::AddrOf(kind, mutbl, oprnd) => {
self.check_expr_addr_of(kind, mutbl, oprnd, expected, expr)
}
- ExprKind::Path(QPath::LangItem(lang_item, _)) => {
- self.check_lang_item_path(lang_item, expr)
+ ExprKind::Path(QPath::LangItem(lang_item, _, hir_id)) => {
+ self.check_lang_item_path(lang_item, expr, hir_id)
}
ExprKind::Path(ref qpath) => self.check_expr_path(qpath, expr, &[]),
ExprKind::InlineAsm(asm) => self.check_expr_asm(asm),
@@ -299,7 +300,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
}
}
ExprKind::Ret(ref expr_opt) => self.check_expr_return(expr_opt.as_deref(), expr),
- ExprKind::Let(pat, let_expr, _) => self.check_expr_let(let_expr, pat),
+ ExprKind::Let(let_expr) => self.check_expr_let(let_expr),
ExprKind::Loop(body, _, source, _) => {
self.check_expr_loop(body, source, expected, expr)
}
@@ -497,8 +498,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
&self,
lang_item: hir::LangItem,
expr: &'tcx hir::Expr<'tcx>,
+ hir_id: Option<hir::HirId>,
) -> Ty<'tcx> {
- self.resolve_lang_item_path(lang_item, expr.span, expr.hir_id).1
+ self.resolve_lang_item_path(lang_item, expr.span, expr.hir_id, hir_id).1
}
pub(crate) fn check_expr_path(
@@ -833,7 +835,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
&self,
lhs: &'tcx hir::Expr<'tcx>,
err_code: &'static str,
- expr_span: &Span,
+ op_span: Span,
) {
if lhs.is_syntactic_place_expr() {
return;
@@ -841,11 +843,53 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
// FIXME: Make this use SessionDiagnostic once error codes can be dynamically set.
let mut err = self.tcx.sess.struct_span_err_with_code(
- *expr_span,
+ op_span,
"invalid left-hand side of assignment",
DiagnosticId::Error(err_code.into()),
);
err.span_label(lhs.span, "cannot assign to this expression");
+
+ let mut parent = self.tcx.hir().get_parent_node(lhs.hir_id);
+ while let Some(node) = self.tcx.hir().find(parent) {
+ match node {
+ hir::Node::Expr(hir::Expr {
+ kind:
+ hir::ExprKind::Loop(
+ hir::Block {
+ expr:
+ Some(hir::Expr {
+ kind:
+ hir::ExprKind::Match(expr, ..) | hir::ExprKind::If(expr, ..),
+ ..
+ }),
+ ..
+ },
+ _,
+ hir::LoopSource::While,
+ _,
+ ),
+ ..
+ }) => {
+ // We have a situation like `while Some(0) = value.get(0) {`, where `while let`
+ // was more likely intended.
+ err.span_suggestion_verbose(
+ expr.span.shrink_to_lo(),
+ "you might have meant to use pattern destructuring",
+ "let ".to_string(),
+ Applicability::MachineApplicable,
+ );
+ break;
+ }
+ hir::Node::Item(_)
+ | hir::Node::ImplItem(_)
+ | hir::Node::TraitItem(_)
+ | hir::Node::Crate(_) => break,
+ _ => {
+ parent = self.tcx.hir().get_parent_node(parent);
+ }
+ }
+ }
+
err.emit();
}
@@ -953,7 +997,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
} else {
(Applicability::MaybeIncorrect, false)
};
- if !lhs.is_syntactic_place_expr() {
+ if !lhs.is_syntactic_place_expr() && !matches!(lhs.kind, hir::ExprKind::Lit(_)) {
// Do not suggest `if let x = y` as `==` is way more likely to be the intention.
let hir = self.tcx.hir();
if let hir::Node::Expr(hir::Expr { kind: ExprKind::If { .. }, .. }) =
@@ -965,7 +1009,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
"let ".to_string(),
applicability,
);
- }
+ };
}
if eq {
err.span_suggestion_verbose(
@@ -986,7 +1030,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
return self.tcx.ty_error();
}
- self.check_lhs_assignable(lhs, "E0070", span);
+ self.check_lhs_assignable(lhs, "E0070", *span);
let lhs_ty = self.check_expr_with_needs(&lhs, Needs::MutPlace);
let rhs_ty = self.check_expr_coercable_to_type(&rhs, lhs_ty, Some(lhs));
@@ -1000,10 +1044,13 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
}
}
- fn check_expr_let(&self, expr: &'tcx hir::Expr<'tcx>, pat: &'tcx hir::Pat<'tcx>) -> Ty<'tcx> {
- self.warn_if_unreachable(expr.hir_id, expr.span, "block in `let` expression");
- let expr_ty = self.demand_scrutinee_type(expr, pat.contains_explicit_ref_binding(), false);
- self.check_pat_top(pat, expr_ty, Some(expr.span), true);
+ fn check_expr_let(&self, let_expr: &'tcx hir::Let<'tcx>) -> Ty<'tcx> {
+ // for let statements, this is done in check_stmt
+ let init = let_expr.init;
+ self.warn_if_unreachable(init.hir_id, init.span, "block in `let` expression");
+ // otherwise check exactly as a let statement
+ self.check_decl(let_expr.into());
+ // but return a bool, for this is a boolean expression
self.tcx.types.bool
}
@@ -1446,7 +1493,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
&self.misc(base_expr.span),
adt_ty,
base_ty,
- Sorts(expected_found_bool(true, adt_ty, base_ty)),
+ Sorts(ExpectedFound::new(true, adt_ty, base_ty)),
)
.emit();
}
@@ -2016,7 +2063,36 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
Some(span),
);
} else {
- err.help("methods are immutable and cannot be assigned to");
+ let mut found = false;
+
+ if let ty::RawPtr(ty_and_mut) = expr_t.kind() {
+ if let ty::Adt(adt_def, _) = ty_and_mut.ty.kind() {
+ if adt_def.variants.len() == 1
+ && adt_def
+ .variants
+ .iter()
+ .next()
+ .unwrap()
+ .fields
+ .iter()
+ .any(|f| f.ident == field)
+ {
+ if let Some(dot_loc) = expr_snippet.rfind('.') {
+ found = true;
+ err.span_suggestion(
+ expr.span.with_hi(expr.span.lo() + BytePos::from_usize(dot_loc)),
+ "to access the field, dereference first",
+ format!("(*{})", &expr_snippet[0..dot_loc]),
+ Applicability::MaybeIncorrect,
+ );
+ }
+ }
+ }
+ }
+
+ if !found {
+ err.help("methods are immutable and cannot be assigned to");
+ }
}
err.emit();
diff --git a/compiler/rustc_typeck/src/check/fn_ctxt/_impl.rs b/compiler/rustc_typeck/src/check/fn_ctxt/_impl.rs
index 142a0a8fc25..67630fd4e58 100644
--- a/compiler/rustc_typeck/src/check/fn_ctxt/_impl.rs
+++ b/compiler/rustc_typeck/src/check/fn_ctxt/_impl.rs
@@ -6,7 +6,6 @@ use crate::check::callee::{self, DeferredCallResolution};
use crate::check::method::{self, MethodCallee, SelfSource};
use crate::check::{BreakableCtxt, Diverges, Expectation, FnCtxt, LocalTy};
-use rustc_ast::TraitObjectSyntax;
use rustc_data_structures::captures::Captures;
use rustc_data_structures::fx::FxHashSet;
use rustc_errors::{Applicability, DiagnosticBuilder, ErrorReported};
@@ -14,7 +13,7 @@ use rustc_hir as hir;
use rustc_hir::def::{CtorOf, DefKind, Res};
use rustc_hir::def_id::DefId;
use rustc_hir::lang_items::LangItem;
-use rustc_hir::{ExprKind, GenericArg, Node, QPath, TyKind};
+use rustc_hir::{ExprKind, GenericArg, Node, QPath};
use rustc_infer::infer::canonical::{Canonical, OriginalQueryValues, QueryResponse};
use rustc_infer::infer::error_reporting::TypeAnnotationNeeded::E0282;
use rustc_infer::infer::{InferOk, InferResult};
@@ -28,8 +27,6 @@ use rustc_middle::ty::{
Ty, UserType,
};
use rustc_session::lint;
-use rustc_session::lint::builtin::BARE_TRAIT_OBJECTS;
-use rustc_span::edition::Edition;
use rustc_span::hygiene::DesugaringKind;
use rustc_span::source_map::{original_sp, DUMMY_SP};
use rustc_span::symbol::{kw, sym, Ident};
@@ -304,20 +301,26 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
// is a valid NeverToAny adjustment, because it can't
// be reached.
(&[Adjustment { kind: Adjust::NeverToAny, .. }], _) => return,
- (&[
- Adjustment { kind: Adjust::Deref(_), .. },
- Adjustment { kind: Adjust::Borrow(AutoBorrow::Ref(..)), .. },
- ], &[
- Adjustment { kind: Adjust::Deref(_), .. },
- .. // Any following adjustments are allowed.
- ]) => {
+ (
+ &[
+ Adjustment { kind: Adjust::Deref(_), .. },
+ Adjustment { kind: Adjust::Borrow(AutoBorrow::Ref(..)), .. },
+ ],
+ &[
+ Adjustment { kind: Adjust::Deref(_), .. },
+ .., // Any following adjustments are allowed.
+ ],
+ ) => {
// A reborrow has no effect before a dereference.
}
// FIXME: currently we never try to compose autoderefs
// and ReifyFnPointer/UnsafeFnPointer, but we could.
- _ =>
- bug!("while adjusting {:?}, can't compose {:?} and {:?}",
- expr, entry.get(), adj)
+ _ => bug!(
+ "while adjusting {:?}, can't compose {:?} and {:?}",
+ expr,
+ entry.get(),
+ adj
+ ),
};
*entry.get_mut() = adj;
}
@@ -610,10 +613,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
#[instrument(skip(self), level = "debug")]
pub(in super::super) fn select_all_obligations_or_error(&self) {
- let errors = self
- .fulfillment_cx
- .borrow_mut()
- .select_all_with_constness_or_error(&self, self.inh.constness);
+ let errors = self.fulfillment_cx.borrow_mut().select_all_or_error(&self);
if !errors.is_empty() {
self.report_fulfillment_errors(&errors, self.inh.body_id, false);
@@ -626,10 +626,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
fallback_has_occurred: bool,
mutate_fulfillment_errors: impl Fn(&mut Vec<traits::FulfillmentError<'tcx>>),
) {
- let mut result = self
- .fulfillment_cx
- .borrow_mut()
- .select_with_constness_where_possible(self, self.inh.constness);
+ let mut result = self.fulfillment_cx.borrow_mut().select_where_possible(self);
if !result.is_empty() {
mutate_fulfillment_errors(&mut result);
self.report_fulfillment_errors(&result, self.inh.body_id, fallback_has_occurred);
@@ -791,6 +788,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
lang_item: hir::LangItem,
span: Span,
hir_id: hir::HirId,
+ expr_hir_id: Option<hir::HirId>,
) -> (Res, Ty<'tcx>) {
let def_id = self.tcx.require_lang_item(lang_item, Some(span));
let def_kind = self.tcx.def_kind(def_id);
@@ -804,7 +802,23 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
let ty = item_ty.subst(self.tcx, substs);
self.write_resolution(hir_id, Ok((def_kind, def_id)));
- self.add_required_obligations(span, def_id, &substs);
+ self.add_required_obligations_with_code(
+ span,
+ def_id,
+ &substs,
+ match lang_item {
+ hir::LangItem::IntoFutureIntoFuture => {
+ ObligationCauseCode::AwaitableExpr(expr_hir_id)
+ }
+ hir::LangItem::IteratorNext | hir::LangItem::IntoIterIntoIter => {
+ ObligationCauseCode::ForLoopIterator
+ }
+ hir::LangItem::TryTraitFromOutput
+ | hir::LangItem::TryTraitFromResidual
+ | hir::LangItem::TryTraitBranch => ObligationCauseCode::QuestionMark,
+ _ => traits::ItemObligation(def_id),
+ },
+ );
(Res::Def(def_kind, def_id), ty)
}
@@ -838,7 +852,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
// to be object-safe.
// We manually call `register_wf_obligation` in the success path
// below.
- (<dyn AstConv<'_>>::ast_ty_to_ty(self, qself), qself, segment)
+ (<dyn AstConv<'_>>::ast_ty_to_ty_in_path(self, qself), qself, segment)
}
QPath::LangItem(..) => {
bug!("`resolve_ty_and_res_fully_qualified_call` called on `LangItem`")
@@ -884,7 +898,6 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
});
if result.is_ok() {
- self.maybe_lint_bare_trait(qpath, hir_id, span);
self.register_wf_obligation(ty.into(), qself.span, traits::WellFormed(None));
}
@@ -897,56 +910,6 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
)
}
- fn maybe_lint_bare_trait(&self, qpath: &QPath<'_>, hir_id: hir::HirId, span: Span) {
- if let QPath::TypeRelative(self_ty, _) = qpath {
- if let TyKind::TraitObject([poly_trait_ref, ..], _, TraitObjectSyntax::None) =
- self_ty.kind
- {
- let msg = "trait objects without an explicit `dyn` are deprecated";
- let (sugg, app) = match self.tcx.sess.source_map().span_to_snippet(self_ty.span) {
- Ok(s) if poly_trait_ref.trait_ref.path.is_global() => {
- (format!("dyn ({})", s), Applicability::MachineApplicable)
- }
- Ok(s) => (format!("dyn {}", s), Applicability::MachineApplicable),
- Err(_) => ("dyn <type>".to_string(), Applicability::HasPlaceholders),
- };
- // Wrap in `<..>` if it isn't already.
- let sugg = match self.tcx.sess.source_map().span_to_snippet(span) {
- Ok(s) if s.starts_with('<') => sugg,
- _ => format!("<{}>", sugg),
- };
- let sugg_label = "use `dyn`";
- if self.sess().edition() >= Edition::Edition2021 {
- let mut err = rustc_errors::struct_span_err!(
- self.sess(),
- self_ty.span,
- E0782,
- "{}",
- msg,
- );
- err.span_suggestion(
- self_ty.span,
- sugg_label,
- sugg,
- Applicability::MachineApplicable,
- )
- .emit();
- } else {
- self.tcx.struct_span_lint_hir(
- BARE_TRAIT_OBJECTS,
- hir_id,
- self_ty.span,
- |lint| {
- let mut db = lint.build(msg);
- db.span_suggestion(self_ty.span, sugg_label, sugg, app);
- db.emit()
- },
- );
- }
- }
- }
- }
-
/// Given a function `Node`, return its `FnDecl` if it exists, or `None` otherwise.
pub(in super::super) fn get_node_fn_decl(
&self,
@@ -1097,12 +1060,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
(_, _) => return None,
};
- let last_hir_id = self.tcx.hir().local_def_id_to_hir_id(last_local_id);
- let exp_hir_id = self.tcx.hir().local_def_id_to_hir_id(exp_local_id);
-
match (
- &self.tcx.hir().expect_item(last_hir_id).kind,
- &self.tcx.hir().expect_item(exp_hir_id).kind,
+ &self.tcx.hir().expect_item(last_local_id).kind,
+ &self.tcx.hir().expect_item(exp_local_id).kind,
) {
(
hir::ItemKind::OpaqueTy(hir::OpaqueTy { bounds: last_bounds, .. }),
@@ -1433,7 +1393,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
<dyn AstConv<'_>>::create_substs_for_generic_args(
tcx,
def_id,
- &[][..],
+ &[],
has_self,
self_ty,
&arg_count,
@@ -1489,12 +1449,27 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
}
/// Add all the obligations that are required, substituting and normalized appropriately.
- #[tracing::instrument(level = "debug", skip(self, span, def_id, substs))]
crate fn add_required_obligations(&self, span: Span, def_id: DefId, substs: &SubstsRef<'tcx>) {
+ self.add_required_obligations_with_code(
+ span,
+ def_id,
+ substs,
+ traits::ItemObligation(def_id),
+ )
+ }
+
+ #[tracing::instrument(level = "debug", skip(self, span, def_id, substs))]
+ fn add_required_obligations_with_code(
+ &self,
+ span: Span,
+ def_id: DefId,
+ substs: &SubstsRef<'tcx>,
+ code: ObligationCauseCode<'tcx>,
+ ) {
let (bounds, _) = self.instantiate_bounds(span, def_id, &substs);
for obligation in traits::predicates_for_generics(
- traits::ObligationCause::new(span, self.body_id, traits::ItemObligation(def_id)),
+ traits::ObligationCause::new(span, self.body_id, code),
self.param_env,
bounds,
) {
diff --git a/compiler/rustc_typeck/src/check/fn_ctxt/checks.rs b/compiler/rustc_typeck/src/check/fn_ctxt/checks.rs
index a119a6838b8..38a8c1bb9f5 100644
--- a/compiler/rustc_typeck/src/check/fn_ctxt/checks.rs
+++ b/compiler/rustc_typeck/src/check/fn_ctxt/checks.rs
@@ -1,5 +1,6 @@
use crate::astconv::AstConv;
use crate::check::coercion::CoerceMany;
+use crate::check::gather_locals::Declaration;
use crate::check::method::MethodCallee;
use crate::check::Expectation::*;
use crate::check::TupleArgumentsFlag::*;
@@ -54,13 +55,13 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
let err_inputs = match tuple_arguments {
DontTupleArguments => err_inputs,
- TupleArguments => vec![self.tcx.intern_tup(&err_inputs[..])],
+ TupleArguments => vec![self.tcx.intern_tup(&err_inputs)],
};
self.check_argument_types(
sp,
expr,
- &err_inputs[..],
+ &err_inputs,
&[],
args_no_rcvr,
false,
@@ -324,7 +325,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
self.point_at_type_arg_instead_of_call_if_possible(errors, expr);
self.point_at_arg_instead_of_call_if_possible(
errors,
- &final_arg_types[..],
+ &final_arg_types,
expr,
sp,
&args,
@@ -538,16 +539,17 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
pub fn check_decl_initializer(
&self,
- local: &'tcx hir::Local<'tcx>,
+ hir_id: hir::HirId,
+ pat: &'tcx hir::Pat<'tcx>,
init: &'tcx hir::Expr<'tcx>,
) -> Ty<'tcx> {
// FIXME(tschottdorf): `contains_explicit_ref_binding()` must be removed
// for #42640 (default match binding modes).
//
// See #44848.
- let ref_bindings = local.pat.contains_explicit_ref_binding();
+ let ref_bindings = pat.contains_explicit_ref_binding();
- let local_ty = self.local_ty(init.span, local.hir_id).revealed_ty;
+ let local_ty = self.local_ty(init.span, hir_id).revealed_ty;
if let Some(m) = ref_bindings {
// Somewhat subtle: if we have a `ref` binding in the pattern,
// we want to avoid introducing coercions for the RHS. This is
@@ -565,29 +567,33 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
}
}
- /// Type check a `let` statement.
- pub fn check_decl_local(&self, local: &'tcx hir::Local<'tcx>) {
+ pub(in super::super) fn check_decl(&self, decl: Declaration<'tcx>) {
// Determine and write the type which we'll check the pattern against.
- let ty = self.local_ty(local.span, local.hir_id).decl_ty;
- self.write_ty(local.hir_id, ty);
+ let decl_ty = self.local_ty(decl.span, decl.hir_id).decl_ty;
+ self.write_ty(decl.hir_id, decl_ty);
// Type check the initializer.
- if let Some(ref init) = local.init {
- let init_ty = self.check_decl_initializer(local, &init);
- self.overwrite_local_ty_if_err(local, ty, init_ty);
+ if let Some(ref init) = decl.init {
+ let init_ty = self.check_decl_initializer(decl.hir_id, decl.pat, &init);
+ self.overwrite_local_ty_if_err(decl.hir_id, decl.pat, decl_ty, init_ty);
}
// Does the expected pattern type originate from an expression and what is the span?
- let (origin_expr, ty_span) = match (local.ty, local.init) {
+ let (origin_expr, ty_span) = match (decl.ty, decl.init) {
(Some(ty), _) => (false, Some(ty.span)), // Bias towards the explicit user type.
(_, Some(init)) => (true, Some(init.span)), // No explicit type; so use the scrutinee.
_ => (false, None), // We have `let $pat;`, so the expected type is unconstrained.
};
// Type check the pattern. Override if necessary to avoid knock-on errors.
- self.check_pat_top(&local.pat, ty, ty_span, origin_expr);
- let pat_ty = self.node_ty(local.pat.hir_id);
- self.overwrite_local_ty_if_err(local, ty, pat_ty);
+ self.check_pat_top(&decl.pat, decl_ty, ty_span, origin_expr);
+ let pat_ty = self.node_ty(decl.pat.hir_id);
+ self.overwrite_local_ty_if_err(decl.hir_id, decl.pat, decl_ty, pat_ty);
+ }
+
+ /// Type check a `let` statement.
+ pub fn check_decl_local(&self, local: &'tcx hir::Local<'tcx>) {
+ self.check_decl(local.into());
}
pub fn check_stmt(&self, stmt: &'tcx hir::Stmt<'tcx>, is_last: bool) {
@@ -737,6 +743,24 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
&mut |err| {
if let Some(expected_ty) = expected.only_has_type(self) {
self.consider_hint_about_removing_semicolon(blk, expected_ty, err);
+ if expected_ty == self.tcx.types.bool {
+ // If this is caused by a missing `let` in a `while let`,
+ // silence this redundant error, as we already emit E0070.
+ let parent = self.tcx.hir().get_parent_node(blk.hir_id);
+ let parent = self.tcx.hir().get_parent_node(parent);
+ let parent = self.tcx.hir().get_parent_node(parent);
+ let parent = self.tcx.hir().get_parent_node(parent);
+ let parent = self.tcx.hir().get_parent_node(parent);
+ match self.tcx.hir().find(parent) {
+ Some(hir::Node::Expr(hir::Expr {
+ kind: hir::ExprKind::Loop(_, _, hir::LoopSource::While, _),
+ ..
+ })) => {
+ err.delay_as_bug();
+ }
+ _ => {}
+ }
+ }
}
if let Some(fn_span) = fn_span {
err.span_label(
@@ -873,17 +897,18 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
fn overwrite_local_ty_if_err(
&self,
- local: &'tcx hir::Local<'tcx>,
+ hir_id: hir::HirId,
+ pat: &'tcx hir::Pat<'tcx>,
decl_ty: Ty<'tcx>,
ty: Ty<'tcx>,
) {
if ty.references_error() {
// Override the types everywhere with `err()` to avoid knock on errors.
- self.write_ty(local.hir_id, ty);
- self.write_ty(local.pat.hir_id, ty);
+ self.write_ty(hir_id, ty);
+ self.write_ty(pat.hir_id, ty);
let local_ty = LocalTy { decl_ty, revealed_ty: ty };
- self.locals.borrow_mut().insert(local.hir_id, local_ty);
- self.locals.borrow_mut().insert(local.pat.hir_id, local_ty);
+ self.locals.borrow_mut().insert(hir_id, local_ty);
+ self.locals.borrow_mut().insert(pat.hir_id, local_ty);
}
}
@@ -920,8 +945,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
(result.map_or(Res::Err, |(kind, def_id)| Res::Def(kind, def_id)), ty)
}
- QPath::LangItem(lang_item, span) => {
- self.resolve_lang_item_path(lang_item, span, hir_id)
+ QPath::LangItem(lang_item, span, id) => {
+ self.resolve_lang_item_path(lang_item, span, hir_id, id)
}
}
}
diff --git a/compiler/rustc_typeck/src/check/gather_locals.rs b/compiler/rustc_typeck/src/check/gather_locals.rs
index 4ebfd7fd212..839bd56b396 100644
--- a/compiler/rustc_typeck/src/check/gather_locals.rs
+++ b/compiler/rustc_typeck/src/check/gather_locals.rs
@@ -7,6 +7,31 @@ use rustc_middle::ty::Ty;
use rustc_span::Span;
use rustc_trait_selection::traits;
+/// A declaration is an abstraction of [hir::Local] and [hir::Let].
+///
+/// It must have a hir_id, as this is how we connect gather_locals to the check functions.
+pub(super) struct Declaration<'a> {
+ pub hir_id: hir::HirId,
+ pub pat: &'a hir::Pat<'a>,
+ pub ty: Option<&'a hir::Ty<'a>>,
+ pub span: Span,
+ pub init: Option<&'a hir::Expr<'a>>,
+}
+
+impl<'a> From<&'a hir::Local<'a>> for Declaration<'a> {
+ fn from(local: &'a hir::Local<'a>) -> Self {
+ let hir::Local { hir_id, pat, ty, span, init, .. } = *local;
+ Declaration { hir_id, pat, ty, span, init }
+ }
+}
+
+impl<'a> From<&'a hir::Let<'a>> for Declaration<'a> {
+ fn from(let_expr: &'a hir::Let<'a>) -> Self {
+ let hir::Let { hir_id, pat, ty, span, init } = *let_expr;
+ Declaration { hir_id, pat, ty, span, init: Some(init) }
+ }
+}
+
pub(super) struct GatherLocalsVisitor<'a, 'tcx> {
fcx: &'a FnCtxt<'a, 'tcx>,
// parameters are special cases of patterns, but we want to handle them as
@@ -41,18 +66,12 @@ impl<'a, 'tcx> GatherLocalsVisitor<'a, 'tcx> {
}
}
}
-}
-
-impl<'a, 'tcx> Visitor<'tcx> for GatherLocalsVisitor<'a, 'tcx> {
- type Map = intravisit::ErasedMap<'tcx>;
-
- fn nested_visit_map(&mut self) -> NestedVisitorMap<Self::Map> {
- NestedVisitorMap::None
- }
- // Add explicitly-declared locals.
- fn visit_local(&mut self, local: &'tcx hir::Local<'tcx>) {
- let local_ty = match local.ty {
+ /// Allocates a [LocalTy] for a declaration, which may have a type annotation. If it does have
+ /// a type annotation, then the LocalTy stored will be the resolved type. This may be found
+ /// again during type checking by querying [FnCtxt::local_ty] for the same hir_id.
+ fn declare(&mut self, decl: Declaration<'tcx>) {
+ let local_ty = match decl.ty {
Some(ref ty) => {
let o_ty = self.fcx.to_ty(&ty);
@@ -68,16 +87,34 @@ impl<'a, 'tcx> Visitor<'tcx> for GatherLocalsVisitor<'a, 'tcx> {
}
None => None,
};
- self.assign(local.span, local.hir_id, local_ty);
+ self.assign(decl.span, decl.hir_id, local_ty);
debug!(
"local variable {:?} is assigned type {}",
- local.pat,
- self.fcx.ty_to_string(&*self.fcx.locals.borrow().get(&local.hir_id).unwrap().decl_ty)
+ decl.pat,
+ self.fcx.ty_to_string(&*self.fcx.locals.borrow().get(&decl.hir_id).unwrap().decl_ty)
);
+ }
+}
+
+impl<'a, 'tcx> Visitor<'tcx> for GatherLocalsVisitor<'a, 'tcx> {
+ type Map = intravisit::ErasedMap<'tcx>;
+
+ fn nested_visit_map(&mut self) -> NestedVisitorMap<Self::Map> {
+ NestedVisitorMap::None
+ }
+
+ // Add explicitly-declared locals.
+ fn visit_local(&mut self, local: &'tcx hir::Local<'tcx>) {
+ self.declare(local.into());
intravisit::walk_local(self, local);
}
+ fn visit_let_expr(&mut self, let_expr: &'tcx hir::Let<'tcx>) {
+ self.declare(let_expr.into());
+ intravisit::walk_let_expr(self, let_expr);
+ }
+
fn visit_param(&mut self, param: &'tcx hir::Param<'tcx>) {
let old_outermost_fn_param_pat = self.outermost_fn_param_pat.replace(param.ty_span);
intravisit::walk_param(self, param);
diff --git a/compiler/rustc_typeck/src/check/generator_interior.rs b/compiler/rustc_typeck/src/check/generator_interior.rs
index 2910ce6de68..37e601fa404 100644
--- a/compiler/rustc_typeck/src/check/generator_interior.rs
+++ b/compiler/rustc_typeck/src/check/generator_interior.rs
@@ -536,22 +536,28 @@ pub fn check_must_not_suspend_ty<'tcx>(
}
has_emitted
}
- ty::Tuple(ref tys) => {
+ ty::Tuple(_) => {
let mut has_emitted = false;
- let spans = if let Some(hir::ExprKind::Tup(comps)) = data.expr.map(|e| &e.kind) {
- debug_assert_eq!(comps.len(), tys.len());
- comps.iter().map(|e| e.span).collect()
- } else {
- vec![]
+ let comps = match data.expr.map(|e| &e.kind) {
+ Some(hir::ExprKind::Tup(comps)) => {
+ debug_assert_eq!(comps.len(), ty.tuple_fields().count());
+ Some(comps)
+ }
+ _ => None,
};
- for (i, ty) in tys.iter().map(|k| k.expect_ty()).enumerate() {
+ for (i, ty) in ty.tuple_fields().enumerate() {
let descr_post = &format!(" in tuple element {}", i);
- let span = *spans.get(i).unwrap_or(&data.source_span);
+ let span = comps.and_then(|c| c.get(i)).map(|e| e.span).unwrap_or(data.source_span);
if check_must_not_suspend_ty(
fcx,
ty,
hir_id,
- SuspendCheckData { descr_post, source_span: span, ..data },
+ SuspendCheckData {
+ descr_post,
+ expr: comps.and_then(|comps| comps.get(i)),
+ source_span: span,
+ ..data
+ },
) {
has_emitted = true;
}
diff --git a/compiler/rustc_typeck/src/check/inherited.rs b/compiler/rustc_typeck/src/check/inherited.rs
index f7552c1f4eb..beb6b371b2b 100644
--- a/compiler/rustc_typeck/src/check/inherited.rs
+++ b/compiler/rustc_typeck/src/check/inherited.rs
@@ -53,9 +53,6 @@ pub struct Inherited<'a, 'tcx> {
pub(super) deferred_generator_interiors:
RefCell<Vec<(hir::BodyId, Ty<'tcx>, hir::GeneratorKind)>>,
- /// Reports whether this is in a const context.
- pub(super) constness: hir::Constness,
-
pub(super) body_id: Option<hir::BodyId>,
/// Whenever we introduce an adjustment from `!` into a type variable,
@@ -79,7 +76,7 @@ pub struct InheritedBuilder<'tcx> {
def_id: LocalDefId,
}
-impl Inherited<'_, 'tcx> {
+impl<'tcx> Inherited<'_, 'tcx> {
pub fn build(tcx: TyCtxt<'tcx>, def_id: LocalDefId) -> InheritedBuilder<'tcx> {
let hir_owner = tcx.hir().local_def_id_to_hir_id(def_id).owner;
@@ -100,20 +97,10 @@ impl<'tcx> InheritedBuilder<'tcx> {
}
}
-impl Inherited<'a, 'tcx> {
+impl<'a, 'tcx> Inherited<'a, 'tcx> {
pub(super) fn new(infcx: InferCtxt<'a, 'tcx>, def_id: LocalDefId) -> Self {
let tcx = infcx.tcx;
let item_id = tcx.hir().local_def_id_to_hir_id(def_id);
- Self::with_constness(infcx, def_id, tcx.hir().get(item_id).constness_for_typeck())
- }
-
- pub(super) fn with_constness(
- infcx: InferCtxt<'a, 'tcx>,
- def_id: LocalDefId,
- constness: hir::Constness,
- ) -> Self {
- let tcx = infcx.tcx;
- let item_id = tcx.hir().local_def_id_to_hir_id(def_id);
let body_id = tcx.hir().maybe_body_owned_by(item_id);
Inherited {
@@ -128,7 +115,6 @@ impl Inherited<'a, 'tcx> {
deferred_cast_checks: RefCell::new(Vec::new()),
deferred_generator_interiors: RefCell::new(Vec::new()),
diverging_type_vars: RefCell::new(Default::default()),
- constness,
body_id,
}
}
diff --git a/compiler/rustc_typeck/src/check/method/mod.rs b/compiler/rustc_typeck/src/check/method/mod.rs
index dbc1d4ec193..03518dc8d12 100644
--- a/compiler/rustc_typeck/src/check/method/mod.rs
+++ b/compiler/rustc_typeck/src/check/method/mod.rs
@@ -22,7 +22,7 @@ use rustc_infer::infer::{self, InferOk};
use rustc_middle::ty::subst::Subst;
use rustc_middle::ty::subst::{InternalSubsts, SubstsRef};
use rustc_middle::ty::GenericParamDefKind;
-use rustc_middle::ty::{self, ToPredicate, Ty, TypeFoldable, WithConstness};
+use rustc_middle::ty::{self, ToPredicate, Ty, TypeFoldable};
use rustc_span::symbol::Ident;
use rustc_span::Span;
use rustc_trait_selection::traits;
diff --git a/compiler/rustc_typeck/src/check/method/prelude2021.rs b/compiler/rustc_typeck/src/check/method/prelude2021.rs
index 5c8056b2442..bc2859719e8 100644
--- a/compiler/rustc_typeck/src/check/method/prelude2021.rs
+++ b/compiler/rustc_typeck/src/check/method/prelude2021.rs
@@ -345,10 +345,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
let import_items: Vec<_> = applicable_trait
.import_ids
.iter()
- .map(|&import_id| {
- let hir_id = self.tcx.hir().local_def_id_to_hir_id(import_id);
- self.tcx.hir().expect_item(hir_id)
- })
+ .map(|&import_id| self.tcx.hir().expect_item(import_id))
.collect();
// Find an identifier with which this trait was imported (note that `_` doesn't count).
diff --git a/compiler/rustc_typeck/src/check/method/probe.rs b/compiler/rustc_typeck/src/check/method/probe.rs
index 9fd7e8c4daa..dc724396094 100644
--- a/compiler/rustc_typeck/src/check/method/probe.rs
+++ b/compiler/rustc_typeck/src/check/method/probe.rs
@@ -21,7 +21,7 @@ use rustc_infer::infer::{self, InferOk, TyCtxtInferExt};
use rustc_middle::middle::stability;
use rustc_middle::ty::subst::{InternalSubsts, Subst, SubstsRef};
use rustc_middle::ty::GenericParamDefKind;
-use rustc_middle::ty::{self, ParamEnvAnd, ToPredicate, Ty, TyCtxt, TypeFoldable, WithConstness};
+use rustc_middle::ty::{self, ParamEnvAnd, ToPredicate, Ty, TyCtxt, TypeFoldable};
use rustc_session::lint;
use rustc_span::def_id::LocalDefId;
use rustc_span::lev_distance::{find_best_match_for_name, lev_distance};
@@ -1372,7 +1372,7 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> {
if applicable_candidates.len() > 1 {
if let Some(pick) =
- self.collapse_candidates_to_trait_pick(self_ty, &applicable_candidates[..])
+ self.collapse_candidates_to_trait_pick(self_ty, &applicable_candidates)
{
return Some(Ok(pick));
}
diff --git a/compiler/rustc_typeck/src/check/method/suggest.rs b/compiler/rustc_typeck/src/check/method/suggest.rs
index ca174ed5e84..168bdce3210 100644
--- a/compiler/rustc_typeck/src/check/method/suggest.rs
+++ b/compiler/rustc_typeck/src/check/method/suggest.rs
@@ -10,9 +10,9 @@ use rustc_hir::def_id::{DefId, LocalDefId, CRATE_DEF_INDEX};
use rustc_hir::lang_items::LangItem;
use rustc_hir::{ExprKind, Node, QPath};
use rustc_infer::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind};
-use rustc_middle::ty::fast_reject::simplify_type;
+use rustc_middle::ty::fast_reject::{simplify_type, SimplifyParams, StripReferences};
use rustc_middle::ty::print::with_crate_prefix;
-use rustc_middle::ty::{self, ToPredicate, Ty, TyCtxt, TypeFoldable, WithConstness};
+use rustc_middle::ty::{self, ToPredicate, Ty, TyCtxt, TypeFoldable};
use rustc_span::lev_distance;
use rustc_span::symbol::{kw, sym, Ident};
use rustc_span::{source_map, FileName, MultiSpan, Span, Symbol};
@@ -67,6 +67,10 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
}
}
+ fn is_slice_ty(&self, ty: Ty<'tcx>, span: Span) -> bool {
+ self.autoderef(span, ty).any(|(ty, _)| matches!(ty.kind(), ty::Slice(..) | ty::Array(..)))
+ }
+
pub fn report_method_error(
&self,
mut span: Span,
@@ -691,7 +695,23 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
let mut restrict_type_params = false;
let mut unsatisfied_bounds = false;
- if !unsatisfied_predicates.is_empty() {
+ if item_name.name == sym::count && self.is_slice_ty(actual, span) {
+ let msg = "consider using `len` instead";
+ if let SelfSource::MethodCall(_expr) = source {
+ err.span_suggestion_short(
+ span,
+ msg,
+ String::from("len"),
+ Applicability::MachineApplicable,
+ );
+ } else {
+ err.span_label(span, msg);
+ }
+ if let Some(iterator_trait) = self.tcx.get_diagnostic_item(sym::Iterator) {
+ let iterator_trait = self.tcx.def_path_str(iterator_trait);
+ err.note(&format!("`count` is defined on `{iterator_trait}`, which `{actual}` does not implement"));
+ }
+ } else if !unsatisfied_predicates.is_empty() {
let def_span = |def_id| {
self.tcx.sess.source_map().guess_head_span(self.tcx.def_span(def_id))
};
@@ -990,9 +1010,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
}
}
- let mut fallback_span = true;
- let msg = "remove this method call";
if item_name.name == sym::as_str && actual.peel_refs().is_str() {
+ let msg = "remove this method call";
+ let mut fallback_span = true;
if let SelfSource::MethodCall(expr) = source {
let call_expr =
self.tcx.hir().expect_expr(self.tcx.hir().get_parent_node(expr.hir_id));
@@ -1324,7 +1344,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
if candidates.len() > limit {
msg.push_str(&format!("\nand {} others", candidates.len() - limit));
}
- err.note(&msg[..]);
+ err.note(&msg);
}
}
@@ -1683,7 +1703,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
// FIXME: Even though negative bounds are not implemented, we could maybe handle
// cases where a positive bound implies a negative impl.
(candidates, Vec::new())
- } else if let Some(simp_rcvr_ty) = simplify_type(self.tcx, rcvr_ty, true) {
+ } else if let Some(simp_rcvr_ty) =
+ simplify_type(self.tcx, rcvr_ty, SimplifyParams::Yes, StripReferences::No)
+ {
let mut potential_candidates = Vec::new();
let mut explicitly_negative = Vec::new();
for candidate in candidates {
@@ -1696,7 +1718,12 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
})
.any(|imp_did| {
let imp = self.tcx.impl_trait_ref(imp_did).unwrap();
- let imp_simp = simplify_type(self.tcx, imp.self_ty(), true);
+ let imp_simp = simplify_type(
+ self.tcx,
+ imp.self_ty(),
+ SimplifyParams::Yes,
+ StripReferences::No,
+ );
imp_simp.map_or(false, |s| s == simp_rcvr_ty)
})
{
@@ -1948,7 +1975,7 @@ fn find_use_placement<'tcx>(tcx: TyCtxt<'tcx>, target_module: LocalDefId) -> (Op
(span, found_use)
}
-fn print_disambiguation_help(
+fn print_disambiguation_help<'tcx>(
item_name: Ident,
args: Option<&'tcx [hir::Expr<'tcx>]>,
err: &mut DiagnosticBuilder<'_>,
diff --git a/compiler/rustc_typeck/src/check/mod.rs b/compiler/rustc_typeck/src/check/mod.rs
index e7fba3a70ff..a9e6b1caff0 100644
--- a/compiler/rustc_typeck/src/check/mod.rs
+++ b/compiler/rustc_typeck/src/check/mod.rs
@@ -391,7 +391,6 @@ fn typeck_with_fallback<'tcx>(
let mut wf_tys = FxHashSet::default();
// Compute the fty from point of view of inside the fn.
let fn_sig = tcx.liberate_late_bound_regions(def_id.to_def_id(), fn_sig);
- wf_tys.extend(fn_sig.inputs_and_output.iter());
let fn_sig = inh.normalize_associated_types_in(
body.value.span,
body_id.hir_id,
@@ -509,7 +508,7 @@ struct GeneratorTypes<'tcx> {
/// Given a `DefId` for an opaque type in return position, find its parent item's return
/// expressions.
-fn get_owner_return_paths(
+fn get_owner_return_paths<'tcx>(
tcx: TyCtxt<'tcx>,
def_id: LocalDefId,
) -> Option<(hir::HirId, ReturnsVisitor<'tcx>)> {
@@ -687,9 +686,8 @@ fn bounds_from_generic_predicates<'tcx>(
};
let mut where_clauses = vec![];
for (ty, bounds) in types {
- for bound in &bounds {
- where_clauses.push(format!("{}: {}", ty, tcx.def_path_str(*bound)));
- }
+ where_clauses
+ .extend(bounds.into_iter().map(|bound| format!("{}: {}", ty, tcx.def_path_str(bound))));
}
for projection in &projections {
let p = projection.skip_binder();
@@ -908,7 +906,7 @@ struct CheckItemTypesVisitor<'tcx> {
tcx: TyCtxt<'tcx>,
}
-impl ItemLikeVisitor<'tcx> for CheckItemTypesVisitor<'tcx> {
+impl<'tcx> ItemLikeVisitor<'tcx> for CheckItemTypesVisitor<'tcx> {
fn visit_item(&mut self, i: &'tcx hir::Item<'tcx>) {
check_item_type(self.tcx, i);
}
diff --git a/compiler/rustc_typeck/src/check/op.rs b/compiler/rustc_typeck/src/check/op.rs
index 9c53a1d4eb6..8ebfcdd539b 100644
--- a/compiler/rustc_typeck/src/check/op.rs
+++ b/compiler/rustc_typeck/src/check/op.rs
@@ -42,7 +42,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
return_ty
};
- self.check_lhs_assignable(lhs, "E0067", &op.span);
+ self.check_lhs_assignable(lhs, "E0067", op.span);
ty
}
@@ -492,7 +492,6 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
) -> bool /* did we suggest to call a function because of missing parentheses? */ {
err.span_label(span, ty.to_string());
if let FnDef(def_id, _) = *ty.kind() {
- let source_map = self.tcx.sess.source_map();
if !self.tcx.has_typeck_results(def_id) {
return false;
}
@@ -517,20 +516,18 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
.lookup_op_method(fn_sig.output(), &[other_ty], Op::Binary(op, is_assign))
.is_ok()
{
- if let Ok(snippet) = source_map.span_to_snippet(span) {
- let (variable_snippet, applicability) = if !fn_sig.inputs().is_empty() {
- (format!("{}( /* arguments */ )", snippet), Applicability::HasPlaceholders)
- } else {
- (format!("{}()", snippet), Applicability::MaybeIncorrect)
- };
+ let (variable_snippet, applicability) = if !fn_sig.inputs().is_empty() {
+ ("( /* arguments */ )".to_string(), Applicability::HasPlaceholders)
+ } else {
+ ("()".to_string(), Applicability::MaybeIncorrect)
+ };
- err.span_suggestion(
- span,
- "you might have forgotten to call this function",
- variable_snippet,
- applicability,
- );
- }
+ err.span_suggestion_verbose(
+ span.shrink_to_hi(),
+ "you might have forgotten to call this function",
+ variable_snippet,
+ applicability,
+ );
return true;
}
}
@@ -896,7 +893,7 @@ enum Op {
}
/// Dereferences a single level of immutable referencing.
-fn deref_ty_if_possible(ty: Ty<'tcx>) -> Ty<'tcx> {
+fn deref_ty_if_possible<'tcx>(ty: Ty<'tcx>) -> Ty<'tcx> {
match ty.kind() {
ty::Ref(_, ty, hir::Mutability::Not) => ty,
_ => ty,
@@ -1010,7 +1007,7 @@ impl<'tcx> TypeVisitor<'tcx> for TypeParamVisitor<'tcx> {
struct TypeParamEraser<'a, 'tcx>(&'a FnCtxt<'a, 'tcx>, Span);
-impl TypeFolder<'tcx> for TypeParamEraser<'_, 'tcx> {
+impl<'tcx> TypeFolder<'tcx> for TypeParamEraser<'_, 'tcx> {
fn tcx(&self) -> TyCtxt<'tcx> {
self.0.tcx
}
diff --git a/compiler/rustc_typeck/src/check/pat.rs b/compiler/rustc_typeck/src/check/pat.rs
index cbf33cf1b78..ec06e0b1126 100644
--- a/compiler/rustc_typeck/src/check/pat.rs
+++ b/compiler/rustc_typeck/src/check/pat.rs
@@ -740,7 +740,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
}
}
- fn check_pat_path(
+ fn check_pat_path<'b>(
&self,
pat: &Pat<'_>,
path_resolution: (Res, Option<Ty<'tcx>>, &'b [hir::PathSegment<'b>]),
@@ -816,7 +816,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
false
}
- fn emit_bad_pat_path(
+ fn emit_bad_pat_path<'b>(
&self,
mut e: DiagnosticBuilder<'_>,
pat_span: Span,
diff --git a/compiler/rustc_typeck/src/check/place_op.rs b/compiler/rustc_typeck/src/check/place_op.rs
index 5d9e6ebd50c..d01e21bcb23 100644
--- a/compiler/rustc_typeck/src/check/place_op.rs
+++ b/compiler/rustc_typeck/src/check/place_op.rs
@@ -440,8 +440,11 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
}
// If we have an autoref followed by unsizing at the end, fix the unsize target.
- if let [.., Adjustment { kind: Adjust::Borrow(AutoBorrow::Ref(..)), .. }, Adjustment { kind: Adjust::Pointer(PointerCast::Unsize), ref mut target }] =
- adjustments[..]
+ if let [
+ ..,
+ Adjustment { kind: Adjust::Borrow(AutoBorrow::Ref(..)), .. },
+ Adjustment { kind: Adjust::Pointer(PointerCast::Unsize), ref mut target },
+ ] = adjustments[..]
{
*target = method.sig.inputs()[0];
}
diff --git a/compiler/rustc_typeck/src/check/regionck.rs b/compiler/rustc_typeck/src/check/regionck.rs
index d2d8b14dd96..1b42edc83be 100644
--- a/compiler/rustc_typeck/src/check/regionck.rs
+++ b/compiler/rustc_typeck/src/check/regionck.rs
@@ -106,7 +106,7 @@ macro_rules! ignore_err {
pub(crate) trait OutlivesEnvironmentExt<'tcx> {
fn add_implied_bounds(
&mut self,
- infcx: &InferCtxt<'a, 'tcx>,
+ infcx: &InferCtxt<'_, 'tcx>,
fn_sig_tys: FxHashSet<Ty<'tcx>>,
body_id: hir::HirId,
span: Span,
@@ -130,7 +130,7 @@ impl<'tcx> OutlivesEnvironmentExt<'tcx> for OutlivesEnvironment<'tcx> {
/// add those assumptions into the outlives-environment.
///
/// Tests: `src/test/ui/regions/regions-free-region-ordering-*.rs`
- fn add_implied_bounds(
+ fn add_implied_bounds<'a>(
&mut self,
infcx: &InferCtxt<'a, 'tcx>,
fn_sig_tys: FxHashSet<Ty<'tcx>>,
diff --git a/compiler/rustc_typeck/src/check/upvar.rs b/compiler/rustc_typeck/src/check/upvar.rs
index 5f5d308a332..ffd7d29bbbb 100644
--- a/compiler/rustc_typeck/src/check/upvar.rs
+++ b/compiler/rustc_typeck/src/check/upvar.rs
@@ -687,15 +687,11 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
r
),
(
- l
- @
- (ProjectionKind::Index
+ l @ (ProjectionKind::Index
| ProjectionKind::Subslice
| ProjectionKind::Deref
| ProjectionKind::Field(..)),
- r
- @
- (ProjectionKind::Index
+ r @ (ProjectionKind::Index
| ProjectionKind::Subslice
| ProjectionKind::Deref
| ProjectionKind::Field(..)),
@@ -908,10 +904,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
) -> MigrationWarningReason {
let mut reasons = MigrationWarningReason::default();
- for auto_trait in auto_trait_reasons {
- reasons.auto_traits.push(auto_trait);
- }
-
+ reasons.auto_traits.extend(auto_trait_reasons);
reasons.drop_order = drop_order;
reasons
@@ -1679,7 +1672,7 @@ fn restrict_repr_packed_field_ref_capture<'tcx>(
}
/// Returns a Ty that applies the specified capture kind on the provided capture Ty
-fn apply_capture_kind_on_capture_ty(
+fn apply_capture_kind_on_capture_ty<'tcx>(
tcx: TyCtxt<'tcx>,
ty: Ty<'tcx>,
capture_kind: UpvarCapture<'tcx>,
@@ -1692,7 +1685,7 @@ fn apply_capture_kind_on_capture_ty(
}
/// Returns the Span of where the value with the provided HirId would be dropped
-fn drop_location_span(tcx: TyCtxt<'tcx>, hir_id: &hir::HirId) -> Span {
+fn drop_location_span<'tcx>(tcx: TyCtxt<'tcx>, hir_id: &hir::HirId) -> Span {
let owner_id = tcx.hir().get_enclosing_scope(*hir_id).unwrap();
let owner_node = tcx.hir().get(owner_id);
@@ -2006,7 +1999,7 @@ fn restrict_precision_for_drop_types<'a, 'tcx>(
/// - No projections are applied to raw pointers, since these require unsafe blocks. We capture
/// them completely.
/// - No projections are applied on top of Union ADTs, since these require unsafe blocks.
-fn restrict_precision_for_unsafe(
+fn restrict_precision_for_unsafe<'tcx>(
mut place: Place<'tcx>,
mut curr_mode: ty::UpvarCapture<'tcx>,
) -> (Place<'tcx>, ty::UpvarCapture<'tcx>) {
@@ -2104,7 +2097,7 @@ fn adjust_for_non_move_closure<'tcx>(
(place, kind)
}
-fn construct_place_string(tcx: TyCtxt<'_>, place: &Place<'tcx>) -> String {
+fn construct_place_string<'tcx>(tcx: TyCtxt<'_>, place: &Place<'tcx>) -> String {
let variable_name = match place.base {
PlaceBase::Upvar(upvar_id) => var_name(tcx, upvar_id.var_path.hir_id).to_string(),
_ => bug!("Capture_information should only contain upvars"),
@@ -2127,7 +2120,7 @@ fn construct_place_string(tcx: TyCtxt<'_>, place: &Place<'tcx>) -> String {
format!("{}[{}]", variable_name, projections_str)
}
-fn construct_capture_kind_reason_string(
+fn construct_capture_kind_reason_string<'tcx>(
tcx: TyCtxt<'_>,
place: &Place<'tcx>,
capture_info: &ty::CaptureInfo<'tcx>,
@@ -2142,13 +2135,13 @@ fn construct_capture_kind_reason_string(
format!("{} captured as {} here", place_str, capture_kind_str)
}
-fn construct_path_string(tcx: TyCtxt<'_>, place: &Place<'tcx>) -> String {
+fn construct_path_string<'tcx>(tcx: TyCtxt<'_>, place: &Place<'tcx>) -> String {
let place_str = construct_place_string(tcx, place);
format!("{} used here", place_str)
}
-fn construct_capture_info_string(
+fn construct_capture_info_string<'tcx>(
tcx: TyCtxt<'_>,
place: &Place<'tcx>,
capture_info: &ty::CaptureInfo<'tcx>,
@@ -2240,7 +2233,7 @@ fn migration_suggestion_for_2229(
/// would've already handled `E1`, and have an existing capture_information for it.
/// Calling `determine_capture_info(existing_info_e1, current_info_e2)` will return
/// `existing_info_e1` in this case, allowing us to point to `E1` in case of diagnostics.
-fn determine_capture_info(
+fn determine_capture_info<'tcx>(
capture_info_a: ty::CaptureInfo<'tcx>,
capture_info_b: ty::CaptureInfo<'tcx>,
) -> ty::CaptureInfo<'tcx> {
@@ -2299,7 +2292,7 @@ fn determine_capture_info(
///
/// Note: Capture kind changes from `MutBorrow` to `UniqueImmBorrow` if the truncated part of the `place`
/// contained `Deref` of `&mut`.
-fn truncate_place_to_len_and_update_capture_kind(
+fn truncate_place_to_len_and_update_capture_kind<'tcx>(
place: &mut Place<'tcx>,
curr_mode: &mut ty::UpvarCapture<'tcx>,
len: usize,
@@ -2337,7 +2330,7 @@ fn truncate_place_to_len_and_update_capture_kind(
/// `PlaceAncestryRelation::Ancestor` implies Place A is ancestor of Place B
/// `PlaceAncestryRelation::Descendant` implies Place A is descendant of Place B
/// `PlaceAncestryRelation::Divergent` implies neither of them is the ancestor of the other.
-fn determine_place_ancestry_relation(
+fn determine_place_ancestry_relation<'tcx>(
place_a: &Place<'tcx>,
place_b: &Place<'tcx>,
) -> PlaceAncestryRelation {
diff --git a/compiler/rustc_typeck/src/check/wfcheck.rs b/compiler/rustc_typeck/src/check/wfcheck.rs
index 0050ac99cb1..7c4f5d16abc 100644
--- a/compiler/rustc_typeck/src/check/wfcheck.rs
+++ b/compiler/rustc_typeck/src/check/wfcheck.rs
@@ -21,7 +21,6 @@ use rustc_middle::ty::subst::{GenericArgKind, InternalSubsts, Subst};
use rustc_middle::ty::trait_def::TraitSpecializationKind;
use rustc_middle::ty::{
self, AdtKind, GenericParamDefKind, ToPredicate, Ty, TyCtxt, TypeFoldable, TypeVisitor,
- WithConstness,
};
use rustc_session::parse::feature_err;
use rustc_span::symbol::{sym, Ident, Symbol};
@@ -84,8 +83,7 @@ impl<'tcx> CheckWfFcxBuilder<'tcx> {
/// the types first.
#[instrument(skip(tcx), level = "debug")]
pub fn check_item_well_formed(tcx: TyCtxt<'_>, def_id: LocalDefId) {
- let hir_id = tcx.hir().local_def_id_to_hir_id(def_id);
- let item = tcx.hir().expect_item(hir_id);
+ let item = tcx.hir().expect_item(def_id);
debug!(
?item.def_id,
@@ -197,7 +195,7 @@ pub fn check_item_well_formed(tcx: TyCtxt<'_>, def_id: LocalDefId) {
pub fn check_trait_item(tcx: TyCtxt<'_>, def_id: LocalDefId) {
let hir_id = tcx.hir().local_def_id_to_hir_id(def_id);
- let trait_item = tcx.hir().expect_trait_item(hir_id);
+ let trait_item = tcx.hir().expect_trait_item(def_id);
let (method_sig, span) = match trait_item.kind {
hir::TraitItemKind::Fn(ref sig, _) => (Some(sig), trait_item.span),
@@ -207,8 +205,8 @@ pub fn check_trait_item(tcx: TyCtxt<'_>, def_id: LocalDefId) {
check_object_unsafe_self_trait_by_name(tcx, trait_item);
check_associated_item(tcx, trait_item.def_id, span, method_sig);
- let encl_trait_hir_id = tcx.hir().get_parent_item(hir_id);
- let encl_trait = tcx.hir().expect_item(encl_trait_hir_id);
+ let encl_trait_def_id = tcx.hir().get_parent_did(hir_id);
+ let encl_trait = tcx.hir().expect_item(encl_trait_def_id);
let encl_trait_def_id = encl_trait.def_id.to_def_id();
let fn_lang_item_name = if Some(encl_trait_def_id) == tcx.lang_items().fn_trait() {
Some("fn")
@@ -428,22 +426,48 @@ fn check_gat_where_clauses(
}
}
- // If there are any missing clauses, emit an error
- let mut clauses = clauses.unwrap_or_default();
+ // If there are any clauses that aren't provable, emit an error
+ let clauses = clauses.unwrap_or_default();
debug!(?clauses);
if !clauses.is_empty() {
- let written_predicates: ty::GenericPredicates<'_> =
- tcx.explicit_predicates_of(trait_item.def_id);
+ let param_env = tcx.param_env(trait_item.def_id);
+
let mut clauses: Vec<_> = clauses
- .drain_filter(|clause| !written_predicates.predicates.iter().any(|p| &p.0 == clause))
+ .into_iter()
+ .filter(|clause| match clause.kind().skip_binder() {
+ ty::PredicateKind::RegionOutlives(ty::OutlivesPredicate(a, b)) => {
+ !region_known_to_outlive(
+ tcx,
+ trait_item.hir_id(),
+ param_env,
+ &FxHashSet::default(),
+ a,
+ b,
+ )
+ }
+ ty::PredicateKind::TypeOutlives(ty::OutlivesPredicate(a, b)) => {
+ !ty_known_to_outlive(
+ tcx,
+ trait_item.hir_id(),
+ param_env,
+ &FxHashSet::default(),
+ a,
+ b,
+ )
+ }
+ _ => bug!("Unexpected PredicateKind"),
+ })
.map(|clause| format!("{}", clause))
.collect();
+
// We sort so that order is predictable
clauses.sort();
+
if !clauses.is_empty() {
+ let plural = if clauses.len() > 1 { "s" } else { "" };
let mut err = tcx.sess.struct_span_err(
trait_item.span,
- &format!("Missing required bounds on {}", trait_item.ident),
+ &format!("missing required bound{} on `{}`", plural, trait_item.ident),
);
let suggestion = format!(
@@ -457,11 +481,22 @@ fn check_gat_where_clauses(
);
err.span_suggestion(
trait_item.generics.where_clause.tail_span_for_suggestion(),
- "add the required where clauses",
+ &format!("add the required where clause{}", plural),
suggestion,
Applicability::MachineApplicable,
);
+ let bound = if clauses.len() > 1 { "these bounds are" } else { "this bound is" };
+ err.note(&format!(
+ "{} currently required to ensure that impls have maximum flexibility",
+ bound
+ ));
+ err.note(
+ "we are soliciting feedback, see issue #87479 \
+ <https://github.com/rust-lang/rust/issues/87479> \
+ for more information",
+ );
+
err.emit()
}
}
@@ -543,7 +578,8 @@ fn region_known_to_outlive<'tcx>(
});
use rustc_infer::infer::outlives::obligations::TypeOutlivesDelegate;
- (&infcx).push_sub_region_constraint(origin, region_a, region_b);
+ // `region_a: region_b` -> `region_b <= region_a`
+ (&infcx).push_sub_region_constraint(origin, region_b, region_a);
let errors = infcx.resolve_regions(
id.expect_owner().to_def_id(),
@@ -680,12 +716,12 @@ fn check_object_unsafe_self_trait_by_name(tcx: TyCtxt<'_>, item: &hir::TraitItem
}
pub fn check_impl_item(tcx: TyCtxt<'_>, def_id: LocalDefId) {
- let hir_id = tcx.hir().local_def_id_to_hir_id(def_id);
- let impl_item = tcx.hir().expect_impl_item(hir_id);
+ let impl_item = tcx.hir().expect_impl_item(def_id);
let (method_sig, span) = match impl_item.kind {
hir::ImplItemKind::Fn(ref sig, _) => (Some(sig), impl_item.span),
- hir::ImplItemKind::TyAlias(ty) => (None, ty.span),
+ // Constrain binding and overflow error spans to `<Ty>` in `type foo = <Ty>`.
+ hir::ImplItemKind::TyAlias(ty) if ty.span != DUMMY_SP => (None, ty.span),
_ => (None, impl_item.span),
};
@@ -698,7 +734,6 @@ fn check_param_wf(tcx: TyCtxt<'_>, param: &hir::GenericParam<'_>) {
hir::GenericParamKind::Lifetime { .. } | hir::GenericParamKind::Type { .. } => (),
// Const parameters are well formed if their type is structural match.
- // FIXME(const_generics_defaults): we also need to check that the `default` is wf.
hir::GenericParamKind::Const { ty: hir_ty, default: _ } => {
let ty = tcx.type_of(tcx.hir().local_def_id(param.hir_id));
@@ -1060,6 +1095,20 @@ fn check_item_type(tcx: TyCtxt<'_>, item_id: LocalDefId, ty_span: Span, allow_fo
);
}
+ // Ensure that the end result is `Sync` in a non-thread local `static`.
+ let should_check_for_sync = tcx.static_mutability(item_id.to_def_id())
+ == Some(hir::Mutability::Not)
+ && !tcx.is_foreign_item(item_id.to_def_id())
+ && !tcx.is_thread_local_static(item_id.to_def_id());
+
+ if should_check_for_sync {
+ fcx.register_bound(
+ item_ty,
+ tcx.require_lang_item(LangItem::Sync, Some(ty_span)),
+ traits::ObligationCause::new(ty_span, fcx.body_id, traits::SharedStatic),
+ );
+ }
+
// No implied bounds in a const, etc.
FxHashSet::default()
});
@@ -1322,11 +1371,6 @@ fn check_fn_or_method<'fcx, 'tcx>(
) {
let sig = fcx.tcx.liberate_late_bound_regions(def_id, sig);
- // Unnormalized types in signature are WF too
- implied_bounds.extend(sig.inputs());
- // FIXME(#27579) return types should not be implied bounds
- implied_bounds.insert(sig.output());
-
// Normalize the input and output types one at a time, using a different
// `WellFormedLoc` for each. We cannot call `normalize_associated_types`
// on the entire `FnSig`, since this would use the same `WellFormedLoc`
@@ -1444,7 +1488,7 @@ fn check_method_receiver<'fcx, 'tcx>(
}
}
-fn e0307(fcx: &FnCtxt<'fcx, 'tcx>, span: Span, receiver_ty: Ty<'_>) {
+fn e0307<'tcx>(fcx: &FnCtxt<'_, 'tcx>, span: Span, receiver_ty: Ty<'_>) {
struct_span_err!(
fcx.tcx.sess.diagnostic(),
span,
@@ -1547,7 +1591,7 @@ fn receiver_is_valid<'fcx, 'tcx>(
true
}
-fn receiver_is_implemented(
+fn receiver_is_implemented<'tcx>(
fcx: &FnCtxt<'_, 'tcx>,
receiver_trait_def_id: DefId,
cause: ObligationCause<'tcx>,
@@ -1690,13 +1734,13 @@ pub struct CheckTypeWellFormedVisitor<'tcx> {
tcx: TyCtxt<'tcx>,
}
-impl CheckTypeWellFormedVisitor<'tcx> {
+impl<'tcx> CheckTypeWellFormedVisitor<'tcx> {
pub fn new(tcx: TyCtxt<'tcx>) -> CheckTypeWellFormedVisitor<'tcx> {
CheckTypeWellFormedVisitor { tcx }
}
}
-impl ParItemLikeVisitor<'tcx> for CheckTypeWellFormedVisitor<'tcx> {
+impl<'tcx> ParItemLikeVisitor<'tcx> for CheckTypeWellFormedVisitor<'tcx> {
fn visit_item(&self, i: &'tcx hir::Item<'tcx>) {
Visitor::visit_item(&mut self.clone(), i);
}
@@ -1714,7 +1758,7 @@ impl ParItemLikeVisitor<'tcx> for CheckTypeWellFormedVisitor<'tcx> {
}
}
-impl Visitor<'tcx> for CheckTypeWellFormedVisitor<'tcx> {
+impl<'tcx> Visitor<'tcx> for CheckTypeWellFormedVisitor<'tcx> {
type Map = hir_map::Map<'tcx>;
fn nested_visit_map(&mut self) -> hir_visit::NestedVisitorMap<Self::Map> {
@@ -1815,7 +1859,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
// Inherent impl: take implied bounds from the `self` type.
let self_ty = self.tcx.type_of(impl_def_id);
let self_ty = self.normalize_associated_types_in(span, self_ty);
- std::array::IntoIter::new([self_ty]).collect()
+ FxHashSet::from_iter([self_ty])
}
}
}
diff --git a/compiler/rustc_typeck/src/check_unused.rs b/compiler/rustc_typeck/src/check_unused.rs
index 89ce3700aad..f45cd3ed689 100644
--- a/compiler/rustc_typeck/src/check_unused.rs
+++ b/compiler/rustc_typeck/src/check_unused.rs
@@ -21,7 +21,7 @@ pub fn check_crate(tcx: TyCtxt<'_>) {
unused_crates_lint(tcx);
}
-impl ItemLikeVisitor<'v> for CheckVisitor<'tcx> {
+impl<'tcx> ItemLikeVisitor<'_> for CheckVisitor<'tcx> {
fn visit_item(&mut self, item: &hir::Item<'_>) {
if item.vis.node.is_pub() || item.span.is_dummy() {
return;
@@ -43,7 +43,7 @@ struct CheckVisitor<'tcx> {
used_trait_imports: FxHashSet<LocalDefId>,
}
-impl CheckVisitor<'tcx> {
+impl<'tcx> CheckVisitor<'tcx> {
fn check_import(&self, item_id: hir::ItemId, span: Span) {
if !self.tcx.maybe_unused_trait_import(item_id.def_id) {
return;
@@ -119,13 +119,13 @@ fn unused_crates_lint(tcx: TyCtxt<'_>) {
for extern_crate in &crates_to_lint {
let def_id = extern_crate.def_id.expect_local();
- let id = tcx.hir().local_def_id_to_hir_id(def_id);
- let item = tcx.hir().expect_item(id);
+ let item = tcx.hir().expect_item(def_id);
// If the crate is fully unused, we suggest removing it altogether.
// We do this in any edition.
if extern_crate.warn_if_unused {
if let Some(&span) = unused_extern_crates.get(&def_id) {
+ let id = tcx.hir().local_def_id_to_hir_id(def_id);
tcx.struct_span_lint_hir(lint, id, span, |lint| {
// Removal suggestion span needs to include attributes (Issue #54400)
let span_with_attrs = tcx
@@ -173,6 +173,7 @@ fn unused_crates_lint(tcx: TyCtxt<'_>) {
if !tcx.get_attrs(extern_crate.def_id).is_empty() {
continue;
}
+ let id = tcx.hir().local_def_id_to_hir_id(def_id);
tcx.struct_span_lint_hir(lint, id, extern_crate.span, |lint| {
// Otherwise, we can convert it into a `use` of some kind.
let base_replacement = match extern_crate.orig_name {
diff --git a/compiler/rustc_typeck/src/coherence/builtin.rs b/compiler/rustc_typeck/src/coherence/builtin.rs
index 372e83592b9..d5494c5a685 100644
--- a/compiler/rustc_typeck/src/coherence/builtin.rs
+++ b/compiler/rustc_typeck/src/coherence/builtin.rs
@@ -52,8 +52,7 @@ fn visit_implementation_of_drop(tcx: TyCtxt<'_>, impl_did: LocalDefId) {
return;
}
- let impl_hir_id = tcx.hir().local_def_id_to_hir_id(impl_did);
- let sp = match tcx.hir().expect_item(impl_hir_id).kind {
+ let sp = match tcx.hir().expect_item(impl_did).kind {
ItemKind::Impl(ref impl_) => impl_.self_ty.span,
_ => bug!("expected Drop impl item"),
};
@@ -78,7 +77,7 @@ fn visit_implementation_of_copy(tcx: TyCtxt<'_>, impl_did: LocalDefId) {
match can_type_implement_copy(tcx, param_env, self_type) {
Ok(()) => {}
Err(CopyImplementationError::InfrigingFields(fields)) => {
- let item = tcx.hir().expect_item(impl_hir_id);
+ let item = tcx.hir().expect_item(impl_did);
let span = if let ItemKind::Impl(hir::Impl { of_trait: Some(ref tr), .. }) = item.kind {
tr.path.span
} else {
@@ -97,7 +96,7 @@ fn visit_implementation_of_copy(tcx: TyCtxt<'_>, impl_did: LocalDefId) {
err.emit()
}
Err(CopyImplementationError::NotAnAdt) => {
- let item = tcx.hir().expect_item(impl_hir_id);
+ let item = tcx.hir().expect_item(impl_did);
let span =
if let ItemKind::Impl(ref impl_) = item.kind { impl_.self_ty.span } else { span };
@@ -109,7 +108,7 @@ fn visit_implementation_of_copy(tcx: TyCtxt<'_>, impl_did: LocalDefId) {
}
}
-fn visit_implementation_of_coerce_unsized(tcx: TyCtxt<'tcx>, impl_did: LocalDefId) {
+fn visit_implementation_of_coerce_unsized<'tcx>(tcx: TyCtxt<'tcx>, impl_did: LocalDefId) {
debug!("visit_implementation_of_coerce_unsized: impl_did={:?}", impl_did);
// Just compute this for the side-effects, in particular reporting
@@ -119,7 +118,7 @@ fn visit_implementation_of_coerce_unsized(tcx: TyCtxt<'tcx>, impl_did: LocalDefI
tcx.at(span).coerce_unsized_info(impl_did);
}
-fn visit_implementation_of_dispatch_from_dyn(tcx: TyCtxt<'_>, impl_did: LocalDefId) {
+fn visit_implementation_of_dispatch_from_dyn<'tcx>(tcx: TyCtxt<'tcx>, impl_did: LocalDefId) {
debug!("visit_implementation_of_dispatch_from_dyn: impl_did={:?}", impl_did);
let impl_hir_id = tcx.hir().local_def_id_to_hir_id(impl_did);
@@ -288,12 +287,12 @@ fn visit_implementation_of_dispatch_from_dyn(tcx: TyCtxt<'_>, impl_did: LocalDef
})
}
-pub fn coerce_unsized_info(tcx: TyCtxt<'tcx>, impl_did: DefId) -> CoerceUnsizedInfo {
+pub fn coerce_unsized_info<'tcx>(tcx: TyCtxt<'tcx>, impl_did: DefId) -> CoerceUnsizedInfo {
debug!("compute_coerce_unsized_info(impl_did={:?})", impl_did);
// this provider should only get invoked for local def-ids
- let impl_hir_id = tcx.hir().local_def_id_to_hir_id(impl_did.expect_local());
- let span = tcx.hir().span(impl_hir_id);
+ let impl_did = impl_did.expect_local();
+ let span = tcx.def_span(impl_did);
let coerce_unsized_trait = tcx.require_lang_item(LangItem::CoerceUnsized, Some(span));
@@ -315,6 +314,7 @@ pub fn coerce_unsized_info(tcx: TyCtxt<'tcx>, impl_did: DefId) -> CoerceUnsizedI
debug!("visit_implementation_of_coerce_unsized: {:?} -> {:?} (free)", source, target);
tcx.infer_ctxt().enter(|infcx| {
+ let impl_hir_id = tcx.hir().local_def_id_to_hir_id(impl_did);
let cause = ObligationCause::misc(span, impl_hir_id);
let check_mutbl = |mt_a: ty::TypeAndMut<'tcx>,
mt_b: ty::TypeAndMut<'tcx>,
@@ -452,13 +452,13 @@ pub fn coerce_unsized_info(tcx: TyCtxt<'tcx>, impl_did: DefId) -> CoerceUnsizedI
.emit();
return err_info;
} else if diff_fields.len() > 1 {
- let item = tcx.hir().expect_item(impl_hir_id);
+ let item = tcx.hir().expect_item(impl_did);
let span = if let ItemKind::Impl(hir::Impl { of_trait: Some(ref t), .. }) =
item.kind
{
t.path.span
} else {
- tcx.hir().span(impl_hir_id)
+ tcx.def_span(impl_did)
};
struct_span_err!(
@@ -530,7 +530,11 @@ pub fn coerce_unsized_info(tcx: TyCtxt<'tcx>, impl_did: DefId) -> CoerceUnsizedI
// Finally, resolve all regions.
let outlives_env = OutlivesEnvironment::new(param_env);
- infcx.resolve_regions_and_report_errors(impl_did, &outlives_env, RegionckMode::default());
+ infcx.resolve_regions_and_report_errors(
+ impl_did.to_def_id(),
+ &outlives_env,
+ RegionckMode::default(),
+ );
CoerceUnsizedInfo { custom_kind: kind }
})
diff --git a/compiler/rustc_typeck/src/coherence/inherent_impls.rs b/compiler/rustc_typeck/src/coherence/inherent_impls.rs
index 6a9ba9d4913..f4e5cce0129 100644
--- a/compiler/rustc_typeck/src/coherence/inherent_impls.rs
+++ b/compiler/rustc_typeck/src/coherence/inherent_impls.rs
@@ -38,7 +38,7 @@ struct InherentCollect<'tcx> {
impls_map: CrateInherentImpls,
}
-impl ItemLikeVisitor<'v> for InherentCollect<'tcx> {
+impl<'tcx> ItemLikeVisitor<'_> for InherentCollect<'tcx> {
fn visit_item(&mut self, item: &hir::Item<'_>) {
let (ty, assoc_items) = match item.kind {
hir::ItemKind::Impl(hir::Impl { of_trait: None, ref self_ty, items, .. }) => {
@@ -370,7 +370,7 @@ impl ItemLikeVisitor<'v> for InherentCollect<'tcx> {
fn visit_foreign_item(&mut self, _foreign_item: &hir::ForeignItem<'_>) {}
}
-impl InherentCollect<'tcx> {
+impl<'tcx> InherentCollect<'tcx> {
fn check_def_id(&mut self, item: &hir::Item<'_>, def_id: DefId) {
if let Some(def_id) = def_id.as_local() {
// Add the implementation to the mapping from implementation to base
diff --git a/compiler/rustc_typeck/src/coherence/inherent_impls_overlap.rs b/compiler/rustc_typeck/src/coherence/inherent_impls_overlap.rs
index beacf301cae..59f211bd2c3 100644
--- a/compiler/rustc_typeck/src/coherence/inherent_impls_overlap.rs
+++ b/compiler/rustc_typeck/src/coherence/inherent_impls_overlap.rs
@@ -18,7 +18,7 @@ struct InherentOverlapChecker<'tcx> {
tcx: TyCtxt<'tcx>,
}
-impl InherentOverlapChecker<'tcx> {
+impl<'tcx> InherentOverlapChecker<'tcx> {
/// Checks whether any associated items in impls 1 and 2 share the same identifier and
/// namespace.
fn impls_have_common_items(
@@ -115,8 +115,8 @@ impl InherentOverlapChecker<'tcx> {
}
}
-impl ItemLikeVisitor<'v> for InherentOverlapChecker<'tcx> {
- fn visit_item(&mut self, item: &'v hir::Item<'v>) {
+impl<'tcx> ItemLikeVisitor<'_> for InherentOverlapChecker<'tcx> {
+ fn visit_item(&mut self, item: &hir::Item<'_>) {
match item.kind {
hir::ItemKind::Enum(..)
| hir::ItemKind::Struct(..)
@@ -300,9 +300,9 @@ impl ItemLikeVisitor<'v> for InherentOverlapChecker<'tcx> {
}
}
- fn visit_trait_item(&mut self, _trait_item: &hir::TraitItem<'v>) {}
+ fn visit_trait_item(&mut self, _trait_item: &hir::TraitItem<'_>) {}
- fn visit_impl_item(&mut self, _impl_item: &hir::ImplItem<'v>) {}
+ fn visit_impl_item(&mut self, _impl_item: &hir::ImplItem<'_>) {}
- fn visit_foreign_item(&mut self, _foreign_item: &hir::ForeignItem<'v>) {}
+ fn visit_foreign_item(&mut self, _foreign_item: &hir::ForeignItem<'_>) {}
}
diff --git a/compiler/rustc_typeck/src/coherence/orphan.rs b/compiler/rustc_typeck/src/coherence/orphan.rs
index b450d3f6c08..e954b4cf512 100644
--- a/compiler/rustc_typeck/src/coherence/orphan.rs
+++ b/compiler/rustc_typeck/src/coherence/orphan.rs
@@ -143,7 +143,7 @@ fn orphan_check_impl(tcx: TyCtxt<'_>, def_id: LocalDefId) -> Result<(), ErrorRep
Ok(())
}
-fn emit_orphan_check_error(
+fn emit_orphan_check_error<'tcx>(
tcx: TyCtxt<'tcx>,
sp: Span,
trait_span: Span,
diff --git a/compiler/rustc_typeck/src/coherence/unsafety.rs b/compiler/rustc_typeck/src/coherence/unsafety.rs
index e7b03fa3ac6..f7aabf2406f 100644
--- a/compiler/rustc_typeck/src/coherence/unsafety.rs
+++ b/compiler/rustc_typeck/src/coherence/unsafety.rs
@@ -16,10 +16,10 @@ struct UnsafetyChecker<'tcx> {
tcx: TyCtxt<'tcx>,
}
-impl UnsafetyChecker<'tcx> {
+impl<'tcx> UnsafetyChecker<'tcx> {
fn check_unsafety_coherence(
&mut self,
- item: &'v hir::Item<'v>,
+ item: &hir::Item<'_>,
impl_generics: Option<&hir::Generics<'_>>,
unsafety: hir::Unsafety,
polarity: hir::ImplPolarity,
@@ -83,8 +83,8 @@ impl UnsafetyChecker<'tcx> {
}
}
-impl ItemLikeVisitor<'v> for UnsafetyChecker<'tcx> {
- fn visit_item(&mut self, item: &'v hir::Item<'v>) {
+impl<'tcx> ItemLikeVisitor<'_> for UnsafetyChecker<'tcx> {
+ fn visit_item(&mut self, item: &hir::Item<'_>) {
if let hir::ItemKind::Impl(ref impl_) = item.kind {
self.check_unsafety_coherence(
item,
diff --git a/compiler/rustc_typeck/src/collect.rs b/compiler/rustc_typeck/src/collect.rs
index b9db8a6be59..b96a5b158a2 100644
--- a/compiler/rustc_typeck/src/collect.rs
+++ b/compiler/rustc_typeck/src/collect.rs
@@ -41,7 +41,7 @@ use rustc_middle::ty::subst::InternalSubsts;
use rustc_middle::ty::util::Discr;
use rustc_middle::ty::util::IntTypeExt;
use rustc_middle::ty::{self, AdtKind, Const, DefIdTree, Ty, TyCtxt};
-use rustc_middle::ty::{ReprOptions, ToPredicate, WithConstness};
+use rustc_middle::ty::{ReprOptions, ToPredicate, TypeFoldable};
use rustc_session::lint;
use rustc_session::parse::feature_err;
use rustc_span::symbol::{kw, sym, Ident, Symbol};
@@ -147,7 +147,7 @@ struct CollectItemTypesVisitor<'tcx> {
/// If there are any placeholder types (`_`), emit an error explaining that this is not allowed
/// and suggest adding type parameters in the appropriate place, taking into consideration any and
/// all already existing generic type parameters to avoid suggesting a name that is already in use.
-crate fn placeholder_type_error(
+crate fn placeholder_type_error<'tcx>(
tcx: TyCtxt<'tcx>,
span: Option<Span>,
generics: &[hir::GenericParam<'_>],
@@ -177,11 +177,9 @@ crate fn placeholder_type_error(
sugg.push((arg.span, (*type_name).to_string()));
} else {
let last = generics.iter().last().unwrap();
- sugg.push((
- // Account for bounds, we want `fn foo<T: E, K>(_: K)` not `fn foo<T, K: E>(_: K)`.
- last.bounds_span().unwrap_or(last.span).shrink_to_hi(),
- format!(", {}", type_name),
- ));
+ // Account for bounds, we want `fn foo<T: E, K>(_: K)` not `fn foo<T, K: E>(_: K)`.
+ let span = last.bounds_span_for_suggestions().unwrap_or(last.span.shrink_to_hi());
+ sugg.push((span, format!(", {}", type_name)));
}
let mut err = bad_placeholder_type(tcx, placeholder_types, kind);
@@ -225,7 +223,10 @@ crate fn placeholder_type_error(
err.emit();
}
-fn reject_placeholder_type_signatures_in_item(tcx: TyCtxt<'tcx>, item: &'tcx hir::Item<'tcx>) {
+fn reject_placeholder_type_signatures_in_item<'tcx>(
+ tcx: TyCtxt<'tcx>,
+ item: &'tcx hir::Item<'tcx>,
+) {
let (generics, suggest) = match &item.kind {
hir::ItemKind::Union(_, generics)
| hir::ItemKind::Enum(_, generics)
@@ -253,7 +254,7 @@ fn reject_placeholder_type_signatures_in_item(tcx: TyCtxt<'tcx>, item: &'tcx hir
);
}
-impl Visitor<'tcx> for CollectItemTypesVisitor<'tcx> {
+impl<'tcx> Visitor<'tcx> for CollectItemTypesVisitor<'tcx> {
type Map = Map<'tcx>;
fn nested_visit_map(&mut self) -> NestedVisitorMap<Self::Map> {
@@ -313,7 +314,7 @@ impl Visitor<'tcx> for CollectItemTypesVisitor<'tcx> {
///////////////////////////////////////////////////////////////////////////
// Utility types and common code for the above passes.
-fn bad_placeholder_type(
+fn bad_placeholder_type<'tcx>(
tcx: TyCtxt<'tcx>,
mut spans: Vec<Span>,
kind: &'static str,
@@ -334,7 +335,7 @@ fn bad_placeholder_type(
err
}
-impl ItemCtxt<'tcx> {
+impl<'tcx> ItemCtxt<'tcx> {
pub fn new(tcx: TyCtxt<'tcx>, item_def_id: DefId) -> ItemCtxt<'tcx> {
ItemCtxt { tcx, item_def_id }
}
@@ -352,7 +353,7 @@ impl ItemCtxt<'tcx> {
}
}
-impl AstConv<'tcx> for ItemCtxt<'tcx> {
+impl<'tcx> AstConv<'tcx> for ItemCtxt<'tcx> {
fn tcx(&self) -> TyCtxt<'tcx> {
self.tcx
}
@@ -431,7 +432,7 @@ impl AstConv<'tcx> for ItemCtxt<'tcx> {
match self.node() {
hir::Node::Field(_) | hir::Node::Ctor(_) | hir::Node::Variant(_) => {
let item =
- self.tcx.hir().expect_item(self.tcx.hir().get_parent_item(self.hir_id()));
+ self.tcx.hir().expect_item(self.tcx.hir().get_parent_did(self.hir_id()));
match &item.kind {
hir::ItemKind::Enum(_, generics)
| hir::ItemKind::Struct(_, generics)
@@ -596,7 +597,11 @@ fn type_param_predicates(
ItemKind::Fn(.., ref generics, _)
| ItemKind::Impl(hir::Impl { ref generics, .. })
| ItemKind::TyAlias(_, ref generics)
- | ItemKind::OpaqueTy(OpaqueTy { ref generics, impl_trait_fn: None, .. })
+ | ItemKind::OpaqueTy(OpaqueTy {
+ ref generics,
+ origin: hir::OpaqueTyOrigin::TyAlias,
+ ..
+ })
| ItemKind::Enum(_, ref generics)
| ItemKind::Struct(_, ref generics)
| ItemKind::Union(_, ref generics) => generics,
@@ -641,7 +646,7 @@ fn type_param_predicates(
result
}
-impl ItemCtxt<'tcx> {
+impl<'tcx> ItemCtxt<'tcx> {
/// Finds bounds from `hir::Generics`. This requires scanning through the
/// AST. We do this to avoid having to convert *all* the bounds, which
/// would create artificial cycles. Instead, we can only convert the
@@ -666,7 +671,7 @@ impl ItemCtxt<'tcx> {
Some(assoc_name) => self.bound_defines_assoc_item(b, assoc_name),
None => true,
})
- .flat_map(|b| predicates_from_bound(self, ty, b));
+ .flat_map(|b| predicates_from_bound(self, ty, b, ty::List::empty()));
let param_def_id = self.tcx.hir().local_def_id(param_id).to_def_id();
let from_where_clauses = ast_generics
@@ -685,15 +690,17 @@ impl ItemCtxt<'tcx> {
} else {
None
};
+ let bvars = self.tcx.late_bound_vars(bp.bounded_ty.hir_id);
+
bp.bounds
.iter()
.filter(|b| match assoc_name {
Some(assoc_name) => self.bound_defines_assoc_item(b, assoc_name),
None => true,
})
- .filter_map(move |b| bt.map(|bt| (bt, b)))
+ .filter_map(move |b| bt.map(|bt| (bt, b, bvars)))
})
- .flat_map(|(bt, b)| predicates_from_bound(self, bt, b));
+ .flat_map(|(bt, b, bvars)| predicates_from_bound(self, bt, b, bvars));
from_ty_params.chain(from_where_clauses).collect()
}
@@ -793,7 +800,10 @@ fn convert_item(tcx: TyCtxt<'_>, item_id: hir::ItemId) {
}
// Desugared from `impl Trait`, so visited by the function's return type.
- hir::ItemKind::OpaqueTy(hir::OpaqueTy { impl_trait_fn: Some(_), .. }) => {}
+ hir::ItemKind::OpaqueTy(hir::OpaqueTy {
+ origin: hir::OpaqueTyOrigin::FnReturn(..) | hir::OpaqueTyOrigin::AsyncFn(..),
+ ..
+ }) => {}
// Don't call `type_of` on opaque types, since that depends on type
// checking function bodies. `check_item_type` ensures that it's called
@@ -1182,8 +1192,7 @@ fn super_predicates_that_define_assoc_type(
}
fn trait_def(tcx: TyCtxt<'_>, def_id: DefId) -> ty::TraitDef {
- let hir_id = tcx.hir().local_def_id_to_hir_id(def_id.expect_local());
- let item = tcx.hir().expect_item(hir_id);
+ let item = tcx.hir().expect_item(def_id.expect_local());
let (is_auto, unsafety) = match item.kind {
hir::ItemKind::Trait(is_auto, unsafety, ..) => (is_auto == hir::IsAuto::Yes, unsafety),
@@ -1233,7 +1242,7 @@ fn has_late_bound_regions<'tcx>(tcx: TyCtxt<'tcx>, node: Node<'tcx>) -> Option<S
has_late_bound_regions: Option<Span>,
}
- impl Visitor<'tcx> for LateBoundRegionsDetector<'tcx> {
+ impl<'tcx> Visitor<'tcx> for LateBoundRegionsDetector<'tcx> {
type Map = intravisit::ErasedMap<'tcx>;
fn nested_visit_map(&mut self) -> NestedVisitorMap<Self::Map> {
@@ -1489,15 +1498,18 @@ fn generics_of(tcx: TyCtxt<'_>, def_id: DefId) -> ty::Generics {
Some(tcx.typeck_root_def_id(def_id))
}
Node::Item(item) => match item.kind {
- ItemKind::OpaqueTy(hir::OpaqueTy { impl_trait_fn, .. }) => {
- impl_trait_fn.or_else(|| {
- let parent_id = tcx.hir().get_parent_item(hir_id);
- assert!(parent_id != hir_id && parent_id != CRATE_HIR_ID);
- debug!("generics_of: parent of opaque ty {:?} is {:?}", def_id, parent_id);
- // Opaque types are always nested within another item, and
- // inherit the generics of the item.
- Some(tcx.hir().local_def_id(parent_id).to_def_id())
- })
+ ItemKind::OpaqueTy(hir::OpaqueTy {
+ origin:
+ hir::OpaqueTyOrigin::FnReturn(fn_def_id) | hir::OpaqueTyOrigin::AsyncFn(fn_def_id),
+ ..
+ }) => Some(fn_def_id.to_def_id()),
+ ItemKind::OpaqueTy(hir::OpaqueTy { origin: hir::OpaqueTyOrigin::TyAlias, .. }) => {
+ let parent_id = tcx.hir().get_parent_item(hir_id);
+ assert!(parent_id != hir_id && parent_id != CRATE_HIR_ID);
+ debug!("generics_of: parent of opaque ty {:?} is {:?}", def_id, parent_id);
+ // Opaque types are always nested within another item, and
+ // inherit the generics of the item.
+ Some(tcx.hir().local_def_id(parent_id).to_def_id())
}
_ => None,
},
@@ -1737,7 +1749,7 @@ fn is_suggestable_infer_ty(ty: &hir::Ty<'_>) -> bool {
}
}
-pub fn get_infer_ret_ty(output: &'hir hir::FnRetTy<'hir>) -> Option<&'hir hir::Ty<'hir>> {
+pub fn get_infer_ret_ty<'hir>(output: &'hir hir::FnRetTy<'hir>) -> Option<&'hir hir::Ty<'hir>> {
if let hir::FnRetTy::Return(ty) = output {
if is_suggestable_infer_ty(ty) {
return Some(&*ty);
@@ -1778,7 +1790,7 @@ fn fn_sig(tcx: TyCtxt<'_>, def_id: DefId) -> ty::PolyFnSig<'_> {
visitor.visit_ty(ty);
let mut diag = bad_placeholder_type(tcx, visitor.0, "return type");
let ret_ty = fn_sig.skip_binder().output();
- if ret_ty != tcx.ty_error() {
+ if !ret_ty.references_error() {
if !ret_ty.is_closure() {
let ret_ty_str = match ret_ty.kind() {
// Suggest a function pointer return type instead of a unique function definition
@@ -1878,9 +1890,7 @@ fn fn_sig(tcx: TyCtxt<'_>, def_id: DefId) -> ty::PolyFnSig<'_> {
fn impl_trait_ref(tcx: TyCtxt<'_>, def_id: DefId) -> Option<ty::TraitRef<'_>> {
let icx = ItemCtxt::new(tcx, def_id);
-
- let hir_id = tcx.hir().local_def_id_to_hir_id(def_id.expect_local());
- match tcx.hir().expect_item(hir_id).kind {
+ match tcx.hir().expect_item(def_id.expect_local()).kind {
hir::ItemKind::Impl(ref impl_) => impl_.of_trait.as_ref().map(|ast_trait_ref| {
let selfty = tcx.type_of(def_id);
<dyn AstConv<'_>>::instantiate_mono_trait_ref(&icx, ast_trait_ref, selfty)
@@ -1890,9 +1900,8 @@ fn impl_trait_ref(tcx: TyCtxt<'_>, def_id: DefId) -> Option<ty::TraitRef<'_>> {
}
fn impl_polarity(tcx: TyCtxt<'_>, def_id: DefId) -> ty::ImplPolarity {
- let hir_id = tcx.hir().local_def_id_to_hir_id(def_id.expect_local());
let is_rustc_reservation = tcx.has_attr(def_id, sym::rustc_reservation_impl);
- let item = tcx.hir().expect_item(hir_id);
+ let item = tcx.hir().expect_item(def_id.expect_local());
match &item.kind {
hir::ItemKind::Impl(hir::Impl {
polarity: hir::ImplPolarity::Negative(span),
@@ -2055,31 +2064,32 @@ fn gather_explicit_predicates_of(tcx: TyCtxt<'_>, def_id: DefId) -> ty::GenericP
generics
}
ItemKind::OpaqueTy(OpaqueTy {
- bounds: _,
- impl_trait_fn,
+ origin: hir::OpaqueTyOrigin::AsyncFn(..) | hir::OpaqueTyOrigin::FnReturn(..),
+ ..
+ }) => {
+ // return-position impl trait
+ //
+ // We don't inherit predicates from the parent here:
+ // If we have, say `fn f<'a, T: 'a>() -> impl Sized {}`
+ // then the return type is `f::<'static, T>::{{opaque}}`.
+ //
+ // If we inherited the predicates of `f` then we would
+ // require that `T: 'static` to show that the return
+ // type is well-formed.
+ //
+ // The only way to have something with this opaque type
+ // is from the return type of the containing function,
+ // which will ensure that the function's predicates
+ // hold.
+ return ty::GenericPredicates { parent: None, predicates: &[] };
+ }
+ ItemKind::OpaqueTy(OpaqueTy {
ref generics,
- origin: _,
+ origin: hir::OpaqueTyOrigin::TyAlias,
+ ..
}) => {
- if impl_trait_fn.is_some() {
- // return-position impl trait
- //
- // We don't inherit predicates from the parent here:
- // If we have, say `fn f<'a, T: 'a>() -> impl Sized {}`
- // then the return type is `f::<'static, T>::{{opaque}}`.
- //
- // If we inherited the predicates of `f` then we would
- // require that `T: 'static` to show that the return
- // type is well-formed.
- //
- // The only way to have something with this opaque type
- // is from the return type of the containing function,
- // which will ensure that the function's predicates
- // hold.
- return ty::GenericPredicates { parent: None, predicates: &[] };
- } else {
- // type-alias impl trait
- generics
- }
+ // type-alias impl trait
+ generics
}
_ => NO_GENERICS,
@@ -2433,14 +2443,10 @@ fn predicates_from_bound<'tcx>(
astconv: &dyn AstConv<'tcx>,
param_ty: Ty<'tcx>,
bound: &'tcx hir::GenericBound<'tcx>,
+ bound_vars: &'tcx ty::List<ty::BoundVariableKind>,
) -> Vec<(ty::Predicate<'tcx>, Span)> {
let mut bounds = Bounds::default();
- astconv.add_bounds(
- param_ty,
- std::array::IntoIter::new([bound]),
- &mut bounds,
- ty::List::empty(),
- );
+ astconv.add_bounds(param_ty, [bound].into_iter(), &mut bounds, bound_vars);
bounds.predicates(astconv.tcx(), param_ty)
}
@@ -3006,9 +3012,9 @@ fn codegen_fn_attrs(tcx: TyCtxt<'_>, id: DefId) -> CodegenFnAttrs {
)
.emit();
InlineAttr::None
- } else if list_contains_name(&items[..], sym::always) {
+ } else if list_contains_name(&items, sym::always) {
InlineAttr::Always
- } else if list_contains_name(&items[..], sym::never) {
+ } else if list_contains_name(&items, sym::never) {
InlineAttr::Never
} else {
struct_span_err!(
@@ -3042,9 +3048,9 @@ fn codegen_fn_attrs(tcx: TyCtxt<'_>, id: DefId) -> CodegenFnAttrs {
if items.len() != 1 {
err(attr.span, "expected one argument");
OptimizeAttr::None
- } else if list_contains_name(&items[..], sym::size) {
+ } else if list_contains_name(&items, sym::size) {
OptimizeAttr::Size
- } else if list_contains_name(&items[..], sym::speed) {
+ } else if list_contains_name(&items, sym::speed) {
OptimizeAttr::Speed
} else {
err(items[0].span(), "invalid argument");
@@ -3227,7 +3233,7 @@ fn check_target_feature_trait_unsafe(tcx: TyCtxt<'_>, id: LocalDefId, attr_span:
let hir_id = tcx.hir().local_def_id_to_hir_id(id);
let node = tcx.hir().get(hir_id);
if let Node::ImplItem(hir::ImplItem { kind: hir::ImplItemKind::Fn(..), .. }) = node {
- let parent_id = tcx.hir().get_parent_item(hir_id);
+ let parent_id = tcx.hir().get_parent_did(hir_id);
let parent_item = tcx.hir().expect_item(parent_id);
if let hir::ItemKind::Impl(hir::Impl { of_trait: Some(_), .. }) = parent_item.kind {
tcx.sess
diff --git a/compiler/rustc_typeck/src/collect/type_of.rs b/compiler/rustc_typeck/src/collect/type_of.rs
index 04a68250ced..99fddcb00ce 100644
--- a/compiler/rustc_typeck/src/collect/type_of.rs
+++ b/compiler/rustc_typeck/src/collect/type_of.rs
@@ -172,7 +172,7 @@ pub(super) fn opt_const_param_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> Option<
// We've encountered an `AnonConst` in some path, so we need to
// figure out which generic parameter it corresponds to and return
// the relevant type.
- let (arg_index, segment) = path
+ let filtered = path
.segments
.iter()
.filter_map(|seg| seg.args.map(|args| (args.args, seg)))
@@ -181,10 +181,17 @@ pub(super) fn opt_const_param_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> Option<
.filter(|arg| arg.is_const())
.position(|arg| arg.id() == hir_id)
.map(|index| (index, seg))
- })
- .unwrap_or_else(|| {
- bug!("no arg matching AnonConst in path");
});
+ let (arg_index, segment) = match filtered {
+ None => {
+ tcx.sess.delay_span_bug(
+ tcx.def_span(def_id),
+ "no arg matching AnonConst in path",
+ );
+ return None;
+ }
+ Some(inner) => inner,
+ };
// Try to use the segment resolution if it is valid, otherwise we
// default to the path resolution.
@@ -387,13 +394,13 @@ pub(super) fn type_of(tcx: TyCtxt<'_>, def_id: DefId) -> Ty<'_> {
let substs = InternalSubsts::identity_for_item(tcx, def_id.to_def_id());
tcx.mk_adt(def, substs)
}
- ItemKind::OpaqueTy(OpaqueTy { impl_trait_fn: None, .. }) => {
+ ItemKind::OpaqueTy(OpaqueTy { origin: hir::OpaqueTyOrigin::TyAlias, .. }) => {
find_opaque_ty_constraints(tcx, def_id)
}
// Opaque types desugared from `impl Trait`.
- ItemKind::OpaqueTy(OpaqueTy { impl_trait_fn: Some(owner), .. }) => {
+ ItemKind::OpaqueTy(OpaqueTy { origin: hir::OpaqueTyOrigin::FnReturn(owner) | hir::OpaqueTyOrigin::AsyncFn(owner), .. }) => {
let concrete_ty = tcx
- .mir_borrowck(owner.expect_local())
+ .mir_borrowck(owner)
.concrete_opaque_types
.get_value_matching(|(key, _)| key.def_id == def_id.to_def_id())
.copied()
@@ -406,7 +413,7 @@ pub(super) fn type_of(tcx: TyCtxt<'_>, def_id: DefId) -> Ty<'_> {
),
);
if let Some(ErrorReported) =
- tcx.typeck(owner.expect_local()).tainted_by_errors
+ tcx.typeck(owner).tainted_by_errors
{
// Some error in the
// owner fn prevented us from populating
@@ -724,7 +731,7 @@ fn infer_placeholder_type<'a>(
}
}
- impl TypeFolder<'tcx> for MakeNameable<'tcx> {
+ impl<'tcx> TypeFolder<'tcx> for MakeNameable<'tcx> {
fn tcx(&self) -> TyCtxt<'tcx> {
self.tcx
}
diff --git a/compiler/rustc_typeck/src/expr_use_visitor.rs b/compiler/rustc_typeck/src/expr_use_visitor.rs
index 7d0600b99e3..32b4018f626 100644
--- a/compiler/rustc_typeck/src/expr_use_visitor.rs
+++ b/compiler/rustc_typeck/src/expr_use_visitor.rs
@@ -229,8 +229,8 @@ impl<'a, 'tcx> ExprUseVisitor<'a, 'tcx> {
}
}
- hir::ExprKind::Let(pat, ref expr, _) => {
- self.walk_local(expr, pat, |t| t.borrow_expr(expr, ty::ImmBorrow));
+ hir::ExprKind::Let(hir::Let { pat, init, .. }) => {
+ self.walk_local(init, pat, |t| t.borrow_expr(init, ty::ImmBorrow));
}
hir::ExprKind::Match(ref discr, arms, _) => {
@@ -482,7 +482,7 @@ impl<'a, 'tcx> ExprUseVisitor<'a, 'tcx> {
}
}
- fn walk_struct_expr(
+ fn walk_struct_expr<'hir>(
&mut self,
fields: &[hir::ExprField<'_>],
opt_with: &Option<&'hir hir::Expr<'_>>,
@@ -705,7 +705,7 @@ impl<'a, 'tcx> ExprUseVisitor<'a, 'tcx> {
/// - When reporting the Place back to the Delegate, ensure that the UpvarId uses the enclosing
/// closure as the DefId.
fn walk_captures(&mut self, closure_expr: &hir::Expr<'_>) {
- fn upvar_is_local_variable(
+ fn upvar_is_local_variable<'tcx>(
upvars: Option<&'tcx FxIndexMap<hir::HirId, hir::Upvar>>,
upvar_id: &hir::HirId,
body_owner_is_closure: bool,
@@ -846,7 +846,7 @@ fn delegate_consume<'a, 'tcx>(
}
}
-fn is_multivariant_adt(ty: Ty<'tcx>) -> bool {
+fn is_multivariant_adt(ty: Ty<'_>) -> bool {
if let ty::Adt(def, _) = ty.kind() {
// Note that if a non-exhaustive SingleVariant is defined in another crate, we need
// to assume that more cases will be added to the variant in the future. This mean
diff --git a/compiler/rustc_typeck/src/impl_wf_check.rs b/compiler/rustc_typeck/src/impl_wf_check.rs
index 5d2f8fc4242..ae6321de7f2 100644
--- a/compiler/rustc_typeck/src/impl_wf_check.rs
+++ b/compiler/rustc_typeck/src/impl_wf_check.rs
@@ -76,7 +76,7 @@ struct ImplWfCheck<'tcx> {
min_specialization: bool,
}
-impl ItemLikeVisitor<'tcx> for ImplWfCheck<'tcx> {
+impl<'tcx> ItemLikeVisitor<'tcx> for ImplWfCheck<'tcx> {
fn visit_item(&mut self, item: &'tcx hir::Item<'tcx>) {
if let hir::ItemKind::Impl(ref impl_) = item.kind {
enforce_impl_params_are_constrained(self.tcx, item.def_id, impl_.items);
diff --git a/compiler/rustc_typeck/src/lib.rs b/compiler/rustc_typeck/src/lib.rs
index 0881cf07586..24e427f4bcf 100644
--- a/compiler/rustc_typeck/src/lib.rs
+++ b/compiler/rustc_typeck/src/lib.rs
@@ -58,11 +58,8 @@ This API is completely unstable and subject to change.
#![doc(html_root_url = "https://doc.rust-lang.org/nightly/nightly-rustc/")]
#![feature(bool_to_option)]
#![feature(crate_visibility_modifier)]
-#![cfg_attr(bootstrap, feature(format_args_capture))]
#![feature(if_let_guard)]
-#![feature(in_band_lifetimes)]
#![feature(is_sorted)]
-#![feature(iter_zip)]
#![feature(let_else)]
#![feature(min_specialization)]
#![feature(nll)]
diff --git a/compiler/rustc_typeck/src/outlives/test.rs b/compiler/rustc_typeck/src/outlives/test.rs
index ec4fa9cd4b5..b3efd9f9ec3 100644
--- a/compiler/rustc_typeck/src/outlives/test.rs
+++ b/compiler/rustc_typeck/src/outlives/test.rs
@@ -12,7 +12,7 @@ struct OutlivesTest<'tcx> {
tcx: TyCtxt<'tcx>,
}
-impl ItemLikeVisitor<'tcx> for OutlivesTest<'tcx> {
+impl<'tcx> ItemLikeVisitor<'tcx> for OutlivesTest<'tcx> {
fn visit_item(&mut self, item: &'tcx hir::Item<'tcx>) {
// For unit testing: check for a special "rustc_outlives"
// attribute and report an error with various results if found.
diff --git a/compiler/rustc_typeck/src/variance/test.rs b/compiler/rustc_typeck/src/variance/test.rs
index 7be3c68e8f6..d6959075d88 100644
--- a/compiler/rustc_typeck/src/variance/test.rs
+++ b/compiler/rustc_typeck/src/variance/test.rs
@@ -12,7 +12,7 @@ struct VarianceTest<'tcx> {
tcx: TyCtxt<'tcx>,
}
-impl ItemLikeVisitor<'tcx> for VarianceTest<'tcx> {
+impl<'tcx> ItemLikeVisitor<'tcx> for VarianceTest<'tcx> {
fn visit_item(&mut self, item: &'tcx hir::Item<'tcx>) {
// For unit testing: check for a special "rustc_variance"
// attribute and report an error with various results if found.
diff --git a/library/alloc/benches/vec.rs b/library/alloc/benches/vec.rs
index 8e1d374b5d4..0da4886278e 100644
--- a/library/alloc/benches/vec.rs
+++ b/library/alloc/benches/vec.rs
@@ -733,11 +733,26 @@ fn bench_flat_map_collect(b: &mut Bencher) {
b.iter(|| v.iter().flat_map(|color| color.rotate_left(8).to_be_bytes()).collect::<Vec<_>>());
}
+/// Reference benchmark that `retain` has to compete with.
+#[bench]
+fn bench_retain_iter_100000(b: &mut Bencher) {
+ let mut v = Vec::with_capacity(100000);
+
+ b.iter(|| {
+ let mut tmp = std::mem::take(&mut v);
+ tmp.clear();
+ tmp.extend(black_box(1..=100000));
+ v = tmp.into_iter().filter(|x| x & 1 == 0).collect();
+ });
+}
+
#[bench]
fn bench_retain_100000(b: &mut Bencher) {
- let v = (1..=100000).collect::<Vec<u32>>();
+ let mut v = Vec::with_capacity(100000);
+
b.iter(|| {
- let mut v = v.clone();
+ v.clear();
+ v.extend(black_box(1..=100000));
v.retain(|x| x & 1 == 0)
});
}
diff --git a/library/alloc/src/borrow.rs b/library/alloc/src/borrow.rs
index 9ecbf058231..63234ee91f0 100644
--- a/library/alloc/src/borrow.rs
+++ b/library/alloc/src/borrow.rs
@@ -170,7 +170,7 @@ where
/// clone_on_write.values.to_mut().push(3);
/// println!("clone_on_write = {:?}", clone_on_write.values);
///
-/// // The data was mutated. Let check it out.
+/// // The data was mutated. Let's check it out.
/// match clone_on_write {
/// Items { values: Cow::Owned(_) } => println!("clone_on_write contains owned data"),
/// _ => panic!("expect owned data"),
diff --git a/library/alloc/src/boxed.rs b/library/alloc/src/boxed.rs
index f6332b072cf..ab41f5646e5 100644
--- a/library/alloc/src/boxed.rs
+++ b/library/alloc/src/boxed.rs
@@ -763,6 +763,42 @@ impl<T, A: Allocator> Box<mem::MaybeUninit<T>, A> {
let (raw, alloc) = Box::into_raw_with_allocator(self);
unsafe { Box::from_raw_in(raw as *mut T, alloc) }
}
+
+ /// Writes the value and converts to `Box<T, A>`.
+ ///
+ /// This method converts the box similarly to [`Box::assume_init`] but
+ /// writes `value` into it before conversion thus guaranteeing safety.
+ /// In some scenarios use of this method may improve performance because
+ /// the compiler may be able to optimize copying from stack.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// #![feature(new_uninit)]
+ ///
+ /// let big_box = Box::<[usize; 1024]>::new_uninit();
+ ///
+ /// let mut array = [0; 1024];
+ /// for (i, place) in array.iter_mut().enumerate() {
+ /// *place = i;
+ /// }
+ ///
+ /// // The optimizer may be able to elide this copy, so previous code writes
+ /// // to heap directly.
+ /// let big_box = Box::write(big_box, array);
+ ///
+ /// for (i, x) in big_box.iter().enumerate() {
+ /// assert_eq!(*x, i);
+ /// }
+ /// ```
+ #[unstable(feature = "new_uninit", issue = "63291")]
+ #[inline]
+ pub fn write(mut boxed: Self, value: T) -> Box<T, A> {
+ unsafe {
+ (*boxed).write(value);
+ boxed.assume_init()
+ }
+ }
}
impl<T, A: Allocator> Box<[mem::MaybeUninit<T>], A> {
@@ -1482,8 +1518,6 @@ impl<T, const N: usize> TryFrom<Box<[T]>> for Box<[T; N]> {
}
impl<A: Allocator> Box<dyn Any, A> {
- #[inline]
- #[stable(feature = "rust1", since = "1.0.0")]
/// Attempt to downcast the box to a concrete type.
///
/// # Examples
@@ -1501,21 +1535,48 @@ impl<A: Allocator> Box<dyn Any, A> {
/// print_if_string(Box::new(my_string));
/// print_if_string(Box::new(0i8));
/// ```
+ #[inline]
+ #[stable(feature = "rust1", since = "1.0.0")]
pub fn downcast<T: Any>(self) -> Result<Box<T, A>, Self> {
- if self.is::<T>() {
- unsafe {
- let (raw, alloc): (*mut dyn Any, _) = Box::into_raw_with_allocator(self);
- Ok(Box::from_raw_in(raw as *mut T, alloc))
- }
- } else {
- Err(self)
+ if self.is::<T>() { unsafe { Ok(self.downcast_unchecked::<T>()) } } else { Err(self) }
+ }
+
+ /// Downcasts the box to a concrete type.
+ ///
+ /// For a safe alternative see [`downcast`].
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// #![feature(downcast_unchecked)]
+ ///
+ /// use std::any::Any;
+ ///
+ /// let x: Box<dyn Any> = Box::new(1_usize);
+ ///
+ /// unsafe {
+ /// assert_eq!(*x.downcast_unchecked::<usize>(), 1);
+ /// }
+ /// ```
+ ///
+ /// # Safety
+ ///
+ /// The contained value must be of type `T`. Calling this method
+ /// with the incorrect type is *undefined behavior*.
+ ///
+ /// [`downcast`]: Self::downcast
+ #[inline]
+ #[unstable(feature = "downcast_unchecked", issue = "90850")]
+ pub unsafe fn downcast_unchecked<T: Any>(self) -> Box<T, A> {
+ debug_assert!(self.is::<T>());
+ unsafe {
+ let (raw, alloc): (*mut dyn Any, _) = Box::into_raw_with_allocator(self);
+ Box::from_raw_in(raw as *mut T, alloc)
}
}
}
impl<A: Allocator> Box<dyn Any + Send, A> {
- #[inline]
- #[stable(feature = "rust1", since = "1.0.0")]
/// Attempt to downcast the box to a concrete type.
///
/// # Examples
@@ -1533,21 +1594,48 @@ impl<A: Allocator> Box<dyn Any + Send, A> {
/// print_if_string(Box::new(my_string));
/// print_if_string(Box::new(0i8));
/// ```
+ #[inline]
+ #[stable(feature = "rust1", since = "1.0.0")]
pub fn downcast<T: Any>(self) -> Result<Box<T, A>, Self> {
- if self.is::<T>() {
- unsafe {
- let (raw, alloc): (*mut (dyn Any + Send), _) = Box::into_raw_with_allocator(self);
- Ok(Box::from_raw_in(raw as *mut T, alloc))
- }
- } else {
- Err(self)
+ if self.is::<T>() { unsafe { Ok(self.downcast_unchecked::<T>()) } } else { Err(self) }
+ }
+
+ /// Downcasts the box to a concrete type.
+ ///
+ /// For a safe alternative see [`downcast`].
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// #![feature(downcast_unchecked)]
+ ///
+ /// use std::any::Any;
+ ///
+ /// let x: Box<dyn Any + Send> = Box::new(1_usize);
+ ///
+ /// unsafe {
+ /// assert_eq!(*x.downcast_unchecked::<usize>(), 1);
+ /// }
+ /// ```
+ ///
+ /// # Safety
+ ///
+ /// The contained value must be of type `T`. Calling this method
+ /// with the incorrect type is *undefined behavior*.
+ ///
+ /// [`downcast`]: Self::downcast
+ #[inline]
+ #[unstable(feature = "downcast_unchecked", issue = "90850")]
+ pub unsafe fn downcast_unchecked<T: Any>(self) -> Box<T, A> {
+ debug_assert!(self.is::<T>());
+ unsafe {
+ let (raw, alloc): (*mut (dyn Any + Send), _) = Box::into_raw_with_allocator(self);
+ Box::from_raw_in(raw as *mut T, alloc)
}
}
}
impl<A: Allocator> Box<dyn Any + Send + Sync, A> {
- #[inline]
- #[stable(feature = "box_send_sync_any_downcast", since = "1.51.0")]
/// Attempt to downcast the box to a concrete type.
///
/// # Examples
@@ -1565,15 +1653,44 @@ impl<A: Allocator> Box<dyn Any + Send + Sync, A> {
/// print_if_string(Box::new(my_string));
/// print_if_string(Box::new(0i8));
/// ```
+ #[inline]
+ #[stable(feature = "box_send_sync_any_downcast", since = "1.51.0")]
pub fn downcast<T: Any>(self) -> Result<Box<T, A>, Self> {
- if self.is::<T>() {
- unsafe {
- let (raw, alloc): (*mut (dyn Any + Send + Sync), _) =
- Box::into_raw_with_allocator(self);
- Ok(Box::from_raw_in(raw as *mut T, alloc))
- }
- } else {
- Err(self)
+ if self.is::<T>() { unsafe { Ok(self.downcast_unchecked::<T>()) } } else { Err(self) }
+ }
+
+ /// Downcasts the box to a concrete type.
+ ///
+ /// For a safe alternative see [`downcast`].
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// #![feature(downcast_unchecked)]
+ ///
+ /// use std::any::Any;
+ ///
+ /// let x: Box<dyn Any + Send + Sync> = Box::new(1_usize);
+ ///
+ /// unsafe {
+ /// assert_eq!(*x.downcast_unchecked::<usize>(), 1);
+ /// }
+ /// ```
+ ///
+ /// # Safety
+ ///
+ /// The contained value must be of type `T`. Calling this method
+ /// with the incorrect type is *undefined behavior*.
+ ///
+ /// [`downcast`]: Self::downcast
+ #[inline]
+ #[unstable(feature = "downcast_unchecked", issue = "90850")]
+ pub unsafe fn downcast_unchecked<T: Any>(self) -> Box<T, A> {
+ debug_assert!(self.is::<T>());
+ unsafe {
+ let (raw, alloc): (*mut (dyn Any + Send + Sync), _) =
+ Box::into_raw_with_allocator(self);
+ Box::from_raw_in(raw as *mut T, alloc)
}
}
}
diff --git a/library/alloc/src/collections/binary_heap.rs b/library/alloc/src/collections/binary_heap.rs
index 7d87974b47e..6fc6002d551 100644
--- a/library/alloc/src/collections/binary_heap.rs
+++ b/library/alloc/src/collections/binary_heap.rs
@@ -149,6 +149,7 @@ use core::mem::{self, swap, ManuallyDrop};
use core::ops::{Deref, DerefMut};
use core::ptr;
+use crate::collections::TryReserveError;
use crate::slice;
use crate::vec::{self, AsIntoIter, Vec};
@@ -953,6 +954,84 @@ impl<T> BinaryHeap<T> {
self.data.reserve(additional);
}
+ /// Tries to reserve the minimum capacity for exactly `additional`
+ /// elements to be inserted in the given `BinaryHeap<T>`. After calling
+ /// `try_reserve_exact`, capacity will be greater than or equal to
+ /// `self.len() + additional` if it returns `Ok(())`.
+ /// Does nothing if the capacity is already sufficient.
+ ///
+ /// Note that the allocator may give the collection more space than it
+ /// requests. Therefore, capacity can not be relied upon to be precisely
+ /// minimal. Prefer [`try_reserve`] if future insertions are expected.
+ ///
+ /// [`try_reserve`]: BinaryHeap::try_reserve
+ ///
+ /// # Errors
+ ///
+ /// If the capacity overflows, or the allocator reports a failure, then an error
+ /// is returned.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// #![feature(try_reserve_2)]
+ /// use std::collections::BinaryHeap;
+ /// use std::collections::TryReserveError;
+ ///
+ /// fn find_max_slow(data: &[u32]) -> Result<Option<u32>, TryReserveError> {
+ /// let mut heap = BinaryHeap::new();
+ ///
+ /// // Pre-reserve the memory, exiting if we can't
+ /// heap.try_reserve_exact(data.len())?;
+ ///
+ /// // Now we know this can't OOM in the middle of our complex work
+ /// heap.extend(data.iter());
+ ///
+ /// Ok(heap.pop())
+ /// }
+ /// # find_max_slow(&[1, 2, 3]).expect("why is the test harness OOMing on 12 bytes?");
+ /// ```
+ #[unstable(feature = "try_reserve_2", issue = "91789")]
+ pub fn try_reserve_exact(&mut self, additional: usize) -> Result<(), TryReserveError> {
+ self.data.try_reserve_exact(additional)
+ }
+
+ /// Tries to reserve capacity for at least `additional` more elements to be inserted
+ /// in the given `BinaryHeap<T>`. The collection may reserve more space to avoid
+ /// frequent reallocations. After calling `try_reserve`, capacity will be
+ /// greater than or equal to `self.len() + additional`. Does nothing if
+ /// capacity is already sufficient.
+ ///
+ /// # Errors
+ ///
+ /// If the capacity overflows, or the allocator reports a failure, then an error
+ /// is returned.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// #![feature(try_reserve_2)]
+ /// use std::collections::BinaryHeap;
+ /// use std::collections::TryReserveError;
+ ///
+ /// fn find_max_slow(data: &[u32]) -> Result<Option<u32>, TryReserveError> {
+ /// let mut heap = BinaryHeap::new();
+ ///
+ /// // Pre-reserve the memory, exiting if we can't
+ /// heap.try_reserve(data.len())?;
+ ///
+ /// // Now we know this can't OOM in the middle of our complex work
+ /// heap.extend(data.iter());
+ ///
+ /// Ok(heap.pop())
+ /// }
+ /// # find_max_slow(&[1, 2, 3]).expect("why is the test harness OOMing on 12 bytes?");
+ /// ```
+ #[unstable(feature = "try_reserve_2", issue = "91789")]
+ pub fn try_reserve(&mut self, additional: usize) -> Result<(), TryReserveError> {
+ self.data.try_reserve(additional)
+ }
+
/// Discards as much additional capacity as possible.
///
/// # Examples
@@ -1500,7 +1579,7 @@ impl<T: Ord, const N: usize> From<[T; N]> for BinaryHeap<T> {
/// }
/// ```
fn from(arr: [T; N]) -> Self {
- core::array::IntoIter::new(arr).collect()
+ Self::from_iter(arr)
}
}
diff --git a/library/alloc/src/collections/btree/map.rs b/library/alloc/src/collections/btree/map.rs
index 2ff7b0fbb75..199c05dc5df 100644
--- a/library/alloc/src/collections/btree/map.rs
+++ b/library/alloc/src/collections/btree/map.rs
@@ -1305,11 +1305,11 @@ impl<K, V> BTreeMap<K, V> {
pub(crate) fn bulk_build_from_sorted_iter<I>(iter: I) -> Self
where
K: Ord,
- I: Iterator<Item = (K, V)>,
+ I: IntoIterator<Item = (K, V)>,
{
let mut root = Root::new();
let mut length = 0;
- root.bulk_push(DedupSortedIter::new(iter), &mut length);
+ root.bulk_push(DedupSortedIter::new(iter.into_iter()), &mut length);
BTreeMap { root: Some(root), length }
}
}
@@ -1944,7 +1944,7 @@ impl<K: Ord, V> FromIterator<(K, V)> for BTreeMap<K, V> {
// use stable sort to preserve the insertion order.
inputs.sort_by(|a, b| a.0.cmp(&b.0));
- BTreeMap::bulk_build_from_sorted_iter(inputs.into_iter())
+ BTreeMap::bulk_build_from_sorted_iter(inputs)
}
}
@@ -2061,7 +2061,7 @@ impl<K: Ord, V, const N: usize> From<[(K, V); N]> for BTreeMap<K, V> {
// use stable sort to preserve the insertion order.
arr.sort_by(|a, b| a.0.cmp(&b.0));
- BTreeMap::bulk_build_from_sorted_iter(core::array::IntoIter::new(arr))
+ BTreeMap::bulk_build_from_sorted_iter(arr)
}
}
@@ -2107,10 +2107,11 @@ impl<K, V> BTreeMap<K, V> {
/// ```
/// use std::collections::BTreeMap;
///
- /// let mut map = BTreeMap::new();
- /// map.insert("a", 1);
- /// map.insert("b", 2);
- /// map.insert("c", 3);
+ /// let mut map = BTreeMap::from([
+ /// ("a", 1),
+ /// ("b", 2),
+ /// ("c", 3),
+ /// ]);
///
/// // add 10 to the value if the key isn't "a"
/// for (key, value) in map.iter_mut() {
diff --git a/library/alloc/src/collections/btree/map/tests.rs b/library/alloc/src/collections/btree/map/tests.rs
index 17389657afb..c95aeeaa605 100644
--- a/library/alloc/src/collections/btree/map/tests.rs
+++ b/library/alloc/src/collections/btree/map/tests.rs
@@ -1556,7 +1556,7 @@ fn test_clone_from() {
}
#[allow(dead_code)]
-fn test_variance() {
+fn assert_covariance() {
fn map_key<'new>(v: BTreeMap<&'static str, ()>) -> BTreeMap<&'new str, ()> {
v
}
@@ -1615,7 +1615,7 @@ fn test_variance() {
}
#[allow(dead_code)]
-fn test_sync() {
+fn assert_sync() {
fn map<T: Sync>(v: &BTreeMap<T, T>) -> impl Sync + '_ {
v
}
@@ -1684,7 +1684,7 @@ fn test_sync() {
}
#[allow(dead_code)]
-fn test_send() {
+fn assert_send() {
fn map<T: Send>(v: BTreeMap<T, T>) -> impl Send {
v
}
diff --git a/library/alloc/src/collections/btree/set.rs b/library/alloc/src/collections/btree/set.rs
index 0322cabccde..394c21bf51c 100644
--- a/library/alloc/src/collections/btree/set.rs
+++ b/library/alloc/src/collections/btree/set.rs
@@ -155,7 +155,7 @@ enum DifferenceInner<'a, T: 'a> {
self_iter: Iter<'a, T>,
other_set: &'a BTreeSet<T>,
},
- Iterate(Iter<'a, T>), // simply produce all values in `self`
+ Iterate(Iter<'a, T>), // simply produce all elements in `self`
}
#[stable(feature = "collection_debug", since = "1.17.0")]
@@ -207,7 +207,7 @@ enum IntersectionInner<'a, T: 'a> {
small_iter: Iter<'a, T>,
large_set: &'a BTreeSet<T>,
},
- Answer(Option<&'a T>), // return a specific value or emptiness
+ Answer(Option<&'a T>), // return a specific element or emptiness
}
#[stable(feature = "collection_debug", since = "1.17.0")]
@@ -295,8 +295,8 @@ impl<T> BTreeSet<T> {
Range { iter: self.map.range(range) }
}
- /// Visits the values representing the difference,
- /// i.e., the values that are in `self` but not in `other`,
+ /// Visits the elements representing the difference,
+ /// i.e., the elements that are in `self` but not in `other`,
/// in ascending order.
///
/// # Examples
@@ -356,8 +356,8 @@ impl<T> BTreeSet<T> {
}
}
- /// Visits the values representing the symmetric difference,
- /// i.e., the values that are in `self` or in `other` but not in both,
+ /// Visits the elements representing the symmetric difference,
+ /// i.e., the elements that are in `self` or in `other` but not in both,
/// in ascending order.
///
/// # Examples
@@ -384,8 +384,8 @@ impl<T> BTreeSet<T> {
SymmetricDifference(MergeIterInner::new(self.iter(), other.iter()))
}
- /// Visits the values representing the intersection,
- /// i.e., the values that are both in `self` and `other`,
+ /// Visits the elements representing the intersection,
+ /// i.e., the elements that are both in `self` and `other`,
/// in ascending order.
///
/// # Examples
@@ -437,8 +437,8 @@ impl<T> BTreeSet<T> {
}
}
- /// Visits the values representing the union,
- /// i.e., all the values in `self` or `other`, without duplicates,
+ /// Visits the elements representing the union,
+ /// i.e., all the elements in `self` or `other`, without duplicates,
/// in ascending order.
///
/// # Examples
@@ -463,7 +463,7 @@ impl<T> BTreeSet<T> {
Union(MergeIterInner::new(self.iter(), other.iter()))
}
- /// Clears the set, removing all values.
+ /// Clears the set, removing all elements.
///
/// # Examples
///
@@ -480,18 +480,18 @@ impl<T> BTreeSet<T> {
self.map.clear()
}
- /// Returns `true` if the set contains a value.
+ /// Returns `true` if the set contains an element equal to the value.
///
- /// The value may be any borrowed form of the set's value type,
+ /// The value may be any borrowed form of the set's element type,
/// but the ordering on the borrowed form *must* match the
- /// ordering on the value type.
+ /// ordering on the element type.
///
/// # Examples
///
/// ```
/// use std::collections::BTreeSet;
///
- /// let set: BTreeSet<_> = [1, 2, 3].iter().cloned().collect();
+ /// let set = BTreeSet::from([1, 2, 3]);
/// assert_eq!(set.contains(&1), true);
/// assert_eq!(set.contains(&4), false);
/// ```
@@ -504,18 +504,19 @@ impl<T> BTreeSet<T> {
self.map.contains_key(value)
}
- /// Returns a reference to the value in the set, if any, that is equal to the given value.
+ /// Returns a reference to the element in the set, if any, that is equal to
+ /// the value.
///
- /// The value may be any borrowed form of the set's value type,
+ /// The value may be any borrowed form of the set's element type,
/// but the ordering on the borrowed form *must* match the
- /// ordering on the value type.
+ /// ordering on the element type.
///
/// # Examples
///
/// ```
/// use std::collections::BTreeSet;
///
- /// let set: BTreeSet<_> = [1, 2, 3].iter().cloned().collect();
+ /// let set = BTreeSet::from([1, 2, 3]);
/// assert_eq!(set.get(&2), Some(&2));
/// assert_eq!(set.get(&4), None);
/// ```
@@ -536,7 +537,7 @@ impl<T> BTreeSet<T> {
/// ```
/// use std::collections::BTreeSet;
///
- /// let a: BTreeSet<_> = [1, 2, 3].iter().cloned().collect();
+ /// let a = BTreeSet::from([1, 2, 3]);
/// let mut b = BTreeSet::new();
///
/// assert_eq!(a.is_disjoint(&b), true);
@@ -555,14 +556,14 @@ impl<T> BTreeSet<T> {
}
/// Returns `true` if the set is a subset of another,
- /// i.e., `other` contains at least all the values in `self`.
+ /// i.e., `other` contains at least all the elements in `self`.
///
/// # Examples
///
/// ```
/// use std::collections::BTreeSet;
///
- /// let sup: BTreeSet<_> = [1, 2, 3].iter().cloned().collect();
+ /// let sup = BTreeSet::from([1, 2, 3]);
/// let mut set = BTreeSet::new();
///
/// assert_eq!(set.is_subset(&sup), true);
@@ -632,14 +633,14 @@ impl<T> BTreeSet<T> {
}
/// Returns `true` if the set is a superset of another,
- /// i.e., `self` contains at least all the values in `other`.
+ /// i.e., `self` contains at least all the elements in `other`.
///
/// # Examples
///
/// ```
/// use std::collections::BTreeSet;
///
- /// let sub: BTreeSet<_> = [1, 2].iter().cloned().collect();
+ /// let sub = BTreeSet::from([1, 2]);
/// let mut set = BTreeSet::new();
///
/// assert_eq!(set.is_superset(&sub), false);
@@ -660,8 +661,8 @@ impl<T> BTreeSet<T> {
other.is_subset(self)
}
- /// Returns a reference to the first value in the set, if any.
- /// This value is always the minimum of all values in the set.
+ /// Returns a reference to the first element in the set, if any.
+ /// This element is always the minimum of all elements in the set.
///
/// # Examples
///
@@ -687,8 +688,8 @@ impl<T> BTreeSet<T> {
self.map.first_key_value().map(|(k, _)| k)
}
- /// Returns a reference to the last value in the set, if any.
- /// This value is always the maximum of all values in the set.
+ /// Returns a reference to the last element in the set, if any.
+ /// This element is always the maximum of all elements in the set.
///
/// # Examples
///
@@ -714,8 +715,8 @@ impl<T> BTreeSet<T> {
self.map.last_key_value().map(|(k, _)| k)
}
- /// Removes the first value from the set and returns it, if any.
- /// The first value is always the minimum value in the set.
+ /// Removes the first element from the set and returns it, if any.
+ /// The first element is always the minimum element in the set.
///
/// # Examples
///
@@ -739,8 +740,8 @@ impl<T> BTreeSet<T> {
self.map.pop_first().map(|kv| kv.0)
}
- /// Removes the last value from the set and returns it, if any.
- /// The last value is always the maximum value in the set.
+ /// Removes the last element from the set and returns it, if any.
+ /// The last element is always the maximum element in the set.
///
/// # Examples
///
@@ -766,10 +767,10 @@ impl<T> BTreeSet<T> {
/// Adds a value to the set.
///
- /// If the set did not have this value present, `true` is returned.
+ /// If the set did not have an equal element present, `true` is returned.
///
- /// If the set did have this value present, `false` is returned, and the
- /// entry is not updated. See the [module-level documentation] for more.
+ /// If the set did have an equal element present, `false` is returned, and
+ /// the entry is not updated. See the [module-level documentation] for more.
///
/// [module-level documentation]: index.html#insert-and-complex-keys
///
@@ -792,8 +793,8 @@ impl<T> BTreeSet<T> {
self.map.insert(value, ()).is_none()
}
- /// Adds a value to the set, replacing the existing value, if any, that is equal to the given
- /// one. Returns the replaced value.
+ /// Adds a value to the set, replacing the existing element, if any, that is
+ /// equal to the value. Returns the replaced element.
///
/// # Examples
///
@@ -815,12 +816,12 @@ impl<T> BTreeSet<T> {
Recover::replace(&mut self.map, value)
}
- /// Removes a value from the set. Returns whether the value was
- /// present in the set.
+ /// If the set contains an element equal to the value, removes it from the
+ /// set and drops it. Returns whether such an element was present.
///
- /// The value may be any borrowed form of the set's value type,
+ /// The value may be any borrowed form of the set's element type,
/// but the ordering on the borrowed form *must* match the
- /// ordering on the value type.
+ /// ordering on the element type.
///
/// # Examples
///
@@ -842,18 +843,19 @@ impl<T> BTreeSet<T> {
self.map.remove(value).is_some()
}
- /// Removes and returns the value in the set, if any, that is equal to the given one.
+ /// Removes and returns the element in the set, if any, that is equal to
+ /// the value.
///
- /// The value may be any borrowed form of the set's value type,
+ /// The value may be any borrowed form of the set's element type,
/// but the ordering on the borrowed form *must* match the
- /// ordering on the value type.
+ /// ordering on the element type.
///
/// # Examples
///
/// ```
/// use std::collections::BTreeSet;
///
- /// let mut set: BTreeSet<_> = [1, 2, 3].iter().cloned().collect();
+ /// let mut set = BTreeSet::from([1, 2, 3]);
/// assert_eq!(set.take(&2), Some(2));
/// assert_eq!(set.take(&2), None);
/// ```
@@ -876,8 +878,7 @@ impl<T> BTreeSet<T> {
/// ```
/// use std::collections::BTreeSet;
///
- /// let xs = [1, 2, 3, 4, 5, 6];
- /// let mut set: BTreeSet<i32> = xs.iter().cloned().collect();
+ /// let mut set = BTreeSet::from([1, 2, 3, 4, 5, 6]);
/// // Keep only the even numbers.
/// set.retain(|&k| k % 2 == 0);
/// assert!(set.iter().eq([2, 4, 6].iter()));
@@ -927,8 +928,8 @@ impl<T> BTreeSet<T> {
self.map.append(&mut other.map);
}
- /// Splits the collection into two at the given value. Returns everything after the given value,
- /// including the value.
+ /// Splits the collection into two at the value. Returns a new collection
+ /// with all elements greater than or equal to the value.
///
/// # Examples
///
@@ -964,20 +965,20 @@ impl<T> BTreeSet<T> {
BTreeSet { map: self.map.split_off(value) }
}
- /// Creates an iterator that visits all values in ascending order and uses a closure
- /// to determine if a value should be removed.
+ /// Creates an iterator that visits all elements in ascending order and
+ /// uses a closure to determine if an element should be removed.
///
- /// If the closure returns `true`, the value is removed from the set and yielded. If
- /// the closure returns `false`, or panics, the value remains in the set and will
- /// not be yielded.
+ /// If the closure returns `true`, the element is removed from the set and
+ /// yielded. If the closure returns `false`, or panics, the element remains
+ /// in the set and will not be yielded.
///
- /// If the iterator is only partially consumed or not consumed at all, each of the
- /// remaining values is still subjected to the closure and removed and dropped if it
- /// returns `true`.
+ /// If the iterator is only partially consumed or not consumed at all, each
+ /// of the remaining elements is still subjected to the closure and removed
+ /// and dropped if it returns `true`.
///
- /// It is unspecified how many more values will be subjected to the closure if a
- /// panic occurs in the closure, or if a panic occurs while dropping a value, or if
- /// the `DrainFilter` itself is leaked.
+ /// It is unspecified how many more elements will be subjected to the
+ /// closure if a panic occurs in the closure, or if a panic occurs while
+ /// dropping an element, or if the `DrainFilter` itself is leaked.
///
/// # Examples
///
@@ -1002,14 +1003,15 @@ impl<T> BTreeSet<T> {
DrainFilter { pred, inner: self.map.drain_filter_inner() }
}
- /// Gets an iterator that visits the values in the `BTreeSet` in ascending order.
+ /// Gets an iterator that visits the elements in the `BTreeSet` in ascending
+ /// order.
///
/// # Examples
///
/// ```
/// use std::collections::BTreeSet;
///
- /// let set: BTreeSet<usize> = [1, 2, 3].iter().cloned().collect();
+ /// let set = BTreeSet::from([1, 2, 3]);
/// let mut set_iter = set.iter();
/// assert_eq!(set_iter.next(), Some(&1));
/// assert_eq!(set_iter.next(), Some(&2));
@@ -1022,7 +1024,7 @@ impl<T> BTreeSet<T> {
/// ```
/// use std::collections::BTreeSet;
///
- /// let set: BTreeSet<usize> = [3, 1, 2].iter().cloned().collect();
+ /// let set = BTreeSet::from([3, 1, 2]);
/// let mut set_iter = set.iter();
/// assert_eq!(set_iter.next(), Some(&1));
/// assert_eq!(set_iter.next(), Some(&2));
@@ -1106,7 +1108,7 @@ impl<T: Ord, const N: usize> From<[T; N]> for BTreeSet<T> {
// use stable sort to preserve the insertion order.
arr.sort();
- let iter = core::array::IntoIter::new(arr).map(|k| (k, ()));
+ let iter = IntoIterator::into_iter(arr).map(|k| (k, ()));
let map = BTreeMap::bulk_build_from_sorted_iter(iter);
BTreeSet { map }
}
@@ -1124,7 +1126,7 @@ impl<T> IntoIterator for BTreeSet<T> {
/// ```
/// use std::collections::BTreeSet;
///
- /// let set: BTreeSet<usize> = [1, 2, 3, 4].iter().cloned().collect();
+ /// let set = BTreeSet::from([1, 2, 3, 4]);
///
/// let v: Vec<_> = set.into_iter().collect();
/// assert_eq!(v, [1, 2, 3, 4]);
@@ -1243,8 +1245,8 @@ impl<T: Ord + Clone> Sub<&BTreeSet<T>> for &BTreeSet<T> {
/// ```
/// use std::collections::BTreeSet;
///
- /// let a: BTreeSet<_> = vec![1, 2, 3].into_iter().collect();
- /// let b: BTreeSet<_> = vec![3, 4, 5].into_iter().collect();
+ /// let a = BTreeSet::from([1, 2, 3]);
+ /// let b = BTreeSet::from([3, 4, 5]);
///
/// let result = &a - &b;
/// let result_vec: Vec<_> = result.into_iter().collect();
@@ -1266,8 +1268,8 @@ impl<T: Ord + Clone> BitXor<&BTreeSet<T>> for &BTreeSet<T> {
/// ```
/// use std::collections::BTreeSet;
///
- /// let a: BTreeSet<_> = vec![1, 2, 3].into_iter().collect();
- /// let b: BTreeSet<_> = vec![2, 3, 4].into_iter().collect();
+ /// let a = BTreeSet::from([1, 2, 3]);
+ /// let b = BTreeSet::from([2, 3, 4]);
///
/// let result = &a ^ &b;
/// let result_vec: Vec<_> = result.into_iter().collect();
@@ -1289,8 +1291,8 @@ impl<T: Ord + Clone> BitAnd<&BTreeSet<T>> for &BTreeSet<T> {
/// ```
/// use std::collections::BTreeSet;
///
- /// let a: BTreeSet<_> = vec![1, 2, 3].into_iter().collect();
- /// let b: BTreeSet<_> = vec![2, 3, 4].into_iter().collect();
+ /// let a = BTreeSet::from([1, 2, 3]);
+ /// let b = BTreeSet::from([2, 3, 4]);
///
/// let result = &a & &b;
/// let result_vec: Vec<_> = result.into_iter().collect();
@@ -1312,8 +1314,8 @@ impl<T: Ord + Clone> BitOr<&BTreeSet<T>> for &BTreeSet<T> {
/// ```
/// use std::collections::BTreeSet;
///
- /// let a: BTreeSet<_> = vec![1, 2, 3].into_iter().collect();
- /// let b: BTreeSet<_> = vec![3, 4, 5].into_iter().collect();
+ /// let a = BTreeSet::from([1, 2, 3]);
+ /// let b = BTreeSet::from([3, 4, 5]);
///
/// let result = &a | &b;
/// let result_vec: Vec<_> = result.into_iter().collect();
diff --git a/library/alloc/src/collections/btree/set/tests.rs b/library/alloc/src/collections/btree/set/tests.rs
index 2fc17a7c860..7390ff5a59c 100644
--- a/library/alloc/src/collections/btree/set/tests.rs
+++ b/library/alloc/src/collections/btree/set/tests.rs
@@ -3,6 +3,7 @@ use super::super::testing::rng::DeterministicRng;
use super::*;
use crate::vec::Vec;
use std::cmp::Ordering;
+use std::hash::{Hash, Hasher};
use std::iter::FromIterator;
use std::panic::{catch_unwind, AssertUnwindSafe};
@@ -513,7 +514,7 @@ fn test_recovery() {
}
#[allow(dead_code)]
-fn test_variance() {
+fn assert_covariance() {
fn set<'new>(v: BTreeSet<&'static str>) -> BTreeSet<&'new str> {
v
}
@@ -530,7 +531,7 @@ fn test_variance() {
}
#[allow(dead_code)]
-fn test_sync() {
+fn assert_sync() {
fn set<T: Sync>(v: &BTreeSet<T>) -> impl Sync + '_ {
v
}
@@ -569,7 +570,7 @@ fn test_sync() {
}
#[allow(dead_code)]
-fn test_send() {
+fn assert_send() {
fn set<T: Send>(v: BTreeSet<T>) -> impl Send {
v
}
@@ -607,6 +608,37 @@ fn test_send() {
}
}
+#[allow(dead_code)]
+// Check that the member-like functions conditionally provided by #[derive()]
+// are not overriden by genuine member functions with a different signature.
+fn assert_derives() {
+ fn hash<T: Hash, H: Hasher>(v: BTreeSet<T>, state: &mut H) {
+ v.hash(state);
+ // Tested much more thoroughly outside the crate in btree_set_hash.rs
+ }
+ fn eq<T: PartialEq>(v: BTreeSet<T>) {
+ let _ = v.eq(&v);
+ }
+ fn ne<T: PartialEq>(v: BTreeSet<T>) {
+ let _ = v.ne(&v);
+ }
+ fn cmp<T: Ord>(v: BTreeSet<T>) {
+ let _ = v.cmp(&v);
+ }
+ fn min<T: Ord>(v: BTreeSet<T>, w: BTreeSet<T>) {
+ let _ = v.min(w);
+ }
+ fn max<T: Ord>(v: BTreeSet<T>, w: BTreeSet<T>) {
+ let _ = v.max(w);
+ }
+ fn clamp<T: Ord>(v: BTreeSet<T>, w: BTreeSet<T>, x: BTreeSet<T>) {
+ let _ = v.clamp(w, x);
+ }
+ fn partial_cmp<T: PartialOrd>(v: &BTreeSet<T>) {
+ let _ = v.partial_cmp(&v);
+ }
+}
+
#[test]
fn test_ord_absence() {
fn set<K>(mut set: BTreeSet<K>) {
diff --git a/library/alloc/src/collections/btree/testing/crash_test.rs b/library/alloc/src/collections/btree/testing/crash_test.rs
index 488eaa07a95..bcf5f5f7251 100644
--- a/library/alloc/src/collections/btree/testing/crash_test.rs
+++ b/library/alloc/src/collections/btree/testing/crash_test.rs
@@ -1,3 +1,4 @@
+// We avoid relying on anything else in the crate, apart from the `Debug` trait.
use crate::fmt::Debug;
use std::cmp::Ordering;
use std::sync::atomic::{AtomicUsize, Ordering::SeqCst};
@@ -7,8 +8,7 @@ use std::sync::atomic::{AtomicUsize, Ordering::SeqCst};
/// Events are `clone`, `drop` or some anonymous `query`.
///
/// Crash test dummies are identified and ordered by an id, so they can be used
-/// as keys in a BTreeMap. The implementation intentionally uses does not rely
-/// on anything defined in the crate, apart from the `Debug` trait.
+/// as keys in a BTreeMap.
#[derive(Debug)]
pub struct CrashTestDummy {
pub id: usize,
diff --git a/library/alloc/src/collections/linked_list.rs b/library/alloc/src/collections/linked_list.rs
index e4913b16adb..4a07d5d4bed 100644
--- a/library/alloc/src/collections/linked_list.rs
+++ b/library/alloc/src/collections/linked_list.rs
@@ -417,7 +417,7 @@ impl<T> LinkedList<T> {
/// let list: LinkedList<u32> = LinkedList::new();
/// ```
#[inline]
- #[rustc_const_stable(feature = "const_linked_list_new", since = "1.32.0")]
+ #[rustc_const_stable(feature = "const_linked_list_new", since = "1.39.0")]
#[stable(feature = "rust1", since = "1.0.0")]
#[must_use]
pub const fn new() -> Self {
@@ -1961,7 +1961,7 @@ impl<T, const N: usize> From<[T; N]> for LinkedList<T> {
/// assert_eq!(list1, list2);
/// ```
fn from(arr: [T; N]) -> Self {
- core::array::IntoIter::new(arr).collect()
+ Self::from_iter(arr)
}
}
diff --git a/library/alloc/src/collections/vec_deque/iter_mut.rs b/library/alloc/src/collections/vec_deque/iter_mut.rs
index 31e6e3b06af..ee2df0d5160 100644
--- a/library/alloc/src/collections/vec_deque/iter_mut.rs
+++ b/library/alloc/src/collections/vec_deque/iter_mut.rs
@@ -12,7 +12,7 @@ use super::{count, wrap_index, RingSlices};
/// [`iter_mut`]: super::VecDeque::iter_mut
#[stable(feature = "rust1", since = "1.0.0")]
pub struct IterMut<'a, T: 'a> {
- // Internal safety invariant: the entire slice is dereferencable.
+ // Internal safety invariant: the entire slice is dereferenceable.
ring: *mut [T],
tail: usize,
head: usize,
@@ -42,7 +42,7 @@ impl<T: fmt::Debug> fmt::Debug for IterMut<'_, T> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
let (front, back) = RingSlices::ring_slices(self.ring, self.head, self.tail);
// SAFETY: these are the elements we have not handed out yet, so aliasing is fine.
- // The `IterMut` invariant also ensures everything is dereferencable.
+ // The `IterMut` invariant also ensures everything is dereferenceable.
let (front, back) = unsafe { (&*front, &*back) };
f.debug_tuple("IterMut").field(&front).field(&back).finish()
}
@@ -78,7 +78,7 @@ impl<'a, T> Iterator for IterMut<'a, T> {
{
let (front, back) = RingSlices::ring_slices(self.ring, self.head, self.tail);
// SAFETY: these are the elements we have not handed out yet, so aliasing is fine.
- // The `IterMut` invariant also ensures everything is dereferencable.
+ // The `IterMut` invariant also ensures everything is dereferenceable.
let (front, back) = unsafe { (&mut *front, &mut *back) };
accum = front.iter_mut().fold(accum, &mut f);
back.iter_mut().fold(accum, &mut f)
@@ -132,7 +132,7 @@ impl<'a, T> DoubleEndedIterator for IterMut<'a, T> {
{
let (front, back) = RingSlices::ring_slices(self.ring, self.head, self.tail);
// SAFETY: these are the elements we have not handed out yet, so aliasing is fine.
- // The `IterMut` invariant also ensures everything is dereferencable.
+ // The `IterMut` invariant also ensures everything is dereferenceable.
let (front, back) = unsafe { (&mut *front, &mut *back) };
accum = back.iter_mut().rfold(accum, &mut f);
front.iter_mut().rfold(accum, &mut f)
diff --git a/library/alloc/src/collections/vec_deque/mod.rs b/library/alloc/src/collections/vec_deque/mod.rs
index de607c8fdab..075becfb7d1 100644
--- a/library/alloc/src/collections/vec_deque/mod.rs
+++ b/library/alloc/src/collections/vec_deque/mod.rs
@@ -720,9 +720,9 @@ impl<T, A: Allocator> VecDeque<T, A> {
///
/// Note that the allocator may give the collection more space than it
/// requests. Therefore, capacity can not be relied upon to be precisely
- /// minimal. Prefer [`reserve`] if future insertions are expected.
+ /// minimal. Prefer [`try_reserve`] if future insertions are expected.
///
- /// [`reserve`]: VecDeque::reserve
+ /// [`try_reserve`]: VecDeque::try_reserve
///
/// # Errors
///
@@ -1020,7 +1020,7 @@ impl<T, A: Allocator> VecDeque<T, A> {
#[stable(feature = "rust1", since = "1.0.0")]
pub fn iter_mut(&mut self) -> IterMut<'_, T> {
// SAFETY: The internal `IterMut` safety invariant is established because the
- // `ring` we create is a dereferencable slice for lifetime '_.
+ // `ring` we create is a dereferenceable slice for lifetime '_.
let ring = ptr::slice_from_raw_parts_mut(self.ptr(), self.cap());
unsafe { IterMut::new(ring, self.tail, self.head, PhantomData) }
@@ -1209,7 +1209,7 @@ impl<T, A: Allocator> VecDeque<T, A> {
let (tail, head) = self.range_tail_head(range);
// SAFETY: The internal `IterMut` safety invariant is established because the
- // `ring` we create is a dereferencable slice for lifetime '_.
+ // `ring` we create is a dereferenceable slice for lifetime '_.
let ring = ptr::slice_from_raw_parts_mut(self.ptr(), self.cap());
unsafe { IterMut::new(ring, tail, head, PhantomData) }
@@ -2149,13 +2149,44 @@ impl<T, A: Allocator> VecDeque<T, A> {
where
F: FnMut(&T) -> bool,
{
+ self.retain_mut(|elem| f(elem));
+ }
+
+ /// Retains only the elements specified by the predicate.
+ ///
+ /// In other words, remove all elements `e` such that `f(&e)` returns false.
+ /// This method operates in place, visiting each element exactly once in the
+ /// original order, and preserves the order of the retained elements.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// #![feature(vec_retain_mut)]
+ ///
+ /// use std::collections::VecDeque;
+ ///
+ /// let mut buf = VecDeque::new();
+ /// buf.extend(1..5);
+ /// buf.retain_mut(|x| if *x % 2 == 0 {
+ /// *x += 1;
+ /// true
+ /// } else {
+ /// false
+ /// });
+ /// assert_eq!(buf, [3, 5]);
+ /// ```
+ #[unstable(feature = "vec_retain_mut", issue = "90829")]
+ pub fn retain_mut<F>(&mut self, mut f: F)
+ where
+ F: FnMut(&mut T) -> bool,
+ {
let len = self.len();
let mut idx = 0;
let mut cur = 0;
// Stage 1: All values are retained.
while cur < len {
- if !f(&self[cur]) {
+ if !f(&mut self[cur]) {
cur += 1;
break;
}
@@ -2164,7 +2195,7 @@ impl<T, A: Allocator> VecDeque<T, A> {
}
// Stage 2: Swap retained value into current idx.
while cur < len {
- if !f(&self[cur]) {
+ if !f(&mut self[cur]) {
cur += 1;
continue;
}
@@ -2173,25 +2204,27 @@ impl<T, A: Allocator> VecDeque<T, A> {
cur += 1;
idx += 1;
}
- // Stage 3: Trancate all values after idx.
+ // Stage 3: Truncate all values after idx.
if cur != idx {
self.truncate(idx);
}
}
+ // Double the buffer size. This method is inline(never), so we expect it to only
+ // be called in cold paths.
// This may panic or abort
#[inline(never)]
fn grow(&mut self) {
- if self.is_full() {
- let old_cap = self.cap();
- // Double the buffer size.
- self.buf.reserve_exact(old_cap, old_cap);
- assert!(self.cap() == old_cap * 2);
- unsafe {
- self.handle_capacity_increase(old_cap);
- }
- debug_assert!(!self.is_full());
+ // Extend or possibly remove this assertion when valid use-cases for growing the
+ // buffer without it being full emerge
+ debug_assert!(self.is_full());
+ let old_cap = self.cap();
+ self.buf.reserve_exact(old_cap, old_cap);
+ assert!(self.cap() == old_cap * 2);
+ unsafe {
+ self.handle_capacity_increase(old_cap);
}
+ debug_assert!(!self.is_full());
}
/// Modifies the `VecDeque` in-place so that `len()` is equal to `new_len`,
diff --git a/library/alloc/src/lib.rs b/library/alloc/src/lib.rs
index 4a66c3f6b2e..600862c4224 100644
--- a/library/alloc/src/lib.rs
+++ b/library/alloc/src/lib.rs
@@ -105,10 +105,8 @@
#![feature(fmt_internals)]
#![feature(fn_traits)]
#![feature(inherent_ascii_escape)]
-#![cfg_attr(bootstrap, feature(format_args_capture))]
#![feature(inplace_iteration)]
#![feature(iter_advance_by)]
-#![feature(iter_zip)]
#![feature(layout_for_ptr)]
#![feature(maybe_uninit_extra)]
#![feature(maybe_uninit_slice)]
@@ -138,7 +136,7 @@
#![feature(cfg_target_has_atomic)]
#![feature(const_fn_trait_bound)]
#![feature(const_trait_impl)]
-#![feature(destructuring_assignment)]
+#![cfg_attr(bootstrap, feature(destructuring_assignment))]
#![feature(dropck_eyepatch)]
#![feature(exclusive_range_pattern)]
#![feature(fundamental)]
diff --git a/library/alloc/src/raw_vec.rs b/library/alloc/src/raw_vec.rs
index 4ab38c802a1..3d38e73305a 100644
--- a/library/alloc/src/raw_vec.rs
+++ b/library/alloc/src/raw_vec.rs
@@ -289,6 +289,14 @@ impl<T, A: Allocator> RawVec<T, A> {
}
}
+ /// A specialized version of `reserve()` used only by the hot and
+ /// oft-instantiated `Vec::push()`, which does its own capacity check.
+ #[cfg(not(no_global_oom_handling))]
+ #[inline(never)]
+ pub fn reserve_for_push(&mut self, len: usize) {
+ handle_reserve(self.grow_amortized(len, 1));
+ }
+
/// The same as `reserve`, but returns on errors instead of panicking or aborting.
pub fn try_reserve(&mut self, len: usize, additional: usize) -> Result<(), TryReserveError> {
if self.needs_to_grow(len, additional) {
diff --git a/library/alloc/src/raw_vec/tests.rs b/library/alloc/src/raw_vec/tests.rs
index 8c15a24409b..ff322f0da97 100644
--- a/library/alloc/src/raw_vec/tests.rs
+++ b/library/alloc/src/raw_vec/tests.rs
@@ -77,3 +77,87 @@ fn reserve_does_not_overallocate() {
assert!(v.capacity() >= 12 + 12 / 2);
}
}
+
+struct ZST;
+
+// A `RawVec` holding zero-sized elements should always look like this.
+fn zst_sanity<T>(v: &RawVec<T>) {
+ assert_eq!(v.capacity(), usize::MAX);
+ assert_eq!(v.ptr(), core::ptr::Unique::<T>::dangling().as_ptr());
+ assert_eq!(v.current_memory(), None);
+}
+
+#[test]
+fn zst() {
+ let cap_err = Err(crate::collections::TryReserveErrorKind::CapacityOverflow.into());
+
+ assert_eq!(std::mem::size_of::<ZST>(), 0);
+
+ // All these different ways of creating the RawVec produce the same thing.
+
+ let v: RawVec<ZST> = RawVec::new();
+ zst_sanity(&v);
+
+ let v: RawVec<ZST> = RawVec::with_capacity_in(100, Global);
+ zst_sanity(&v);
+
+ let v: RawVec<ZST> = RawVec::with_capacity_in(100, Global);
+ zst_sanity(&v);
+
+ let v: RawVec<ZST> = RawVec::allocate_in(0, AllocInit::Uninitialized, Global);
+ zst_sanity(&v);
+
+ let v: RawVec<ZST> = RawVec::allocate_in(100, AllocInit::Uninitialized, Global);
+ zst_sanity(&v);
+
+ let mut v: RawVec<ZST> = RawVec::allocate_in(usize::MAX, AllocInit::Uninitialized, Global);
+ zst_sanity(&v);
+
+ // Check all these operations work as expected with zero-sized elements.
+
+ assert!(!v.needs_to_grow(100, usize::MAX - 100));
+ assert!(v.needs_to_grow(101, usize::MAX - 100));
+ zst_sanity(&v);
+
+ v.reserve(100, usize::MAX - 100);
+ //v.reserve(101, usize::MAX - 100); // panics, in `zst_reserve_panic` below
+ zst_sanity(&v);
+
+ v.reserve_exact(100, usize::MAX - 100);
+ //v.reserve_exact(101, usize::MAX - 100); // panics, in `zst_reserve_exact_panic` below
+ zst_sanity(&v);
+
+ assert_eq!(v.try_reserve(100, usize::MAX - 100), Ok(()));
+ assert_eq!(v.try_reserve(101, usize::MAX - 100), cap_err);
+ zst_sanity(&v);
+
+ assert_eq!(v.try_reserve_exact(100, usize::MAX - 100), Ok(()));
+ assert_eq!(v.try_reserve_exact(101, usize::MAX - 100), cap_err);
+ zst_sanity(&v);
+
+ assert_eq!(v.grow_amortized(100, usize::MAX - 100), cap_err);
+ assert_eq!(v.grow_amortized(101, usize::MAX - 100), cap_err);
+ zst_sanity(&v);
+
+ assert_eq!(v.grow_exact(100, usize::MAX - 100), cap_err);
+ assert_eq!(v.grow_exact(101, usize::MAX - 100), cap_err);
+ zst_sanity(&v);
+}
+
+#[test]
+#[should_panic(expected = "capacity overflow")]
+fn zst_reserve_panic() {
+ let mut v: RawVec<ZST> = RawVec::new();
+ zst_sanity(&v);
+
+ v.reserve(101, usize::MAX - 100);
+}
+
+#[test]
+#[should_panic(expected = "capacity overflow")]
+fn zst_reserve_exact_panic() {
+ let mut v: RawVec<ZST> = RawVec::new();
+ zst_sanity(&v);
+
+ v.reserve_exact(101, usize::MAX - 100);
+}
diff --git a/library/alloc/src/rc.rs b/library/alloc/src/rc.rs
index c4e5e44fec0..33bee4324fd 100644
--- a/library/alloc/src/rc.rs
+++ b/library/alloc/src/rc.rs
@@ -2121,7 +2121,7 @@ impl<T: ?Sized> Weak<T> {
// a valid payload address, as the payload is at least as aligned as RcBox (usize).
ptr as *const T
} else {
- // SAFETY: if is_dangling returns false, then the pointer is dereferencable.
+ // SAFETY: if is_dangling returns false, then the pointer is dereferenceable.
// The payload may be dropped at this point, and we have to maintain provenance,
// so use raw pointer manipulation.
unsafe { ptr::addr_of_mut!((*ptr).value) }
diff --git a/library/alloc/src/str.rs b/library/alloc/src/str.rs
index 104f5556566..69495f31c32 100644
--- a/library/alloc/src/str.rs
+++ b/library/alloc/src/str.rs
@@ -178,12 +178,20 @@ where
unsafe {
let pos = result.len();
- let target = result.get_unchecked_mut(pos..reserved_len);
+ let target = result.spare_capacity_mut().get_unchecked_mut(..reserved_len - pos);
+
+ // Convert the separator and slices to slices of MaybeUninit
+ // to simplify implementation in specialize_for_lengths
+ let sep_uninit = core::slice::from_raw_parts(sep.as_ptr().cast(), sep.len());
+ let iter_uninit = iter.map(|it| {
+ let it = it.borrow().as_ref();
+ core::slice::from_raw_parts(it.as_ptr().cast(), it.len())
+ });
// copy separator and slices over without bounds checks
// generate loops with hardcoded offsets for small separators
// massive improvements possible (~ x2)
- let remain = specialize_for_lengths!(sep, target, iter; 0, 1, 2, 3, 4);
+ let remain = specialize_for_lengths!(sep_uninit, target, iter_uninit; 0, 1, 2, 3, 4);
// A weird borrow implementation may return different
// slices for the length calculation and the actual copy.
diff --git a/library/alloc/src/string.rs b/library/alloc/src/string.rs
index 906b0187f7b..b151842458d 100644
--- a/library/alloc/src/string.rs
+++ b/library/alloc/src/string.rs
@@ -558,13 +558,13 @@ impl String {
pub fn from_utf8_lossy(v: &[u8]) -> Cow<'_, str> {
let mut iter = lossy::Utf8Lossy::from_bytes(v).chunks();
- let (first_valid, first_broken) = if let Some(chunk) = iter.next() {
+ let first_valid = if let Some(chunk) = iter.next() {
let lossy::Utf8LossyChunk { valid, broken } = chunk;
- if valid.len() == v.len() {
- debug_assert!(broken.is_empty());
+ if broken.is_empty() {
+ debug_assert_eq!(valid.len(), v.len());
return Cow::Borrowed(valid);
}
- (valid, broken)
+ valid
} else {
return Cow::Borrowed("");
};
@@ -573,9 +573,7 @@ impl String {
let mut res = String::with_capacity(v.len());
res.push_str(first_valid);
- if !first_broken.is_empty() {
- res.push_str(REPLACEMENT);
- }
+ res.push_str(REPLACEMENT);
for lossy::Utf8LossyChunk { valid, broken } in iter {
res.push_str(valid);
@@ -1046,9 +1044,9 @@ impl String {
///
/// Note that the allocator may give the collection more space than it
/// requests. Therefore, capacity can not be relied upon to be precisely
- /// minimal. Prefer [`reserve`] if future insertions are expected.
+ /// minimal. Prefer [`try_reserve`] if future insertions are expected.
///
- /// [`reserve`]: String::reserve
+ /// [`try_reserve`]: String::try_reserve
///
/// # Errors
///
diff --git a/library/alloc/src/sync.rs b/library/alloc/src/sync.rs
index 733a898b285..7c065f37d1f 100644
--- a/library/alloc/src/sync.rs
+++ b/library/alloc/src/sync.rs
@@ -1743,7 +1743,7 @@ impl<T: ?Sized> Weak<T> {
// a valid payload address, as the payload is at least as aligned as ArcInner (usize).
ptr as *const T
} else {
- // SAFETY: if is_dangling returns false, then the pointer is dereferencable.
+ // SAFETY: if is_dangling returns false, then the pointer is dereferenceable.
// The payload may be dropped at this point, and we have to maintain provenance,
// so use raw pointer manipulation.
unsafe { ptr::addr_of_mut!((*ptr).data) }
diff --git a/library/alloc/src/vec/drain.rs b/library/alloc/src/vec/drain.rs
index ff98091a0d2..1bff19d05c1 100644
--- a/library/alloc/src/vec/drain.rs
+++ b/library/alloc/src/vec/drain.rs
@@ -1,7 +1,7 @@
use crate::alloc::{Allocator, Global};
use core::fmt;
use core::iter::{FusedIterator, TrustedLen};
-use core::mem::{self};
+use core::mem;
use core::ptr::{self, NonNull};
use core::slice::{self};
@@ -104,16 +104,11 @@ impl<T, A: Allocator> DoubleEndedIterator for Drain<'_, T, A> {
#[stable(feature = "drain", since = "1.6.0")]
impl<T, A: Allocator> Drop for Drain<'_, T, A> {
fn drop(&mut self) {
- /// Continues dropping the remaining elements in the `Drain`, then moves back the
- /// un-`Drain`ed elements to restore the original `Vec`.
+ /// Moves back the un-`Drain`ed elements to restore the original `Vec`.
struct DropGuard<'r, 'a, T, A: Allocator>(&'r mut Drain<'a, T, A>);
impl<'r, 'a, T, A: Allocator> Drop for DropGuard<'r, 'a, T, A> {
fn drop(&mut self) {
- // Continue the same loop we have below. If the loop already finished, this does
- // nothing.
- self.0.for_each(drop);
-
if self.0.tail_len > 0 {
unsafe {
let source_vec = self.0.vec.as_mut();
@@ -131,15 +126,47 @@ impl<T, A: Allocator> Drop for Drain<'_, T, A> {
}
}
- // exhaust self first
- while let Some(item) = self.next() {
- let guard = DropGuard(self);
- drop(item);
- mem::forget(guard);
+ let iter = mem::replace(&mut self.iter, (&mut []).iter());
+ let drop_len = iter.len();
+
+ let mut vec = self.vec;
+
+ if mem::size_of::<T>() == 0 {
+ // ZSTs have no identity, so we don't need to move them around, we only need to drop the correct amount.
+ // this can be achieved by manipulating the Vec length instead of moving values out from `iter`.
+ unsafe {
+ let vec = vec.as_mut();
+ let old_len = vec.len();
+ vec.set_len(old_len + drop_len + self.tail_len);
+ vec.truncate(old_len + self.tail_len);
+ }
+
+ return;
}
- // Drop a `DropGuard` to move back the non-drained tail of `self`.
- DropGuard(self);
+ // ensure elements are moved back into their appropriate places, even when drop_in_place panics
+ let _guard = DropGuard(self);
+
+ if drop_len == 0 {
+ return;
+ }
+
+ // as_slice() must only be called when iter.len() is > 0 because
+ // vec::Splice modifies vec::Drain fields and may grow the vec which would invalidate
+ // the iterator's internal pointers. Creating a reference to deallocated memory
+ // is invalid even when it is zero-length
+ let drop_ptr = iter.as_slice().as_ptr();
+
+ unsafe {
+ // drop_ptr comes from a slice::Iter which only gives us a &[T] but for drop_in_place
+ // a pointer with mutable provenance is necessary. Therefore we must reconstruct
+ // it from the original vec but also avoid creating a &mut to the front since that could
+ // invalidate raw pointers to it which some unsafe code might rely on.
+ let vec_ptr = vec.as_mut().as_mut_ptr();
+ let drop_offset = drop_ptr.offset_from(vec_ptr) as usize;
+ let to_drop = ptr::slice_from_raw_parts_mut(vec_ptr.add(drop_offset), drop_len);
+ ptr::drop_in_place(to_drop);
+ }
}
}
diff --git a/library/alloc/src/vec/mod.rs b/library/alloc/src/vec/mod.rs
index 85759917765..d24b4bdffde 100644
--- a/library/alloc/src/vec/mod.rs
+++ b/library/alloc/src/vec/mod.rs
@@ -822,7 +822,7 @@ impl<T, A: Allocator> Vec<T, A> {
///
/// # Panics
///
- /// Panics if the new capacity overflows `usize`.
+ /// Panics if the new capacity exceeds `isize::MAX` bytes.
///
/// # Examples
///
@@ -881,9 +881,9 @@ impl<T, A: Allocator> Vec<T, A> {
///
/// Note that the allocator may give the collection more space than it
/// requests. Therefore, capacity can not be relied upon to be precisely
- /// minimal. Prefer [`reserve`] if future insertions are expected.
+ /// minimal. Prefer [`try_reserve`] if future insertions are expected.
///
- /// [`reserve`]: Vec::reserve
+ /// [`try_reserve`]: Vec::try_reserve
///
/// # Errors
///
@@ -1520,49 +1520,46 @@ impl<T, A: Allocator> Vec<T, A> {
let mut g = BackshiftOnDrop { v: self, processed_len: 0, deleted_cnt: 0, original_len };
- // process_one return a bool indicates whether the processing element should be retained.
- #[inline(always)]
- fn process_one<F, T, A: Allocator, const DELETED: bool>(
+ fn process_loop<F, T, A: Allocator, const DELETED: bool>(
+ original_len: usize,
f: &mut F,
g: &mut BackshiftOnDrop<'_, T, A>,
- ) -> bool
- where
+ ) where
F: FnMut(&mut T) -> bool,
{
- // SAFETY: Unchecked element must be valid.
- let cur = unsafe { &mut *g.v.as_mut_ptr().add(g.processed_len) };
- if !f(cur) {
- // Advance early to avoid double drop if `drop_in_place` panicked.
- g.processed_len += 1;
- g.deleted_cnt += 1;
- // SAFETY: We never touch this element again after dropped.
- unsafe { ptr::drop_in_place(cur) };
- // We already advanced the counter.
- return false;
- }
- if DELETED {
- // SAFETY: `deleted_cnt` > 0, so the hole slot must not overlap with current element.
- // We use copy for move, and never touch this element again.
- unsafe {
- let hole_slot = g.v.as_mut_ptr().add(g.processed_len - g.deleted_cnt);
- ptr::copy_nonoverlapping(cur, hole_slot, 1);
+ while g.processed_len != original_len {
+ // SAFETY: Unchecked element must be valid.
+ let cur = unsafe { &mut *g.v.as_mut_ptr().add(g.processed_len) };
+ if !f(cur) {
+ // Advance early to avoid double drop if `drop_in_place` panicked.
+ g.processed_len += 1;
+ g.deleted_cnt += 1;
+ // SAFETY: We never touch this element again after dropped.
+ unsafe { ptr::drop_in_place(cur) };
+ // We already advanced the counter.
+ if DELETED {
+ continue;
+ } else {
+ break;
+ }
}
+ if DELETED {
+ // SAFETY: `deleted_cnt` > 0, so the hole slot must not overlap with current element.
+ // We use copy for move, and never touch this element again.
+ unsafe {
+ let hole_slot = g.v.as_mut_ptr().add(g.processed_len - g.deleted_cnt);
+ ptr::copy_nonoverlapping(cur, hole_slot, 1);
+ }
+ }
+ g.processed_len += 1;
}
- g.processed_len += 1;
- return true;
}
// Stage 1: Nothing was deleted.
- while g.processed_len != original_len {
- if !process_one::<F, T, A, false>(&mut f, &mut g) {
- break;
- }
- }
+ process_loop::<F, T, A, false>(original_len, &mut f, &mut g);
// Stage 2: Some elements were deleted.
- while g.processed_len != original_len {
- process_one::<F, T, A, true>(&mut f, &mut g);
- }
+ process_loop::<F, T, A, true>(original_len, &mut f, &mut g);
// All item are processed. This can be optimized to `set_len` by LLVM.
drop(g);
@@ -1726,7 +1723,7 @@ impl<T, A: Allocator> Vec<T, A> {
// This will panic or abort if we would allocate > isize::MAX bytes
// or if the length increment would overflow for zero-sized types.
if self.len == self.buf.capacity() {
- self.reserve(1);
+ self.buf.reserve_for_push(self.len);
}
unsafe {
let end = self.as_mut_ptr().add(self.len);
@@ -2199,7 +2196,7 @@ impl<T: Clone, A: Allocator> Vec<T, A> {
/// Clones and appends all elements in a slice to the `Vec`.
///
/// Iterates over the slice `other`, clones each element, and then appends
- /// it to this `Vec`. The `other` vector is traversed in-order.
+ /// it to this `Vec`. The `other` slice is traversed in-order.
///
/// Note that this function is same as [`extend`] except that it is
/// specialized to work with slices instead. If and when Rust gets
diff --git a/library/alloc/tests/boxed.rs b/library/alloc/tests/boxed.rs
index a38b5c471bf..bfe66b2687e 100644
--- a/library/alloc/tests/boxed.rs
+++ b/library/alloc/tests/boxed.rs
@@ -3,7 +3,7 @@ use std::mem::MaybeUninit;
use std::ptr::NonNull;
#[test]
-fn unitialized_zero_size_box() {
+fn uninitialized_zero_size_box() {
assert_eq!(
&*Box::<()>::new_uninit() as *const _,
NonNull::<MaybeUninit<()>>::dangling().as_ptr(),
diff --git a/library/alloc/tests/slice.rs b/library/alloc/tests/slice.rs
index 13b8c059e37..18ea6a21413 100644
--- a/library/alloc/tests/slice.rs
+++ b/library/alloc/tests/slice.rs
@@ -863,7 +863,7 @@ fn test_splitator_inclusive() {
assert_eq!(xs.split_inclusive(|_| true).collect::<Vec<&[i32]>>(), splits);
let xs: &[i32] = &[];
- let splits: &[&[i32]] = &[&[]];
+ let splits: &[&[i32]] = &[];
assert_eq!(xs.split_inclusive(|x| *x == 5).collect::<Vec<&[i32]>>(), splits);
}
@@ -883,7 +883,7 @@ fn test_splitator_inclusive_reverse() {
assert_eq!(xs.split_inclusive(|_| true).rev().collect::<Vec<_>>(), splits);
let xs: &[i32] = &[];
- let splits: &[&[i32]] = &[&[]];
+ let splits: &[&[i32]] = &[];
assert_eq!(xs.split_inclusive(|x| *x == 5).rev().collect::<Vec<_>>(), splits);
}
@@ -903,7 +903,7 @@ fn test_splitator_mut_inclusive() {
assert_eq!(xs.split_inclusive_mut(|_| true).collect::<Vec<_>>(), splits);
let xs: &mut [i32] = &mut [];
- let splits: &[&[i32]] = &[&[]];
+ let splits: &[&[i32]] = &[];
assert_eq!(xs.split_inclusive_mut(|x| *x == 5).collect::<Vec<_>>(), splits);
}
@@ -923,7 +923,7 @@ fn test_splitator_mut_inclusive_reverse() {
assert_eq!(xs.split_inclusive_mut(|_| true).rev().collect::<Vec<_>>(), splits);
let xs: &mut [i32] = &mut [];
- let splits: &[&[i32]] = &[&[]];
+ let splits: &[&[i32]] = &[];
assert_eq!(xs.split_inclusive_mut(|x| *x == 5).rev().collect::<Vec<_>>(), splits);
}
diff --git a/library/alloc/tests/str.rs b/library/alloc/tests/str.rs
index 1b741f174fb..7bd0abbad01 100644
--- a/library/alloc/tests/str.rs
+++ b/library/alloc/tests/str.rs
@@ -162,7 +162,7 @@ fn test_join_for_different_lengths_with_long_separator() {
}
#[test]
-fn test_join_isue_80335() {
+fn test_join_issue_80335() {
use core::{borrow::Borrow, cell::Cell};
struct WeirdBorrow {
diff --git a/library/alloc/tests/vec.rs b/library/alloc/tests/vec.rs
index 00a878c0794..77314282532 100644
--- a/library/alloc/tests/vec.rs
+++ b/library/alloc/tests/vec.rs
@@ -985,6 +985,9 @@ fn test_into_iter_advance_by() {
assert_eq!(i.advance_by(usize::MAX), Err(0));
+ i.advance_by(0).unwrap();
+ i.advance_back_by(0).unwrap();
+
assert_eq!(i.len(), 0);
}
diff --git a/library/core/src/alloc/layout.rs b/library/core/src/alloc/layout.rs
index cc32d5223b4..ea639268652 100644
--- a/library/core/src/alloc/layout.rs
+++ b/library/core/src/alloc/layout.rs
@@ -157,11 +157,11 @@ impl Layout {
///
/// - If `T` is `Sized`, this function is always safe to call.
/// - If the unsized tail of `T` is:
- /// - a [slice], then the length of the slice tail must be an intialized
+ /// - a [slice], then the length of the slice tail must be an initialized
/// integer, and the size of the *entire value*
/// (dynamic tail length + statically sized prefix) must fit in `isize`.
/// - a [trait object], then the vtable part of the pointer must point
- /// to a valid vtable for the type `T` acquired by an unsizing coersion,
+ /// to a valid vtable for the type `T` acquired by an unsizing coercion,
/// and the size of the *entire value*
/// (dynamic tail length + statically sized prefix) must fit in `isize`.
/// - an (unstable) [extern type], then this function is always safe to
@@ -281,7 +281,9 @@ impl Layout {
// > `usize::MAX`)
let new_size = self.size() + pad;
- Layout::from_size_align(new_size, self.align()).unwrap()
+ // SAFETY: self.align is already known to be valid and new_size has been
+ // padded already.
+ unsafe { Layout::from_size_align_unchecked(new_size, self.align()) }
}
/// Creates a layout describing the record for `n` instances of
@@ -403,9 +405,17 @@ impl Layout {
#[stable(feature = "alloc_layout_manipulation", since = "1.44.0")]
#[inline]
pub fn array<T>(n: usize) -> Result<Self, LayoutError> {
- let (layout, offset) = Layout::new::<T>().repeat(n)?;
- debug_assert_eq!(offset, mem::size_of::<T>());
- Ok(layout.pad_to_align())
+ let array_size = mem::size_of::<T>().checked_mul(n).ok_or(LayoutError)?;
+
+ // SAFETY:
+ // - Size: `array_size` cannot be too big because `size_of::<T>()` must
+ // be a multiple of `align_of::<T>()`. Therefore, `array_size`
+ // rounded up to the nearest multiple of `align_of::<T>()` is just
+ // `array_size`. And `array_size` cannot be too big because it was
+ // just checked by the `checked_mul()`.
+ // - Alignment: `align_of::<T>()` will always give an acceptable
+ // (non-zero, power of two) alignment.
+ Ok(unsafe { Layout::from_size_align_unchecked(array_size, mem::align_of::<T>()) })
}
}
diff --git a/library/core/src/any.rs b/library/core/src/any.rs
index 1fd5aa27fce..72528185707 100644
--- a/library/core/src/any.rs
+++ b/library/core/src/any.rs
@@ -164,7 +164,7 @@ impl fmt::Debug for dyn Any + Send + Sync {
}
impl dyn Any {
- /// Returns `true` if the boxed type is the same as `T`.
+ /// Returns `true` if the inner type is the same as `T`.
///
/// # Examples
///
@@ -195,7 +195,7 @@ impl dyn Any {
t == concrete
}
- /// Returns some reference to the boxed value if it is of type `T`, or
+ /// Returns some reference to the inner value if it is of type `T`, or
/// `None` if it isn't.
///
/// # Examples
@@ -221,13 +221,13 @@ impl dyn Any {
// SAFETY: just checked whether we are pointing to the correct type, and we can rely on
// that check for memory safety because we have implemented Any for all types; no other
// impls can exist as they would conflict with our impl.
- unsafe { Some(&*(self as *const dyn Any as *const T)) }
+ unsafe { Some(self.downcast_ref_unchecked()) }
} else {
None
}
}
- /// Returns some mutable reference to the boxed value if it is of type `T`, or
+ /// Returns some mutable reference to the inner value if it is of type `T`, or
/// `None` if it isn't.
///
/// # Examples
@@ -257,15 +257,73 @@ impl dyn Any {
// SAFETY: just checked whether we are pointing to the correct type, and we can rely on
// that check for memory safety because we have implemented Any for all types; no other
// impls can exist as they would conflict with our impl.
- unsafe { Some(&mut *(self as *mut dyn Any as *mut T)) }
+ unsafe { Some(self.downcast_mut_unchecked()) }
} else {
None
}
}
+
+ /// Returns a reference to the inner value as type `dyn T`.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// #![feature(downcast_unchecked)]
+ ///
+ /// use std::any::Any;
+ ///
+ /// let x: Box<dyn Any> = Box::new(1_usize);
+ ///
+ /// unsafe {
+ /// assert_eq!(*x.downcast_ref_unchecked::<usize>(), 1);
+ /// }
+ /// ```
+ ///
+ /// # Safety
+ ///
+ /// The contained value must be of type `T`. Calling this method
+ /// with the incorrect type is *undefined behavior*.
+ #[unstable(feature = "downcast_unchecked", issue = "90850")]
+ #[inline]
+ pub unsafe fn downcast_ref_unchecked<T: Any>(&self) -> &T {
+ debug_assert!(self.is::<T>());
+ // SAFETY: caller guarantees that T is the correct type
+ unsafe { &*(self as *const dyn Any as *const T) }
+ }
+
+ /// Returns a mutable reference to the inner value as type `dyn T`.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// #![feature(downcast_unchecked)]
+ ///
+ /// use std::any::Any;
+ ///
+ /// let mut x: Box<dyn Any> = Box::new(1_usize);
+ ///
+ /// unsafe {
+ /// *x.downcast_mut_unchecked::<usize>() += 1;
+ /// }
+ ///
+ /// assert_eq!(*x.downcast_ref::<usize>().unwrap(), 2);
+ /// ```
+ ///
+ /// # Safety
+ ///
+ /// The contained value must be of type `T`. Calling this method
+ /// with the incorrect type is *undefined behavior*.
+ #[unstable(feature = "downcast_unchecked", issue = "90850")]
+ #[inline]
+ pub unsafe fn downcast_mut_unchecked<T: Any>(&mut self) -> &mut T {
+ debug_assert!(self.is::<T>());
+ // SAFETY: caller guarantees that T is the correct type
+ unsafe { &mut *(self as *mut dyn Any as *mut T) }
+ }
}
impl dyn Any + Send {
- /// Forwards to the method defined on the type `Any`.
+ /// Forwards to the method defined on the type `dyn Any`.
///
/// # Examples
///
@@ -289,7 +347,7 @@ impl dyn Any + Send {
<dyn Any>::is::<T>(self)
}
- /// Forwards to the method defined on the type `Any`.
+ /// Forwards to the method defined on the type `dyn Any`.
///
/// # Examples
///
@@ -313,7 +371,7 @@ impl dyn Any + Send {
<dyn Any>::downcast_ref::<T>(self)
}
- /// Forwards to the method defined on the type `Any`.
+ /// Forwards to the method defined on the type `dyn Any`.
///
/// # Examples
///
@@ -340,6 +398,60 @@ impl dyn Any + Send {
pub fn downcast_mut<T: Any>(&mut self) -> Option<&mut T> {
<dyn Any>::downcast_mut::<T>(self)
}
+
+ /// Forwards to the method defined on the type `dyn Any`.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// #![feature(downcast_unchecked)]
+ ///
+ /// use std::any::Any;
+ ///
+ /// let x: Box<dyn Any> = Box::new(1_usize);
+ ///
+ /// unsafe {
+ /// assert_eq!(*x.downcast_ref_unchecked::<usize>(), 1);
+ /// }
+ /// ```
+ ///
+ /// # Safety
+ ///
+ /// Same as the method on the type `dyn Any`.
+ #[unstable(feature = "downcast_unchecked", issue = "90850")]
+ #[inline]
+ pub unsafe fn downcast_ref_unchecked<T: Any>(&self) -> &T {
+ // SAFETY: guaranteed by caller
+ unsafe { <dyn Any>::downcast_ref_unchecked::<T>(self) }
+ }
+
+ /// Forwards to the method defined on the type `dyn Any`.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// #![feature(downcast_unchecked)]
+ ///
+ /// use std::any::Any;
+ ///
+ /// let mut x: Box<dyn Any> = Box::new(1_usize);
+ ///
+ /// unsafe {
+ /// *x.downcast_mut_unchecked::<usize>() += 1;
+ /// }
+ ///
+ /// assert_eq!(*x.downcast_ref::<usize>().unwrap(), 2);
+ /// ```
+ ///
+ /// # Safety
+ ///
+ /// Same as the method on the type `dyn Any`.
+ #[unstable(feature = "downcast_unchecked", issue = "90850")]
+ #[inline]
+ pub unsafe fn downcast_mut_unchecked<T: Any>(&mut self) -> &mut T {
+ // SAFETY: guaranteed by caller
+ unsafe { <dyn Any>::downcast_mut_unchecked::<T>(self) }
+ }
}
impl dyn Any + Send + Sync {
@@ -418,6 +530,52 @@ impl dyn Any + Send + Sync {
pub fn downcast_mut<T: Any>(&mut self) -> Option<&mut T> {
<dyn Any>::downcast_mut::<T>(self)
}
+
+ /// Forwards to the method defined on the type `Any`.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// #![feature(downcast_unchecked)]
+ ///
+ /// use std::any::Any;
+ ///
+ /// let x: Box<dyn Any> = Box::new(1_usize);
+ ///
+ /// unsafe {
+ /// assert_eq!(*x.downcast_ref_unchecked::<usize>(), 1);
+ /// }
+ /// ```
+ #[unstable(feature = "downcast_unchecked", issue = "90850")]
+ #[inline]
+ pub unsafe fn downcast_ref_unchecked<T: Any>(&self) -> &T {
+ // SAFETY: guaranteed by caller
+ unsafe { <dyn Any>::downcast_ref_unchecked::<T>(self) }
+ }
+
+ /// Forwards to the method defined on the type `Any`.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// #![feature(downcast_unchecked)]
+ ///
+ /// use std::any::Any;
+ ///
+ /// let mut x: Box<dyn Any> = Box::new(1_usize);
+ ///
+ /// unsafe {
+ /// *x.downcast_mut_unchecked::<usize>() += 1;
+ /// }
+ ///
+ /// assert_eq!(*x.downcast_ref::<usize>().unwrap(), 2);
+ /// ```
+ #[unstable(feature = "downcast_unchecked", issue = "90850")]
+ #[inline]
+ pub unsafe fn downcast_mut_unchecked<T: Any>(&mut self) -> &mut T {
+ // SAFETY: guaranteed by caller
+ unsafe { <dyn Any>::downcast_mut_unchecked::<T>(self) }
+ }
}
///////////////////////////////////////////////////////////////////////////////
diff --git a/library/core/src/array/equality.rs b/library/core/src/array/equality.rs
index a882d18b151..33f7f494e9d 100644
--- a/library/core/src/array/equality.rs
+++ b/library/core/src/array/equality.rs
@@ -1,3 +1,7 @@
+use crate::convert::TryInto;
+use crate::num::{NonZeroI128, NonZeroI16, NonZeroI32, NonZeroI64, NonZeroI8, NonZeroIsize};
+use crate::num::{NonZeroU128, NonZeroU16, NonZeroU32, NonZeroU64, NonZeroU8, NonZeroUsize};
+
#[stable(feature = "rust1", since = "1.0.0")]
impl<A, B, const N: usize> PartialEq<[B; N]> for [A; N]
where
@@ -20,11 +24,19 @@ where
{
#[inline]
fn eq(&self, other: &[B]) -> bool {
- self[..] == other[..]
+ let b: Result<&[B; N], _> = other.try_into();
+ match b {
+ Ok(b) => *self == *b,
+ Err(_) => false,
+ }
}
#[inline]
fn ne(&self, other: &[B]) -> bool {
- self[..] != other[..]
+ let b: Result<&[B; N], _> = other.try_into();
+ match b {
+ Ok(b) => *self != *b,
+ Err(_) => true,
+ }
}
}
@@ -35,11 +47,19 @@ where
{
#[inline]
fn eq(&self, other: &[A; N]) -> bool {
- self[..] == other[..]
+ let b: Result<&[B; N], _> = self.try_into();
+ match b {
+ Ok(b) => *b == *other,
+ Err(_) => false,
+ }
}
#[inline]
fn ne(&self, other: &[A; N]) -> bool {
- self[..] != other[..]
+ let b: Result<&[B; N], _> = self.try_into();
+ match b {
+ Ok(b) => *b != *other,
+ Err(_) => true,
+ }
}
}
@@ -50,11 +70,11 @@ where
{
#[inline]
fn eq(&self, other: &&[B]) -> bool {
- self[..] == other[..]
+ *self == **other
}
#[inline]
fn ne(&self, other: &&[B]) -> bool {
- self[..] != other[..]
+ *self != **other
}
}
@@ -65,11 +85,11 @@ where
{
#[inline]
fn eq(&self, other: &[A; N]) -> bool {
- self[..] == other[..]
+ **self == *other
}
#[inline]
fn ne(&self, other: &[A; N]) -> bool {
- self[..] != other[..]
+ **self != *other
}
}
@@ -80,11 +100,11 @@ where
{
#[inline]
fn eq(&self, other: &&mut [B]) -> bool {
- self[..] == other[..]
+ *self == **other
}
#[inline]
fn ne(&self, other: &&mut [B]) -> bool {
- self[..] != other[..]
+ *self != **other
}
}
@@ -95,11 +115,11 @@ where
{
#[inline]
fn eq(&self, other: &[A; N]) -> bool {
- self[..] == other[..]
+ **self == *other
}
#[inline]
fn ne(&self, other: &[A; N]) -> bool {
- self[..] != other[..]
+ **self != *other
}
}
@@ -124,7 +144,7 @@ impl<T: PartialEq<Other>, Other, const N: usize> SpecArrayEq<Other, N> for T {
}
}
-impl<T: PartialEq<U> + IsRawEqComparable<U>, U, const N: usize> SpecArrayEq<U, N> for T {
+impl<T: IsRawEqComparable<U>, U, const N: usize> SpecArrayEq<U, N> for T {
fn spec_eq(a: &[T; N], b: &[U; N]) -> bool {
// SAFETY: This is why `IsRawEqComparable` is an `unsafe trait`.
unsafe {
@@ -145,11 +165,52 @@ impl<T: PartialEq<U> + IsRawEqComparable<U>, U, const N: usize> SpecArrayEq<U, N
/// - `Self` and `U` have the same layout.
/// - `Self: PartialEq<U>` is byte-wise (this means no floats, among other things)
#[rustc_specialization_trait]
-unsafe trait IsRawEqComparable<U> {}
+unsafe trait IsRawEqComparable<U>: PartialEq<U> {}
-macro_rules! is_raw_comparable {
- ($($t:ty),+) => {$(
+macro_rules! is_raw_eq_comparable {
+ ($($t:ty),+ $(,)?) => {$(
unsafe impl IsRawEqComparable<$t> for $t {}
)+};
}
-is_raw_comparable!(bool, char, u8, u16, u32, u64, u128, usize, i8, i16, i32, i64, i128, isize);
+
+// SAFETY: All the ordinary integer types allow all bit patterns as distinct values
+is_raw_eq_comparable!(u8, u16, u32, u64, u128, usize, i8, i16, i32, i64, i128, isize);
+
+// SAFETY: bool and char have *niches*, but no *padding*, so this is sound
+is_raw_eq_comparable!(bool, char);
+
+// SAFETY: Similarly, the non-zero types have a niche, but no undef,
+// and they compare like their underlying numeric type.
+is_raw_eq_comparable!(
+ NonZeroU8,
+ NonZeroU16,
+ NonZeroU32,
+ NonZeroU64,
+ NonZeroU128,
+ NonZeroUsize,
+ NonZeroI8,
+ NonZeroI16,
+ NonZeroI32,
+ NonZeroI64,
+ NonZeroI128,
+ NonZeroIsize,
+);
+
+// SAFETY: The NonZero types have the "null" optimization guaranteed, and thus
+// are also safe to equality-compare bitwise inside an `Option`.
+// The way `PartialOrd` is defined for `Option` means that this wouldn't work
+// for `<` or `>` on the signed types, but since we only do `==` it's fine.
+is_raw_eq_comparable!(
+ Option<NonZeroU8>,
+ Option<NonZeroU16>,
+ Option<NonZeroU32>,
+ Option<NonZeroU64>,
+ Option<NonZeroU128>,
+ Option<NonZeroUsize>,
+ Option<NonZeroI8>,
+ Option<NonZeroI16>,
+ Option<NonZeroI32>,
+ Option<NonZeroI64>,
+ Option<NonZeroI128>,
+ Option<NonZeroIsize>,
+);
diff --git a/library/core/src/array/iter.rs b/library/core/src/array/iter.rs
index 5d63cf03fcb..72a634443e8 100644
--- a/library/core/src/array/iter.rs
+++ b/library/core/src/array/iter.rs
@@ -1,7 +1,7 @@
//! Defines the `IntoIter` owned iterator for arrays.
use crate::{
- fmt,
+ cmp, fmt,
iter::{self, ExactSizeIterator, FusedIterator, TrustedLen},
mem::{self, MaybeUninit},
ops::Range,
@@ -34,30 +34,23 @@ pub struct IntoIter<T, const N: usize> {
alive: Range<usize>,
}
-impl<T, const N: usize> IntoIter<T, N> {
- /// Creates a new iterator over the given `array`.
- ///
- /// *Note*: this method might be deprecated in the future,
- /// since [`IntoIterator`] is now implemented for arrays.
- ///
- /// # Examples
- ///
- /// ```
- /// use std::array;
+// Note: the `#[rustc_skip_array_during_method_dispatch]` on `trait IntoIterator`
+// hides this implementation from explicit `.into_iter()` calls on editions < 2021,
+// so those calls will still resolve to the slice implementation, by reference.
+#[stable(feature = "array_into_iter_impl", since = "1.53.0")]
+impl<T, const N: usize> IntoIterator for [T; N] {
+ type Item = T;
+ type IntoIter = IntoIter<T, N>;
+
+ /// Creates a consuming iterator, that is, one that moves each value out of
+ /// the array (from start to end). The array cannot be used after calling
+ /// this unless `T` implements `Copy`, so the whole array is copied.
///
- /// for value in array::IntoIter::new([1, 2, 3, 4, 5]) {
- /// // The type of `value` is an `i32` here, instead of `&i32`
- /// let _: i32 = value;
- /// }
+ /// Arrays have special behavior when calling `.into_iter()` prior to the
+ /// 2021 edition -- see the [array] Editions section for more information.
///
- /// // Since Rust 1.53, arrays implement IntoIterator directly:
- /// for value in [1, 2, 3, 4, 5] {
- /// // The type of `value` is an `i32` here, instead of `&i32`
- /// let _: i32 = value;
- /// }
- /// ```
- #[stable(feature = "array_value_iter", since = "1.51.0")]
- pub fn new(array: [T; N]) -> Self {
+ /// [array]: prim@array
+ fn into_iter(self) -> Self::IntoIter {
// SAFETY: The transmute here is actually safe. The docs of `MaybeUninit`
// promise:
//
@@ -76,11 +69,149 @@ impl<T, const N: usize> IntoIter<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);
+ let iter = IntoIter { data: mem::transmute_copy(&self), alive: 0..N };
+ mem::forget(self);
iter
}
}
+}
+
+impl<T, const N: usize> IntoIter<T, N> {
+ /// Creates a new iterator over the given `array`.
+ #[stable(feature = "array_value_iter", since = "1.51.0")]
+ #[rustc_deprecated(since = "1.59.0", reason = "use `IntoIterator::into_iter` instead")]
+ pub fn new(array: [T; N]) -> Self {
+ IntoIterator::into_iter(array)
+ }
+
+ /// Creates an iterator over the elements in a partially-initialized buffer.
+ ///
+ /// If you have a fully-initialized array, then use [`IntoIterator`].
+ /// But this is useful for returning partial results from unsafe code.
+ ///
+ /// # Safety
+ ///
+ /// - The `buffer[initialized]` elements must all be initialized.
+ /// - The range must be canonical, with `initialized.start <= initialized.end`.
+ /// - The range must in in-bounds for the buffer, with `initialized.end <= N`.
+ /// (Like how indexing `[0][100..100]` fails despite the range being empty.)
+ ///
+ /// It's sound to have more elements initialized than mentioned, though that
+ /// will most likely result in them being leaked.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// #![feature(array_into_iter_constructors)]
+ ///
+ /// #![feature(maybe_uninit_array_assume_init)]
+ /// #![feature(maybe_uninit_uninit_array)]
+ /// use std::array::IntoIter;
+ /// use std::mem::MaybeUninit;
+ ///
+ /// # // Hi! Thanks for reading the code. This is restricted to `Copy` because
+ /// # // otherwise it could leak. A fully-general version this would need a drop
+ /// # // guard to handle panics from the iterator, but this works for an example.
+ /// fn next_chunk<T: Copy, const N: usize>(
+ /// it: &mut impl Iterator<Item = T>,
+ /// ) -> Result<[T; N], IntoIter<T, N>> {
+ /// let mut buffer = MaybeUninit::uninit_array();
+ /// let mut i = 0;
+ /// while i < N {
+ /// match it.next() {
+ /// Some(x) => {
+ /// buffer[i].write(x);
+ /// i += 1;
+ /// }
+ /// None => {
+ /// // SAFETY: We've initialized the first `i` items
+ /// unsafe {
+ /// return Err(IntoIter::new_unchecked(buffer, 0..i));
+ /// }
+ /// }
+ /// }
+ /// }
+ ///
+ /// // SAFETY: We've initialized all N items
+ /// unsafe { Ok(MaybeUninit::array_assume_init(buffer)) }
+ /// }
+ ///
+ /// let r: [_; 4] = next_chunk(&mut (10..16)).unwrap();
+ /// assert_eq!(r, [10, 11, 12, 13]);
+ /// let r: IntoIter<_, 40> = next_chunk(&mut (10..16)).unwrap_err();
+ /// assert_eq!(r.collect::<Vec<_>>(), vec![10, 11, 12, 13, 14, 15]);
+ /// ```
+ #[unstable(feature = "array_into_iter_constructors", issue = "91583")]
+ #[rustc_const_unstable(feature = "const_array_into_iter_constructors", issue = "91583")]
+ pub const unsafe fn new_unchecked(
+ buffer: [MaybeUninit<T>; N],
+ initialized: Range<usize>,
+ ) -> Self {
+ Self { data: buffer, alive: initialized }
+ }
+
+ /// Creates an iterator over `T` which returns no elements.
+ ///
+ /// If you just need an empty iterator, then use
+ /// [`iter::empty()`](crate::iter::empty) instead.
+ /// And if you need an empty array, use `[]`.
+ ///
+ /// But this is useful when you need an `array::IntoIter<T, N>` *specifically*.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// #![feature(array_into_iter_constructors)]
+ /// use std::array::IntoIter;
+ ///
+ /// let empty = IntoIter::<i32, 3>::empty();
+ /// assert_eq!(empty.len(), 0);
+ /// assert_eq!(empty.as_slice(), &[]);
+ ///
+ /// let empty = IntoIter::<std::convert::Infallible, 200>::empty();
+ /// assert_eq!(empty.len(), 0);
+ /// ```
+ ///
+ /// `[1, 2].into_iter()` and `[].into_iter()` have different types
+ /// ```should_fail,edition2021
+ /// #![feature(array_into_iter_constructors)]
+ /// use std::array::IntoIter;
+ ///
+ /// pub fn get_bytes(b: bool) -> IntoIter<i8, 4> {
+ /// if b {
+ /// [1, 2, 3, 4].into_iter()
+ /// } else {
+ /// [].into_iter() // error[E0308]: mismatched types
+ /// }
+ /// }
+ /// ```
+ ///
+ /// But using this method you can get an empty iterator of appropriate size:
+ /// ```edition2021
+ /// #![feature(array_into_iter_constructors)]
+ /// use std::array::IntoIter;
+ ///
+ /// pub fn get_bytes(b: bool) -> IntoIter<i8, 4> {
+ /// if b {
+ /// [1, 2, 3, 4].into_iter()
+ /// } else {
+ /// IntoIter::empty()
+ /// }
+ /// }
+ ///
+ /// assert_eq!(get_bytes(true).collect::<Vec<_>>(), vec![1, 2, 3, 4]);
+ /// assert_eq!(get_bytes(false).collect::<Vec<_>>(), vec![]);
+ /// ```
+ #[unstable(feature = "array_into_iter_constructors", issue = "91583")]
+ #[rustc_const_unstable(feature = "const_array_into_iter_constructors", issue = "91583")]
+ pub const fn empty() -> Self {
+ let buffer = MaybeUninit::uninit_array();
+ let initialized = 0..0;
+
+ // SAFETY: We're telling it that none of the elements are initialized,
+ // which is trivially true. And ∀N: usize, 0 <= N.
+ unsafe { Self::new_unchecked(buffer, initialized) }
+ }
/// Returns an immutable slice of all elements that have not been yielded
/// yet.
@@ -150,6 +281,27 @@ impl<T, const N: usize> Iterator for IntoIter<T, N> {
fn last(mut self) -> Option<Self::Item> {
self.next_back()
}
+
+ fn advance_by(&mut self, n: usize) -> Result<(), usize> {
+ let len = self.len();
+
+ // The number of elements to drop. Always in-bounds by construction.
+ let delta = cmp::min(n, len);
+
+ let range_to_drop = self.alive.start..(self.alive.start + delta);
+
+ // Moving the start marks them as conceptually "dropped", so if anything
+ // goes bad then our drop impl won't double-free them.
+ self.alive.start += delta;
+
+ // SAFETY: These elements are currently initialized, so it's fine to drop them.
+ unsafe {
+ let slice = self.data.get_unchecked_mut(range_to_drop);
+ ptr::drop_in_place(MaybeUninit::slice_assume_init_mut(slice));
+ }
+
+ if n > len { Err(len) } else { Ok(()) }
+ }
}
#[stable(feature = "array_value_iter_impls", since = "1.40.0")]
@@ -170,6 +322,27 @@ impl<T, const N: usize> DoubleEndedIterator for IntoIter<T, N> {
unsafe { self.data.get_unchecked(idx).assume_init_read() }
})
}
+
+ fn advance_back_by(&mut self, n: usize) -> Result<(), usize> {
+ let len = self.len();
+
+ // The number of elements to drop. Always in-bounds by construction.
+ let delta = cmp::min(n, len);
+
+ let range_to_drop = (self.alive.end - delta)..self.alive.end;
+
+ // Moving the end marks them as conceptually "dropped", so if anything
+ // goes bad then our drop impl won't double-free them.
+ self.alive.end -= delta;
+
+ // SAFETY: These elements are currently initialized, so it's fine to drop them.
+ unsafe {
+ let slice = self.data.get_unchecked_mut(range_to_drop);
+ ptr::drop_in_place(MaybeUninit::slice_assume_init_mut(slice));
+ }
+
+ if n > len { Err(len) } else { Ok(()) }
+ }
}
#[stable(feature = "array_value_iter_impls", since = "1.40.0")]
diff --git a/library/core/src/array/mod.rs b/library/core/src/array/mod.rs
index 09bb4519170..37292bf8e26 100644
--- a/library/core/src/array/mod.rs
+++ b/library/core/src/array/mod.rs
@@ -11,7 +11,9 @@ use crate::fmt;
use crate::hash::{self, Hash};
use crate::iter::TrustedLen;
use crate::mem::{self, MaybeUninit};
-use crate::ops::{Index, IndexMut};
+use crate::ops::{
+ ChangeOutputType, ControlFlow, FromResidual, Index, IndexMut, NeverShortCircuit, Residual, Try,
+};
use crate::slice::{Iter, IterMut};
mod equality;
@@ -49,9 +51,13 @@ where
}
/// Creates an array `[T; N]` where each fallible array element `T` is returned by the `cb` call.
-/// Unlike `core::array::from_fn`, where the element creation can't fail, this version will return an error
+/// Unlike [`from_fn`], where the element creation can't fail, this version will return an error
/// if any element creation was unsuccessful.
///
+/// The return type of this function depends on the return type of the closure.
+/// If you return `Result<T, E>` from the closure, you'll get a `Result<[T; N]; E>`.
+/// If you return `Option<T>` from the closure, you'll get an `Option<[T; N]>`.
+///
/// # Arguments
///
/// * `cb`: Callback where the passed argument is the current array index.
@@ -60,27 +66,32 @@ where
///
/// ```rust
/// #![feature(array_from_fn)]
+/// # // Apparently these doc tests are still on edition2018
+/// # use std::convert::TryInto;
///
-/// #[derive(Debug, PartialEq)]
-/// enum SomeError {
-/// Foo,
-/// }
-///
-/// let array = core::array::try_from_fn(|i| Ok::<_, SomeError>(i));
+/// let array: Result<[u8; 5], _> = std::array::try_from_fn(|i| i.try_into());
/// assert_eq!(array, Ok([0, 1, 2, 3, 4]));
///
-/// let another_array = core::array::try_from_fn::<SomeError, _, (), 2>(|_| Err(SomeError::Foo));
-/// assert_eq!(another_array, Err(SomeError::Foo));
+/// let array: Result<[i8; 200], _> = std::array::try_from_fn(|i| i.try_into());
+/// assert!(array.is_err());
+///
+/// let array: Option<[_; 4]> = std::array::try_from_fn(|i| i.checked_add(100));
+/// assert_eq!(array, Some([100, 101, 102, 103]));
+///
+/// let array: Option<[_; 4]> = std::array::try_from_fn(|i| i.checked_sub(100));
+/// assert_eq!(array, None);
/// ```
#[inline]
#[unstable(feature = "array_from_fn", issue = "89379")]
-pub fn try_from_fn<E, F, T, const N: usize>(cb: F) -> Result<[T; N], E>
+pub fn try_from_fn<F, R, const N: usize>(cb: F) -> ChangeOutputType<R, [R::Output; N]>
where
- F: FnMut(usize) -> Result<T, E>,
+ F: FnMut(usize) -> R,
+ R: Try,
+ R::Residual: Residual<[R::Output; N]>,
{
// SAFETY: we know for certain that this iterator will yield exactly `N`
// items.
- unsafe { collect_into_array_rslt_unchecked(&mut (0..N).map(cb)) }
+ unsafe { try_collect_into_array_unchecked(&mut (0..N).map(cb)) }
}
/// Converts a reference to `T` into a reference to an array of length 1 (without copying).
@@ -151,14 +162,16 @@ impl<T, const N: usize> AsMut<[T]> for [T; N] {
}
#[stable(feature = "array_borrow", since = "1.4.0")]
-impl<T, const N: usize> Borrow<[T]> for [T; N] {
+#[rustc_const_unstable(feature = "const_borrow", issue = "91522")]
+impl<T, const N: usize> const Borrow<[T]> for [T; N] {
fn borrow(&self) -> &[T] {
self
}
}
#[stable(feature = "array_borrow", since = "1.4.0")]
-impl<T, const N: usize> BorrowMut<[T]> for [T; N] {
+#[rustc_const_unstable(feature = "const_borrow", issue = "91522")]
+impl<T, const N: usize> const BorrowMut<[T]> for [T; N] {
fn borrow_mut(&mut self) -> &mut [T] {
self
}
@@ -176,6 +189,18 @@ where
}
}
+#[stable(feature = "try_from_mut_slice_to_array", since = "1.59.0")]
+impl<T, const N: usize> TryFrom<&mut [T]> for [T; N]
+where
+ T: Copy,
+{
+ type Error = TryFromSliceError;
+
+ fn try_from(slice: &mut [T]) -> Result<[T; N], TryFromSliceError> {
+ <Self>::try_from(&*slice)
+ }
+}
+
#[stable(feature = "try_from", since = "1.34.0")]
impl<'a, T, const N: usize> TryFrom<&'a [T]> for &'a [T; N] {
type Error = TryFromSliceError;
@@ -232,27 +257,6 @@ impl<T: fmt::Debug, const N: usize> fmt::Debug for [T; N] {
}
}
-// Note: the `#[rustc_skip_array_during_method_dispatch]` on `trait IntoIterator`
-// hides this implementation from explicit `.into_iter()` calls on editions < 2021,
-// so those calls will still resolve to the slice implementation, by reference.
-#[stable(feature = "array_into_iter_impl", since = "1.53.0")]
-impl<T, const N: usize> IntoIterator for [T; N] {
- type Item = T;
- type IntoIter = IntoIter<T, N>;
-
- /// Creates a consuming iterator, that is, one that moves each value out of
- /// the array (from start to end). The array cannot be used after calling
- /// this unless `T` implements `Copy`, so the whole array is copied.
- ///
- /// Arrays have special behavior when calling `.into_iter()` prior to the
- /// 2021 edition -- see the [array] Editions section for more information.
- ///
- /// [array]: prim@array
- fn into_iter(self) -> Self::IntoIter {
- IntoIter::new(self)
- }
-}
-
#[stable(feature = "rust1", since = "1.0.0")]
impl<'a, T, const N: usize> IntoIterator for &'a [T; N] {
type Item = &'a T;
@@ -330,11 +334,9 @@ impl<T: Ord, const N: usize> Ord for [T; N] {
}
}
-#[cfg(not(bootstrap))]
#[stable(feature = "copy_clone_array_lib", since = "1.58.0")]
impl<T: Copy, const N: usize> Copy for [T; N] {}
-#[cfg(not(bootstrap))]
#[stable(feature = "copy_clone_array_lib", since = "1.58.0")]
impl<T: Clone, const N: usize> Clone for [T; N] {
#[inline]
@@ -348,12 +350,10 @@ impl<T: Clone, const N: usize> Clone for [T; N] {
}
}
-#[cfg(not(bootstrap))]
trait SpecArrayClone: Clone {
fn clone<const N: usize>(array: &[Self; N]) -> [Self; N];
}
-#[cfg(not(bootstrap))]
impl<T: Clone> SpecArrayClone for T {
#[inline]
default fn clone<const N: usize>(array: &[T; N]) -> [T; N] {
@@ -363,7 +363,6 @@ impl<T: Clone> SpecArrayClone for T {
}
}
-#[cfg(not(bootstrap))]
impl<T: Copy> SpecArrayClone for T {
#[inline]
fn clone<const N: usize>(array: &[T; N]) -> [T; N] {
@@ -449,6 +448,45 @@ impl<T, const N: usize> [T; N] {
unsafe { collect_into_array_unchecked(&mut IntoIterator::into_iter(self).map(f)) }
}
+ /// A fallible function `f` applied to each element on array `self` in order to
+ /// return an array the same size as `self` or the first error encountered.
+ ///
+ /// The return type of this function depends on the return type of the closure.
+ /// If you return `Result<T, E>` from the closure, you'll get a `Result<[T; N]; E>`.
+ /// If you return `Option<T>` from the closure, you'll get an `Option<[T; N]>`.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// #![feature(array_try_map)]
+ /// let a = ["1", "2", "3"];
+ /// let b = a.try_map(|v| v.parse::<u32>()).unwrap().map(|v| v + 1);
+ /// assert_eq!(b, [2, 3, 4]);
+ ///
+ /// let a = ["1", "2a", "3"];
+ /// let b = a.try_map(|v| v.parse::<u32>());
+ /// assert!(b.is_err());
+ ///
+ /// use std::num::NonZeroU32;
+ /// let z = [1, 2, 0, 3, 4];
+ /// assert_eq!(z.try_map(NonZeroU32::new), None);
+ /// let a = [1, 2, 3];
+ /// let b = a.try_map(NonZeroU32::new);
+ /// let c = b.map(|x| x.map(NonZeroU32::get));
+ /// assert_eq!(c, Some(a));
+ /// ```
+ #[unstable(feature = "array_try_map", issue = "79711")]
+ pub fn try_map<F, R>(self, f: F) -> ChangeOutputType<R, [R::Output; N]>
+ where
+ F: FnMut(T) -> R,
+ R: Try,
+ R::Residual: Residual<[R::Output; N]>,
+ {
+ // SAFETY: we know for certain that this iterator will yield exactly `N`
+ // items.
+ unsafe { try_collect_into_array_unchecked(&mut IntoIterator::into_iter(self).map(f)) }
+ }
+
/// 'Zips up' two arrays into a single array of pairs.
///
/// `zip()` returns a new array where every element is a tuple where the
@@ -621,47 +659,125 @@ impl<T, const N: usize> [T; N] {
pub fn split_array_mut<const M: usize>(&mut self) -> (&mut [T; M], &mut [T]) {
(&mut self[..]).split_array_mut::<M>()
}
+
+ /// Divides one array reference into two at an index from the end.
+ ///
+ /// The first will contain all indices from `[0, N - M)` (excluding
+ /// the index `N - M` itself) and the second will contain all
+ /// indices from `[N - M, N)` (excluding the index `N` itself).
+ ///
+ /// # Panics
+ ///
+ /// Panics if `M > N`.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// #![feature(split_array)]
+ ///
+ /// let v = [1, 2, 3, 4, 5, 6];
+ ///
+ /// {
+ /// let (left, right) = v.rsplit_array_ref::<0>();
+ /// assert_eq!(left, &[1, 2, 3, 4, 5, 6]);
+ /// assert_eq!(right, &[]);
+ /// }
+ ///
+ /// {
+ /// let (left, right) = v.rsplit_array_ref::<2>();
+ /// assert_eq!(left, &[1, 2, 3, 4]);
+ /// assert_eq!(right, &[5, 6]);
+ /// }
+ ///
+ /// {
+ /// let (left, right) = v.rsplit_array_ref::<6>();
+ /// assert_eq!(left, &[]);
+ /// assert_eq!(right, &[1, 2, 3, 4, 5, 6]);
+ /// }
+ /// ```
+ #[unstable(
+ feature = "split_array",
+ reason = "return type should have array as 2nd element",
+ issue = "90091"
+ )]
+ #[inline]
+ pub fn rsplit_array_ref<const M: usize>(&self) -> (&[T], &[T; M]) {
+ (&self[..]).rsplit_array_ref::<M>()
+ }
+
+ /// Divides one mutable array reference into two at an index from the end.
+ ///
+ /// The first will contain all indices from `[0, N - M)` (excluding
+ /// the index `N - M` itself) and the second will contain all
+ /// indices from `[N - M, N)` (excluding the index `N` itself).
+ ///
+ /// # Panics
+ ///
+ /// Panics if `M > N`.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// #![feature(split_array)]
+ ///
+ /// let mut v = [1, 0, 3, 0, 5, 6];
+ /// let (left, right) = v.rsplit_array_mut::<4>();
+ /// assert_eq!(left, &mut [1, 0]);
+ /// assert_eq!(right, &mut [3, 0, 5, 6][..]);
+ /// left[1] = 2;
+ /// right[1] = 4;
+ /// assert_eq!(v, [1, 2, 3, 4, 5, 6]);
+ /// ```
+ #[unstable(
+ feature = "split_array",
+ reason = "return type should have array as 2nd element",
+ issue = "90091"
+ )]
+ #[inline]
+ pub fn rsplit_array_mut<const M: usize>(&mut self) -> (&mut [T], &mut [T; M]) {
+ (&mut self[..]).rsplit_array_mut::<M>()
+ }
}
/// Pulls `N` items from `iter` and returns them as an array. If the iterator
/// yields fewer than `N` items, this function exhibits undefined behavior.
///
-/// See [`collect_into_array`] for more information.
+/// See [`try_collect_into_array`] for more information.
///
///
/// # Safety
///
/// It is up to the caller to guarantee that `iter` yields at least `N` items.
/// Violating this condition causes undefined behavior.
-unsafe fn collect_into_array_rslt_unchecked<E, I, T, const N: usize>(
- iter: &mut I,
-) -> Result<[T; N], E>
+unsafe fn try_collect_into_array_unchecked<I, T, R, const N: usize>(iter: &mut I) -> R::TryType
where
// Note: `TrustedLen` here is somewhat of an experiment. This is just an
// internal function, so feel free to remove if this bound turns out to be a
// bad idea. In that case, remember to also remove the lower bound
// `debug_assert!` below!
- I: Iterator<Item = Result<T, E>> + TrustedLen,
+ I: Iterator + TrustedLen,
+ I::Item: Try<Output = T, Residual = R>,
+ R: Residual<[T; N]>,
{
debug_assert!(N <= iter.size_hint().1.unwrap_or(usize::MAX));
debug_assert!(N <= iter.size_hint().0);
// SAFETY: covered by the function contract.
- unsafe { collect_into_array(iter).unwrap_unchecked() }
+ unsafe { try_collect_into_array(iter).unwrap_unchecked() }
}
-// Infallible version of `collect_into_array_rslt_unchecked`.
+// Infallible version of `try_collect_into_array_unchecked`.
unsafe fn collect_into_array_unchecked<I, const N: usize>(iter: &mut I) -> [I::Item; N]
where
I: Iterator + TrustedLen,
{
- let mut map = iter.map(Ok::<_, Infallible>);
+ let mut map = iter.map(NeverShortCircuit);
// SAFETY: The same safety considerations w.r.t. the iterator length
- // apply for `collect_into_array_rslt_unchecked` as for
+ // apply for `try_collect_into_array_unchecked` as for
// `collect_into_array_unchecked`
- match unsafe { collect_into_array_rslt_unchecked(&mut map) } {
- Ok(array) => array,
+ match unsafe { try_collect_into_array_unchecked(&mut map) } {
+ NeverShortCircuit(array) => array,
}
}
@@ -675,13 +791,15 @@ where
///
/// If `iter.next()` panicks, all items already yielded by the iterator are
/// dropped.
-fn collect_into_array<E, I, T, const N: usize>(iter: &mut I) -> Option<Result<[T; N], E>>
+fn try_collect_into_array<I, T, R, const N: usize>(iter: &mut I) -> Option<R::TryType>
where
- I: Iterator<Item = Result<T, E>>,
+ I: Iterator,
+ I::Item: Try<Output = T, Residual = R>,
+ R: Residual<[T; N]>,
{
if N == 0 {
// SAFETY: An empty array is always inhabited and has no validity invariants.
- return unsafe { Some(Ok(mem::zeroed())) };
+ return unsafe { Some(Try::from_output(mem::zeroed())) };
}
struct Guard<'a, T, const N: usize> {
@@ -706,11 +824,11 @@ where
let mut guard = Guard { array_mut: &mut array, initialized: 0 };
while let Some(item_rslt) = iter.next() {
- let item = match item_rslt {
- Err(err) => {
- return Some(Err(err));
+ let item = match item_rslt.branch() {
+ ControlFlow::Break(r) => {
+ return Some(FromResidual::from_residual(r));
}
- Ok(elem) => elem,
+ ControlFlow::Continue(elem) => elem,
};
// SAFETY: `guard.initialized` starts at 0, is increased by one in the
@@ -728,7 +846,7 @@ where
// SAFETY: the condition above asserts that all elements are
// initialized.
let out = unsafe { MaybeUninit::array_assume_init(array) };
- return Some(Ok(out));
+ return Some(Try::from_output(out));
}
}
diff --git a/library/core/src/bool.rs b/library/core/src/bool.rs
index f14c2a46416..d5119d0b7c3 100644
--- a/library/core/src/bool.rs
+++ b/library/core/src/bool.rs
@@ -14,8 +14,12 @@ impl bool {
/// assert_eq!(true.then_some(0), Some(0));
/// ```
#[unstable(feature = "bool_to_option", issue = "80967")]
+ #[rustc_const_unstable(feature = "const_bool_to_option", issue = "91917")]
#[inline]
- pub fn then_some<T>(self, t: T) -> Option<T> {
+ pub const fn then_some<T>(self, t: T) -> Option<T>
+ where
+ T: ~const Drop,
+ {
if self { Some(t) } else { None }
}
@@ -29,8 +33,13 @@ impl bool {
/// assert_eq!(true.then(|| 0), Some(0));
/// ```
#[stable(feature = "lazy_bool_to_option", since = "1.50.0")]
+ #[rustc_const_unstable(feature = "const_bool_to_option", issue = "91917")]
#[inline]
- pub fn then<T, F: FnOnce() -> T>(self, f: F) -> Option<T> {
+ pub const fn then<T, F>(self, f: F) -> Option<T>
+ where
+ F: ~const FnOnce() -> T,
+ F: ~const Drop,
+ {
if self { Some(f()) } else { None }
}
}
diff --git a/library/core/src/borrow.rs b/library/core/src/borrow.rs
index f28be20aaa1..58eabecf3f0 100644
--- a/library/core/src/borrow.rs
+++ b/library/core/src/borrow.rs
@@ -205,7 +205,8 @@ pub trait BorrowMut<Borrowed: ?Sized>: Borrow<Borrowed> {
}
#[stable(feature = "rust1", since = "1.0.0")]
-impl<T: ?Sized> Borrow<T> for T {
+#[rustc_const_unstable(feature = "const_borrow", issue = "91522")]
+impl<T: ?Sized> const Borrow<T> for T {
#[rustc_diagnostic_item = "noop_method_borrow"]
fn borrow(&self) -> &T {
self
@@ -213,28 +214,32 @@ impl<T: ?Sized> Borrow<T> for T {
}
#[stable(feature = "rust1", since = "1.0.0")]
-impl<T: ?Sized> BorrowMut<T> for T {
+#[rustc_const_unstable(feature = "const_borrow", issue = "91522")]
+impl<T: ?Sized> const BorrowMut<T> for T {
fn borrow_mut(&mut self) -> &mut T {
self
}
}
#[stable(feature = "rust1", since = "1.0.0")]
-impl<T: ?Sized> Borrow<T> for &T {
+#[rustc_const_unstable(feature = "const_borrow", issue = "91522")]
+impl<T: ?Sized> const Borrow<T> for &T {
fn borrow(&self) -> &T {
&**self
}
}
#[stable(feature = "rust1", since = "1.0.0")]
-impl<T: ?Sized> Borrow<T> for &mut T {
+#[rustc_const_unstable(feature = "const_borrow", issue = "91522")]
+impl<T: ?Sized> const Borrow<T> for &mut T {
fn borrow(&self) -> &T {
&**self
}
}
#[stable(feature = "rust1", since = "1.0.0")]
-impl<T: ?Sized> BorrowMut<T> for &mut T {
+#[rustc_const_unstable(feature = "const_borrow", issue = "91522")]
+impl<T: ?Sized> const BorrowMut<T> for &mut T {
fn borrow_mut(&mut self) -> &mut T {
&mut **self
}
diff --git a/library/core/src/cell.rs b/library/core/src/cell.rs
index 06dc5ecf2ff..bc3f7167fac 100644
--- a/library/core/src/cell.rs
+++ b/library/core/src/cell.rs
@@ -898,7 +898,7 @@ impl<T: ?Sized> RefCell<T> {
Ok(Ref { value: unsafe { &*self.value.get() }, borrow: b })
}
None => Err(BorrowError {
- // If a borrow occured, then we must already have an outstanding borrow,
+ // If a borrow occurred, then we must already have an outstanding borrow,
// so `borrowed_at` will be `Some`
#[cfg(feature = "debug_refcell")]
location: self.borrowed_at.get().unwrap(),
@@ -983,7 +983,7 @@ impl<T: ?Sized> RefCell<T> {
Ok(RefMut { value: unsafe { &mut *self.value.get() }, borrow: b })
}
None => Err(BorrowMutError {
- // If a borrow occured, then we must already have an outstanding borrow,
+ // If a borrow occurred, then we must already have an outstanding borrow,
// so `borrowed_at` will be `Some`
#[cfg(feature = "debug_refcell")]
location: self.borrowed_at.get().unwrap(),
@@ -1104,7 +1104,7 @@ impl<T: ?Sized> RefCell<T> {
Ok(unsafe { &*self.value.get() })
} else {
Err(BorrowError {
- // If a borrow occured, then we must already have an outstanding borrow,
+ // If a borrow occurred, then we must already have an outstanding borrow,
// so `borrowed_at` will be `Some`
#[cfg(feature = "debug_refcell")]
location: self.borrowed_at.get().unwrap(),
diff --git a/library/core/src/cmp.rs b/library/core/src/cmp.rs
index 7456f886ea5..deed9901cc9 100644
--- a/library/core/src/cmp.rs
+++ b/library/core/src/cmp.rs
@@ -215,6 +215,7 @@ pub trait PartialEq<Rhs: ?Sized = Self> {
#[inline]
#[must_use]
#[stable(feature = "rust1", since = "1.0.0")]
+ #[default_method_body_is_const]
fn ne(&self, other: &Rhs) -> bool {
!self.eq(other)
}
@@ -1031,6 +1032,7 @@ pub trait PartialOrd<Rhs: ?Sized = Self>: PartialEq<Rhs> {
#[inline]
#[must_use]
#[stable(feature = "rust1", since = "1.0.0")]
+ #[default_method_body_is_const]
fn lt(&self, other: &Rhs) -> bool {
matches!(self.partial_cmp(other), Some(Less))
}
@@ -1050,6 +1052,7 @@ pub trait PartialOrd<Rhs: ?Sized = Self>: PartialEq<Rhs> {
#[inline]
#[must_use]
#[stable(feature = "rust1", since = "1.0.0")]
+ #[default_method_body_is_const]
fn le(&self, other: &Rhs) -> bool {
// Pattern `Some(Less | Eq)` optimizes worse than negating `None | Some(Greater)`.
// FIXME: The root cause was fixed upstream in LLVM with:
@@ -1072,6 +1075,7 @@ pub trait PartialOrd<Rhs: ?Sized = Self>: PartialEq<Rhs> {
#[inline]
#[must_use]
#[stable(feature = "rust1", since = "1.0.0")]
+ #[default_method_body_is_const]
fn gt(&self, other: &Rhs) -> bool {
matches!(self.partial_cmp(other), Some(Greater))
}
@@ -1091,6 +1095,7 @@ pub trait PartialOrd<Rhs: ?Sized = Self>: PartialEq<Rhs> {
#[inline]
#[must_use]
#[stable(feature = "rust1", since = "1.0.0")]
+ #[default_method_body_is_const]
fn ge(&self, other: &Rhs) -> bool {
matches!(self.partial_cmp(other), Some(Greater | Equal))
}
diff --git a/library/core/src/convert/mod.rs b/library/core/src/convert/mod.rs
index 5aa53deee34..1c2e673d604 100644
--- a/library/core/src/convert/mod.rs
+++ b/library/core/src/convert/mod.rs
@@ -534,9 +534,10 @@ where
// From implies Into
#[stable(feature = "rust1", since = "1.0.0")]
-impl<T, U> Into<U> for T
+#[rustc_const_unstable(feature = "const_convert", issue = "88674")]
+impl<T, U> const Into<U> for T
where
- U: From<T>,
+ U: ~const From<T>,
{
fn into(self) -> U {
U::from(self)
diff --git a/library/core/src/fmt/mod.rs b/library/core/src/fmt/mod.rs
index 80d3270d73c..6fc3cd0b7c4 100644
--- a/library/core/src/fmt/mod.rs
+++ b/library/core/src/fmt/mod.rs
@@ -2186,28 +2186,34 @@ impl Display for char {
#[stable(feature = "rust1", since = "1.0.0")]
impl<T: ?Sized> Pointer for *const T {
fn fmt(&self, f: &mut Formatter<'_>) -> Result {
- let old_width = f.width;
- let old_flags = f.flags;
-
- // The alternate flag is already treated by LowerHex as being special-
- // it denotes whether to prefix with 0x. We use it to work out whether
- // or not to zero extend, and then unconditionally set it to get the
- // prefix.
- if f.alternate() {
- f.flags |= 1 << (FlagV1::SignAwareZeroPad as u32);
-
- if f.width.is_none() {
- f.width = Some((usize::BITS / 4) as usize + 2);
+ /// Since the formatting will be identical for all pointer types, use a non-monomorphized
+ /// implementation for the actual formatting to reduce the amount of codegen work needed
+ fn inner(ptr: *const (), f: &mut Formatter<'_>) -> Result {
+ let old_width = f.width;
+ let old_flags = f.flags;
+
+ // The alternate flag is already treated by LowerHex as being special-
+ // it denotes whether to prefix with 0x. We use it to work out whether
+ // or not to zero extend, and then unconditionally set it to get the
+ // prefix.
+ if f.alternate() {
+ f.flags |= 1 << (FlagV1::SignAwareZeroPad as u32);
+
+ if f.width.is_none() {
+ f.width = Some((usize::BITS / 4) as usize + 2);
+ }
}
- }
- f.flags |= 1 << (FlagV1::Alternate as u32);
+ f.flags |= 1 << (FlagV1::Alternate as u32);
+
+ let ret = LowerHex::fmt(&(ptr as usize), f);
- let ret = LowerHex::fmt(&(*self as *const () as usize), f);
+ f.width = old_width;
+ f.flags = old_flags;
- f.width = old_width;
- f.flags = old_flags;
+ ret
+ }
- ret
+ inner(*self as *const (), f)
}
}
diff --git a/library/core/src/future/future.rs b/library/core/src/future/future.rs
index 09d8a2aac26..6b62236b32f 100644
--- a/library/core/src/future/future.rs
+++ b/library/core/src/future/future.rs
@@ -28,7 +28,11 @@ use crate::task::{Context, Poll};
#[must_use = "futures do nothing unless you `.await` or poll them"]
#[stable(feature = "futures_api", since = "1.36.0")]
#[lang = "future_trait"]
-#[rustc_on_unimplemented(label = "`{Self}` is not a future", message = "`{Self}` is not a future")]
+#[rustc_on_unimplemented(
+ label = "`{Self}` is not a future",
+ message = "`{Self}` is not a future",
+ note = "{Self} must be a future or must implement `IntoFuture` to be awaited"
+)]
pub trait Future {
/// The type of value produced on completion.
#[stable(feature = "futures_api", since = "1.36.0")]
diff --git a/library/core/src/future/into_future.rs b/library/core/src/future/into_future.rs
index 4020c254446..cac1866188e 100644
--- a/library/core/src/future/into_future.rs
+++ b/library/core/src/future/into_future.rs
@@ -13,6 +13,7 @@ pub trait IntoFuture {
/// Creates a future from a value.
#[unstable(feature = "into_future", issue = "67644")]
+ #[cfg_attr(not(bootstrap), lang = "into_future")]
fn into_future(self) -> Self::Future;
}
diff --git a/library/core/src/future/join.rs b/library/core/src/future/join.rs
new file mode 100644
index 00000000000..a6ffbe07d91
--- /dev/null
+++ b/library/core/src/future/join.rs
@@ -0,0 +1,193 @@
+#![allow(unused_imports, unused_macros)] // items are used by the macro
+
+use crate::cell::UnsafeCell;
+use crate::future::{poll_fn, Future};
+use crate::mem;
+use crate::pin::Pin;
+use crate::task::{Context, Poll};
+
+/// Polls multiple futures simultaneously, returning a tuple
+/// of all results once complete.
+///
+/// While `join!(a, b)` is similar to `(a.await, b.await)`,
+/// `join!` polls both futures concurrently and is therefore more efficient.
+///
+/// # Examples
+///
+/// ```
+/// #![feature(future_join, future_poll_fn)]
+///
+/// use std::future::join;
+///
+/// async fn one() -> usize { 1 }
+/// async fn two() -> usize { 2 }
+///
+/// # let _ = async {
+/// let x = join!(one(), two()).await;
+/// assert_eq!(x, (1, 2));
+/// # };
+/// ```
+///
+/// `join!` is variadic, so you can pass any number of futures:
+///
+/// ```
+/// #![feature(future_join, future_poll_fn)]
+///
+/// use std::future::join;
+///
+/// async fn one() -> usize { 1 }
+/// async fn two() -> usize { 2 }
+/// async fn three() -> usize { 3 }
+///
+/// # let _ = async {
+/// let x = join!(one(), two(), three()).await;
+/// assert_eq!(x, (1, 2, 3));
+/// # };
+/// ```
+#[unstable(feature = "future_join", issue = "91642")]
+pub macro join( $($fut:expr),+ $(,)? ) {
+ // Funnel through an internal macro not to leak implementation details.
+ join_internal! {
+ current_position: []
+ futures_and_positions: []
+ munching: [ $($fut)+ ]
+ }
+}
+
+// FIXME(danielhenrymantilla): a private macro should need no stability guarantee.
+#[unstable(feature = "future_join", issue = "91642")]
+/// To be able to *name* the i-th future in the tuple (say we want the .4-th),
+/// the following trick will be used: `let (_, _, _, _, it, ..) = tuple;`
+/// In order to do that, we need to generate a `i`-long repetition of `_`,
+/// for each i-th fut. Hence the recursive muncher approach.
+macro join_internal {
+ // Recursion step: map each future with its "position" (underscore count).
+ (
+ // Accumulate a token for each future that has been expanded: "_ _ _".
+ current_position: [
+ $($underscores:tt)*
+ ]
+ // Accumulate Futures and their positions in the tuple: `_0th () _1st ( _ ) …`.
+ futures_and_positions: [
+ $($acc:tt)*
+ ]
+ // Munch one future.
+ munching: [
+ $current:tt
+ $($rest:tt)*
+ ]
+ ) => (
+ join_internal! {
+ current_position: [
+ $($underscores)*
+ _
+ ]
+ futures_and_positions: [
+ $($acc)*
+ $current ( $($underscores)* )
+ ]
+ munching: [
+ $($rest)*
+ ]
+ }
+ ),
+
+ // End of recursion: generate the output future.
+ (
+ current_position: $_:tt
+ futures_and_positions: [
+ $(
+ $fut_expr:tt ( $($pos:tt)* )
+ )*
+ ]
+ // Nothing left to munch.
+ munching: []
+ ) => (
+ match ( $( MaybeDone::Future($fut_expr), )* ) { futures => async {
+ let mut futures = futures;
+ // SAFETY: this is `pin_mut!`.
+ let mut futures = unsafe { Pin::new_unchecked(&mut futures) };
+ poll_fn(move |cx| {
+ let mut done = true;
+ // For each `fut`, pin-project to it, and poll it.
+ $(
+ // SAFETY: pinning projection
+ let fut = unsafe {
+ futures.as_mut().map_unchecked_mut(|it| {
+ let ( $($pos,)* fut, .. ) = it;
+ fut
+ })
+ };
+ // Despite how tempting it may be to `let () = fut.poll(cx).ready()?;`
+ // doing so would defeat the point of `join!`: to start polling eagerly all
+ // of the futures, to allow parallelizing the waits.
+ done &= fut.poll(cx).is_ready();
+ )*
+ if !done {
+ return Poll::Pending;
+ }
+ // All ready; time to extract all the outputs.
+
+ // SAFETY: `.take_output()` does not break the `Pin` invariants for that `fut`.
+ let futures = unsafe {
+ futures.as_mut().get_unchecked_mut()
+ };
+ Poll::Ready(
+ ($(
+ {
+ let ( $($pos,)* fut, .. ) = &mut *futures;
+ fut.take_output().unwrap()
+ }
+ ),*) // <- no trailing comma since we don't want 1-tuples.
+ )
+ }).await
+ }}
+ ),
+}
+
+/// Future used by `join!` that stores it's output to
+/// be later taken and doesn't panic when polled after ready.
+///
+/// This type is public in a private module for use by the macro.
+#[allow(missing_debug_implementations)]
+#[unstable(feature = "future_join", issue = "91642")]
+pub enum MaybeDone<F: Future> {
+ Future(F),
+ Done(F::Output),
+ Taken,
+}
+
+#[unstable(feature = "future_join", issue = "91642")]
+impl<F: Future> MaybeDone<F> {
+ pub fn take_output(&mut self) -> Option<F::Output> {
+ match *self {
+ MaybeDone::Done(_) => match mem::replace(self, Self::Taken) {
+ MaybeDone::Done(val) => Some(val),
+ _ => unreachable!(),
+ },
+ _ => None,
+ }
+ }
+}
+
+#[unstable(feature = "future_join", issue = "91642")]
+impl<F: Future> Future for MaybeDone<F> {
+ type Output = ();
+
+ fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
+ // SAFETY: pinning in structural for `f`
+ unsafe {
+ // Do not mix match ergonomics with unsafe.
+ match *self.as_mut().get_unchecked_mut() {
+ MaybeDone::Future(ref mut f) => {
+ let val = Pin::new_unchecked(f).poll(cx).ready()?;
+ self.set(Self::Done(val));
+ }
+ MaybeDone::Done(_) => {}
+ MaybeDone::Taken => unreachable!(),
+ }
+ }
+
+ Poll::Ready(())
+ }
+}
diff --git a/library/core/src/future/mod.rs b/library/core/src/future/mod.rs
index 7a3af70d6d9..88db584aefd 100644
--- a/library/core/src/future/mod.rs
+++ b/library/core/src/future/mod.rs
@@ -11,6 +11,7 @@ use crate::{
mod future;
mod into_future;
+mod join;
mod pending;
mod poll_fn;
mod ready;
@@ -18,6 +19,9 @@ mod ready;
#[stable(feature = "futures_api", since = "1.36.0")]
pub use self::future::Future;
+#[unstable(feature = "future_join", issue = "91642")]
+pub use self::join::join;
+
#[unstable(feature = "into_future", issue = "67644")]
pub use into_future::IntoFuture;
diff --git a/library/core/src/future/ready.rs b/library/core/src/future/ready.rs
index cc905d288f9..48f20f90a32 100644
--- a/library/core/src/future/ready.rs
+++ b/library/core/src/future/ready.rs
@@ -2,7 +2,7 @@ use crate::future::Future;
use crate::pin::Pin;
use crate::task::{Context, Poll};
-/// Creates a future that is immediately ready with a value.
+/// A future that is immediately ready with a value.
///
/// This `struct` is created by [`ready()`]. See its
/// documentation for more.
diff --git a/library/core/src/hash/mod.rs b/library/core/src/hash/mod.rs
index 540160bc4c2..3ff84cc9672 100644
--- a/library/core/src/hash/mod.rs
+++ b/library/core/src/hash/mod.rs
@@ -164,6 +164,19 @@ mod sip;
/// `0xFF` byte to the `Hasher` so that the values `("ab", "c")` and `("a",
/// "bc")` hash differently.
///
+/// ## Portability
+///
+/// Due to differences in endianness and type sizes, data fed by `Hash` to a `Hasher`
+/// should not be considered portable across platforms. Additionally the data passed by most
+/// standard library types should not be considered stable between compiler versions.
+///
+/// This means tests shouldn't probe hard-coded hash values or data fed to a `Hasher` and
+/// instead should check consistency with `Eq`.
+///
+/// Serialization formats intended to be portable between platforms or compiler versions should
+/// either avoid encoding hashes or only rely on `Hash` and `Hasher` implementations that
+/// provide additional guarantees.
+///
/// [`HashMap`]: ../../std/collections/struct.HashMap.html
/// [`HashSet`]: ../../std/collections/struct.HashSet.html
/// [`hash`]: Hash::hash
diff --git a/library/core/src/hint.rs b/library/core/src/hint.rs
index 95798879155..f49aefea81b 100644
--- a/library/core/src/hint.rs
+++ b/library/core/src/hint.rs
@@ -137,6 +137,11 @@ pub fn spin_loop() {
unsafe { crate::arch::arm::__yield() };
}
}
+
+ #[cfg(any(target_arch = "riscv32", target_arch = "riscv64"))]
+ {
+ crate::arch::riscv::pause();
+ }
}
/// An identity function that *__hints__* to the compiler to be maximally pessimistic about what
diff --git a/library/core/src/intrinsics.rs b/library/core/src/intrinsics.rs
index 0f57fb5b141..46370f76e7c 100644
--- a/library/core/src/intrinsics.rs
+++ b/library/core/src/intrinsics.rs
@@ -811,7 +811,8 @@ extern "rust-intrinsic" {
/// The preferred alignment of a type.
///
/// This intrinsic does not have a stable counterpart.
- #[rustc_const_unstable(feature = "const_pref_align_of", issue = "none")]
+ /// It's "tracking issue" is [#91971](https://github.com/rust-lang/rust/issues/91971).
+ #[rustc_const_unstable(feature = "const_pref_align_of", issue = "91971")]
pub fn pref_align_of<T>() -> usize;
/// The size of the referenced value in bytes.
@@ -853,19 +854,21 @@ extern "rust-intrinsic" {
/// This will statically either panic, or do nothing.
///
/// This intrinsic does not have a stable counterpart.
- #[rustc_const_unstable(feature = "const_assert_type", issue = "none")]
+ #[rustc_const_stable(feature = "const_assert_type", since = "1.59.0")]
pub fn assert_inhabited<T>();
/// A guard for unsafe functions that cannot ever be executed if `T` does not permit
/// zero-initialization: This will statically either panic, or do nothing.
///
/// This intrinsic does not have a stable counterpart.
+ #[rustc_const_unstable(feature = "const_assert_type2", issue = "none")]
pub fn assert_zero_valid<T>();
/// A guard for unsafe functions that cannot ever be executed if `T` has invalid
/// bit patterns: This will statically either panic, or do nothing.
///
/// This intrinsic does not have a stable counterpart.
+ #[rustc_const_unstable(feature = "const_assert_type2", issue = "none")]
pub fn assert_uninit_valid<T>();
/// Gets a reference to a static `Location` indicating where it was called.
@@ -1917,7 +1920,7 @@ extern "rust-intrinsic" {
/// Determines whether the raw bytes of the two values are equal.
///
- /// The is particularly handy for arrays, since it allows things like just
+ /// This is particularly handy for arrays, since it allows things like just
/// comparing `i96`s instead of forcing `alloca`s for `[6 x i16]`.
///
/// Above some backend-decided threshold this will emit calls to `memcmp`,
@@ -2068,8 +2071,8 @@ pub const unsafe fn copy_nonoverlapping<T>(src: *const T, dst: *mut T, count: us
#[cfg(debug_assertions)]
const fn compiletime_check<T>(_src: *const T, _dst: *mut T, _count: usize) {}
#[cfg(debug_assertions)]
- // SAFETY: runtime debug-assertions are a best-effort basis; it's fine to
- // not do them during compile time
+ // SAFETY: As per our safety precondition, we may assume that the `abort` above is never reached.
+ // Therefore, compiletime_check and runtime_check are observably equivalent.
unsafe {
const_eval_select((src, dst, count), compiletime_check, runtime_check);
}
@@ -2159,8 +2162,8 @@ pub const unsafe fn copy<T>(src: *const T, dst: *mut T, count: usize) {
#[cfg(debug_assertions)]
const fn compiletime_check<T>(_src: *const T, _dst: *mut T) {}
#[cfg(debug_assertions)]
- // SAFETY: runtime debug-assertions are a best-effort basis; it's fine to
- // not do them during compile time
+ // SAFETY: As per our safety precondition, we may assume that the `abort` above is never reached.
+ // Therefore, compiletime_check and runtime_check are observably equivalent.
unsafe {
const_eval_select((src, dst), compiletime_check, runtime_check);
}
@@ -2242,13 +2245,29 @@ pub const unsafe fn copy<T>(src: *const T, dst: *mut T, count: usize) {
/// assert_eq!(*v, 42);
/// ```
#[stable(feature = "rust1", since = "1.0.0")]
+#[rustc_const_unstable(feature = "const_ptr_write", issue = "86302")]
#[inline]
-pub unsafe fn write_bytes<T>(dst: *mut T, val: u8, count: usize) {
+pub const unsafe fn write_bytes<T>(dst: *mut T, val: u8, count: usize) {
extern "rust-intrinsic" {
+ #[rustc_const_unstable(feature = "const_ptr_write", issue = "86302")]
fn write_bytes<T>(dst: *mut T, val: u8, count: usize);
}
- debug_assert!(is_aligned_and_not_null(dst), "attempt to write to unaligned or null pointer");
+ #[cfg(debug_assertions)]
+ fn runtime_check<T>(ptr: *mut T) {
+ debug_assert!(
+ is_aligned_and_not_null(ptr),
+ "attempt to write to unaligned or null pointer"
+ );
+ }
+ #[cfg(debug_assertions)]
+ const fn compiletime_check<T>(_ptr: *mut T) {}
+ #[cfg(debug_assertions)]
+ // SAFETY: runtime debug-assertions are a best-effort basis; it's fine to
+ // not do them during compile time
+ unsafe {
+ const_eval_select((dst,), compiletime_check, runtime_check);
+ }
// SAFETY: the safety contract for `write_bytes` must be upheld by the caller.
unsafe { write_bytes(dst, val, count) }
@@ -2271,19 +2290,40 @@ pub unsafe fn write_bytes<T>(dst: *mut T, val: u8, count: usize) {
///
/// # Safety
///
-/// This intrinsic allows breaking [referential transparency] in `const fn`
-/// and is therefore `unsafe`.
+/// The two functions must behave observably equivalent. Safe code in other
+/// crates may assume that calling a `const fn` at compile-time and at run-time
+/// produces the same result. A function that produces a different result when
+/// evaluated at run-time, or has any other observable side-effects, is
+/// *unsound*.
///
-/// Code that uses this intrinsic must be extremely careful to ensure that
-/// `const fn`s remain referentially-transparent independently of when they
-/// are evaluated.
+/// Here is an example of how this could cause a problem:
+/// ```no_run
+/// #![feature(const_eval_select)]
+/// use std::hint::unreachable_unchecked;
+/// use std::intrinsics::const_eval_select;
///
-/// The Rust compiler assumes that it is sound to replace a call to a `const
-/// fn` with the result produced by evaluating it at compile-time. If
-/// evaluating the function at run-time were to produce a different result,
-/// or have any other observable side-effects, the behavior is undefined.
+/// // Crate A
+/// pub const fn inconsistent() -> i32 {
+/// fn runtime() -> i32 { 1 }
+/// const fn compiletime() -> i32 { 2 }
+///
+/// unsafe {
+// // ⚠ This code violates the required equivalence of `compiletime`
+/// // and `runtime`.
+/// const_eval_select((), compiletime, runtime)
+/// }
+/// }
+///
+/// // Crate B
+/// const X: i32 = inconsistent();
+/// let x = inconsistent();
+/// if x != X { unsafe { unreachable_unchecked(); }}
+/// ```
///
-/// [referential transparency]: https://en.wikipedia.org/wiki/Referential_transparency
+/// This code causes Undefined Behavior when being run, since the
+/// `unreachable_unchecked` is actually being reached. The bug is in *crate A*,
+/// which violates the principle that a `const fn` must behave the same at
+/// compile-time and at run-time. The unsafe code in crate B is fine.
#[unstable(
feature = "const_eval_select",
issue = "none",
diff --git a/library/core/src/iter/adapters/mod.rs b/library/core/src/iter/adapters/mod.rs
index 9e1f4e425f9..b1b917775c3 100644
--- a/library/core/src/iter/adapters/mod.rs
+++ b/library/core/src/iter/adapters/mod.rs
@@ -54,7 +54,7 @@ pub use self::zip::TrustedRandomAccess;
#[unstable(feature = "trusted_random_access", issue = "none")]
pub use self::zip::TrustedRandomAccessNoCoerce;
-#[unstable(feature = "iter_zip", issue = "83574")]
+#[stable(feature = "iter_zip", since = "1.59.0")]
pub use self::zip::zip;
/// This trait provides transitive access to source-stage in an iterator-adapter pipeline
diff --git a/library/core/src/iter/adapters/skip.rs b/library/core/src/iter/adapters/skip.rs
index 565fc224f53..ea1da8ba434 100644
--- a/library/core/src/iter/adapters/skip.rs
+++ b/library/core/src/iter/adapters/skip.rs
@@ -119,8 +119,8 @@ where
#[rustc_inherit_overflow_checks]
fn advance_by(&mut self, n: usize) -> Result<(), usize> {
let mut rem = n;
-
let step_one = self.n.saturating_add(rem);
+
match self.iter.advance_by(step_one) {
Ok(_) => {
rem -= step_one - self.n;
@@ -129,7 +129,7 @@ where
Err(advanced) => {
let advanced_without_skip = advanced.saturating_sub(self.n);
self.n = self.n.saturating_sub(advanced);
- return Err(advanced_without_skip);
+ return if n == 0 { Ok(()) } else { Err(advanced_without_skip) };
}
}
diff --git a/library/core/src/iter/adapters/take.rs b/library/core/src/iter/adapters/take.rs
index 81f6c294fac..2962e0104d1 100644
--- a/library/core/src/iter/adapters/take.rs
+++ b/library/core/src/iter/adapters/take.rs
@@ -215,21 +215,22 @@ where
}
#[inline]
+ #[rustc_inherit_overflow_checks]
fn advance_back_by(&mut self, n: usize) -> Result<(), usize> {
- let inner_len = self.iter.len();
- let len = self.n;
- let remainder = len.saturating_sub(n);
- let to_advance = inner_len - remainder;
- match self.iter.advance_back_by(to_advance) {
- Ok(_) => {
- self.n = remainder;
- if n > len {
- return Err(len);
- }
- return Ok(());
- }
- _ => panic!("ExactSizeIterator contract violation"),
- }
+ // The amount by which the inner iterator needs to be shortened for it to be
+ // at most as long as the take() amount.
+ let trim_inner = self.iter.len().saturating_sub(self.n);
+ // The amount we need to advance inner to fulfill the caller's request.
+ // take(), advance_by() and len() all can be at most usize, so we don't have to worry
+ // about having to advance more than usize::MAX here.
+ let advance_by = trim_inner.saturating_add(n);
+
+ let advanced = match self.iter.advance_back_by(advance_by) {
+ Ok(_) => advance_by - trim_inner,
+ Err(advanced) => advanced - trim_inner,
+ };
+ self.n -= advanced;
+ return if advanced < n { Err(advanced) } else { Ok(()) };
}
}
diff --git a/library/core/src/iter/adapters/zip.rs b/library/core/src/iter/adapters/zip.rs
index 4b89bc36326..f50e71da20f 100644
--- a/library/core/src/iter/adapters/zip.rs
+++ b/library/core/src/iter/adapters/zip.rs
@@ -40,22 +40,29 @@ impl<A: Iterator, B: Iterator> Zip<A, B> {
/// # Examples
///
/// ```
-/// #![feature(iter_zip)]
/// use std::iter::zip;
///
/// let xs = [1, 2, 3];
/// let ys = [4, 5, 6];
-/// for (x, y) in zip(&xs, &ys) {
-/// println!("x:{}, y:{}", x, y);
-/// }
+///
+/// let mut iter = zip(xs, ys);
+///
+/// assert_eq!(iter.next().unwrap(), (1, 4));
+/// assert_eq!(iter.next().unwrap(), (2, 5));
+/// assert_eq!(iter.next().unwrap(), (3, 6));
+/// assert!(iter.next().is_none());
///
/// // Nested zips are also possible:
/// let zs = [7, 8, 9];
-/// for ((x, y), z) in zip(zip(&xs, &ys), &zs) {
-/// println!("x:{}, y:{}, z:{}", x, y, z);
-/// }
+///
+/// let mut iter = zip(zip(xs, ys), zs);
+///
+/// assert_eq!(iter.next().unwrap(), ((1, 4), 7));
+/// assert_eq!(iter.next().unwrap(), ((2, 5), 8));
+/// assert_eq!(iter.next().unwrap(), ((3, 6), 9));
+/// assert!(iter.next().is_none());
/// ```
-#[unstable(feature = "iter_zip", issue = "83574")]
+#[stable(feature = "iter_zip", since = "1.59.0")]
pub fn zip<A, B>(a: A, b: B) -> Zip<A::IntoIter, B::IntoIter>
where
A: IntoIterator,
@@ -509,7 +516,7 @@ impl<A: Debug + TrustedRandomAccessNoCoerce, B: Debug + TrustedRandomAccessNoCoe
/// * It must also be safe to drop `self` after calling `self.__iterator_get_unchecked(idx)`.
/// * If `T` is a subtype of `Self`, then it must be safe to coerce `self` to `T`.
//
-// FIXME: Clarify interaction with SourceIter/InPlaceIterable. Calling `SouceIter::as_inner`
+// FIXME: Clarify interaction with SourceIter/InPlaceIterable. Calling `SourceIter::as_inner`
// after `__iterator_get_unchecked` is supposed to be allowed.
#[doc(hidden)]
#[unstable(feature = "trusted_random_access", issue = "none")]
diff --git a/library/core/src/iter/mod.rs b/library/core/src/iter/mod.rs
index dc32df4e2b4..da459ed7c68 100644
--- a/library/core/src/iter/mod.rs
+++ b/library/core/src/iter/mod.rs
@@ -391,7 +391,7 @@ pub use self::traits::{
DoubleEndedIterator, ExactSizeIterator, Extend, FromIterator, IntoIterator, Product, Sum,
};
-#[unstable(feature = "iter_zip", issue = "83574")]
+#[stable(feature = "iter_zip", since = "1.59.0")]
pub use self::adapters::zip;
#[stable(feature = "iter_cloned", since = "1.1.0")]
pub use self::adapters::Cloned;
diff --git a/library/core/src/iter/range.rs b/library/core/src/iter/range.rs
index 06733a1b50b..0ae94c05da6 100644
--- a/library/core/src/iter/range.rs
+++ b/library/core/src/iter/range.rs
@@ -777,7 +777,7 @@ range_exact_iter_impl! {
usize u8 u16
isize i8 i16
- // These are incorect per the reasoning above,
+ // These are incorrect per the reasoning above,
// but removing them would be a breaking change as they were stabilized in Rust 1.0.0.
// So e.g. `(0..66_000_u32).len()` for example will compile without error or warnings
// on 16-bit platforms, but continue to give a wrong result.
@@ -805,7 +805,7 @@ range_incl_exact_iter_impl! {
u8
i8
- // These are incorect per the reasoning above,
+ // These are incorrect per the reasoning above,
// but removing them would be a breaking change as they were stabilized in Rust 1.26.0.
// So e.g. `(0..=u16::MAX).len()` for example will compile without error or warnings
// on 16-bit platforms, but continue to give a wrong result.
diff --git a/library/core/src/iter/traits/double_ended.rs b/library/core/src/iter/traits/double_ended.rs
index 9a589c1f3b5..a6aed6d210b 100644
--- a/library/core/src/iter/traits/double_ended.rs
+++ b/library/core/src/iter/traits/double_ended.rs
@@ -106,9 +106,6 @@ pub trait DoubleEndedIterator: Iterator {
/// Calling `advance_back_by(0)` can do meaningful work, for example [`Flatten`] can advance its
/// outer iterator until it finds an inner iterator that is not empty, which then often
/// allows it to return a more accurate `size_hint()` than in its initial state.
- /// `advance_back_by(0)` may either return `Ok()` or `Err(0)`. The former conveys no information
- /// whether the iterator is or is not exhausted, the latter can be treated as if [`next_back`]
- /// had returned `None`. Replacing a `Err(0)` with `Ok` is only correct for `n = 0`.
///
/// [`advance_by`]: Iterator::advance_by
/// [`Flatten`]: crate::iter::Flatten
diff --git a/library/core/src/iter/traits/iterator.rs b/library/core/src/iter/traits/iterator.rs
index d957a7527cf..9a9a844f41b 100644
--- a/library/core/src/iter/traits/iterator.rs
+++ b/library/core/src/iter/traits/iterator.rs
@@ -1,5 +1,5 @@
use crate::cmp::{self, Ordering};
-use crate::ops::{ControlFlow, Try};
+use crate::ops::{ChangeOutputType, ControlFlow, FromResidual, Residual, Try};
use super::super::TrustedRandomAccessNoCoerce;
use super::super::{Chain, Cloned, Copied, Cycle, Enumerate, Filter, FilterMap, Fuse};
@@ -249,9 +249,6 @@ pub trait Iterator {
/// Calling `advance_by(0)` can do meaningful work, for example [`Flatten`]
/// can advance its outer iterator until it finds an inner iterator that is not empty, which
/// then often allows it to return a more accurate `size_hint()` than in its initial state.
- /// `advance_by(0)` may either return `Ok()` or `Err(0)`. The former conveys no information
- /// whether the iterator is or is not exhausted, the latter can be treated as if [`next`]
- /// had returned `None`. Replacing a `Err(0)` with `Ok` is only correct for `n = 0`.
///
/// [`Flatten`]: crate::iter::Flatten
/// [`next`]: Iterator::next
@@ -461,8 +458,10 @@ pub trait Iterator {
/// In other words, it zips two iterators together, into a single one.
///
/// If either iterator returns [`None`], [`next`] from the zipped iterator
- /// will return [`None`]. If the first iterator returns [`None`], `zip` will
- /// short-circuit and `next` will not be called on the second iterator.
+ /// will return [`None`].
+ /// If the zipped iterator has no more elements to return then each further attempt to advance
+ /// it will first try to advance the first iterator at most one time and if it still yielded an item
+ /// try to advance the second iterator at most one time.
///
/// # Examples
///
@@ -1024,6 +1023,7 @@ pub trait Iterator {
/// assert_eq!(iter.next(), None);
/// ```
#[inline]
+ #[doc(alias = "drop_while")]
#[stable(feature = "rust1", since = "1.0.0")]
fn skip_while<P>(self, predicate: P) -> SkipWhile<Self, P>
where
@@ -2216,6 +2216,86 @@ pub trait Iterator {
Some(self.fold(first, f))
}
+ /// Reduces the elements to a single one by repeatedly applying a reducing operation. If the
+ /// closure returns a failure, the failure is propagated back to the caller immediately.
+ ///
+ /// The return type of this method depends on the return type of the closure. If the closure
+ /// returns `Result<Self::Item, E>`, then this function will return `Result<Option<Self::Item>,
+ /// E>`. If the closure returns `Option<Self::Item>`, then this function will return
+ /// `Option<Option<Self::Item>>`.
+ ///
+ /// When called on an empty iterator, this function will return either `Some(None)` or
+ /// `Ok(None)` depending on the type of the provided closure.
+ ///
+ /// For iterators with at least one element, this is essentially the same as calling
+ /// [`try_fold()`] with the first element of the iterator as the initial accumulator value.
+ ///
+ /// [`try_fold()`]: Iterator::try_fold
+ ///
+ /// # Examples
+ ///
+ /// Safely calculate the sum of a series of numbers:
+ ///
+ /// ```
+ /// #![feature(iterator_try_reduce)]
+ ///
+ /// let numbers: Vec<usize> = vec![10, 20, 5, 23, 0];
+ /// let sum = numbers.into_iter().try_reduce(|x, y| x.checked_add(y));
+ /// assert_eq!(sum, Some(Some(58)));
+ /// ```
+ ///
+ /// Determine when a reduction short circuited:
+ ///
+ /// ```
+ /// #![feature(iterator_try_reduce)]
+ ///
+ /// let numbers = vec![1, 2, 3, usize::MAX, 4, 5];
+ /// let sum = numbers.into_iter().try_reduce(|x, y| x.checked_add(y));
+ /// assert_eq!(sum, None);
+ /// ```
+ ///
+ /// Determine when a reduction was not performed because there are no elements:
+ ///
+ /// ```
+ /// #![feature(iterator_try_reduce)]
+ ///
+ /// let numbers: Vec<usize> = Vec::new();
+ /// let sum = numbers.into_iter().try_reduce(|x, y| x.checked_add(y));
+ /// assert_eq!(sum, Some(None));
+ /// ```
+ ///
+ /// Use a [`Result`] instead of an [`Option`]:
+ ///
+ /// ```
+ /// #![feature(iterator_try_reduce)]
+ ///
+ /// let numbers = vec!["1", "2", "3", "4", "5"];
+ /// let max: Result<Option<_>, <usize as std::str::FromStr>::Err> =
+ /// numbers.into_iter().try_reduce(|x, y| {
+ /// if x.parse::<usize>()? > y.parse::<usize>()? { Ok(x) } else { Ok(y) }
+ /// });
+ /// assert_eq!(max, Ok(Some("5")));
+ /// ```
+ #[inline]
+ #[unstable(feature = "iterator_try_reduce", reason = "new API", issue = "87053")]
+ fn try_reduce<F, R>(&mut self, f: F) -> ChangeOutputType<R, Option<R::Output>>
+ where
+ Self: Sized,
+ F: FnMut(Self::Item, Self::Item) -> R,
+ R: Try<Output = Self::Item>,
+ R::Residual: Residual<Option<Self::Item>>,
+ {
+ let first = match self.next() {
+ Some(i) => i,
+ None => return Try::from_output(None),
+ };
+
+ match self.try_fold(first, f).branch() {
+ ControlFlow::Break(r) => FromResidual::from_residual(r),
+ ControlFlow::Continue(i) => Try::from_output(Some(i)),
+ }
+ }
+
/// Tests if every element of the iterator matches a predicate.
///
/// `all()` takes a closure that returns `true` or `false`. It applies
@@ -2418,6 +2498,10 @@ pub trait Iterator {
/// Applies function to the elements of iterator and returns
/// the first true result or the first error.
///
+ /// The return type of this method depends on the return type of the closure.
+ /// If you return `Result<bool, E>` from the closure, you'll get a `Result<Option<Self::Item>; E>`.
+ /// If you return `Option<bool>` from the closure, you'll get an `Option<Option<Self::Item>>`.
+ ///
/// # Examples
///
/// ```
@@ -2435,32 +2519,48 @@ pub trait Iterator {
/// let result = a.iter().try_find(|&&s| is_my_num(s, 5));
/// assert!(result.is_err());
/// ```
+ ///
+ /// This also supports other types which implement `Try`, not just `Result`.
+ /// ```
+ /// #![feature(try_find)]
+ ///
+ /// use std::num::NonZeroU32;
+ /// let a = [3, 5, 7, 4, 9, 0, 11];
+ /// let result = a.iter().try_find(|&&x| NonZeroU32::new(x).map(|y| y.is_power_of_two()));
+ /// assert_eq!(result, Some(Some(&4)));
+ /// let result = a.iter().take(3).try_find(|&&x| NonZeroU32::new(x).map(|y| y.is_power_of_two()));
+ /// assert_eq!(result, Some(None));
+ /// let result = a.iter().rev().try_find(|&&x| NonZeroU32::new(x).map(|y| y.is_power_of_two()));
+ /// assert_eq!(result, None);
+ /// ```
#[inline]
#[unstable(feature = "try_find", reason = "new API", issue = "63178")]
- fn try_find<F, R, E>(&mut self, f: F) -> Result<Option<Self::Item>, E>
+ fn try_find<F, R>(&mut self, f: F) -> ChangeOutputType<R, Option<Self::Item>>
where
Self: Sized,
F: FnMut(&Self::Item) -> R,
R: Try<Output = bool>,
- // FIXME: This bound is rather strange, but means minimal breakage on nightly.
- // See #85115 for the issue tracking a holistic solution for this and try_map.
- R: Try<Residual = Result<crate::convert::Infallible, E>>,
+ R::Residual: Residual<Option<Self::Item>>,
{
#[inline]
- fn check<F, T, R, E>(mut f: F) -> impl FnMut((), T) -> ControlFlow<Result<T, E>>
+ fn check<I, V, R>(
+ mut f: impl FnMut(&I) -> V,
+ ) -> impl FnMut((), I) -> ControlFlow<R::TryType>
where
- F: FnMut(&T) -> R,
- R: Try<Output = bool>,
- R: Try<Residual = Result<crate::convert::Infallible, E>>,
+ V: Try<Output = bool, Residual = R>,
+ R: Residual<Option<I>>,
{
move |(), x| match f(&x).branch() {
ControlFlow::Continue(false) => ControlFlow::CONTINUE,
- ControlFlow::Continue(true) => ControlFlow::Break(Ok(x)),
- ControlFlow::Break(Err(x)) => ControlFlow::Break(Err(x)),
+ ControlFlow::Continue(true) => ControlFlow::Break(Try::from_output(Some(x))),
+ ControlFlow::Break(r) => ControlFlow::Break(FromResidual::from_residual(r)),
}
}
- self.try_fold((), check(f)).break_value().transpose()
+ match self.try_fold((), check(f)) {
+ ControlFlow::Break(x) => x,
+ ControlFlow::Continue(()) => Try::from_output(None),
+ }
}
/// Searches for an element in an iterator, returning its index.
@@ -2928,7 +3028,8 @@ pub trait Iterator {
///
/// Instead of stopping at [`None`], the iterator will instead start again,
/// from the beginning. After iterating again, it will start at the
- /// beginning again. And again. And again. Forever.
+ /// beginning again. And again. And again. Forever. Note that in case the
+ /// original iterator is empty, the resulting iterator will also be empty.
///
/// # Examples
///
diff --git a/library/core/src/lib.rs b/library/core/src/lib.rs
index 4a64e2e2d10..67f77f14a6e 100644
--- a/library/core/src/lib.rs
+++ b/library/core/src/lib.rs
@@ -101,7 +101,7 @@
#![feature(const_align_of_val)]
#![feature(const_alloc_layout)]
#![feature(const_arguments_as_str)]
-#![feature(const_assert_type)]
+#![feature(const_array_into_iter_constructors)]
#![feature(const_bigint_helper_methods)]
#![feature(const_caller_location)]
#![feature(const_cell_into_inner)]
@@ -112,18 +112,21 @@
#![feature(const_float_classify)]
#![feature(const_fmt_arguments_new)]
#![feature(const_heap)]
+#![feature(const_convert)]
#![feature(const_inherent_unchecked_arith)]
#![feature(const_int_unchecked_arith)]
#![feature(const_intrinsic_copy)]
#![feature(const_intrinsic_forget)]
#![feature(const_likely)]
-#![feature(const_maybe_uninit_as_ptr)]
+#![feature(const_maybe_uninit_as_mut_ptr)]
#![feature(const_maybe_uninit_assume_init)]
#![feature(const_num_from_num)]
#![feature(const_ops)]
#![feature(const_option)]
+#![feature(const_option_ext)]
#![feature(const_pin)]
#![feature(const_replace)]
+#![feature(const_ptr_is_null)]
#![feature(const_ptr_offset)]
#![feature(const_ptr_offset_from)]
#![feature(const_ptr_read)]
@@ -138,7 +141,8 @@
#![feature(const_type_id)]
#![feature(const_type_name)]
#![feature(const_default_impls)]
-#![feature(duration_consts_2)]
+#![feature(duration_consts_float)]
+#![feature(maybe_uninit_uninit_array)]
#![feature(ptr_metadata)]
#![feature(slice_ptr_get)]
#![feature(str_internals)]
@@ -150,7 +154,6 @@
#![feature(abi_unadjusted)]
#![feature(allow_internal_unsafe)]
#![feature(allow_internal_unstable)]
-#![feature(asm)]
#![feature(associated_type_bounds)]
#![feature(auto_traits)]
#![feature(cfg_target_has_atomic)]
@@ -160,12 +163,12 @@
#![feature(const_impl_trait)]
#![feature(const_mut_refs)]
#![feature(const_precise_live_drops)]
-#![cfg_attr(bootstrap, feature(const_raw_ptr_deref))]
#![feature(const_refs_to_cell)]
#![feature(decl_macro)]
+#![feature(derive_default_enum)]
#![feature(doc_cfg)]
#![feature(doc_notable_trait)]
-#![feature(doc_primitive)]
+#![feature(rustdoc_internals)]
#![feature(exhaustive_patterns)]
#![feature(doc_cfg_hide)]
#![feature(extern_types)]
@@ -197,7 +200,7 @@
#![feature(try_blocks)]
#![feature(unboxed_closures)]
#![feature(unsized_fn_params)]
-#![cfg_attr(not(bootstrap), feature(asm_const))]
+#![feature(asm_const)]
//
// Target features:
#![feature(aarch64_target_feature)]
@@ -370,26 +373,14 @@ pub mod arch {
pub use crate::core_arch::arch::*;
/// Inline assembly.
- ///
- /// Read the [unstable book] for the usage.
- ///
- /// [unstable book]: ../../unstable-book/library-features/asm.html
- #[unstable(
- feature = "asm",
- issue = "72016",
- reason = "inline assembly is not stable enough for use and is subject to change"
- )]
+ #[stable(feature = "asm", since = "1.59.0")]
#[rustc_builtin_macro]
pub macro asm("assembly template", $(operands,)* $(options($(option),*))?) {
/* compiler built-in */
}
/// Module-level inline assembly.
- #[unstable(
- feature = "global_asm",
- issue = "35119",
- reason = "`global_asm!` is not stable enough for use and is subject to change"
- )]
+ #[stable(feature = "global_asm", since = "1.59.0")]
#[rustc_builtin_macro]
pub macro global_asm("assembly template", $(operands,)* $(options($(option),*))?) {
/* compiler built-in */
@@ -407,13 +398,11 @@ pub mod arch {
#[allow(rustdoc::bare_urls)]
#[unstable(feature = "portable_simd", issue = "86656")]
#[cfg(not(all(miri, doctest)))] // Miri does not support all SIMD intrinsics
-#[cfg(not(bootstrap))]
mod core_simd;
#[doc = include_str!("../../portable-simd/crates/core_simd/src/core_simd_docs.md")]
#[unstable(feature = "portable_simd", issue = "86656")]
#[cfg(not(all(miri, doctest)))] // Miri does not support all SIMD intrinsics
-#[cfg(not(bootstrap))]
pub mod simd {
#[unstable(feature = "portable_simd", issue = "86656")]
pub use crate::core_simd::simd::*;
diff --git a/library/core/src/macros/mod.rs b/library/core/src/macros/mod.rs
index 993ae723229..b18508186a6 100644
--- a/library/core/src/macros/mod.rs
+++ b/library/core/src/macros/mod.rs
@@ -967,6 +967,34 @@ pub(crate) mod builtin {
($($e:ident),+ $(,)?) => {{ /* compiler built-in */ }};
}
+ /// Concatenates literals into a byte slice.
+ ///
+ /// This macro takes any number of comma-separated literals, and concatenates them all into
+ /// one, yielding an expression of type `&[u8, _]`, which represents all of the literals
+ /// concatenated left-to-right. The literals passed can be any combination of:
+ ///
+ /// - byte literals (`b'r'`)
+ /// - byte strings (`b"Rust"`)
+ /// - arrays of bytes/numbers (`[b'A', 66, b'C']`)
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// #![feature(concat_bytes)]
+ ///
+ /// # fn main() {
+ /// let s: &[u8; 6] = concat_bytes!(b'A', b"BC", [68, b'E', 70]);
+ /// assert_eq!(s, b"ABCDEF");
+ /// # }
+ /// ```
+ #[cfg(not(bootstrap))]
+ #[unstable(feature = "concat_bytes", issue = "87555")]
+ #[rustc_builtin_macro]
+ #[macro_export]
+ macro_rules! concat_bytes {
+ ($($e:literal),+ $(,)?) => {{ /* compiler built-in */ }};
+ }
+
/// Concatenates literals into a static string slice.
///
/// This macro takes any number of comma-separated literals, yielding an
diff --git a/library/core/src/mem/manually_drop.rs b/library/core/src/mem/manually_drop.rs
index 20b6453990d..f577f102e8d 100644
--- a/library/core/src/mem/manually_drop.rs
+++ b/library/core/src/mem/manually_drop.rs
@@ -64,7 +64,7 @@ impl<T> ManuallyDrop<T> {
/// ```
#[must_use = "if you don't need the wrapper, you can use `mem::forget` instead"]
#[stable(feature = "manually_drop", since = "1.20.0")]
- #[rustc_const_stable(feature = "const_manually_drop", since = "1.36.0")]
+ #[rustc_const_stable(feature = "const_manually_drop", since = "1.32.0")]
#[inline(always)]
pub const fn new(value: T) -> ManuallyDrop<T> {
ManuallyDrop { value }
@@ -82,7 +82,7 @@ impl<T> ManuallyDrop<T> {
/// let _: Box<()> = ManuallyDrop::into_inner(x); // This drops the `Box`.
/// ```
#[stable(feature = "manually_drop", since = "1.20.0")]
- #[rustc_const_stable(feature = "const_manually_drop", since = "1.36.0")]
+ #[rustc_const_stable(feature = "const_manually_drop", since = "1.32.0")]
#[inline(always)]
pub const fn into_inner(slot: ManuallyDrop<T>) -> T {
slot.value
diff --git a/library/core/src/mem/maybe_uninit.rs b/library/core/src/mem/maybe_uninit.rs
index 624e8795502..3b0e4a31db1 100644
--- a/library/core/src/mem/maybe_uninit.rs
+++ b/library/core/src/mem/maybe_uninit.rs
@@ -394,10 +394,11 @@ impl<T> MaybeUninit<T> {
/// // This is undefined behavior. ⚠️
/// ```
#[stable(feature = "maybe_uninit", since = "1.36.0")]
+ #[rustc_const_unstable(feature = "const_maybe_uninit_zeroed", issue = "91850")]
#[must_use]
#[inline]
#[rustc_diagnostic_item = "maybe_uninit_zeroed"]
- pub fn zeroed() -> MaybeUninit<T> {
+ pub const fn zeroed() -> MaybeUninit<T> {
let mut u = MaybeUninit::<T>::uninit();
// SAFETY: `u.as_mut_ptr()` points to allocated memory.
unsafe {
@@ -528,7 +529,7 @@ impl<T> MaybeUninit<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")]
+ #[rustc_const_stable(feature = "const_maybe_uninit_as_ptr", since = "1.59.0")]
#[inline(always)]
pub const fn as_ptr(&self) -> *const T {
// `MaybeUninit` and `ManuallyDrop` are both `repr(transparent)` so we can cast the pointer.
@@ -567,7 +568,7 @@ impl<T> MaybeUninit<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")]
+ #[rustc_const_unstable(feature = "const_maybe_uninit_as_mut_ptr", issue = "75251")]
#[inline(always)]
pub const fn as_mut_ptr(&mut self) -> *mut T {
// `MaybeUninit` and `ManuallyDrop` are both `repr(transparent)` so we can cast the pointer.
@@ -620,7 +621,7 @@ impl<T> MaybeUninit<T> {
/// // `x` had not been initialized yet, so this last line caused undefined behavior. ⚠️
/// ```
#[stable(feature = "maybe_uninit", since = "1.36.0")]
- #[rustc_const_unstable(feature = "const_maybe_uninit_assume_init", issue = "none")]
+ #[rustc_const_stable(feature = "const_maybe_uninit_assume_init", since = "1.59.0")]
#[inline(always)]
#[rustc_diagnostic_item = "assume_init"]
#[track_caller]
@@ -788,7 +789,7 @@ impl<T> MaybeUninit<T> {
/// }
/// ```
#[stable(feature = "maybe_uninit_ref", since = "1.55.0")]
- #[rustc_const_unstable(feature = "const_maybe_uninit_assume_init", issue = "none")]
+ #[rustc_const_stable(feature = "const_maybe_uninit_assume_init", since = "1.59.0")]
#[inline(always)]
pub const unsafe fn assume_init_ref(&self) -> &T {
// SAFETY: the caller must guarantee that `self` is initialized.
@@ -968,11 +969,11 @@ impl<T> MaybeUninit<T> {
///
/// [`assume_init_ref`]: MaybeUninit::assume_init_ref
#[unstable(feature = "maybe_uninit_slice", issue = "63569")]
- #[rustc_const_unstable(feature = "const_maybe_uninit_assume_init", issue = "none")]
+ #[rustc_const_unstable(feature = "maybe_uninit_slice", issue = "63569")]
#[inline(always)]
pub const unsafe fn slice_assume_init_ref(slice: &[Self]) -> &[T] {
- // SAFETY: casting slice to a `*const [T]` is safe since the caller guarantees that
- // `slice` is initialized, and`MaybeUninit` is guaranteed to have the same layout as `T`.
+ // SAFETY: casting `slice` to a `*const [T]` is safe since the caller guarantees that
+ // `slice` is initialized, and `MaybeUninit` is guaranteed to have the same layout as `T`.
// The pointer obtained is valid since it refers to memory owned by `slice` which is a
// reference and thus guaranteed to be valid for reads.
unsafe { &*(slice as *const [Self] as *const [T]) }
diff --git a/library/core/src/num/dec2flt/fpu.rs b/library/core/src/num/dec2flt/fpu.rs
index 24492d9a1dd..ec5fa45fdad 100644
--- a/library/core/src/num/dec2flt/fpu.rs
+++ b/library/core/src/num/dec2flt/fpu.rs
@@ -10,6 +10,7 @@ pub use fpu_precision::set_precision;
// computations are performed in the desired precision.
#[cfg(all(target_arch = "x86", not(target_feature = "sse2")))]
mod fpu_precision {
+ use core::arch::asm;
use core::mem::size_of;
/// A structure used to preserve the original value of the FPU control word, so that it can be
diff --git a/library/core/src/num/dec2flt/number.rs b/library/core/src/num/dec2flt/number.rs
index 36432718af4..405f7e7b613 100644
--- a/library/core/src/num/dec2flt/number.rs
+++ b/library/core/src/num/dec2flt/number.rs
@@ -40,7 +40,7 @@ impl Number {
&& !self.many_digits
}
- /// The fast path algorithmn using machine-sized integers and floats.
+ /// The fast path algorithm using machine-sized integers and floats.
///
/// This is extracted into a separate function so that it can be attempted before constructing
/// a Decimal. This only works if both the mantissa and the exponent
diff --git a/library/core/src/num/fmt.rs b/library/core/src/num/fmt.rs
index 578288bda25..ed61197157b 100644
--- a/library/core/src/num/fmt.rs
+++ b/library/core/src/num/fmt.rs
@@ -1,4 +1,4 @@
-//! Shared utilties used by both float and integer formatting.
+//! Shared utilities used by both float and integer formatting.
#![doc(hidden)]
#![unstable(
feature = "numfmt",
diff --git a/library/core/src/num/nonzero.rs b/library/core/src/num/nonzero.rs
index 7708094e1fc..8f895c33a63 100644
--- a/library/core/src/num/nonzero.rs
+++ b/library/core/src/num/nonzero.rs
@@ -915,15 +915,13 @@ macro_rules! nonzero_unsigned_is_power_of_two {
/// Basic usage:
///
/// ```
- /// #![feature(nonzero_is_power_of_two)]
- ///
#[doc = concat!("let eight = std::num::", stringify!($Ty), "::new(8).unwrap();")]
/// assert!(eight.is_power_of_two());
#[doc = concat!("let ten = std::num::", stringify!($Ty), "::new(10).unwrap();")]
/// assert!(!ten.is_power_of_two());
/// ```
#[must_use]
- #[unstable(feature = "nonzero_is_power_of_two", issue = "81106")]
+ #[stable(feature = "nonzero_is_power_of_two", since = "1.59.0")]
#[inline]
pub const fn is_power_of_two(self) -> bool {
// LLVM 11 normalizes `unchecked_sub(x, 1) & x == 0` to the implementation seen here.
diff --git a/library/core/src/num/saturating.rs b/library/core/src/num/saturating.rs
index ba81f3f9fd6..d9b14c82e96 100644
--- a/library/core/src/num/saturating.rs
+++ b/library/core/src/num/saturating.rs
@@ -628,7 +628,7 @@ macro_rules! saturating_int_impl {
/// ```
#[inline]
#[unstable(feature = "saturating_int_impl", issue = "87920")]
- #[rustc_const_stable(feature = "const_reverse_bits", since = "1.37.0")]
+ #[rustc_const_unstable(feature = "saturating_int_impl", issue = "87920")]
#[must_use = "this returns the result of the operation, \
without modifying the original"]
pub const fn reverse_bits(self) -> Self {
diff --git a/library/core/src/num/uint_macros.rs b/library/core/src/num/uint_macros.rs
index d54b4116e98..3cc454baf35 100644
--- a/library/core/src/num/uint_macros.rs
+++ b/library/core/src/num/uint_macros.rs
@@ -2223,7 +2223,7 @@ macro_rules! uint_impl {
/// ```
#[unstable(feature = "wrapping_next_power_of_two", issue = "32463",
reason = "needs decision on wrapping behaviour")]
- #[rustc_const_stable(feature = "const_int_pow", since = "1.50.0")]
+ #[rustc_const_unstable(feature = "wrapping_next_power_of_two", issue = "32463")]
#[must_use = "this returns the result of the operation, \
without modifying the original"]
pub const fn wrapping_next_power_of_two(self) -> Self {
diff --git a/library/core/src/ops/control_flow.rs b/library/core/src/ops/control_flow.rs
index b0c15898a1f..10a24a545d3 100644
--- a/library/core/src/ops/control_flow.rs
+++ b/library/core/src/ops/control_flow.rs
@@ -123,6 +123,11 @@ impl<B, C> ops::FromResidual for ControlFlow<B, C> {
}
}
+#[unstable(feature = "try_trait_v2_residual", issue = "91285")]
+impl<B, C> ops::Residual<C> for ControlFlow<B, convert::Infallible> {
+ type TryType = ControlFlow<B, C>;
+}
+
impl<B, C> ControlFlow<B, C> {
/// Returns `true` if this is a `Break` variant.
///
@@ -136,7 +141,7 @@ impl<B, C> ControlFlow<B, C> {
/// assert!(!ControlFlow::<String, i32>::Continue(3).is_break());
/// ```
#[inline]
- #[unstable(feature = "control_flow_enum", reason = "new API", issue = "75744")]
+ #[stable(feature = "control_flow_enum_is", since = "1.59.0")]
pub fn is_break(&self) -> bool {
matches!(*self, ControlFlow::Break(_))
}
@@ -153,7 +158,7 @@ impl<B, C> ControlFlow<B, C> {
/// assert!(ControlFlow::<String, i32>::Continue(3).is_continue());
/// ```
#[inline]
- #[unstable(feature = "control_flow_enum", reason = "new API", issue = "75744")]
+ #[stable(feature = "control_flow_enum_is", since = "1.59.0")]
pub fn is_continue(&self) -> bool {
matches!(*self, ControlFlow::Continue(_))
}
diff --git a/library/core/src/ops/generator.rs b/library/core/src/ops/generator.rs
index 4f23620b92b..52a2e464e3a 100644
--- a/library/core/src/ops/generator.rs
+++ b/library/core/src/ops/generator.rs
@@ -82,6 +82,7 @@ pub trait Generator<R = ()> {
/// `return` statement or implicitly as the last expression of a generator
/// literal. For example futures would use this as `Result<T, E>` as it
/// represents a completed future.
+ #[lang = "generator_return"]
type Return;
/// Resumes the execution of this generator.
diff --git a/library/core/src/ops/mod.rs b/library/core/src/ops/mod.rs
index bd7feb8b183..9d1e7e81b0e 100644
--- a/library/core/src/ops/mod.rs
+++ b/library/core/src/ops/mod.rs
@@ -181,9 +181,17 @@ pub use self::range::{Range, RangeFrom, RangeFull, RangeTo};
#[stable(feature = "inclusive_range", since = "1.26.0")]
pub use self::range::{Bound, RangeBounds, RangeInclusive, RangeToInclusive};
+#[unstable(feature = "one_sided_range", issue = "69780")]
+pub use self::range::OneSidedRange;
+
#[unstable(feature = "try_trait_v2", issue = "84277")]
pub use self::try_trait::{FromResidual, Try};
+#[unstable(feature = "try_trait_v2_residual", issue = "91285")]
+pub use self::try_trait::Residual;
+
+pub(crate) use self::try_trait::{ChangeOutputType, NeverShortCircuit};
+
#[unstable(feature = "generator_trait", issue = "43122")]
pub use self::generator::{Generator, GeneratorState};
diff --git a/library/core/src/ops/range.rs b/library/core/src/ops/range.rs
index b74ba92c76e..11367220678 100644
--- a/library/core/src/ops/range.rs
+++ b/library/core/src/ops/range.rs
@@ -971,3 +971,21 @@ impl<T> RangeBounds<T> for RangeToInclusive<&T> {
Included(self.end)
}
}
+
+/// `OneSidedRange` is implemented for built-in range types that are unbounded
+/// on one side. For example, `a..`, `..b` and `..=c` implement `OneSidedRange`,
+/// but `..`, `d..e`, and `f..=g` do not.
+///
+/// Types that implement `OneSidedRange<T>` must return `Bound::Unbounded`
+/// from one of `RangeBounds::start_bound` or `RangeBounds::end_bound`.
+#[unstable(feature = "one_sided_range", issue = "69780")]
+pub trait OneSidedRange<T: ?Sized>: RangeBounds<T> {}
+
+#[unstable(feature = "one_sided_range", issue = "69780")]
+impl<T> OneSidedRange<T> for RangeTo<T> where Self: RangeBounds<T> {}
+
+#[unstable(feature = "one_sided_range", issue = "69780")]
+impl<T> OneSidedRange<T> for RangeFrom<T> where Self: RangeBounds<T> {}
+
+#[unstable(feature = "one_sided_range", issue = "69780")]
+impl<T> OneSidedRange<T> for RangeToInclusive<T> where Self: RangeBounds<T> {}
diff --git a/library/core/src/ops/try_trait.rs b/library/core/src/ops/try_trait.rs
index 6bdcda775ee..6a414ae8c4b 100644
--- a/library/core/src/ops/try_trait.rs
+++ b/library/core/src/ops/try_trait.rs
@@ -115,15 +115,14 @@ use crate::ops::ControlFlow;
#[unstable(feature = "try_trait_v2", issue = "84277")]
#[rustc_on_unimplemented(
on(
- all(from_method = "from_output", from_desugaring = "TryBlock"),
+ all(from_desugaring = "TryBlock"),
message = "a `try` block must return `Result` or `Option` \
(or another type that implements `{Try}`)",
label = "could not wrap the final value of the block as `{Self}` doesn't implement `Try`",
),
on(
- all(from_method = "branch", from_desugaring = "QuestionMark"),
- message = "the `?` operator can only be applied to values \
- that implement `{Try}`",
+ all(from_desugaring = "QuestionMark"),
+ message = "the `?` operator can only be applied to values that implement `{Try}`",
label = "the `?` operator cannot be applied to type `{Self}`"
)
)]
@@ -226,7 +225,6 @@ pub trait Try: FromResidual {
#[rustc_on_unimplemented(
on(
all(
- from_method = "from_residual",
from_desugaring = "QuestionMark",
_Self = "std::result::Result<T, E>",
R = "std::option::Option<std::convert::Infallible>"
@@ -238,7 +236,6 @@ pub trait Try: FromResidual {
),
on(
all(
- from_method = "from_residual",
from_desugaring = "QuestionMark",
_Self = "std::result::Result<T, E>",
),
@@ -252,7 +249,6 @@ pub trait Try: FromResidual {
),
on(
all(
- from_method = "from_residual",
from_desugaring = "QuestionMark",
_Self = "std::option::Option<T>",
R = "std::result::Result<T, E>",
@@ -264,7 +260,6 @@ pub trait Try: FromResidual {
),
on(
all(
- from_method = "from_residual",
from_desugaring = "QuestionMark",
_Self = "std::option::Option<T>",
),
@@ -277,7 +272,6 @@ pub trait Try: FromResidual {
),
on(
all(
- from_method = "from_residual",
from_desugaring = "QuestionMark",
_Self = "std::ops::ControlFlow<B, C>",
R = "std::ops::ControlFlow<B, C>",
@@ -290,7 +284,6 @@ pub trait Try: FromResidual {
),
on(
all(
- from_method = "from_residual",
from_desugaring = "QuestionMark",
_Self = "std::ops::ControlFlow<B, C>",
// `R` is not a `ControlFlow`, as that case was matched previously
@@ -301,10 +294,7 @@ pub trait Try: FromResidual {
enclosing_scope = "this function returns a `ControlFlow`",
),
on(
- all(
- from_method = "from_residual",
- from_desugaring = "QuestionMark"
- ),
+ all(from_desugaring = "QuestionMark"),
message = "the `?` operator can only be used in {ItemContext} \
that returns `Result` or `Option` \
(or another type that implements `{FromResidual}`)",
@@ -338,3 +328,61 @@ pub trait FromResidual<R = <Self as Try>::Residual> {
#[unstable(feature = "try_trait_v2", issue = "84277")]
fn from_residual(residual: R) -> Self;
}
+
+/// Allows retrieving the canonical type implementing [`Try`] that has this type
+/// as its residual and allows it to hold an `O` as its output.
+///
+/// If you think of the `Try` trait as splitting a type into its [`Try::Output`]
+/// and [`Try::Residual`] components, this allows putting them back together.
+///
+/// For example,
+/// `Result<T, E>: Try<Output = T, Residual = Result<Infallible, E>>`,
+/// and in the other direction,
+/// `<Result<Infallible, E> as Residual<T>>::TryType = Result<T, E>`.
+#[unstable(feature = "try_trait_v2_residual", issue = "91285")]
+pub trait Residual<O> {
+ /// The "return" type of this meta-function.
+ #[unstable(feature = "try_trait_v2_residual", issue = "91285")]
+ type TryType: Try<Output = O, Residual = Self>;
+}
+
+#[unstable(feature = "pub_crate_should_not_need_unstable_attr", issue = "none")]
+pub(crate) type ChangeOutputType<T, V> = <<T as Try>::Residual as Residual<V>>::TryType;
+
+/// An adapter for implementing non-try methods via the `Try` implementation.
+///
+/// Conceptually the same as `Result<T, !>`, but requiring less work in trait
+/// solving and inhabited-ness checking and such, by being an obvious newtype
+/// and not having `From` bounds lying around.
+///
+/// Not currently planned to be exposed publicly, so just `pub(crate)`.
+#[repr(transparent)]
+pub(crate) struct NeverShortCircuit<T>(pub T);
+
+pub(crate) enum NeverShortCircuitResidual {}
+
+impl<T> Try for NeverShortCircuit<T> {
+ type Output = T;
+ type Residual = NeverShortCircuitResidual;
+
+ #[inline]
+ fn branch(self) -> ControlFlow<NeverShortCircuitResidual, T> {
+ ControlFlow::Continue(self.0)
+ }
+
+ #[inline]
+ fn from_output(x: T) -> Self {
+ NeverShortCircuit(x)
+ }
+}
+
+impl<T> FromResidual for NeverShortCircuit<T> {
+ #[inline]
+ fn from_residual(never: NeverShortCircuitResidual) -> Self {
+ match never {}
+ }
+}
+
+impl<T> Residual<T> for NeverShortCircuitResidual {
+ type TryType = NeverShortCircuit<T>;
+}
diff --git a/library/core/src/option.rs b/library/core/src/option.rs
index baf9948857b..8969c6f6171 100644
--- a/library/core/src/option.rs
+++ b/library/core/src/option.rs
@@ -512,11 +512,11 @@ use crate::{
#[rustc_diagnostic_item = "Option"]
#[stable(feature = "rust1", since = "1.0.0")]
pub enum Option<T> {
- /// No value
+ /// No value.
#[lang = "None"]
#[stable(feature = "rust1", since = "1.0.0")]
None,
- /// Some value `T`
+ /// Some value of type `T`.
#[lang = "Some"]
#[stable(feature = "rust1", since = "1.0.0")]
Some(#[stable(feature = "rust1", since = "1.0.0")] T),
@@ -589,12 +589,13 @@ impl<T> Option<T> {
#[must_use]
#[inline]
#[unstable(feature = "option_result_contains", issue = "62358")]
- pub fn contains<U>(&self, x: &U) -> bool
+ #[rustc_const_unstable(feature = "const_option_ext", issue = "91930")]
+ pub const fn contains<U>(&self, x: &U) -> bool
where
- U: PartialEq<T>,
+ U: ~const PartialEq<T>,
{
match self {
- Some(y) => x == y,
+ Some(y) => x.eq(y),
None => false,
}
}
@@ -660,10 +661,14 @@ impl<T> Option<T> {
#[inline]
#[must_use]
#[stable(feature = "pin", since = "1.33.0")]
- pub fn as_pin_ref(self: Pin<&Self>) -> Option<Pin<&T>> {
- // SAFETY: `x` is guaranteed to be pinned because it comes from `self`
- // which is pinned.
- unsafe { Pin::get_ref(self).as_ref().map(|x| Pin::new_unchecked(x)) }
+ #[rustc_const_unstable(feature = "const_option_ext", issue = "91930")]
+ pub const fn as_pin_ref(self: Pin<&Self>) -> Option<Pin<&T>> {
+ match Pin::get_ref(self).as_ref() {
+ // SAFETY: `x` is guaranteed to be pinned because it comes from `self`
+ // which is pinned.
+ Some(x) => unsafe { Some(Pin::new_unchecked(x)) },
+ None => None,
+ }
}
/// Converts from <code>[Pin]<[&mut] Option\<T>></code> to <code>Option<[Pin]<[&mut] T>></code>.
@@ -672,10 +677,16 @@ impl<T> Option<T> {
#[inline]
#[must_use]
#[stable(feature = "pin", since = "1.33.0")]
- pub fn as_pin_mut(self: Pin<&mut Self>) -> Option<Pin<&mut T>> {
+ #[rustc_const_unstable(feature = "const_option_ext", issue = "91930")]
+ pub const fn as_pin_mut(self: Pin<&mut Self>) -> Option<Pin<&mut T>> {
// SAFETY: `get_unchecked_mut` is never used to move the `Option` inside `self`.
// `x` is guaranteed to be pinned because it comes from `self` which is pinned.
- unsafe { Pin::get_unchecked_mut(self).as_mut().map(|x| Pin::new_unchecked(x)) }
+ unsafe {
+ match Pin::get_unchecked_mut(self).as_mut() {
+ Some(x) => Some(Pin::new_unchecked(x)),
+ None => None,
+ }
+ }
}
/////////////////////////////////////////////////////////////////////////
@@ -703,7 +714,8 @@ impl<T> Option<T> {
#[inline]
#[track_caller]
#[stable(feature = "rust1", since = "1.0.0")]
- pub fn expect(self, msg: &str) -> T {
+ #[rustc_const_unstable(feature = "const_option", issue = "67441")]
+ pub const fn expect(self, msg: &str) -> T {
match self {
Some(val) => val,
None => expect_failed(msg),
@@ -763,7 +775,11 @@ impl<T> Option<T> {
/// ```
#[inline]
#[stable(feature = "rust1", since = "1.0.0")]
- pub fn unwrap_or(self, default: T) -> T {
+ #[rustc_const_unstable(feature = "const_option_ext", issue = "91930")]
+ pub const fn unwrap_or(self, default: T) -> T
+ where
+ T: ~const Drop,
+ {
match self {
Some(x) => x,
None => default,
@@ -781,7 +797,12 @@ impl<T> Option<T> {
/// ```
#[inline]
#[stable(feature = "rust1", since = "1.0.0")]
- pub fn unwrap_or_else<F: FnOnce() -> T>(self, f: F) -> T {
+ #[rustc_const_unstable(feature = "const_option_ext", issue = "91930")]
+ pub const fn unwrap_or_else<F>(self, f: F) -> T
+ where
+ F: ~const FnOnce() -> T,
+ F: ~const Drop,
+ {
match self {
Some(x) => x,
None => f(),
@@ -811,7 +832,8 @@ impl<T> Option<T> {
#[inline]
#[track_caller]
#[stable(feature = "option_result_unwrap_unchecked", since = "1.58.0")]
- pub unsafe fn unwrap_unchecked(self) -> T {
+ #[rustc_const_unstable(feature = "const_option_ext", issue = "91930")]
+ pub const unsafe fn unwrap_unchecked(self) -> T {
debug_assert!(self.is_some());
match self {
Some(val) => val,
@@ -841,13 +863,48 @@ impl<T> Option<T> {
/// ```
#[inline]
#[stable(feature = "rust1", since = "1.0.0")]
- pub fn map<U, F: FnOnce(T) -> U>(self, f: F) -> Option<U> {
+ #[rustc_const_unstable(feature = "const_option_ext", issue = "91930")]
+ pub const fn map<U, F>(self, f: F) -> Option<U>
+ where
+ F: ~const FnOnce(T) -> U,
+ F: ~const Drop,
+ {
match self {
Some(x) => Some(f(x)),
None => None,
}
}
+ /// Calls the provided closure with a reference to the contained value (if [`Some`]).
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// #![feature(result_option_inspect)]
+ ///
+ /// let v = vec![1, 2, 3, 4, 5];
+ ///
+ /// // prints "got: 4"
+ /// let x: Option<&usize> = v.get(3).inspect(|x| println!("got: {}", x));
+ ///
+ /// // prints nothing
+ /// let x: Option<&usize> = v.get(5).inspect(|x| println!("got: {}", x));
+ /// ```
+ #[inline]
+ #[unstable(feature = "result_option_inspect", issue = "91345")]
+ #[rustc_const_unstable(feature = "const_option_ext", issue = "91930")]
+ pub const fn inspect<F>(self, f: F) -> Self
+ where
+ F: ~const FnOnce(&T),
+ F: ~const Drop,
+ {
+ if let Some(ref x) = self {
+ f(x);
+ }
+
+ self
+ }
+
/// Returns the provided default result (if none),
/// or applies a function to the contained value (if any).
///
@@ -868,7 +925,13 @@ impl<T> Option<T> {
/// ```
#[inline]
#[stable(feature = "rust1", since = "1.0.0")]
- pub fn map_or<U, F: FnOnce(T) -> U>(self, default: U, f: F) -> U {
+ #[rustc_const_unstable(feature = "const_option_ext", issue = "91930")]
+ pub const fn map_or<U, F>(self, default: U, f: F) -> U
+ where
+ F: ~const FnOnce(T) -> U,
+ F: ~const Drop,
+ U: ~const Drop,
+ {
match self {
Some(t) => f(t),
None => default,
@@ -891,7 +954,14 @@ impl<T> Option<T> {
/// ```
#[inline]
#[stable(feature = "rust1", since = "1.0.0")]
- pub fn map_or_else<U, D: FnOnce() -> U, F: FnOnce(T) -> U>(self, default: D, f: F) -> U {
+ #[rustc_const_unstable(feature = "const_option_ext", issue = "91930")]
+ pub const fn map_or_else<U, D, F>(self, default: D, f: F) -> U
+ where
+ D: ~const FnOnce() -> U,
+ D: ~const Drop,
+ F: ~const FnOnce(T) -> U,
+ F: ~const Drop,
+ {
match self {
Some(t) => f(t),
None => default(),
@@ -921,7 +991,11 @@ impl<T> Option<T> {
/// ```
#[inline]
#[stable(feature = "rust1", since = "1.0.0")]
- pub fn ok_or<E>(self, err: E) -> Result<T, E> {
+ #[rustc_const_unstable(feature = "const_option_ext", issue = "91930")]
+ pub const fn ok_or<E>(self, err: E) -> Result<T, E>
+ where
+ E: ~const Drop,
+ {
match self {
Some(v) => Ok(v),
None => Err(err),
@@ -946,7 +1020,12 @@ impl<T> Option<T> {
/// ```
#[inline]
#[stable(feature = "rust1", since = "1.0.0")]
- pub fn ok_or_else<E, F: FnOnce() -> E>(self, err: F) -> Result<T, E> {
+ #[rustc_const_unstable(feature = "const_option_ext", issue = "91930")]
+ pub const fn ok_or_else<E, F>(self, err: F) -> Result<T, E>
+ where
+ F: ~const FnOnce() -> E,
+ F: ~const Drop,
+ {
match self {
Some(v) => Ok(v),
None => Err(err()),
@@ -1023,7 +1102,12 @@ impl<T> Option<T> {
/// ```
#[inline]
#[stable(feature = "rust1", since = "1.0.0")]
- pub fn and<U>(self, optb: Option<U>) -> Option<U> {
+ #[rustc_const_unstable(feature = "const_option_ext", issue = "91930")]
+ pub const fn and<U>(self, optb: Option<U>) -> Option<U>
+ where
+ T: ~const Drop,
+ U: ~const Drop,
+ {
match self {
Some(_) => optb,
None => None,
@@ -1048,7 +1132,12 @@ impl<T> Option<T> {
/// ```
#[inline]
#[stable(feature = "rust1", since = "1.0.0")]
- pub fn and_then<U, F: FnOnce(T) -> Option<U>>(self, f: F) -> Option<U> {
+ #[rustc_const_unstable(feature = "const_option_ext", issue = "91930")]
+ pub const fn and_then<U, F>(self, f: F) -> Option<U>
+ where
+ F: ~const FnOnce(T) -> Option<U>,
+ F: ~const Drop,
+ {
match self {
Some(x) => f(x),
None => None,
@@ -1081,7 +1170,13 @@ impl<T> Option<T> {
/// [`Some(t)`]: Some
#[inline]
#[stable(feature = "option_filter", since = "1.27.0")]
- pub fn filter<P: FnOnce(&T) -> bool>(self, predicate: P) -> Self {
+ #[rustc_const_unstable(feature = "const_option_ext", issue = "91930")]
+ pub const fn filter<P>(self, predicate: P) -> Self
+ where
+ T: ~const Drop,
+ P: ~const FnOnce(&T) -> bool,
+ P: ~const Drop,
+ {
if let Some(x) = self {
if predicate(&x) {
return Some(x);
@@ -1119,9 +1214,13 @@ impl<T> Option<T> {
/// ```
#[inline]
#[stable(feature = "rust1", since = "1.0.0")]
- pub fn or(self, optb: Option<T>) -> Option<T> {
+ #[rustc_const_unstable(feature = "const_option_ext", issue = "91930")]
+ pub const fn or(self, optb: Option<T>) -> Option<T>
+ where
+ T: ~const Drop,
+ {
match self {
- Some(_) => self,
+ Some(x) => Some(x),
None => optb,
}
}
@@ -1141,9 +1240,14 @@ impl<T> Option<T> {
/// ```
#[inline]
#[stable(feature = "rust1", since = "1.0.0")]
- pub fn or_else<F: FnOnce() -> Option<T>>(self, f: F) -> Option<T> {
+ #[rustc_const_unstable(feature = "const_option_ext", issue = "91930")]
+ pub const fn or_else<F>(self, f: F) -> Option<T>
+ where
+ F: ~const FnOnce() -> Option<T>,
+ F: ~const Drop,
+ {
match self {
- Some(_) => self,
+ Some(x) => Some(x),
None => f(),
}
}
@@ -1171,7 +1275,11 @@ impl<T> Option<T> {
/// ```
#[inline]
#[stable(feature = "option_xor", since = "1.37.0")]
- pub fn xor(self, optb: Option<T>) -> Option<T> {
+ #[rustc_const_unstable(feature = "const_option_ext", issue = "91930")]
+ pub const fn xor(self, optb: Option<T>) -> Option<T>
+ where
+ T: ~const Drop,
+ {
match (self, optb) {
(Some(a), None) => Some(a),
(None, Some(b)) => Some(b),
@@ -1205,7 +1313,11 @@ impl<T> Option<T> {
#[must_use = "if you intended to set a value, consider assignment instead"]
#[inline]
#[stable(feature = "option_insert", since = "1.53.0")]
- pub fn insert(&mut self, value: T) -> &mut T {
+ #[rustc_const_unstable(feature = "const_option_ext", issue = "91930")]
+ pub const fn insert(&mut self, value: T) -> &mut T
+ where
+ T: ~const Drop,
+ {
*self = Some(value);
// SAFETY: the code above just filled the option
@@ -1234,8 +1346,18 @@ impl<T> Option<T> {
/// ```
#[inline]
#[stable(feature = "option_entry", since = "1.20.0")]
- pub fn get_or_insert(&mut self, value: T) -> &mut T {
- self.get_or_insert_with(|| value)
+ #[rustc_const_unstable(feature = "const_option_ext", issue = "91930")]
+ pub const fn get_or_insert(&mut self, value: T) -> &mut T
+ where
+ T: ~const Drop,
+ {
+ if let None = *self {
+ *self = Some(value);
+ }
+
+ // SAFETY: a `None` variant for `self` would have been replaced by a `Some`
+ // variant in the code above.
+ unsafe { self.as_mut().unwrap_unchecked() }
}
/// Inserts the default value into the option if it is [`None`], then
@@ -1259,11 +1381,17 @@ impl<T> Option<T> {
/// ```
#[inline]
#[unstable(feature = "option_get_or_insert_default", issue = "82901")]
- pub fn get_or_insert_default(&mut self) -> &mut T
+ #[rustc_const_unstable(feature = "const_option_ext", issue = "91930")]
+ pub const fn get_or_insert_default(&mut self) -> &mut T
where
- T: Default,
+ T: ~const Default,
{
- self.get_or_insert_with(Default::default)
+ #[rustc_allow_const_fn_unstable(const_fn_trait_bound)]
+ const fn default<T: ~const Default>() -> T {
+ T::default()
+ }
+
+ self.get_or_insert_with(default)
}
/// Inserts a value computed from `f` into the option if it is [`None`],
@@ -1285,17 +1413,21 @@ impl<T> Option<T> {
/// ```
#[inline]
#[stable(feature = "option_entry", since = "1.20.0")]
- pub fn get_or_insert_with<F: FnOnce() -> T>(&mut self, f: F) -> &mut T {
+ #[rustc_const_unstable(feature = "const_option_ext", issue = "91930")]
+ pub const fn get_or_insert_with<F>(&mut self, f: F) -> &mut T
+ where
+ F: ~const FnOnce() -> T,
+ F: ~const Drop,
+ {
if let None = *self {
- *self = Some(f());
+ // the compiler isn't smart enough to know that we are not dropping a `T`
+ // here and wants us to ensure `T` can be dropped at compile time.
+ mem::forget(mem::replace(self, Some(f())))
}
- match self {
- Some(v) => v,
- // SAFETY: a `None` variant for `self` would have been replaced by a `Some`
- // variant in the code above.
- None => unsafe { hint::unreachable_unchecked() },
- }
+ // SAFETY: a `None` variant for `self` would have been replaced by a `Some`
+ // variant in the code above.
+ unsafe { self.as_mut().unwrap_unchecked() }
}
/////////////////////////////////////////////////////////////////////////
@@ -1365,7 +1497,12 @@ impl<T> Option<T> {
/// assert_eq!(x.zip(z), None);
/// ```
#[stable(feature = "option_zip_option", since = "1.46.0")]
- pub fn zip<U>(self, other: Option<U>) -> Option<(T, U)> {
+ #[rustc_const_unstable(feature = "const_option_ext", issue = "91930")]
+ pub const fn zip<U>(self, other: Option<U>) -> Option<(T, U)>
+ where
+ T: ~const Drop,
+ U: ~const Drop,
+ {
match (self, other) {
(Some(a), Some(b)) => Some((a, b)),
_ => None,
@@ -1401,11 +1538,18 @@ impl<T> Option<T> {
/// assert_eq!(x.zip_with(None, Point::new), None);
/// ```
#[unstable(feature = "option_zip", issue = "70086")]
- pub fn zip_with<U, F, R>(self, other: Option<U>, f: F) -> Option<R>
+ #[rustc_const_unstable(feature = "const_option_ext", issue = "91930")]
+ pub const fn zip_with<U, F, R>(self, other: Option<U>, f: F) -> Option<R>
where
- F: FnOnce(T, U) -> R,
+ F: ~const FnOnce(T, U) -> R,
+ F: ~const Drop,
+ T: ~const Drop,
+ U: ~const Drop,
{
- Some(f(self?, other?))
+ match (self, other) {
+ (Some(a), Some(b)) => Some(f(a, b)),
+ _ => None,
+ }
}
}
@@ -1477,8 +1621,12 @@ impl<T: Copy> Option<&mut T> {
/// ```
#[must_use = "`self` will be dropped if the result is not used"]
#[stable(feature = "copied", since = "1.35.0")]
- pub fn copied(self) -> Option<T> {
- self.map(|&mut t| t)
+ #[rustc_const_unstable(feature = "const_option_ext", issue = "91930")]
+ pub const fn copied(self) -> Option<T> {
+ match self {
+ Some(&mut t) => Some(t),
+ None => None,
+ }
}
}
@@ -1497,8 +1645,15 @@ impl<T: Clone> Option<&T> {
/// ```
#[must_use = "`self` will be dropped if the result is not used"]
#[stable(feature = "rust1", since = "1.0.0")]
- pub fn cloned(self) -> Option<T> {
- self.map(|t| t.clone())
+ #[rustc_const_unstable(feature = "const_option_cloned", issue = "91582")]
+ pub const fn cloned(self) -> Option<T>
+ where
+ T: ~const Clone,
+ {
+ match self {
+ Some(t) => Some(t.clone()),
+ None => None,
+ }
}
}
@@ -1515,9 +1670,17 @@ impl<T: Clone> Option<&mut T> {
/// let cloned = opt_x.cloned();
/// assert_eq!(cloned, Some(12));
/// ```
+ #[must_use = "`self` will be dropped if the result is not used"]
#[stable(since = "1.26.0", feature = "option_ref_mut_cloned")]
- pub fn cloned(self) -> Option<T> {
- self.map(|t| t.clone())
+ #[rustc_const_unstable(feature = "const_option_cloned", issue = "91582")]
+ pub const fn cloned(self) -> Option<T>
+ where
+ T: ~const Clone,
+ {
+ match self {
+ Some(t) => Some(t.clone()),
+ None => None,
+ }
}
}
@@ -1550,7 +1713,11 @@ impl<T: Default> Option<T> {
/// [`FromStr`]: crate::str::FromStr
#[inline]
#[stable(feature = "rust1", since = "1.0.0")]
- pub fn unwrap_or_default(self) -> T {
+ #[rustc_const_unstable(feature = "const_option_ext", issue = "91930")]
+ pub const fn unwrap_or_default(self) -> T
+ where
+ T: ~const Default,
+ {
match self {
Some(x) => x,
None => Default::default(),
@@ -1574,8 +1741,15 @@ impl<T: Deref> Option<T> {
/// assert_eq!(x.as_deref(), None);
/// ```
#[stable(feature = "option_deref", since = "1.40.0")]
- pub fn as_deref(&self) -> Option<&T::Target> {
- self.as_ref().map(|t| t.deref())
+ #[rustc_const_unstable(feature = "const_option_ext", issue = "91930")]
+ pub const fn as_deref(&self) -> Option<&T::Target>
+ where
+ T: ~const Deref,
+ {
+ match self.as_ref() {
+ Some(t) => Some(t.deref()),
+ None => None,
+ }
}
}
@@ -1595,8 +1769,15 @@ impl<T: DerefMut> Option<T> {
/// }), Some("HEY".to_owned().as_mut_str()));
/// ```
#[stable(feature = "option_deref", since = "1.40.0")]
- pub fn as_deref_mut(&mut self) -> Option<&mut T::Target> {
- self.as_mut().map(|t| t.deref_mut())
+ #[rustc_const_unstable(feature = "const_option_ext", issue = "91930")]
+ pub const fn as_deref_mut(&mut self) -> Option<&mut T::Target>
+ where
+ T: ~const DerefMut,
+ {
+ match self.as_mut() {
+ Some(t) => Some(t.deref_mut()),
+ None => None,
+ }
}
}
@@ -1630,10 +1811,11 @@ impl<T, E> Option<Result<T, E>> {
}
// This is a separate function to reduce the code size of .expect() itself.
-#[inline(never)]
+#[cfg_attr(not(feature = "panic_immediate_abort"), inline(never))]
+#[cfg_attr(feature = "panic_immediate_abort", inline)]
#[cold]
#[track_caller]
-fn expect_failed(msg: &str) -> ! {
+const fn expect_failed(msg: &str) -> ! {
panic!("{}", msg)
}
@@ -2035,7 +2217,8 @@ impl<A, V: FromIterator<A>> FromIterator<Option<A>> for Option<V> {
}
#[unstable(feature = "try_trait_v2", issue = "84277")]
-impl<T> ops::Try for Option<T> {
+#[rustc_const_unstable(feature = "const_convert", issue = "88674")]
+impl<T> const ops::Try for Option<T> {
type Output = T;
type Residual = Option<convert::Infallible>;
@@ -2054,6 +2237,7 @@ impl<T> ops::Try for Option<T> {
}
#[unstable(feature = "try_trait_v2", issue = "84277")]
+#[rustc_const_unstable(feature = "const_convert", issue = "88674")]
impl<T> const ops::FromResidual for Option<T> {
#[inline]
fn from_residual(residual: Option<convert::Infallible>) -> Self {
@@ -2063,6 +2247,11 @@ impl<T> const ops::FromResidual for Option<T> {
}
}
+#[unstable(feature = "try_trait_v2_residual", issue = "91285")]
+impl<T> ops::Residual<T> for Option<convert::Infallible> {
+ type TryType = Option<T>;
+}
+
impl<T> Option<Option<T>> {
/// Converts from `Option<Option<T>>` to `Option<T>`.
///
diff --git a/library/core/src/prelude/v1.rs b/library/core/src/prelude/v1.rs
index 6b51ef5b012..54f498d1dc1 100644
--- a/library/core/src/prelude/v1.rs
+++ b/library/core/src/prelude/v1.rs
@@ -61,20 +61,13 @@ pub use crate::{
};
#[unstable(
- feature = "asm",
- issue = "72016",
- reason = "inline assembly is not stable enough for use and is subject to change"
+ feature = "concat_bytes",
+ issue = "87555",
+ reason = "`concat_bytes` is not stable enough for use and is subject to change"
)]
+#[cfg(not(bootstrap))]
#[doc(no_inline)]
-pub use crate::arch::asm;
-
-#[unstable(
- feature = "global_asm",
- issue = "35119",
- reason = "`global_asm!` is not stable enough for use and is subject to change"
-)]
-#[doc(no_inline)]
-pub use crate::arch::global_asm;
+pub use crate::concat_bytes;
#[stable(feature = "builtin_macro_prelude", since = "1.38.0")]
#[allow(deprecated, deprecated_in_future)]
diff --git a/library/core/src/primitive_docs.rs b/library/core/src/primitive_docs.rs
index f47a30c9b5d..8fcd8cdeb10 100644
--- a/library/core/src/primitive_docs.rs
+++ b/library/core/src/primitive_docs.rs
@@ -606,8 +606,7 @@ mod prim_pointer {}
/// println!("array[{}] = {}", i, x);
/// }
///
-/// // You can explicitly iterate an array by value using
-/// // `IntoIterator::into_iter` or `std::array::IntoIter::new`:
+/// // You can explicitly iterate an array by value using `IntoIterator::into_iter`
/// for item in IntoIterator::into_iter(array).enumerate() {
/// let (i, x): (usize, i32) = item;
/// println!("array[{}] = {}", i, x);
diff --git a/library/core/src/ptr/const_ptr.rs b/library/core/src/ptr/const_ptr.rs
index 344b483662a..332be06dd16 100644
--- a/library/core/src/ptr/const_ptr.rs
+++ b/library/core/src/ptr/const_ptr.rs
@@ -48,6 +48,54 @@ impl<T: ?Sized> *const T {
self as _
}
+ /// Casts a pointer to its raw bits.
+ ///
+ /// This is equivalent to `as usize`, but is more specific to enhance readability.
+ /// The inverse method is [`from_bits`](#method.from_bits).
+ ///
+ /// In particular, `*p as usize` and `p as usize` will both compile for
+ /// pointers to numeric types but do very different things, so using this
+ /// helps emphasize that reading the bits was intentional.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// #![feature(ptr_to_from_bits)]
+ /// let array = [13, 42];
+ /// let p0: *const i32 = &array[0];
+ /// assert_eq!(<*const _>::from_bits(p0.to_bits()), p0);
+ /// let p1: *const i32 = &array[1];
+ /// assert_eq!(p1.to_bits() - p0.to_bits(), 4);
+ /// ```
+ #[unstable(feature = "ptr_to_from_bits", issue = "91126")]
+ pub fn to_bits(self) -> usize
+ where
+ T: Sized,
+ {
+ self as usize
+ }
+
+ /// Creates a pointer from its raw bits.
+ ///
+ /// This is equivalent to `as *const T`, but is more specific to enhance readability.
+ /// The inverse method is [`to_bits`](#method.to_bits).
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// #![feature(ptr_to_from_bits)]
+ /// use std::ptr::NonNull;
+ /// let dangling: *const u8 = NonNull::dangling().as_ptr();
+ /// assert_eq!(<*const u8>::from_bits(1), dangling);
+ /// ```
+ #[unstable(feature = "ptr_to_from_bits", issue = "91126")]
+ pub fn from_bits(bits: usize) -> Self
+ where
+ T: Sized,
+ {
+ bits as Self
+ }
+
/// Decompose a (possibly wide) pointer into its address and metadata components.
///
/// The pointer can be later reconstructed with [`from_raw_parts`].
@@ -71,7 +119,7 @@ impl<T: ?Sized> *const T {
///
/// * The pointer must be properly aligned.
///
- /// * It must be "dereferencable" in the sense defined in [the module documentation].
+ /// * It must be "dereferenceable" in the sense defined in [the module documentation].
///
/// * The pointer must point to an initialized instance of `T`.
///
@@ -135,7 +183,7 @@ impl<T: ?Sized> *const T {
///
/// * The pointer must be properly aligned.
///
- /// * It must be "dereferencable" in the sense defined in [the module documentation].
+ /// * It must be "dereferenceable" in the sense defined in [the module documentation].
///
/// * You must enforce Rust's aliasing rules, since the returned lifetime `'a` is
/// arbitrarily chosen and does not necessarily reflect the actual lifetime of the data.
@@ -955,7 +1003,7 @@ impl<T> *const [T] {
/// Returns a raw pointer to an element or subslice, without doing bounds
/// checking.
///
- /// Calling this method with an out-of-bounds index or when `self` is not dereferencable
+ /// Calling this method with an out-of-bounds index or when `self` is not dereferenceable
/// is *[undefined behavior]* even if the resulting pointer is not used.
///
/// [undefined behavior]: https://doc.rust-lang.org/reference/behavior-considered-undefined.html
@@ -977,7 +1025,7 @@ impl<T> *const [T] {
where
I: SliceIndex<[T]>,
{
- // SAFETY: the caller ensures that `self` is dereferencable and `index` in-bounds.
+ // SAFETY: the caller ensures that `self` is dereferenceable and `index` in-bounds.
unsafe { index.get_unchecked(self) }
}
diff --git a/library/core/src/ptr/mut_ptr.rs b/library/core/src/ptr/mut_ptr.rs
index f3b2bdfefe5..f3655edb3d0 100644
--- a/library/core/src/ptr/mut_ptr.rs
+++ b/library/core/src/ptr/mut_ptr.rs
@@ -47,6 +47,55 @@ impl<T: ?Sized> *mut T {
self as _
}
+ /// Casts a pointer to its raw bits.
+ ///
+ /// This is equivalent to `as usize`, but is more specific to enhance readability.
+ /// The inverse method is [`from_bits`](#method.from_bits-1).
+ ///
+ /// In particular, `*p as usize` and `p as usize` will both compile for
+ /// pointers to numeric types but do very different things, so using this
+ /// helps emphasize that reading the bits was intentional.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// #![feature(ptr_to_from_bits)]
+ /// let mut array = [13, 42];
+ /// let mut it = array.iter_mut();
+ /// let p0: *mut i32 = it.next().unwrap();
+ /// assert_eq!(<*mut _>::from_bits(p0.to_bits()), p0);
+ /// let p1: *mut i32 = it.next().unwrap();
+ /// assert_eq!(p1.to_bits() - p0.to_bits(), 4);
+ /// ```
+ #[unstable(feature = "ptr_to_from_bits", issue = "91126")]
+ pub fn to_bits(self) -> usize
+ where
+ T: Sized,
+ {
+ self as usize
+ }
+
+ /// Creates a pointer from its raw bits.
+ ///
+ /// This is equivalent to `as *mut T`, but is more specific to enhance readability.
+ /// The inverse method is [`to_bits`](#method.to_bits-1).
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// #![feature(ptr_to_from_bits)]
+ /// use std::ptr::NonNull;
+ /// let dangling: *mut u8 = NonNull::dangling().as_ptr();
+ /// assert_eq!(<*mut u8>::from_bits(1), dangling);
+ /// ```
+ #[unstable(feature = "ptr_to_from_bits", issue = "91126")]
+ pub fn from_bits(bits: usize) -> Self
+ where
+ T: Sized,
+ {
+ bits as Self
+ }
+
/// Decompose a (possibly wide) pointer into its address and metadata components.
///
/// The pointer can be later reconstructed with [`from_raw_parts_mut`].
@@ -73,7 +122,7 @@ impl<T: ?Sized> *mut T {
///
/// * The pointer must be properly aligned.
///
- /// * It must be "dereferencable" in the sense defined in [the module documentation].
+ /// * It must be "dereferenceable" in the sense defined in [the module documentation].
///
/// * The pointer must point to an initialized instance of `T`.
///
@@ -140,7 +189,7 @@ impl<T: ?Sized> *mut T {
///
/// * The pointer must be properly aligned.
///
- /// * It must be "dereferencable" in the sense defined in [the module documentation].
+ /// * It must be "dereferenceable" in the sense defined in [the module documentation].
///
/// * You must enforce Rust's aliasing rules, since the returned lifetime `'a` is
/// arbitrarily chosen and does not necessarily reflect the actual lifetime of the data.
@@ -319,7 +368,7 @@ impl<T: ?Sized> *mut T {
///
/// * The pointer must be properly aligned.
///
- /// * It must be "dereferencable" in the sense defined in [the module documentation].
+ /// * It must be "dereferenceable" in the sense defined in [the module documentation].
///
/// * The pointer must point to an initialized instance of `T`.
///
@@ -385,7 +434,7 @@ impl<T: ?Sized> *mut T {
///
/// * The pointer must be properly aligned.
///
- /// * It must be "dereferencable" in the sense defined in [the module documentation].
+ /// * It must be "dereferenceable" in the sense defined in [the module documentation].
///
/// * You must enforce Rust's aliasing rules, since the returned lifetime `'a` is
/// arbitrarily chosen and does not necessarily reflect the actual lifetime of the data.
@@ -1020,8 +1069,9 @@ impl<T: ?Sized> *mut T {
///
/// [`ptr::write_bytes`]: crate::ptr::write_bytes()
#[stable(feature = "pointer_methods", since = "1.26.0")]
+ #[rustc_const_unstable(feature = "const_ptr_write", issue = "86302")]
#[inline(always)]
- pub unsafe fn write_bytes(self, val: u8, count: usize)
+ pub const unsafe fn write_bytes(self, val: u8, count: usize)
where
T: Sized,
{
@@ -1217,7 +1267,7 @@ impl<T> *mut [T] {
/// Returns a raw pointer to an element or subslice, without doing bounds
/// checking.
///
- /// Calling this method with an out-of-bounds index or when `self` is not dereferencable
+ /// Calling this method with an out-of-bounds index or when `self` is not dereferenceable
/// is *[undefined behavior]* even if the resulting pointer is not used.
///
/// [undefined behavior]: https://doc.rust-lang.org/reference/behavior-considered-undefined.html
@@ -1239,7 +1289,7 @@ impl<T> *mut [T] {
where
I: SliceIndex<[T]>,
{
- // SAFETY: the caller ensures that `self` is dereferencable and `index` in-bounds.
+ // SAFETY: the caller ensures that `self` is dereferenceable and `index` in-bounds.
unsafe { index.get_unchecked_mut(self) }
}
diff --git a/library/core/src/ptr/non_null.rs b/library/core/src/ptr/non_null.rs
index 58110b06809..4f4e7eca281 100644
--- a/library/core/src/ptr/non_null.rs
+++ b/library/core/src/ptr/non_null.rs
@@ -109,7 +109,7 @@ impl<T: Sized> NonNull<T> {
///
/// * The pointer must be properly aligned.
///
- /// * It must be "dereferencable" in the sense defined in [the module documentation].
+ /// * It must be "dereferenceable" in the sense defined in [the module documentation].
///
/// * You must enforce Rust's aliasing rules, since the returned lifetime `'a` is
/// arbitrarily chosen and does not necessarily reflect the actual lifetime of the data.
@@ -142,7 +142,7 @@ impl<T: Sized> NonNull<T> {
///
/// * The pointer must be properly aligned.
///
- /// * It must be "dereferencable" in the sense defined in [the module documentation].
+ /// * It must be "dereferenceable" in the sense defined in [the module documentation].
///
/// * You must enforce Rust's aliasing rules, since the returned lifetime `'a` is
/// arbitrarily chosen and does not necessarily reflect the actual lifetime of the data.
@@ -289,7 +289,7 @@ impl<T: ?Sized> NonNull<T> {
///
/// * The pointer must be properly aligned.
///
- /// * It must be "dereferencable" in the sense defined in [the module documentation].
+ /// * It must be "dereferenceable" in the sense defined in [the module documentation].
///
/// * The pointer must point to an initialized instance of `T`.
///
@@ -338,7 +338,7 @@ impl<T: ?Sized> NonNull<T> {
///
/// * The pointer must be properly aligned.
///
- /// * It must be "dereferencable" in the sense defined in [the module documentation].
+ /// * It must be "dereferenceable" in the sense defined in [the module documentation].
///
/// * The pointer must point to an initialized instance of `T`.
///
@@ -604,7 +604,7 @@ impl<T> NonNull<[T]> {
/// Returns a raw pointer to an element or subslice, without doing bounds
/// checking.
///
- /// Calling this method with an out-of-bounds index or when `self` is not dereferencable
+ /// Calling this method with an out-of-bounds index or when `self` is not dereferenceable
/// is *[undefined behavior]* even if the resulting pointer is not used.
///
/// [undefined behavior]: https://doc.rust-lang.org/reference/behavior-considered-undefined.html
@@ -628,7 +628,7 @@ impl<T> NonNull<[T]> {
where
I: SliceIndex<[T]>,
{
- // SAFETY: the caller ensures that `self` is dereferencable and `index` in-bounds.
+ // SAFETY: the caller ensures that `self` is dereferenceable and `index` in-bounds.
// As a consequence, the resulting pointer cannot be null.
unsafe { NonNull::new_unchecked(self.as_ptr().get_unchecked_mut(index)) }
}
diff --git a/library/core/src/ptr/unique.rs b/library/core/src/ptr/unique.rs
index d650a6f974b..f5c624c225f 100644
--- a/library/core/src/ptr/unique.rs
+++ b/library/core/src/ptr/unique.rs
@@ -92,7 +92,7 @@ impl<T: ?Sized> Unique<T> {
/// Creates a new `Unique` if `ptr` is non-null.
#[inline]
- pub fn new(ptr: *mut T) -> Option<Self> {
+ pub const fn new(ptr: *mut T) -> Option<Self> {
if !ptr.is_null() {
// SAFETY: The pointer has already been checked and is not null.
Some(unsafe { Unique { pointer: ptr as _, _marker: PhantomData } })
@@ -115,7 +115,7 @@ impl<T: ?Sized> Unique<T> {
/// (unbound) lifetime is needed, use `&*my_ptr.as_ptr()`.
#[must_use]
#[inline]
- pub unsafe fn as_ref(&self) -> &T {
+ pub const unsafe fn as_ref(&self) -> &T {
// SAFETY: the caller must guarantee that `self` meets all the
// requirements for a reference.
unsafe { &*self.as_ptr() }
@@ -128,7 +128,7 @@ impl<T: ?Sized> Unique<T> {
/// (unbound) lifetime is needed, use `&mut *my_ptr.as_ptr()`.
#[must_use]
#[inline]
- pub unsafe fn as_mut(&mut self) -> &mut T {
+ pub const unsafe fn as_mut(&mut self) -> &mut T {
// SAFETY: the caller must guarantee that `self` meets all the
// requirements for a mutable reference.
unsafe { &mut *self.as_ptr() }
diff --git a/library/core/src/result.rs b/library/core/src/result.rs
index 8fec2e928aa..3cde63493d3 100644
--- a/library/core/src/result.rs
+++ b/library/core/src/result.rs
@@ -854,6 +854,53 @@ impl<T, E> Result<T, E> {
}
}
+ /// Calls the provided closure with a reference to the contained value (if [`Ok`]).
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// #![feature(result_option_inspect)]
+ ///
+ /// let x: u8 = "4"
+ /// .parse::<u8>()
+ /// .inspect(|x| println!("original: {}", x))
+ /// .map(|x| x.pow(3))
+ /// .expect("failed to parse number");
+ /// ```
+ #[inline]
+ #[unstable(feature = "result_option_inspect", issue = "91345")]
+ pub fn inspect<F: FnOnce(&T)>(self, f: F) -> Self {
+ if let Ok(ref t) = self {
+ f(t);
+ }
+
+ self
+ }
+
+ /// Calls the provided closure with a reference to the contained error (if [`Err`]).
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// #![feature(result_option_inspect)]
+ ///
+ /// use std::{fs, io};
+ ///
+ /// fn read() -> io::Result<String> {
+ /// fs::read_to_string("address.txt")
+ /// .inspect_err(|e| eprintln!("failed to read file: {}", e))
+ /// }
+ /// ```
+ #[inline]
+ #[unstable(feature = "result_option_inspect", issue = "91345")]
+ pub fn inspect_err<F: FnOnce(&E)>(self, f: F) -> Self {
+ if let Err(ref e) = self {
+ f(e);
+ }
+
+ self
+ }
+
/////////////////////////////////////////////////////////////////////////
// Iterator constructors
/////////////////////////////////////////////////////////////////////////
@@ -1606,6 +1653,7 @@ impl<T> Result<T, T> {
}
// This is a separate function to reduce the code size of the methods
+#[cfg(not(feature = "panic_immediate_abort"))]
#[inline(never)]
#[cold]
#[track_caller]
@@ -1613,6 +1661,18 @@ fn unwrap_failed(msg: &str, error: &dyn fmt::Debug) -> ! {
panic!("{}: {:?}", msg, error)
}
+// This is a separate function to avoid constructing a `dyn Debug`
+// that gets immediately thrown away, since vtables don't get cleaned up
+// by dead code elimination if a trait object is constructed even if it goes
+// unused
+#[cfg(feature = "panic_immediate_abort")]
+#[inline]
+#[cold]
+#[track_caller]
+fn unwrap_failed<T>(_msg: &str, _error: &T) -> ! {
+ panic!()
+}
+
/////////////////////////////////////////////////////////////////////////////
// Trait implementations
/////////////////////////////////////////////////////////////////////////////
@@ -1885,7 +1945,8 @@ impl<A, E, V: FromIterator<A>> FromIterator<Result<A, E>> for Result<V, E> {
}
#[unstable(feature = "try_trait_v2", issue = "84277")]
-impl<T, E> ops::Try for Result<T, E> {
+#[rustc_const_unstable(feature = "const_convert", issue = "88674")]
+impl<T, E> const ops::Try for Result<T, E> {
type Output = T;
type Residual = Result<convert::Infallible, E>;
@@ -1904,11 +1965,20 @@ impl<T, E> ops::Try for Result<T, E> {
}
#[unstable(feature = "try_trait_v2", issue = "84277")]
-impl<T, E, F: From<E>> ops::FromResidual<Result<convert::Infallible, E>> for Result<T, F> {
+#[rustc_const_unstable(feature = "const_convert", issue = "88674")]
+impl<T, E, F: ~const From<E>> const ops::FromResidual<Result<convert::Infallible, E>>
+ for Result<T, F>
+{
#[inline]
+ #[track_caller]
fn from_residual(residual: Result<convert::Infallible, E>) -> Self {
match residual {
Err(e) => Err(From::from(e)),
}
}
}
+
+#[unstable(feature = "try_trait_v2_residual", issue = "91285")]
+impl<T, E> ops::Residual<T> for Result<convert::Infallible, E> {
+ type TryType = Result<T, E>;
+}
diff --git a/library/core/src/slice/index.rs b/library/core/src/slice/index.rs
index f7224303549..0298bba8d32 100644
--- a/library/core/src/slice/index.rs
+++ b/library/core/src/slice/index.rs
@@ -27,35 +27,40 @@ where
}
}
-#[inline(never)]
+#[cfg_attr(not(feature = "panic_immediate_abort"), inline(never))]
+#[cfg_attr(feature = "panic_immediate_abort", inline)]
#[cold]
#[track_caller]
fn slice_start_index_len_fail(index: usize, len: usize) -> ! {
panic!("range start index {} out of range for slice of length {}", index, len);
}
-#[inline(never)]
+#[cfg_attr(not(feature = "panic_immediate_abort"), inline(never))]
+#[cfg_attr(feature = "panic_immediate_abort", inline)]
#[cold]
#[track_caller]
fn slice_end_index_len_fail(index: usize, len: usize) -> ! {
panic!("range end index {} out of range for slice of length {}", index, len);
}
-#[inline(never)]
+#[cfg_attr(not(feature = "panic_immediate_abort"), inline(never))]
+#[cfg_attr(feature = "panic_immediate_abort", inline)]
#[cold]
#[track_caller]
fn slice_index_order_fail(index: usize, end: usize) -> ! {
panic!("slice index starts at {} but ends at {}", index, end);
}
-#[inline(never)]
+#[cfg_attr(not(feature = "panic_immediate_abort"), inline(never))]
+#[cfg_attr(feature = "panic_immediate_abort", inline)]
#[cold]
#[track_caller]
fn slice_start_index_overflow_fail() -> ! {
panic!("attempted to index slice from after maximum usize");
}
-#[inline(never)]
+#[cfg_attr(not(feature = "panic_immediate_abort"), inline(never))]
+#[cfg_attr(feature = "panic_immediate_abort", inline)]
#[cold]
#[track_caller]
fn slice_end_index_overflow_fail() -> ! {
diff --git a/library/core/src/slice/iter.rs b/library/core/src/slice/iter.rs
index ad1d6b8b846..176820efe39 100644
--- a/library/core/src/slice/iter.rs
+++ b/library/core/src/slice/iter.rs
@@ -221,7 +221,7 @@ impl<'a, T> IterMut<'a, T> {
// the length, to also allows for the fast `ptr == end` check.
//
// See the `next_unchecked!` and `is_empty!` macros as well as the
- // `post_inc_start` method for more informations.
+ // `post_inc_start` method for more information.
unsafe {
assume(!ptr.is_null());
@@ -481,7 +481,8 @@ where
impl<'a, T: 'a, P: FnMut(&T) -> bool> SplitInclusive<'a, T, P> {
#[inline]
pub(super) fn new(slice: &'a [T], pred: P) -> Self {
- Self { v: slice, pred, finished: false }
+ let finished = slice.is_empty();
+ Self { v: slice, pred, finished }
}
}
@@ -729,7 +730,8 @@ where
impl<'a, T: 'a, P: FnMut(&T) -> bool> SplitInclusiveMut<'a, T, P> {
#[inline]
pub(super) fn new(slice: &'a mut [T], pred: P) -> Self {
- Self { v: slice, pred, finished: false }
+ let finished = slice.is_empty();
+ Self { v: slice, pred, finished }
}
}
diff --git a/library/core/src/slice/mod.rs b/library/core/src/slice/mod.rs
index 34754cffae1..49dce89a494 100644
--- a/library/core/src/slice/mod.rs
+++ b/library/core/src/slice/mod.rs
@@ -10,12 +10,14 @@ use crate::cmp::Ordering::{self, Greater, Less};
use crate::marker::Copy;
use crate::mem;
use crate::num::NonZeroUsize;
-use crate::ops::{FnMut, Range, RangeBounds};
+use crate::ops::{Bound, FnMut, OneSidedRange, Range, RangeBounds};
use crate::option::Option;
use crate::option::Option::{None, Some};
use crate::ptr;
use crate::result::Result;
use crate::result::Result::{Err, Ok};
+#[cfg(not(miri))] // Miri does not support all SIMD intrinsics
+use crate::simd::{self, Simd};
use crate::slice;
#[unstable(
@@ -82,6 +84,29 @@ pub use index::range;
#[unstable(feature = "inherent_ascii_escape", issue = "77174")]
pub use ascii::EscapeAscii;
+/// Calculates the direction and split point of a one-sided range.
+///
+/// This is a helper function for `take` and `take_mut` that returns
+/// the direction of the split (front or back) as well as the index at
+/// which to split. Returns `None` if the split index would overflow.
+#[inline]
+fn split_point_of(range: impl OneSidedRange<usize>) -> Option<(Direction, usize)> {
+ use Bound::*;
+
+ Some(match (range.start_bound(), range.end_bound()) {
+ (Unbounded, Excluded(i)) => (Direction::Front, *i),
+ (Unbounded, Included(i)) => (Direction::Front, i.checked_add(1)?),
+ (Excluded(i), Unbounded) => (Direction::Back, i.checked_add(1)?),
+ (Included(i), Unbounded) => (Direction::Back, *i),
+ _ => unreachable!(),
+ })
+}
+
+enum Direction {
+ Front,
+ Back,
+}
+
#[lang = "slice"]
#[cfg(not(test))]
impl<T> [T] {
@@ -357,7 +382,7 @@ impl<T> [T] {
I: SliceIndex<Self>,
{
// SAFETY: the caller must uphold most of the safety requirements for `get_unchecked`;
- // the slice is dereferencable because `self` is a safe reference.
+ // the slice is dereferenceable because `self` is a safe reference.
// The returned pointer is safe because impls of `SliceIndex` have to guarantee that it is.
unsafe { &*index.get_unchecked(self) }
}
@@ -393,7 +418,7 @@ impl<T> [T] {
I: SliceIndex<Self>,
{
// SAFETY: the caller must uphold the safety requirements for `get_unchecked_mut`;
- // the slice is dereferencable because `self` is a safe reference.
+ // the slice is dereferenceable because `self` is a safe reference.
// The returned pointer is safe because impls of `SliceIndex` have to guarantee that it is.
unsafe { &mut *index.get_unchecked_mut(self) }
}
@@ -1682,6 +1707,84 @@ impl<T> [T] {
unsafe { (&mut *(a.as_mut_ptr() as *mut [T; N]), b) }
}
+ /// Divides one slice into an array and a remainder slice at an index from
+ /// the end.
+ ///
+ /// The slice will contain all indices from `[0, len - N)` (excluding
+ /// the index `len - N` itself) and the array will contain all
+ /// indices from `[len - N, len)` (excluding the index `len` itself).
+ ///
+ /// # Panics
+ ///
+ /// Panics if `N > len`.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// #![feature(split_array)]
+ ///
+ /// let v = &[1, 2, 3, 4, 5, 6][..];
+ ///
+ /// {
+ /// let (left, right) = v.rsplit_array_ref::<0>();
+ /// assert_eq!(left, [1, 2, 3, 4, 5, 6]);
+ /// assert_eq!(right, &[]);
+ /// }
+ ///
+ /// {
+ /// let (left, right) = v.rsplit_array_ref::<2>();
+ /// assert_eq!(left, [1, 2, 3, 4]);
+ /// assert_eq!(right, &[5, 6]);
+ /// }
+ ///
+ /// {
+ /// let (left, right) = v.rsplit_array_ref::<6>();
+ /// assert_eq!(left, []);
+ /// assert_eq!(right, &[1, 2, 3, 4, 5, 6]);
+ /// }
+ /// ```
+ #[unstable(feature = "split_array", reason = "new API", issue = "90091")]
+ #[inline]
+ pub fn rsplit_array_ref<const N: usize>(&self) -> (&[T], &[T; N]) {
+ assert!(N <= self.len());
+ let (a, b) = self.split_at(self.len() - N);
+ // SAFETY: b points to [T; N]? Yes it's [T] of length N (checked by split_at)
+ unsafe { (a, &*(b.as_ptr() as *const [T; N])) }
+ }
+
+ /// Divides one mutable slice into an array and a remainder slice at an
+ /// index from the end.
+ ///
+ /// The slice will contain all indices from `[0, len - N)` (excluding
+ /// the index `N` itself) and the array will contain all
+ /// indices from `[len - N, len)` (excluding the index `len` itself).
+ ///
+ /// # Panics
+ ///
+ /// Panics if `N > len`.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// #![feature(split_array)]
+ ///
+ /// let mut v = &mut [1, 0, 3, 0, 5, 6][..];
+ /// let (left, right) = v.rsplit_array_mut::<4>();
+ /// assert_eq!(left, [1, 0]);
+ /// assert_eq!(right, &mut [3, 0, 5, 6]);
+ /// left[1] = 2;
+ /// right[1] = 4;
+ /// assert_eq!(v, [1, 2, 3, 4, 5, 6]);
+ /// ```
+ #[unstable(feature = "split_array", reason = "new API", issue = "90091")]
+ #[inline]
+ pub fn rsplit_array_mut<const N: usize>(&mut self) -> (&mut [T], &mut [T; N]) {
+ assert!(N <= self.len());
+ let (a, b) = self.split_at_mut(self.len() - N);
+ // SAFETY: b points to [T; N]? Yes it's [T] of length N (checked by split_at_mut)
+ unsafe { (a, &mut *(b.as_mut_ptr() as *mut [T; N])) }
+ }
+
/// Returns an iterator over subslices separated by elements that match
/// `pred`. The matched element is not contained in the subslices.
///
@@ -3411,6 +3514,123 @@ impl<T> [T] {
}
}
+ /// Split a slice into a prefix, a middle of aligned SIMD types, and a suffix.
+ ///
+ /// This is a safe wrapper around [`slice::align_to`], so has the same weak
+ /// postconditions as that method. You're only assured that
+ /// `self.len() == prefix.len() + middle.len() * LANES + suffix.len()`.
+ ///
+ /// Notably, all of the following are possible:
+ /// - `prefix.len() >= LANES`.
+ /// - `middle.is_empty()` despite `self.len() >= 3 * LANES`.
+ /// - `suffix.len() >= LANES`.
+ ///
+ /// That said, this is a safe method, so if you're only writing safe code,
+ /// then this can at most cause incorrect logic, not unsoundness.
+ ///
+ /// # Panics
+ ///
+ /// This will panic if the size of the SIMD type is different from
+ /// `LANES` times that of the scalar.
+ ///
+ /// At the time of writing, the trait restrictions on `Simd<T, LANES>` keeps
+ /// that from ever happening, as only power-of-two numbers of lanes are
+ /// supported. It's possible that, in the future, those restrictions might
+ /// be lifted in a way that would make it possible to see panics from this
+ /// method for something like `LANES == 3`.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// #![feature(portable_simd)]
+ ///
+ /// let short = &[1, 2, 3];
+ /// let (prefix, middle, suffix) = short.as_simd::<4>();
+ /// assert_eq!(middle, []); // Not enough elements for anything in the middle
+ ///
+ /// // They might be split in any possible way between prefix and suffix
+ /// let it = prefix.iter().chain(suffix).copied();
+ /// assert_eq!(it.collect::<Vec<_>>(), vec![1, 2, 3]);
+ ///
+ /// fn basic_simd_sum(x: &[f32]) -> f32 {
+ /// use std::ops::Add;
+ /// use std::simd::f32x4;
+ /// let (prefix, middle, suffix) = x.as_simd();
+ /// let sums = f32x4::from_array([
+ /// prefix.iter().copied().sum(),
+ /// 0.0,
+ /// 0.0,
+ /// suffix.iter().copied().sum(),
+ /// ]);
+ /// let sums = middle.iter().copied().fold(sums, f32x4::add);
+ /// sums.horizontal_sum()
+ /// }
+ ///
+ /// let numbers: Vec<f32> = (1..101).map(|x| x as _).collect();
+ /// assert_eq!(basic_simd_sum(&numbers[1..99]), 4949.0);
+ /// ```
+ #[unstable(feature = "portable_simd", issue = "86656")]
+ #[cfg(not(miri))] // Miri does not support all SIMD intrinsics
+ pub fn as_simd<const LANES: usize>(&self) -> (&[T], &[Simd<T, LANES>], &[T])
+ where
+ Simd<T, LANES>: AsRef<[T; LANES]>,
+ T: simd::SimdElement,
+ simd::LaneCount<LANES>: simd::SupportedLaneCount,
+ {
+ // These are expected to always match, as vector types are laid out like
+ // arrays per <https://llvm.org/docs/LangRef.html#vector-type>, but we
+ // might as well double-check since it'll optimize away anyhow.
+ assert_eq!(mem::size_of::<Simd<T, LANES>>(), mem::size_of::<[T; LANES]>());
+
+ // SAFETY: The simd types have the same layout as arrays, just with
+ // potentially-higher alignment, so the de-facto transmutes are sound.
+ unsafe { self.align_to() }
+ }
+
+ /// Split a slice into a prefix, a middle of aligned SIMD types, and a suffix.
+ ///
+ /// This is a safe wrapper around [`slice::align_to_mut`], so has the same weak
+ /// postconditions as that method. You're only assured that
+ /// `self.len() == prefix.len() + middle.len() * LANES + suffix.len()`.
+ ///
+ /// Notably, all of the following are possible:
+ /// - `prefix.len() >= LANES`.
+ /// - `middle.is_empty()` despite `self.len() >= 3 * LANES`.
+ /// - `suffix.len() >= LANES`.
+ ///
+ /// That said, this is a safe method, so if you're only writing safe code,
+ /// then this can at most cause incorrect logic, not unsoundness.
+ ///
+ /// This is the mutable version of [`slice::as_simd`]; see that for examples.
+ ///
+ /// # Panics
+ ///
+ /// This will panic if the size of the SIMD type is different from
+ /// `LANES` times that of the scalar.
+ ///
+ /// At the time of writing, the trait restrictions on `Simd<T, LANES>` keeps
+ /// that from ever happening, as only power-of-two numbers of lanes are
+ /// supported. It's possible that, in the future, those restrictions might
+ /// be lifted in a way that would make it possible to see panics from this
+ /// method for something like `LANES == 3`.
+ #[unstable(feature = "portable_simd", issue = "86656")]
+ #[cfg(not(miri))] // Miri does not support all SIMD intrinsics
+ pub fn as_simd_mut<const LANES: usize>(&mut self) -> (&mut [T], &mut [Simd<T, LANES>], &mut [T])
+ where
+ Simd<T, LANES>: AsMut<[T; LANES]>,
+ T: simd::SimdElement,
+ simd::LaneCount<LANES>: simd::SupportedLaneCount,
+ {
+ // These are expected to always match, as vector types are laid out like
+ // arrays per <https://llvm.org/docs/LangRef.html#vector-type>, but we
+ // might as well double-check since it'll optimize away anyhow.
+ assert_eq!(mem::size_of::<Simd<T, LANES>>(), mem::size_of::<[T; LANES]>());
+
+ // SAFETY: The simd types have the same layout as arrays, just with
+ // potentially-higher alignment, so the de-facto transmutes are sound.
+ unsafe { self.align_to_mut() }
+ }
+
/// Checks if the elements of this slice are sorted.
///
/// That is, for each element `a` and its following element `b`, `a <= b` must hold. If the
@@ -3517,6 +3737,245 @@ impl<T> [T] {
{
self.binary_search_by(|x| if pred(x) { Less } else { Greater }).unwrap_or_else(|i| i)
}
+
+ /// Removes the subslice corresponding to the given range
+ /// and returns a reference to it.
+ ///
+ /// Returns `None` and does not modify the slice if the given
+ /// range is out of bounds.
+ ///
+ /// Note that this method only accepts one-sided ranges such as
+ /// `2..` or `..6`, but not `2..6`.
+ ///
+ /// # Examples
+ ///
+ /// Taking the first three elements of a slice:
+ ///
+ /// ```
+ /// #![feature(slice_take)]
+ ///
+ /// let mut slice: &[_] = &['a', 'b', 'c', 'd'];
+ /// let mut first_three = slice.take(..3).unwrap();
+ ///
+ /// assert_eq!(slice, &['d']);
+ /// assert_eq!(first_three, &['a', 'b', 'c']);
+ /// ```
+ ///
+ /// Taking the last two elements of a slice:
+ ///
+ /// ```
+ /// #![feature(slice_take)]
+ ///
+ /// let mut slice: &[_] = &['a', 'b', 'c', 'd'];
+ /// let mut tail = slice.take(2..).unwrap();
+ ///
+ /// assert_eq!(slice, &['a', 'b']);
+ /// assert_eq!(tail, &['c', 'd']);
+ /// ```
+ ///
+ /// Getting `None` when `range` is out of bounds:
+ ///
+ /// ```
+ /// #![feature(slice_take)]
+ ///
+ /// let mut slice: &[_] = &['a', 'b', 'c', 'd'];
+ ///
+ /// assert_eq!(None, slice.take(5..));
+ /// assert_eq!(None, slice.take(..5));
+ /// assert_eq!(None, slice.take(..=4));
+ /// let expected: &[char] = &['a', 'b', 'c', 'd'];
+ /// assert_eq!(Some(expected), slice.take(..4));
+ /// ```
+ #[inline]
+ #[must_use = "method does not modify the slice if the range is out of bounds"]
+ #[unstable(feature = "slice_take", issue = "62280")]
+ pub fn take<'a, R: OneSidedRange<usize>>(self: &mut &'a Self, range: R) -> Option<&'a Self> {
+ let (direction, split_index) = split_point_of(range)?;
+ if split_index > self.len() {
+ return None;
+ }
+ let (front, back) = self.split_at(split_index);
+ match direction {
+ Direction::Front => {
+ *self = back;
+ Some(front)
+ }
+ Direction::Back => {
+ *self = front;
+ Some(back)
+ }
+ }
+ }
+
+ /// Removes the subslice corresponding to the given range
+ /// and returns a mutable reference to it.
+ ///
+ /// Returns `None` and does not modify the slice if the given
+ /// range is out of bounds.
+ ///
+ /// Note that this method only accepts one-sided ranges such as
+ /// `2..` or `..6`, but not `2..6`.
+ ///
+ /// # Examples
+ ///
+ /// Taking the first three elements of a slice:
+ ///
+ /// ```
+ /// #![feature(slice_take)]
+ ///
+ /// let mut slice: &mut [_] = &mut ['a', 'b', 'c', 'd'];
+ /// let mut first_three = slice.take_mut(..3).unwrap();
+ ///
+ /// assert_eq!(slice, &mut ['d']);
+ /// assert_eq!(first_three, &mut ['a', 'b', 'c']);
+ /// ```
+ ///
+ /// Taking the last two elements of a slice:
+ ///
+ /// ```
+ /// #![feature(slice_take)]
+ ///
+ /// let mut slice: &mut [_] = &mut ['a', 'b', 'c', 'd'];
+ /// let mut tail = slice.take_mut(2..).unwrap();
+ ///
+ /// assert_eq!(slice, &mut ['a', 'b']);
+ /// assert_eq!(tail, &mut ['c', 'd']);
+ /// ```
+ ///
+ /// Getting `None` when `range` is out of bounds:
+ ///
+ /// ```
+ /// #![feature(slice_take)]
+ ///
+ /// let mut slice: &mut [_] = &mut ['a', 'b', 'c', 'd'];
+ ///
+ /// assert_eq!(None, slice.take_mut(5..));
+ /// assert_eq!(None, slice.take_mut(..5));
+ /// assert_eq!(None, slice.take_mut(..=4));
+ /// let expected: &mut [_] = &mut ['a', 'b', 'c', 'd'];
+ /// assert_eq!(Some(expected), slice.take_mut(..4));
+ /// ```
+ #[inline]
+ #[must_use = "method does not modify the slice if the range is out of bounds"]
+ #[unstable(feature = "slice_take", issue = "62280")]
+ pub fn take_mut<'a, R: OneSidedRange<usize>>(
+ self: &mut &'a mut Self,
+ range: R,
+ ) -> Option<&'a mut Self> {
+ let (direction, split_index) = split_point_of(range)?;
+ if split_index > self.len() {
+ return None;
+ }
+ let (front, back) = mem::take(self).split_at_mut(split_index);
+ match direction {
+ Direction::Front => {
+ *self = back;
+ Some(front)
+ }
+ Direction::Back => {
+ *self = front;
+ Some(back)
+ }
+ }
+ }
+
+ /// Removes the first element of the slice and returns a reference
+ /// to it.
+ ///
+ /// Returns `None` if the slice is empty.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// #![feature(slice_take)]
+ ///
+ /// let mut slice: &[_] = &['a', 'b', 'c'];
+ /// let first = slice.take_first().unwrap();
+ ///
+ /// assert_eq!(slice, &['b', 'c']);
+ /// assert_eq!(first, &'a');
+ /// ```
+ #[inline]
+ #[unstable(feature = "slice_take", issue = "62280")]
+ pub fn take_first<'a>(self: &mut &'a Self) -> Option<&'a T> {
+ let (first, rem) = self.split_first()?;
+ *self = rem;
+ Some(first)
+ }
+
+ /// Removes the first element of the slice and returns a mutable
+ /// reference to it.
+ ///
+ /// Returns `None` if the slice is empty.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// #![feature(slice_take)]
+ ///
+ /// let mut slice: &mut [_] = &mut ['a', 'b', 'c'];
+ /// let first = slice.take_first_mut().unwrap();
+ /// *first = 'd';
+ ///
+ /// assert_eq!(slice, &['b', 'c']);
+ /// assert_eq!(first, &'d');
+ /// ```
+ #[inline]
+ #[unstable(feature = "slice_take", issue = "62280")]
+ pub fn take_first_mut<'a>(self: &mut &'a mut Self) -> Option<&'a mut T> {
+ let (first, rem) = mem::take(self).split_first_mut()?;
+ *self = rem;
+ Some(first)
+ }
+
+ /// Removes the last element of the slice and returns a reference
+ /// to it.
+ ///
+ /// Returns `None` if the slice is empty.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// #![feature(slice_take)]
+ ///
+ /// let mut slice: &[_] = &['a', 'b', 'c'];
+ /// let last = slice.take_last().unwrap();
+ ///
+ /// assert_eq!(slice, &['a', 'b']);
+ /// assert_eq!(last, &'c');
+ /// ```
+ #[inline]
+ #[unstable(feature = "slice_take", issue = "62280")]
+ pub fn take_last<'a>(self: &mut &'a Self) -> Option<&'a T> {
+ let (last, rem) = self.split_last()?;
+ *self = rem;
+ Some(last)
+ }
+
+ /// Removes the last element of the slice and returns a mutable
+ /// reference to it.
+ ///
+ /// Returns `None` if the slice is empty.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// #![feature(slice_take)]
+ ///
+ /// let mut slice: &mut [_] = &mut ['a', 'b', 'c'];
+ /// let last = slice.take_last_mut().unwrap();
+ /// *last = 'd';
+ ///
+ /// assert_eq!(slice, &['a', 'b']);
+ /// assert_eq!(last, &'d');
+ /// ```
+ #[inline]
+ #[unstable(feature = "slice_take", issue = "62280")]
+ pub fn take_last_mut<'a>(self: &mut &'a mut Self) -> Option<&'a mut T> {
+ let (last, rem) = mem::take(self).split_last_mut()?;
+ *self = rem;
+ Some(last)
+ }
}
trait CloneFromSpec<T> {
diff --git a/library/core/src/slice/raw.rs b/library/core/src/slice/raw.rs
index 81bb16d5401..e7972838184 100644
--- a/library/core/src/slice/raw.rs
+++ b/library/core/src/slice/raw.rs
@@ -131,7 +131,7 @@ pub const unsafe fn from_raw_parts_mut<'a, T>(data: *mut T, len: usize) -> &'a m
}
// In debug builds checks that `data` pointer is aligned and non-null and that slice with given `len` would cover less than half the address space
-#[cfg(all(not(bootstrap), debug_assertions))]
+#[cfg(debug_assertions)]
#[unstable(feature = "const_slice_from_raw_parts", issue = "67456")]
#[rustc_const_unstable(feature = "const_slice_from_raw_parts", issue = "67456")]
const fn debug_check_data_len<T>(data: *const T, len: usize) {
@@ -149,8 +149,8 @@ const fn debug_check_data_len<T>(data: *const T, len: usize) {
// it is not required for safety (the safety must be guatanteed by
// the `from_raw_parts[_mut]` caller).
//
- // Since the checks are not required, we ignore them in CTFE as they can't
- // be done there (alignment does not make much sense there).
+ // As per our safety precondition, we may assume that assertion above never fails.
+ // Therefore, noop and rt_check are observably equivalent.
unsafe {
crate::intrinsics::const_eval_select((data,), noop, rt_check);
}
@@ -161,7 +161,7 @@ const fn debug_check_data_len<T>(data: *const T, len: usize) {
);
}
-#[cfg(not(all(not(bootstrap), debug_assertions)))]
+#[cfg(not(debug_assertions))]
const fn debug_check_data_len<T>(_data: *const T, _len: usize) {}
/// Converts a reference to T into a slice of length 1 (without copying).
diff --git a/library/core/src/slice/rotate.rs b/library/core/src/slice/rotate.rs
index 7528927ef33..4589c6c0f04 100644
--- a/library/core/src/slice/rotate.rs
+++ b/library/core/src/slice/rotate.rs
@@ -104,7 +104,7 @@ pub unsafe fn ptr_rotate<T>(mut left: usize, mut mid: *mut T, mut right: usize)
// - overflows cannot happen for `i` since the function's safety contract ask for
// `mid+right-1 = x+left+right` to be valid for writing
// - underflows cannot happen because `i` must be bigger or equal to `left` for
- // a substraction of `left` to happen.
+ // a subtraction of `left` to happen.
//
// So `x+i` is valid for reading and writing if the caller respected the contract
tmp = unsafe { x.add(i).replace(tmp) };
@@ -202,7 +202,7 @@ pub unsafe fn ptr_rotate<T>(mut left: usize, mut mid: *mut T, mut right: usize)
loop {
// SAFETY:
// `left >= right` so `[mid-right, mid+right)` is valid for reading and writing
- // Substracting `right` from `mid` each turn is counterbalanced by the addition and
+ // Subtracting `right` from `mid` each turn is counterbalanced by the addition and
// check after it.
unsafe {
ptr::swap_nonoverlapping(mid.sub(right), mid, right);
@@ -218,7 +218,7 @@ pub unsafe fn ptr_rotate<T>(mut left: usize, mut mid: *mut T, mut right: usize)
loop {
// SAFETY: `[mid-left, mid+left)` is valid for reading and writing because
// `left < right` so `mid+left < mid+right`.
- // Adding `left` to `mid` each turn is counterbalanced by the substraction and check
+ // Adding `left` to `mid` each turn is counterbalanced by the subtraction and check
// after it.
unsafe {
ptr::swap_nonoverlapping(mid.sub(left), mid, left);
diff --git a/library/core/src/slice/sort.rs b/library/core/src/slice/sort.rs
index 60b39295caf..b5e6083c663 100644
--- a/library/core/src/slice/sort.rs
+++ b/library/core/src/slice/sort.rs
@@ -33,8 +33,8 @@ where
F: FnMut(&T, &T) -> bool,
{
let len = v.len();
- // SAFETY: The unsafe operations below involves indexing without a bound check (`get_unchecked` and `get_unchecked_mut`)
- // and copying memory (`ptr::copy_nonoverlapping`).
+ // SAFETY: The unsafe operations below involves indexing without a bounds check (by offsetting a
+ // pointer) and copying memory (`ptr::copy_nonoverlapping`).
//
// a. Indexing:
// 1. We checked the size of the array to >=2.
@@ -55,17 +55,18 @@ where
// operation panics, `hole` will get dropped and automatically write the element back
// into the slice.
let mut tmp = mem::ManuallyDrop::new(ptr::read(v.get_unchecked(0)));
- let mut hole = CopyOnDrop { src: &mut *tmp, dest: v.get_unchecked_mut(1) };
- ptr::copy_nonoverlapping(v.get_unchecked(1), v.get_unchecked_mut(0), 1);
+ let v = v.as_mut_ptr();
+ let mut hole = CopyOnDrop { src: &mut *tmp, dest: v.add(1) };
+ ptr::copy_nonoverlapping(v.add(1), v.add(0), 1);
for i in 2..len {
- if !is_less(v.get_unchecked(i), &*tmp) {
+ if !is_less(&*v.add(i), &*tmp) {
break;
}
// Move `i`-th element one place to the left, thus shifting the hole to the right.
- ptr::copy_nonoverlapping(v.get_unchecked(i), v.get_unchecked_mut(i - 1), 1);
- hole.dest = v.get_unchecked_mut(i);
+ ptr::copy_nonoverlapping(v.add(i), v.add(i - 1), 1);
+ hole.dest = v.add(i);
}
// `hole` gets dropped and thus copies `tmp` into the remaining hole in `v`.
}
@@ -78,8 +79,8 @@ where
F: FnMut(&T, &T) -> bool,
{
let len = v.len();
- // SAFETY: The unsafe operations below involves indexing without a bound check (`get_unchecked` and `get_unchecked_mut`)
- // and copying memory (`ptr::copy_nonoverlapping`).
+ // SAFETY: The unsafe operations below involves indexing without a bound check (by offsetting a
+ // pointer) and copying memory (`ptr::copy_nonoverlapping`).
//
// a. Indexing:
// 1. We checked the size of the array to >= 2.
@@ -100,17 +101,18 @@ where
// operation panics, `hole` will get dropped and automatically write the element back
// into the slice.
let mut tmp = mem::ManuallyDrop::new(ptr::read(v.get_unchecked(len - 1)));
- let mut hole = CopyOnDrop { src: &mut *tmp, dest: v.get_unchecked_mut(len - 2) };
- ptr::copy_nonoverlapping(v.get_unchecked(len - 2), v.get_unchecked_mut(len - 1), 1);
+ let v = v.as_mut_ptr();
+ let mut hole = CopyOnDrop { src: &mut *tmp, dest: v.add(len - 2) };
+ ptr::copy_nonoverlapping(v.add(len - 2), v.add(len - 1), 1);
for i in (0..len - 2).rev() {
- if !is_less(&*tmp, v.get_unchecked(i)) {
+ if !is_less(&*tmp, &*v.add(i)) {
break;
}
// Move `i`-th element one place to the right, thus shifting the hole to the left.
- ptr::copy_nonoverlapping(v.get_unchecked(i), v.get_unchecked_mut(i + 1), 1);
- hole.dest = v.get_unchecked_mut(i);
+ ptr::copy_nonoverlapping(v.add(i), v.add(i + 1), 1);
+ hole.dest = v.add(i);
}
// `hole` gets dropped and thus copies `tmp` into the remaining hole in `v`.
}
@@ -302,7 +304,7 @@ where
if start_l == end_l {
// Trace `block_l` elements from the left side.
start_l = MaybeUninit::slice_as_mut_ptr(&mut offsets_l);
- end_l = MaybeUninit::slice_as_mut_ptr(&mut offsets_l);
+ end_l = start_l;
let mut elem = l;
for i in 0..block_l {
@@ -328,7 +330,7 @@ where
if start_r == end_r {
// Trace `block_r` elements from the right side.
start_r = MaybeUninit::slice_as_mut_ptr(&mut offsets_r);
- end_r = MaybeUninit::slice_as_mut_ptr(&mut offsets_r);
+ end_r = start_r;
let mut elem = r;
for i in 0..block_r {
@@ -579,7 +581,8 @@ where
// Swap the found pair of out-of-order elements.
r -= 1;
- ptr::swap(v.get_unchecked_mut(l), v.get_unchecked_mut(r));
+ let ptr = v.as_mut_ptr();
+ ptr::swap(ptr.add(l), ptr.add(r));
l += 1;
}
}
diff --git a/library/core/src/str/iter.rs b/library/core/src/str/iter.rs
index 48410446716..de6e6d52b36 100644
--- a/library/core/src/str/iter.rs
+++ b/library/core/src/str/iter.rs
@@ -748,7 +748,7 @@ generate_pattern_iterators! {
}
impl<'a, P: Pattern<'a>> Split<'a, P> {
- /// Returns remainder of the splitted string
+ /// Returns remainder of the split string
///
/// # Examples
///
@@ -769,7 +769,7 @@ impl<'a, P: Pattern<'a>> Split<'a, P> {
}
impl<'a, P: Pattern<'a>> RSplit<'a, P> {
- /// Returns remainder of the splitted string
+ /// Returns remainder of the split string
///
/// # Examples
///
@@ -808,7 +808,7 @@ generate_pattern_iterators! {
}
impl<'a, P: Pattern<'a>> SplitTerminator<'a, P> {
- /// Returns remainder of the splitted string
+ /// Returns remainder of the split string
///
/// # Examples
///
@@ -829,7 +829,7 @@ impl<'a, P: Pattern<'a>> SplitTerminator<'a, P> {
}
impl<'a, P: Pattern<'a>> RSplitTerminator<'a, P> {
- /// Returns remainder of the splitted string
+ /// Returns remainder of the split string
///
/// # Examples
///
@@ -931,7 +931,7 @@ generate_pattern_iterators! {
}
impl<'a, P: Pattern<'a>> SplitN<'a, P> {
- /// Returns remainder of the splitted string
+ /// Returns remainder of the split string
///
/// # Examples
///
@@ -952,7 +952,7 @@ impl<'a, P: Pattern<'a>> SplitN<'a, P> {
}
impl<'a, P: Pattern<'a>> RSplitN<'a, P> {
- /// Returns remainder of the splitted string
+ /// Returns remainder of the split string
///
/// # Examples
///
@@ -1236,7 +1236,7 @@ impl<'a> DoubleEndedIterator for SplitWhitespace<'a> {
impl FusedIterator for SplitWhitespace<'_> {}
impl<'a> SplitWhitespace<'a> {
- /// Returns remainder of the splitted string
+ /// Returns remainder of the split string
///
/// # Examples
///
@@ -1292,7 +1292,7 @@ impl<'a> DoubleEndedIterator for SplitAsciiWhitespace<'a> {
impl FusedIterator for SplitAsciiWhitespace<'_> {}
impl<'a> SplitAsciiWhitespace<'a> {
- /// Returns remainder of the splitted string
+ /// Returns remainder of the split string
///
/// # Examples
///
@@ -1360,7 +1360,7 @@ impl<'a, P: Pattern<'a, Searcher: ReverseSearcher<'a>>> DoubleEndedIterator
impl<'a, P: Pattern<'a>> FusedIterator for SplitInclusive<'a, P> {}
impl<'a, P: Pattern<'a>> SplitInclusive<'a, P> {
- /// Returns remainder of the splitted string
+ /// Returns remainder of the split string
///
/// # Examples
///
diff --git a/library/core/src/str/lossy.rs b/library/core/src/str/lossy.rs
index 6c21a5e8020..6ec1c93908f 100644
--- a/library/core/src/str/lossy.rs
+++ b/library/core/src/str/lossy.rs
@@ -13,11 +13,6 @@ pub struct Utf8Lossy {
impl Utf8Lossy {
#[must_use]
- pub fn from_str(s: &str) -> &Utf8Lossy {
- Utf8Lossy::from_bytes(s.as_bytes())
- }
-
- #[must_use]
pub fn from_bytes(bytes: &[u8]) -> &Utf8Lossy {
// SAFETY: Both use the same memory layout, and UTF-8 correctness isn't required.
unsafe { mem::transmute(bytes) }
@@ -61,36 +56,26 @@ impl<'a> Iterator for Utf8LossyChunksIter<'a> {
}
let mut i = 0;
+ let mut valid_up_to = 0;
while i < self.source.len() {
- let i_ = i;
-
- // SAFETY: `i` starts at `0`, is less than `self.source.len()`, and
- // only increases, so `0 <= i < self.source.len()`.
+ // SAFETY: `i < self.source.len()` per previous line.
+ // For some reason the following are both significantly slower:
+ // while let Some(&byte) = self.source.get(i) {
+ // while let Some(byte) = self.source.get(i).copied() {
let byte = unsafe { *self.source.get_unchecked(i) };
i += 1;
if byte < 128 {
+ // This could be a `1 => ...` case in the match below, but for
+ // the common case of all-ASCII inputs, we bypass loading the
+ // sizeable UTF8_CHAR_WIDTH table into cache.
} else {
let w = utf8_char_width(byte);
- macro_rules! error {
- () => {{
- // SAFETY: We have checked up to `i` that source is valid UTF-8.
- unsafe {
- let r = Utf8LossyChunk {
- valid: from_utf8_unchecked(&self.source[0..i_]),
- broken: &self.source[i_..i],
- };
- self.source = &self.source[i..];
- return Some(r);
- }
- }};
- }
-
match w {
2 => {
if safe_get(self.source, i) & 192 != TAG_CONT_U8 {
- error!();
+ break;
}
i += 1;
}
@@ -100,13 +85,11 @@ impl<'a> Iterator for Utf8LossyChunksIter<'a> {
(0xE1..=0xEC, 0x80..=0xBF) => (),
(0xED, 0x80..=0x9F) => (),
(0xEE..=0xEF, 0x80..=0xBF) => (),
- _ => {
- error!();
- }
+ _ => break,
}
i += 1;
if safe_get(self.source, i) & 192 != TAG_CONT_U8 {
- error!();
+ break;
}
i += 1;
}
@@ -115,34 +98,45 @@ impl<'a> Iterator for Utf8LossyChunksIter<'a> {
(0xF0, 0x90..=0xBF) => (),
(0xF1..=0xF3, 0x80..=0xBF) => (),
(0xF4, 0x80..=0x8F) => (),
- _ => {
- error!();
- }
+ _ => break,
}
i += 1;
if safe_get(self.source, i) & 192 != TAG_CONT_U8 {
- error!();
+ break;
}
i += 1;
if safe_get(self.source, i) & 192 != TAG_CONT_U8 {
- error!();
+ break;
}
i += 1;
}
- _ => {
- error!();
- }
+ _ => break,
}
}
+
+ valid_up_to = i;
}
- let r = Utf8LossyChunk {
- // SAFETY: We have checked that the entire source is valid UTF-8.
- valid: unsafe { from_utf8_unchecked(self.source) },
- broken: &[],
- };
- self.source = &[];
- Some(r)
+ // SAFETY: `i <= self.source.len()` because it is only ever incremented
+ // via `i += 1` and in between every single one of those increments, `i`
+ // is compared against `self.source.len()`. That happens either
+ // literally by `i < self.source.len()` in the while-loop's condition,
+ // or indirectly by `safe_get(self.source, i) & 192 != TAG_CONT_U8`. The
+ // loop is terminated as soon as the latest `i += 1` has made `i` no
+ // longer less than `self.source.len()`, which means it'll be at most
+ // equal to `self.source.len()`.
+ let (inspected, remaining) = unsafe { self.source.split_at_unchecked(i) };
+ self.source = remaining;
+
+ // SAFETY: `valid_up_to <= i` because it is only ever assigned via
+ // `valid_up_to = i` and `i` only increases.
+ let (valid, broken) = unsafe { inspected.split_at_unchecked(valid_up_to) };
+
+ Some(Utf8LossyChunk {
+ // SAFETY: All bytes up to `valid_up_to` are valid UTF-8.
+ valid: unsafe { from_utf8_unchecked(valid) },
+ broken,
+ })
}
}
diff --git a/library/core/src/str/mod.rs b/library/core/src/str/mod.rs
index cd5ed35be79..1d4600fa4a2 100644
--- a/library/core/src/str/mod.rs
+++ b/library/core/src/str/mod.rs
@@ -416,7 +416,7 @@ impl str {
#[inline]
pub unsafe fn get_unchecked<I: SliceIndex<str>>(&self, i: I) -> &I::Output {
// SAFETY: the caller must uphold the safety contract for `get_unchecked`;
- // the slice is dereferencable because `self` is a safe reference.
+ // the slice is dereferenceable because `self` is a safe reference.
// The returned pointer is safe because impls of `SliceIndex` have to guarantee that it is.
unsafe { &*i.get_unchecked(self) }
}
@@ -451,7 +451,7 @@ impl str {
#[inline]
pub unsafe fn get_unchecked_mut<I: SliceIndex<str>>(&mut self, i: I) -> &mut I::Output {
// SAFETY: the caller must uphold the safety contract for `get_unchecked_mut`;
- // the slice is dereferencable because `self` is a safe reference.
+ // the slice is dereferenceable because `self` is a safe reference.
// The returned pointer is safe because impls of `SliceIndex` have to guarantee that it is.
unsafe { &mut *i.get_unchecked_mut(self) }
}
@@ -504,7 +504,7 @@ impl str {
#[inline]
pub unsafe fn slice_unchecked(&self, begin: usize, end: usize) -> &str {
// SAFETY: the caller must uphold the safety contract for `get_unchecked`;
- // the slice is dereferencable because `self` is a safe reference.
+ // the slice is dereferenceable because `self` is a safe reference.
// The returned pointer is safe because impls of `SliceIndex` have to guarantee that it is.
unsafe { &*(begin..end).get_unchecked(self) }
}
@@ -537,7 +537,7 @@ impl str {
#[inline]
pub unsafe fn slice_mut_unchecked(&mut self, begin: usize, end: usize) -> &mut str {
// SAFETY: the caller must uphold the safety contract for `get_unchecked_mut`;
- // the slice is dereferencable because `self` is a safe reference.
+ // the slice is dereferenceable because `self` is a safe reference.
// The returned pointer is safe because impls of `SliceIndex` have to guarantee that it is.
unsafe { &mut *(begin..end).get_unchecked_mut(self) }
}
diff --git a/library/core/src/str/validations.rs b/library/core/src/str/validations.rs
index be9c41a491b..b2ea86d699a 100644
--- a/library/core/src/str/validations.rs
+++ b/library/core/src/str/validations.rs
@@ -244,22 +244,23 @@ pub(super) const fn run_utf8_validation(v: &[u8]) -> Result<(), Utf8Error> {
// https://tools.ietf.org/html/rfc3629
const UTF8_CHAR_WIDTH: &[u8; 256] = &[
- 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
- 1, // 0x1F
- 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
- 1, // 0x3F
- 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
- 1, // 0x5F
- 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
- 1, // 0x7F
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, // 0x9F
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, // 0xBF
- 0, 0, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
- 2, // 0xDF
- 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, // 0xEF
- 4, 4, 4, 4, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 0xFF
+ // 1 2 3 4 5 6 7 8 9 A B C D E F
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 0
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 1
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 2
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 3
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 4
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 5
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 6
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 7
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 8
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 9
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // A
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // B
+ 0, 0, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, // C
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, // D
+ 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, // E
+ 4, 4, 4, 4, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // F
];
/// Given a first byte, determines how many bytes are in this UTF-8 character.
diff --git a/library/core/src/stream/mod.rs b/library/core/src/stream/mod.rs
index 58dc8e1e5e6..b59a46d5f3a 100644
--- a/library/core/src/stream/mod.rs
+++ b/library/core/src/stream/mod.rs
@@ -114,9 +114,9 @@
//! # Laziness
//!
//! Streams are *lazy*. This means that just creating a stream doesn't _do_ a
-//! whole lot. Nothing really happens until you call `next`. This is sometimes a
-//! source of confusion when creating a stream solely for its side effects. The
-//! compiler will warn us about this kind of behavior:
+//! whole lot. Nothing really happens until you call `poll_next`. This is
+//! sometimes a source of confusion when creating a stream solely for its side
+//! effects. The compiler will warn us about this kind of behavior:
//!
//! ```text
//! warning: unused result that must be used: streams do nothing unless polled
diff --git a/library/core/src/stream/stream/mod.rs b/library/core/src/stream/stream.rs
index d102619b8e5..2cfddf9ad01 100644
--- a/library/core/src/stream/stream/mod.rs
+++ b/library/core/src/stream/stream.rs
@@ -95,13 +95,13 @@ impl<S: ?Sized + Stream + Unpin> Stream for &mut S {
#[unstable(feature = "async_stream", issue = "79024")]
impl<P> Stream for Pin<P>
where
- P: DerefMut + Unpin,
+ P: DerefMut,
P::Target: Stream,
{
type Item = <P::Target as Stream>::Item;
fn poll_next(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Option<Self::Item>> {
- self.get_mut().as_mut().poll_next(cx)
+ <P::Target as Stream>::poll_next(self.as_deref_mut(), cx)
}
fn size_hint(&self) -> (usize, Option<usize>) {
diff --git a/library/core/src/time.rs b/library/core/src/time.rs
index 7330c86a11a..746d1cacfd0 100644
--- a/library/core/src/time.rs
+++ b/library/core/src/time.rs
@@ -180,8 +180,8 @@ impl Duration {
/// ```
#[stable(feature = "duration", since = "1.3.0")]
#[inline]
- #[rustc_const_unstable(feature = "duration_consts_2", issue = "72440")]
#[must_use]
+ #[rustc_const_stable(feature = "duration_consts_2", since = "1.58.0")]
pub const fn new(secs: u64, nanos: u32) -> Duration {
let secs = match secs.checked_add((nanos / NANOS_PER_SEC) as u64) {
Some(secs) => secs,
@@ -480,7 +480,7 @@ impl Duration {
#[must_use = "this returns the result of the operation, \
without modifying the original"]
#[inline]
- #[rustc_const_unstable(feature = "duration_consts_2", issue = "72440")]
+ #[rustc_const_stable(feature = "duration_consts_2", since = "1.58.0")]
pub const fn checked_add(self, rhs: Duration) -> Option<Duration> {
if let Some(mut secs) = self.secs.checked_add(rhs.secs) {
let mut nanos = self.nanos + rhs.nanos;
@@ -515,7 +515,7 @@ impl Duration {
#[must_use = "this returns the result of the operation, \
without modifying the original"]
#[inline]
- #[rustc_const_unstable(feature = "duration_consts_2", issue = "72440")]
+ #[rustc_const_stable(feature = "duration_consts_2", since = "1.58.0")]
pub const fn saturating_add(self, rhs: Duration) -> Duration {
match self.checked_add(rhs) {
Some(res) => res,
@@ -540,7 +540,7 @@ impl Duration {
#[must_use = "this returns the result of the operation, \
without modifying the original"]
#[inline]
- #[rustc_const_unstable(feature = "duration_consts_2", issue = "72440")]
+ #[rustc_const_stable(feature = "duration_consts_2", since = "1.58.0")]
pub const fn checked_sub(self, rhs: Duration) -> Option<Duration> {
if let Some(mut secs) = self.secs.checked_sub(rhs.secs) {
let nanos = if self.nanos >= rhs.nanos {
@@ -573,7 +573,7 @@ impl Duration {
#[must_use = "this returns the result of the operation, \
without modifying the original"]
#[inline]
- #[rustc_const_unstable(feature = "duration_consts_2", issue = "72440")]
+ #[rustc_const_stable(feature = "duration_consts_2", since = "1.58.0")]
pub const fn saturating_sub(self, rhs: Duration) -> Duration {
match self.checked_sub(rhs) {
Some(res) => res,
@@ -598,7 +598,7 @@ impl Duration {
#[must_use = "this returns the result of the operation, \
without modifying the original"]
#[inline]
- #[rustc_const_unstable(feature = "duration_consts_2", issue = "72440")]
+ #[rustc_const_stable(feature = "duration_consts_2", since = "1.58.0")]
pub const fn checked_mul(self, rhs: u32) -> Option<Duration> {
// Multiply nanoseconds as u64, because it cannot overflow that way.
let total_nanos = self.nanos as u64 * rhs as u64;
@@ -629,7 +629,7 @@ impl Duration {
#[must_use = "this returns the result of the operation, \
without modifying the original"]
#[inline]
- #[rustc_const_unstable(feature = "duration_consts_2", issue = "72440")]
+ #[rustc_const_stable(feature = "duration_consts_2", since = "1.58.0")]
pub const fn saturating_mul(self, rhs: u32) -> Duration {
match self.checked_mul(rhs) {
Some(res) => res,
@@ -655,7 +655,7 @@ impl Duration {
#[must_use = "this returns the result of the operation, \
without modifying the original"]
#[inline]
- #[rustc_const_unstable(feature = "duration_consts_2", issue = "72440")]
+ #[rustc_const_stable(feature = "duration_consts_2", since = "1.58.0")]
pub const fn checked_div(self, rhs: u32) -> Option<Duration> {
if rhs != 0 {
let secs = self.secs / (rhs as u64);
@@ -683,7 +683,7 @@ impl Duration {
#[stable(feature = "duration_float", since = "1.38.0")]
#[must_use]
#[inline]
- #[rustc_const_unstable(feature = "duration_consts_2", issue = "72440")]
+ #[rustc_const_unstable(feature = "duration_consts_float", issue = "72440")]
pub const fn as_secs_f64(&self) -> f64 {
(self.secs as f64) + (self.nanos as f64) / (NANOS_PER_SEC as f64)
}
@@ -702,7 +702,7 @@ impl Duration {
#[stable(feature = "duration_float", since = "1.38.0")]
#[must_use]
#[inline]
- #[rustc_const_unstable(feature = "duration_consts_2", issue = "72440")]
+ #[rustc_const_unstable(feature = "duration_consts_float", issue = "72440")]
pub const fn as_secs_f32(&self) -> f32 {
(self.secs as f32) + (self.nanos as f32) / (NANOS_PER_SEC as f32)
}
@@ -723,7 +723,7 @@ impl Duration {
#[stable(feature = "duration_float", since = "1.38.0")]
#[must_use]
#[inline]
- #[rustc_const_unstable(feature = "duration_consts_2", issue = "72440")]
+ #[rustc_const_unstable(feature = "duration_consts_float", issue = "72440")]
pub const fn from_secs_f64(secs: f64) -> Duration {
match Duration::try_from_secs_f64(secs) {
Ok(v) => v,
@@ -784,7 +784,7 @@ impl Duration {
#[stable(feature = "duration_float", since = "1.38.0")]
#[must_use]
#[inline]
- #[rustc_const_unstable(feature = "duration_consts_2", issue = "72440")]
+ #[rustc_const_unstable(feature = "duration_consts_float", issue = "72440")]
pub const fn from_secs_f32(secs: f32) -> Duration {
match Duration::try_from_secs_f32(secs) {
Ok(v) => v,
@@ -846,7 +846,7 @@ impl Duration {
#[must_use = "this returns the result of the operation, \
without modifying the original"]
#[inline]
- #[rustc_const_unstable(feature = "duration_consts_2", issue = "72440")]
+ #[rustc_const_unstable(feature = "duration_consts_float", issue = "72440")]
pub const fn mul_f64(self, rhs: f64) -> Duration {
Duration::from_secs_f64(rhs * self.as_secs_f64())
}
@@ -870,7 +870,7 @@ impl Duration {
#[must_use = "this returns the result of the operation, \
without modifying the original"]
#[inline]
- #[rustc_const_unstable(feature = "duration_consts_2", issue = "72440")]
+ #[rustc_const_unstable(feature = "duration_consts_float", issue = "72440")]
pub const fn mul_f32(self, rhs: f32) -> Duration {
Duration::from_secs_f32(rhs * self.as_secs_f32())
}
@@ -893,7 +893,7 @@ impl Duration {
#[must_use = "this returns the result of the operation, \
without modifying the original"]
#[inline]
- #[rustc_const_unstable(feature = "duration_consts_2", issue = "72440")]
+ #[rustc_const_unstable(feature = "duration_consts_float", issue = "72440")]
pub const fn div_f64(self, rhs: f64) -> Duration {
Duration::from_secs_f64(self.as_secs_f64() / rhs)
}
@@ -918,7 +918,7 @@ impl Duration {
#[must_use = "this returns the result of the operation, \
without modifying the original"]
#[inline]
- #[rustc_const_unstable(feature = "duration_consts_2", issue = "72440")]
+ #[rustc_const_unstable(feature = "duration_consts_float", issue = "72440")]
pub const fn div_f32(self, rhs: f32) -> Duration {
Duration::from_secs_f32(self.as_secs_f32() / rhs)
}
@@ -938,7 +938,7 @@ impl Duration {
#[must_use = "this returns the result of the operation, \
without modifying the original"]
#[inline]
- #[rustc_const_unstable(feature = "duration_consts_2", issue = "72440")]
+ #[rustc_const_unstable(feature = "duration_consts_float", issue = "72440")]
pub const fn div_duration_f64(self, rhs: Duration) -> f64 {
self.as_secs_f64() / rhs.as_secs_f64()
}
@@ -958,7 +958,7 @@ impl Duration {
#[must_use = "this returns the result of the operation, \
without modifying the original"]
#[inline]
- #[rustc_const_unstable(feature = "duration_consts_2", issue = "72440")]
+ #[rustc_const_unstable(feature = "duration_consts_float", issue = "72440")]
pub const fn div_duration_f32(self, rhs: Duration) -> f32 {
self.as_secs_f32() / rhs.as_secs_f32()
}
diff --git a/library/core/tests/array.rs b/library/core/tests/array.rs
index 7dc071b7423..a778779c0fd 100644
--- a/library/core/tests/array.rs
+++ b/library/core/tests/array.rs
@@ -28,11 +28,22 @@ fn array_try_from() {
($($N:expr)+) => {
$({
type Array = [u8; $N];
- let array: Array = [0; $N];
+ let mut array: Array = [0; $N];
let slice: &[u8] = &array[..];
let result = <&Array>::try_from(slice);
assert_eq!(&array, result.unwrap());
+
+ let result = <Array>::try_from(slice);
+ assert_eq!(&array, &result.unwrap());
+
+ let mut_slice: &mut [u8] = &mut array[..];
+ let result = <&mut Array>::try_from(mut_slice);
+ assert_eq!(&[0; $N], result.unwrap());
+
+ let mut_slice: &mut [u8] = &mut array[..];
+ let result = <Array>::try_from(mut_slice);
+ assert_eq!(&array, &result.unwrap());
})+
}
}
@@ -248,7 +259,7 @@ fn iterator_drops() {
// This test does not work on targets without panic=unwind support.
// To work around this problem, test is marked is should_panic, so it will
// be automagically skipped on unsuitable targets, such as
-// wasm32-unknown-unkown.
+// wasm32-unknown-unknown.
//
// It means that we use panic for indicating success.
#[test]
@@ -377,7 +388,7 @@ fn array_try_from_fn() {
let array = core::array::try_from_fn(|i| Ok::<_, SomeError>(i));
assert_eq!(array, Ok([0, 1, 2, 3, 4]));
- let another_array = core::array::try_from_fn::<SomeError, _, (), 2>(|_| Err(SomeError::Foo));
+ let another_array = core::array::try_from_fn::<_, Result<(), _>, 2>(|_| Err(SomeError::Foo));
assert_eq!(another_array, Err(SomeError::Foo));
}
@@ -459,6 +470,23 @@ fn array_split_array_mut() {
}
}
+#[test]
+fn array_rsplit_array_mut() {
+ let mut v = [1, 2, 3, 4, 5, 6];
+
+ {
+ let (left, right) = v.rsplit_array_mut::<0>();
+ assert_eq!(left, &mut [1, 2, 3, 4, 5, 6]);
+ assert_eq!(right, &mut []);
+ }
+
+ {
+ let (left, right) = v.rsplit_array_mut::<6>();
+ assert_eq!(left, &mut []);
+ assert_eq!(right, &mut [1, 2, 3, 4, 5, 6]);
+ }
+}
+
#[should_panic]
#[test]
fn array_split_array_ref_out_of_bounds() {
@@ -474,3 +502,169 @@ fn array_split_array_mut_out_of_bounds() {
v.split_array_mut::<7>();
}
+
+#[should_panic]
+#[test]
+fn array_rsplit_array_ref_out_of_bounds() {
+ let v = [1, 2, 3, 4, 5, 6];
+
+ v.rsplit_array_ref::<7>();
+}
+
+#[should_panic]
+#[test]
+fn array_rsplit_array_mut_out_of_bounds() {
+ let mut v = [1, 2, 3, 4, 5, 6];
+
+ v.rsplit_array_mut::<7>();
+}
+
+#[test]
+fn array_intoiter_advance_by() {
+ use std::cell::Cell;
+ struct DropCounter<'a>(usize, &'a Cell<usize>);
+ impl Drop for DropCounter<'_> {
+ fn drop(&mut self) {
+ let x = self.1.get();
+ self.1.set(x + 1);
+ }
+ }
+
+ let counter = Cell::new(0);
+ let a: [_; 100] = std::array::from_fn(|i| DropCounter(i, &counter));
+ let mut it = IntoIterator::into_iter(a);
+
+ let r = it.advance_by(1);
+ assert_eq!(r, Ok(()));
+ assert_eq!(it.len(), 99);
+ assert_eq!(counter.get(), 1);
+
+ let r = it.advance_by(0);
+ assert_eq!(r, Ok(()));
+ assert_eq!(it.len(), 99);
+ assert_eq!(counter.get(), 1);
+
+ let r = it.advance_by(11);
+ assert_eq!(r, Ok(()));
+ assert_eq!(it.len(), 88);
+ assert_eq!(counter.get(), 12);
+
+ let x = it.next();
+ assert_eq!(x.as_ref().map(|x| x.0), Some(12));
+ assert_eq!(it.len(), 87);
+ assert_eq!(counter.get(), 12);
+ drop(x);
+ assert_eq!(counter.get(), 13);
+
+ let r = it.advance_by(123456);
+ assert_eq!(r, Err(87));
+ assert_eq!(it.len(), 0);
+ assert_eq!(counter.get(), 100);
+
+ let r = it.advance_by(0);
+ assert_eq!(r, Ok(()));
+ assert_eq!(it.len(), 0);
+ assert_eq!(counter.get(), 100);
+
+ let r = it.advance_by(10);
+ assert_eq!(r, Err(0));
+ assert_eq!(it.len(), 0);
+ assert_eq!(counter.get(), 100);
+}
+
+#[test]
+fn array_intoiter_advance_back_by() {
+ use std::cell::Cell;
+ struct DropCounter<'a>(usize, &'a Cell<usize>);
+ impl Drop for DropCounter<'_> {
+ fn drop(&mut self) {
+ let x = self.1.get();
+ self.1.set(x + 1);
+ }
+ }
+
+ let counter = Cell::new(0);
+ let a: [_; 100] = std::array::from_fn(|i| DropCounter(i, &counter));
+ let mut it = IntoIterator::into_iter(a);
+
+ let r = it.advance_back_by(1);
+ assert_eq!(r, Ok(()));
+ assert_eq!(it.len(), 99);
+ assert_eq!(counter.get(), 1);
+
+ let r = it.advance_back_by(0);
+ assert_eq!(r, Ok(()));
+ assert_eq!(it.len(), 99);
+ assert_eq!(counter.get(), 1);
+
+ let r = it.advance_back_by(11);
+ assert_eq!(r, Ok(()));
+ assert_eq!(it.len(), 88);
+ assert_eq!(counter.get(), 12);
+
+ let x = it.next_back();
+ assert_eq!(x.as_ref().map(|x| x.0), Some(87));
+ assert_eq!(it.len(), 87);
+ assert_eq!(counter.get(), 12);
+ drop(x);
+ assert_eq!(counter.get(), 13);
+
+ let r = it.advance_back_by(123456);
+ assert_eq!(r, Err(87));
+ assert_eq!(it.len(), 0);
+ assert_eq!(counter.get(), 100);
+
+ let r = it.advance_back_by(0);
+ assert_eq!(r, Ok(()));
+ assert_eq!(it.len(), 0);
+ assert_eq!(counter.get(), 100);
+
+ let r = it.advance_back_by(10);
+ assert_eq!(r, Err(0));
+ assert_eq!(it.len(), 0);
+ assert_eq!(counter.get(), 100);
+}
+
+#[test]
+fn array_mixed_equality_integers() {
+ let array3: [i32; 3] = [1, 2, 3];
+ let array3b: [i32; 3] = [3, 2, 1];
+ let array4: [i32; 4] = [1, 2, 3, 4];
+
+ let slice3: &[i32] = &{ array3 };
+ let slice3b: &[i32] = &{ array3b };
+ let slice4: &[i32] = &{ array4 };
+ assert!(array3 == slice3);
+ assert!(array3 != slice3b);
+ assert!(array3 != slice4);
+ assert!(slice3 == array3);
+ assert!(slice3b != array3);
+ assert!(slice4 != array3);
+
+ let mut3: &mut [i32] = &mut { array3 };
+ let mut3b: &mut [i32] = &mut { array3b };
+ let mut4: &mut [i32] = &mut { array4 };
+ assert!(array3 == mut3);
+ assert!(array3 != mut3b);
+ assert!(array3 != mut4);
+ assert!(mut3 == array3);
+ assert!(mut3b != array3);
+ assert!(mut4 != array3);
+}
+
+#[test]
+fn array_mixed_equality_nans() {
+ let array3: [f32; 3] = [1.0, std::f32::NAN, 3.0];
+
+ let slice3: &[f32] = &{ array3 };
+ assert!(!(array3 == slice3));
+ assert!(array3 != slice3);
+ assert!(!(slice3 == array3));
+ assert!(slice3 != array3);
+
+ let mut3: &mut [f32] = &mut { array3 };
+ assert!(!(array3 == mut3));
+ assert!(array3 != mut3);
+ assert!(!(mut3 == array3));
+ assert!(mut3 != array3);
+}
diff --git a/library/core/tests/bool.rs b/library/core/tests/bool.rs
index e40f0482aee..4819ce911d6 100644
--- a/library/core/tests/bool.rs
+++ b/library/core/tests/bool.rs
@@ -88,4 +88,18 @@ fn test_bool_to_option() {
assert_eq!(true.then_some(0), Some(0));
assert_eq!(false.then(|| 0), None);
assert_eq!(true.then(|| 0), Some(0));
+
+ const fn zero() -> i32 {
+ 0
+ }
+
+ const A: Option<i32> = false.then_some(0);
+ const B: Option<i32> = true.then_some(0);
+ const C: Option<i32> = false.then(zero);
+ const D: Option<i32> = true.then(zero);
+
+ assert_eq!(A, None);
+ assert_eq!(B, Some(0));
+ assert_eq!(C, None);
+ assert_eq!(D, Some(0));
}
diff --git a/library/core/tests/cmp.rs b/library/core/tests/cmp.rs
index 11cf7add07a..58fee19ca74 100644
--- a/library/core/tests/cmp.rs
+++ b/library/core/tests/cmp.rs
@@ -203,3 +203,36 @@ fn cmp_default() {
assert!(Fool(false) != Fool(false));
assert_eq!(Fool(false), Fool(true));
}
+
+#[cfg(not(bootstrap))]
+mod const_cmp {
+ use super::*;
+
+ struct S(i32);
+
+ impl const PartialEq for S {
+ fn eq(&self, other: &Self) -> bool {
+ self.0 == other.0
+ }
+ }
+
+ impl const PartialOrd for S {
+ fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
+ let ret = match (self.0, other.0) {
+ (a, b) if a > b => Ordering::Greater,
+ (a, b) if a < b => Ordering::Less,
+ _ => Ordering::Equal,
+ };
+
+ Some(ret)
+ }
+ }
+
+ const _: () = assert!(S(1) == S(1));
+ const _: () = assert!(S(0) != S(1));
+
+ const _: () = assert!(S(1) <= S(1));
+ const _: () = assert!(S(1) >= S(1));
+ const _: () = assert!(S(0) < S(1));
+ const _: () = assert!(S(1) > S(0));
+}
diff --git a/library/core/tests/convert.rs b/library/core/tests/convert.rs
new file mode 100644
index 00000000000..f1048f4cf09
--- /dev/null
+++ b/library/core/tests/convert.rs
@@ -0,0 +1,16 @@
+#[test]
+fn convert() {
+ const fn from(x: i32) -> i32 {
+ i32::from(x)
+ }
+
+ const FOO: i32 = from(42);
+ assert_eq!(FOO, 42);
+
+ const fn into(x: Vec<String>) -> Vec<String> {
+ x.into()
+ }
+
+ const BAR: Vec<String> = into(Vec::new());
+ assert_eq!(BAR, Vec::<String>::new());
+}
diff --git a/library/core/tests/future.rs b/library/core/tests/future.rs
new file mode 100644
index 00000000000..e8b83b5cbc2
--- /dev/null
+++ b/library/core/tests/future.rs
@@ -0,0 +1,119 @@
+use std::future::{join, Future};
+use std::pin::Pin;
+use std::sync::Arc;
+use std::task::{Context, Poll, Wake};
+use std::thread;
+
+struct PollN {
+ val: usize,
+ polled: usize,
+ num: usize,
+}
+
+impl Future for PollN {
+ type Output = usize;
+
+ fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
+ self.polled += 1;
+
+ if self.polled == self.num {
+ return Poll::Ready(self.val);
+ }
+
+ cx.waker().wake_by_ref();
+ Poll::Pending
+ }
+}
+
+fn poll_n(val: usize, num: usize) -> PollN {
+ PollN { val, num, polled: 0 }
+}
+
+#[test]
+fn test_join() {
+ block_on(async move {
+ let x = join!(async { 0 }).await;
+ assert_eq!(x, 0);
+
+ let x = join!(async { 0 }, async { 1 }).await;
+ assert_eq!(x, (0, 1));
+
+ let x = join!(async { 0 }, async { 1 }, async { 2 }).await;
+ assert_eq!(x, (0, 1, 2));
+
+ let x = join!(
+ poll_n(0, 1),
+ poll_n(1, 5),
+ poll_n(2, 2),
+ poll_n(3, 1),
+ poll_n(4, 2),
+ poll_n(5, 3),
+ poll_n(6, 4),
+ poll_n(7, 1)
+ )
+ .await;
+ assert_eq!(x, (0, 1, 2, 3, 4, 5, 6, 7));
+
+ let y = String::new();
+ let x = join!(async {
+ println!("{}", &y);
+ 1
+ })
+ .await;
+ assert_eq!(x, 1);
+ });
+}
+
+/// Tests that `join!(…)` behaves "like a function": evaluating its arguments
+/// before applying any of its own logic.
+///
+/// _e.g._, `join!(async_fn(&borrowed), …)` does not consume `borrowed`;
+/// and `join!(opt_fut?, …)` does let that `?` refer to the callsite scope.
+mod test_join_function_like_value_arg_semantics {
+ use super::*;
+
+ async fn async_fn(_: impl Sized) {}
+
+ // no need to _run_ this test, just to compile it.
+ fn _join_does_not_unnecessarily_move_mentioned_bindings() {
+ let not_copy = vec![()];
+ let _ = join!(async_fn(&not_copy)); // should not move `not_copy`
+ let _ = &not_copy; // OK
+ }
+
+ #[test]
+ fn join_lets_control_flow_effects_such_as_try_flow_through() {
+ let maybe_fut = None;
+ if false {
+ *&mut { maybe_fut } = Some(async {});
+ loop {}
+ }
+ assert!(Option::is_none(&try { join!(maybe_fut?, async { unreachable!() }) }));
+ }
+
+ #[test]
+ fn join_is_able_to_handle_temporaries() {
+ let _ = join!(async_fn(&String::from("temporary")));
+ let () = block_on(join!(async_fn(&String::from("temporary"))));
+ }
+}
+
+fn block_on(fut: impl Future) {
+ struct Waker;
+ impl Wake for Waker {
+ fn wake(self: Arc<Self>) {
+ thread::current().unpark()
+ }
+ }
+
+ let waker = Arc::new(Waker).into();
+ let mut cx = Context::from_waker(&waker);
+ let mut fut = Box::pin(fut);
+
+ loop {
+ match fut.as_mut().poll(&mut cx) {
+ Poll::Ready(_) => break,
+ Poll::Pending => thread::park(),
+ }
+ }
+}
diff --git a/library/core/tests/intrinsics.rs b/library/core/tests/intrinsics.rs
index de163a60c98..84cef53b358 100644
--- a/library/core/tests/intrinsics.rs
+++ b/library/core/tests/intrinsics.rs
@@ -35,3 +35,33 @@ fn test_assume_can_be_in_const_contexts() {
let rs = unsafe { foo(42, 97) };
assert_eq!(rs, 0);
}
+
+#[test]
+#[cfg(not(bootstrap))]
+const fn test_write_bytes_in_const_contexts() {
+ use core::intrinsics::write_bytes;
+
+ const TEST: [u32; 3] = {
+ let mut arr = [1u32, 2, 3];
+ unsafe {
+ write_bytes(arr.as_mut_ptr(), 0, 2);
+ }
+ arr
+ };
+
+ assert!(TEST[0] == 0);
+ assert!(TEST[1] == 0);
+ assert!(TEST[2] == 3);
+
+ const TEST2: [u32; 3] = {
+ let mut arr = [1u32, 2, 3];
+ unsafe {
+ write_bytes(arr.as_mut_ptr(), 1, 2);
+ }
+ arr
+ };
+
+ assert!(TEST2[0] == 16843009);
+ assert!(TEST2[1] == 16843009);
+ assert!(TEST2[2] == 3);
+}
diff --git a/library/core/tests/iter/adapters/chain.rs b/library/core/tests/iter/adapters/chain.rs
index 4cd79687b53..f419f9cec12 100644
--- a/library/core/tests/iter/adapters/chain.rs
+++ b/library/core/tests/iter/adapters/chain.rs
@@ -34,6 +34,7 @@ fn test_iterator_chain_advance_by() {
iter.advance_by(i).unwrap();
assert_eq!(iter.next(), Some(&xs[i]));
assert_eq!(iter.advance_by(100), Err(len - i - 1));
+ iter.advance_by(0).unwrap();
}
for i in 0..ys.len() {
@@ -41,14 +42,17 @@ fn test_iterator_chain_advance_by() {
iter.advance_by(xs.len() + i).unwrap();
assert_eq!(iter.next(), Some(&ys[i]));
assert_eq!(iter.advance_by(100), Err(ys.len() - i - 1));
+ iter.advance_by(0).unwrap();
}
let mut iter = xs.iter().chain(ys);
iter.advance_by(len).unwrap();
assert_eq!(iter.next(), None);
+ iter.advance_by(0).unwrap();
let mut iter = xs.iter().chain(ys);
assert_eq!(iter.advance_by(len + 1), Err(len));
+ iter.advance_by(0).unwrap();
}
test_chain(&[], &[]);
@@ -67,6 +71,7 @@ fn test_iterator_chain_advance_back_by() {
iter.advance_back_by(i).unwrap();
assert_eq!(iter.next_back(), Some(&ys[ys.len() - i - 1]));
assert_eq!(iter.advance_back_by(100), Err(len - i - 1));
+ iter.advance_back_by(0).unwrap();
}
for i in 0..xs.len() {
@@ -74,14 +79,17 @@ fn test_iterator_chain_advance_back_by() {
iter.advance_back_by(ys.len() + i).unwrap();
assert_eq!(iter.next_back(), Some(&xs[xs.len() - i - 1]));
assert_eq!(iter.advance_back_by(100), Err(xs.len() - i - 1));
+ iter.advance_back_by(0).unwrap();
}
let mut iter = xs.iter().chain(ys);
iter.advance_back_by(len).unwrap();
assert_eq!(iter.next_back(), None);
+ iter.advance_back_by(0).unwrap();
let mut iter = xs.iter().chain(ys);
assert_eq!(iter.advance_back_by(len + 1), Err(len));
+ iter.advance_back_by(0).unwrap();
}
test_chain(&[], &[]);
diff --git a/library/core/tests/iter/adapters/flatten.rs b/library/core/tests/iter/adapters/flatten.rs
index 4ae50a2f066..f8ab8c9d444 100644
--- a/library/core/tests/iter/adapters/flatten.rs
+++ b/library/core/tests/iter/adapters/flatten.rs
@@ -1,5 +1,4 @@
use super::*;
-use core::array;
use core::iter::*;
#[test]
@@ -61,6 +60,7 @@ fn test_flatten_try_folds() {
#[test]
fn test_flatten_advance_by() {
let mut it = once(0..10).chain(once(10..30)).chain(once(30..40)).flatten();
+
it.advance_by(5).unwrap();
assert_eq!(it.next(), Some(5));
it.advance_by(9).unwrap();
@@ -72,6 +72,8 @@ fn test_flatten_advance_by() {
assert_eq!(it.advance_by(usize::MAX), Err(9));
assert_eq!(it.advance_back_by(usize::MAX), Err(0));
+ it.advance_by(0).unwrap();
+ it.advance_back_by(0).unwrap();
assert_eq!(it.size_hint(), (0, Some(0)));
}
@@ -131,7 +133,7 @@ fn test_double_ended_flatten() {
#[test]
fn test_trusted_len_flatten() {
fn assert_trusted_len<T: TrustedLen>(_: &T) {}
- let mut iter = array::IntoIter::new([[0; 3]; 4]).flatten();
+ let mut iter = IntoIterator::into_iter([[0; 3]; 4]).flatten();
assert_trusted_len(&iter);
assert_eq!(iter.size_hint(), (12, Some(12)));
@@ -140,21 +142,21 @@ fn test_trusted_len_flatten() {
iter.next_back();
assert_eq!(iter.size_hint(), (10, Some(10)));
- let iter = array::IntoIter::new([[(); usize::MAX]; 1]).flatten();
+ let iter = IntoIterator::into_iter([[(); usize::MAX]; 1]).flatten();
assert_eq!(iter.size_hint(), (usize::MAX, Some(usize::MAX)));
- let iter = array::IntoIter::new([[(); usize::MAX]; 2]).flatten();
+ let iter = IntoIterator::into_iter([[(); usize::MAX]; 2]).flatten();
assert_eq!(iter.size_hint(), (usize::MAX, None));
let mut a = [(); 10];
let mut b = [(); 10];
- let iter = array::IntoIter::new([&mut a, &mut b]).flatten();
+ let iter = IntoIterator::into_iter([&mut a, &mut b]).flatten();
assert_trusted_len(&iter);
assert_eq!(iter.size_hint(), (20, Some(20)));
core::mem::drop(iter);
- let iter = array::IntoIter::new([&a, &b]).flatten();
+ let iter = IntoIterator::into_iter([&a, &b]).flatten();
assert_trusted_len(&iter);
assert_eq!(iter.size_hint(), (20, Some(20)));
diff --git a/library/core/tests/iter/adapters/skip.rs b/library/core/tests/iter/adapters/skip.rs
index cf60057a164..0c464bdd03a 100644
--- a/library/core/tests/iter/adapters/skip.rs
+++ b/library/core/tests/iter/adapters/skip.rs
@@ -70,6 +70,17 @@ fn test_iterator_skip_nth() {
}
#[test]
+fn test_skip_advance_by() {
+ assert_eq!((0..0).skip(10).advance_by(0), Ok(()));
+ assert_eq!((0..0).skip(10).advance_by(1), Err(0));
+ assert_eq!((0u128..(usize::MAX as u128) + 1).skip(usize::MAX).advance_by(usize::MAX), Err(1));
+ assert_eq!((0u128..u128::MAX).skip(usize::MAX).advance_by(1), Ok(()));
+
+ assert_eq!((0..2).skip(1).advance_back_by(10), Err(1));
+ assert_eq!((0..0).skip(1).advance_back_by(0), Ok(()));
+}
+
+#[test]
fn test_iterator_skip_count() {
let xs = [0, 1, 2, 3, 5, 13, 15, 16, 17, 19, 20, 30];
diff --git a/library/core/tests/iter/adapters/take.rs b/library/core/tests/iter/adapters/take.rs
index 89f9cb1e2ed..bfb659f0a83 100644
--- a/library/core/tests/iter/adapters/take.rs
+++ b/library/core/tests/iter/adapters/take.rs
@@ -74,6 +74,28 @@ fn test_iterator_take_nth_back() {
}
#[test]
+fn test_take_advance_by() {
+ let mut take = (0..10).take(3);
+ assert_eq!(take.advance_by(2), Ok(()));
+ assert_eq!(take.next(), Some(2));
+ assert_eq!(take.advance_by(1), Err(0));
+
+ assert_eq!((0..0).take(10).advance_by(0), Ok(()));
+ assert_eq!((0..0).take(10).advance_by(1), Err(0));
+ assert_eq!((0..10).take(4).advance_by(5), Err(4));
+
+ let mut take = (0..10).take(3);
+ assert_eq!(take.advance_back_by(2), Ok(()));
+ assert_eq!(take.next(), Some(0));
+ assert_eq!(take.advance_back_by(1), Err(0));
+
+ assert_eq!((0..2).take(1).advance_back_by(10), Err(1));
+ assert_eq!((0..0).take(1).advance_back_by(1), Err(0));
+ assert_eq!((0..0).take(1).advance_back_by(0), Ok(()));
+ assert_eq!((0..usize::MAX).take(100).advance_back_by(usize::MAX), Err(100));
+}
+
+#[test]
fn test_iterator_take_short() {
let xs = [0, 1, 2, 3];
diff --git a/library/core/tests/iter/range.rs b/library/core/tests/iter/range.rs
index 6b4cf33efe1..84498a8eae5 100644
--- a/library/core/tests/iter/range.rs
+++ b/library/core/tests/iter/range.rs
@@ -300,6 +300,9 @@ fn test_range_advance_by() {
assert_eq!(r.advance_by(usize::MAX), Err(usize::MAX - 2));
+ r.advance_by(0).unwrap();
+ r.advance_back_by(0).unwrap();
+
let mut r = 0u128..u128::MAX;
r.advance_by(usize::MAX).unwrap();
diff --git a/library/core/tests/iter/traits/iterator.rs b/library/core/tests/iter/traits/iterator.rs
index 422e389e380..d38bca1e3b3 100644
--- a/library/core/tests/iter/traits/iterator.rs
+++ b/library/core/tests/iter/traits/iterator.rs
@@ -455,6 +455,34 @@ fn test_find_map() {
}
#[test]
+fn test_try_reduce() {
+ let v: Vec<usize> = vec![1, 2, 3, 4, 5];
+ let sum = v.into_iter().try_reduce(|x, y| x.checked_add(y));
+ assert_eq!(sum, Some(Some(15)));
+
+ let v: Vec<usize> = vec![1, 2, 3, 4, 5, usize::MAX];
+ let sum = v.into_iter().try_reduce(|x, y| x.checked_add(y));
+ assert_eq!(sum, None);
+
+ let v: Vec<usize> = Vec::new();
+ let sum = v.into_iter().try_reduce(|x, y| x.checked_add(y));
+ assert_eq!(sum, Some(None));
+
+ let v = vec!["1", "2", "3", "4", "5"];
+ let max = v.into_iter().try_reduce(|x, y| {
+ if x.parse::<usize>().ok()? > y.parse::<usize>().ok()? { Some(x) } else { Some(y) }
+ });
+ assert_eq!(max, Some(Some("5")));
+
+ let v = vec!["1", "2", "3", "4", "5"];
+ let max: Result<Option<_>, <usize as std::str::FromStr>::Err> =
+ v.into_iter().try_reduce(|x, y| {
+ if x.parse::<usize>()? > y.parse::<usize>()? { Ok(x) } else { Ok(y) }
+ });
+ assert_eq!(max, Ok(Some("5")));
+}
+
+#[test]
fn test_iterator_len() {
let v: &[_] = &[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
assert_eq!(v[..4].iter().count(), 4);
diff --git a/library/core/tests/lib.rs b/library/core/tests/lib.rs
index a56a1dbd17a..21562acf3d7 100644
--- a/library/core/tests/lib.rs
+++ b/library/core/tests/lib.rs
@@ -8,26 +8,30 @@
#![feature(cfg_panic)]
#![feature(cfg_target_has_atomic)]
#![feature(const_assume)]
+#![feature(const_bool_to_option)]
#![feature(const_cell_into_inner)]
#![feature(const_convert)]
+#![feature(const_maybe_uninit_as_mut_ptr)]
#![feature(const_maybe_uninit_assume_init)]
+#![feature(const_num_from_num)]
#![feature(const_ptr_read)]
#![feature(const_ptr_write)]
#![feature(const_ptr_offset)]
#![feature(const_trait_impl)]
-#![feature(const_num_from_num)]
#![feature(core_intrinsics)]
#![feature(core_private_bignum)]
#![feature(core_private_diy_float)]
#![feature(dec2flt)]
#![feature(div_duration)]
-#![feature(duration_consts_2)]
+#![feature(duration_consts_float)]
#![feature(duration_constants)]
#![feature(exact_size_is_empty)]
#![feature(extern_types)]
#![feature(flt2dec)]
#![feature(fmt_internals)]
#![feature(float_minimum_maximum)]
+#![feature(future_join)]
+#![feature(future_poll_fn)]
#![feature(array_from_fn)]
#![feature(hashmap_internals)]
#![feature(try_find)]
@@ -35,6 +39,7 @@
#![feature(pattern)]
#![feature(sort_internals)]
#![feature(slice_partition_at_index)]
+#![feature(slice_take)]
#![feature(maybe_uninit_uninit_array)]
#![feature(maybe_uninit_array_assume_init)]
#![feature(maybe_uninit_extra)]
@@ -45,6 +50,7 @@
#![feature(str_internals)]
#![feature(test)]
#![feature(trusted_len)]
+#![feature(try_blocks)]
#![feature(try_trait_v2)]
#![feature(slice_internals)]
#![feature(slice_partition_dedup)]
@@ -54,18 +60,20 @@
#![feature(iter_intersperse)]
#![feature(iter_is_partitioned)]
#![feature(iter_order_by)]
+#![feature(iterator_try_reduce)]
#![feature(const_mut_refs)]
#![feature(const_pin)]
#![feature(const_slice_from_raw_parts)]
-#![cfg_attr(bootstrap, feature(const_raw_ptr_deref))]
#![feature(never_type)]
#![feature(unwrap_infallible)]
#![feature(result_into_ok_or_err)]
-#![cfg_attr(not(bootstrap), feature(portable_simd))]
+#![feature(portable_simd)]
#![feature(ptr_metadata)]
#![feature(once_cell)]
+#![feature(option_result_contains)]
#![feature(unsized_tuple_coercion)]
#![feature(const_option)]
+#![feature(const_option_ext)]
#![feature(const_result)]
#![feature(integer_atomics)]
#![feature(int_roundings)]
@@ -91,7 +99,9 @@ mod char;
mod clone;
mod cmp;
mod const_ptr;
+mod convert;
mod fmt;
+mod future;
mod hash;
mod intrinsics;
mod iter;
@@ -107,7 +117,6 @@ mod pattern;
mod pin;
mod ptr;
mod result;
-#[cfg(not(bootstrap))]
mod simd;
mod slice;
mod str;
diff --git a/library/core/tests/mem.rs b/library/core/tests/mem.rs
index c780bb32ca9..3b13dc0832f 100644
--- a/library/core/tests/mem.rs
+++ b/library/core/tests/mem.rs
@@ -269,3 +269,35 @@ fn uninit_const_assume_init_read() {
const FOO: u32 = unsafe { MaybeUninit::new(42).assume_init_read() };
assert_eq!(FOO, 42);
}
+
+#[test]
+fn const_maybe_uninit() {
+ use std::ptr;
+
+ #[derive(Debug, PartialEq)]
+ struct Foo {
+ x: u8,
+ y: u8,
+ }
+
+ const FIELD_BY_FIELD: Foo = unsafe {
+ let mut val = MaybeUninit::uninit();
+ init_y(&mut val); // order shouldn't matter
+ init_x(&mut val);
+ val.assume_init()
+ };
+
+ const fn init_x(foo: &mut MaybeUninit<Foo>) {
+ unsafe {
+ *ptr::addr_of_mut!((*foo.as_mut_ptr()).x) = 1;
+ }
+ }
+
+ const fn init_y(foo: &mut MaybeUninit<Foo>) {
+ unsafe {
+ *ptr::addr_of_mut!((*foo.as_mut_ptr()).y) = 2;
+ }
+ }
+
+ assert_eq!(FIELD_BY_FIELD, Foo { x: 1, y: 2 });
+}
diff --git a/library/core/tests/option.rs b/library/core/tests/option.rs
index cd07d6c52c2..da692461261 100644
--- a/library/core/tests/option.rs
+++ b/library/core/tests/option.rs
@@ -86,17 +86,49 @@ fn test_and() {
let x: Option<isize> = None;
assert_eq!(x.and(Some(2)), None);
assert_eq!(x.and(None::<isize>), None);
+
+ const FOO: Option<isize> = Some(1);
+ const A: Option<isize> = FOO.and(Some(2));
+ const B: Option<isize> = FOO.and(None);
+ assert_eq!(A, Some(2));
+ assert_eq!(B, None);
+
+ const BAR: Option<isize> = None;
+ const C: Option<isize> = BAR.and(Some(2));
+ const D: Option<isize> = BAR.and(None);
+ assert_eq!(C, None);
+ assert_eq!(D, None);
}
#[test]
fn test_and_then() {
+ const fn plus_one(x: isize) -> Option<isize> {
+ Some(x + 1)
+ }
+
+ const fn none(_: isize) -> Option<isize> {
+ None
+ }
+
let x: Option<isize> = Some(1);
- assert_eq!(x.and_then(|x| Some(x + 1)), Some(2));
- assert_eq!(x.and_then(|_| None::<isize>), None);
+ assert_eq!(x.and_then(plus_one), Some(2));
+ assert_eq!(x.and_then(none), None);
let x: Option<isize> = None;
- assert_eq!(x.and_then(|x| Some(x + 1)), None);
- assert_eq!(x.and_then(|_| None::<isize>), None);
+ assert_eq!(x.and_then(plus_one), None);
+ assert_eq!(x.and_then(none), None);
+
+ const FOO: Option<isize> = Some(1);
+ const A: Option<isize> = FOO.and_then(plus_one);
+ const B: Option<isize> = FOO.and_then(none);
+ assert_eq!(A, Some(2));
+ assert_eq!(B, None);
+
+ const BAR: Option<isize> = None;
+ const C: Option<isize> = BAR.and_then(plus_one);
+ const D: Option<isize> = BAR.and_then(none);
+ assert_eq!(C, None);
+ assert_eq!(D, None);
}
#[test]
@@ -108,17 +140,49 @@ fn test_or() {
let x: Option<isize> = None;
assert_eq!(x.or(Some(2)), Some(2));
assert_eq!(x.or(None), None);
+
+ const FOO: Option<isize> = Some(1);
+ const A: Option<isize> = FOO.or(Some(2));
+ const B: Option<isize> = FOO.or(None);
+ assert_eq!(A, Some(1));
+ assert_eq!(B, Some(1));
+
+ const BAR: Option<isize> = None;
+ const C: Option<isize> = BAR.or(Some(2));
+ const D: Option<isize> = BAR.or(None);
+ assert_eq!(C, Some(2));
+ assert_eq!(D, None);
}
#[test]
fn test_or_else() {
+ const fn two() -> Option<isize> {
+ Some(2)
+ }
+
+ const fn none() -> Option<isize> {
+ None
+ }
+
let x: Option<isize> = Some(1);
- assert_eq!(x.or_else(|| Some(2)), Some(1));
- assert_eq!(x.or_else(|| None), Some(1));
+ assert_eq!(x.or_else(two), Some(1));
+ assert_eq!(x.or_else(none), Some(1));
let x: Option<isize> = None;
- assert_eq!(x.or_else(|| Some(2)), Some(2));
- assert_eq!(x.or_else(|| None), None);
+ assert_eq!(x.or_else(two), Some(2));
+ assert_eq!(x.or_else(none), None);
+
+ const FOO: Option<isize> = Some(1);
+ const A: Option<isize> = FOO.or_else(two);
+ const B: Option<isize> = FOO.or_else(none);
+ assert_eq!(A, Some(1));
+ assert_eq!(B, Some(1));
+
+ const BAR: Option<isize> = None;
+ const C: Option<isize> = BAR.or_else(two);
+ const D: Option<isize> = BAR.or_else(none);
+ assert_eq!(C, Some(2));
+ assert_eq!(D, None);
}
#[test]
@@ -149,15 +213,29 @@ fn test_unwrap_or() {
let x: Option<isize> = None;
assert_eq!(x.unwrap_or(2), 2);
+
+ const A: isize = Some(1).unwrap_or(2);
+ const B: isize = None.unwrap_or(2);
+ assert_eq!(A, 1);
+ assert_eq!(B, 2);
}
#[test]
fn test_unwrap_or_else() {
+ const fn two() -> isize {
+ 2
+ }
+
let x: Option<isize> = Some(1);
- assert_eq!(x.unwrap_or_else(|| 2), 1);
+ assert_eq!(x.unwrap_or_else(two), 1);
let x: Option<isize> = None;
- assert_eq!(x.unwrap_or_else(|| 2), 2);
+ assert_eq!(x.unwrap_or_else(two), 2);
+
+ const A: isize = Some(1).unwrap_or_else(two);
+ const B: isize = None.unwrap_or_else(two);
+ assert_eq!(A, 1);
+ assert_eq!(B, 2);
}
#[test]
diff --git a/library/core/tests/ptr.rs b/library/core/tests/ptr.rs
index 11af8090c3a..b9c0d75b702 100644
--- a/library/core/tests/ptr.rs
+++ b/library/core/tests/ptr.rs
@@ -251,6 +251,21 @@ fn test_set_memory() {
}
#[test]
+#[cfg(not(bootstrap))]
+fn test_set_memory_const() {
+ const XS: [u8; 20] = {
+ let mut xs = [0u8; 20];
+ let ptr = xs.as_mut_ptr();
+ unsafe {
+ ptr.write_bytes(5u8, xs.len());
+ }
+ xs
+ };
+
+ assert!(XS == [5u8; 20]);
+}
+
+#[test]
fn test_unsized_nonnull() {
let xs: &[i32] = &[1, 2, 3];
let ptr = unsafe { NonNull::new_unchecked(xs as *const [i32] as *mut [i32]) };
diff --git a/library/core/tests/simd.rs b/library/core/tests/simd.rs
index 50c92968c9d..b84f3228e78 100644
--- a/library/core/tests/simd.rs
+++ b/library/core/tests/simd.rs
@@ -7,7 +7,7 @@ fn testing() {
let x = f32x4::from_array([1.0, 1.0, 1.0, 1.0]);
let y = -x;
- let h = x * 0.5;
+ let h = x * f32x4::splat(0.5);
let r = y.abs();
assert_eq!(x, r);
diff --git a/library/core/tests/slice.rs b/library/core/tests/slice.rs
index 8d05e47edf4..20e2d8d47c0 100644
--- a/library/core/tests/slice.rs
+++ b/library/core/tests/slice.rs
@@ -154,6 +154,7 @@ fn test_iterator_advance_by() {
assert_eq!(iter.as_slice(), &v[3..]);
iter.advance_by(2).unwrap();
assert_eq!(iter.as_slice(), &[]);
+ iter.advance_by(0).unwrap();
}
#[test]
@@ -175,6 +176,7 @@ fn test_iterator_advance_back_by() {
assert_eq!(iter.as_slice(), &v[..v.len() - 3]);
iter.advance_back_by(2).unwrap();
assert_eq!(iter.as_slice(), &[]);
+ iter.advance_back_by(0).unwrap();
}
#[test]
@@ -2217,6 +2219,23 @@ fn slice_split_array_mut() {
}
}
+#[test]
+fn slice_rsplit_array_mut() {
+ let v = &mut [1, 2, 3, 4, 5, 6][..];
+
+ {
+ let (left, right) = v.rsplit_array_mut::<0>();
+ assert_eq!(left, [1, 2, 3, 4, 5, 6]);
+ assert_eq!(right, &mut []);
+ }
+
+ {
+ let (left, right) = v.rsplit_array_mut::<6>();
+ assert_eq!(left, []);
+ assert_eq!(right, &mut [1, 2, 3, 4, 5, 6]);
+ }
+}
+
#[should_panic]
#[test]
fn slice_split_array_ref_out_of_bounds() {
@@ -2232,3 +2251,130 @@ fn slice_split_array_mut_out_of_bounds() {
v.split_array_mut::<7>();
}
+
+#[should_panic]
+#[test]
+fn slice_rsplit_array_ref_out_of_bounds() {
+ let v = &[1, 2, 3, 4, 5, 6][..];
+
+ v.rsplit_array_ref::<7>();
+}
+
+#[should_panic]
+#[test]
+fn slice_rsplit_array_mut_out_of_bounds() {
+ let v = &mut [1, 2, 3, 4, 5, 6][..];
+
+ v.rsplit_array_mut::<7>();
+}
+
+macro_rules! take_tests {
+ (slice: &[], $($tts:tt)*) => {
+ take_tests!(ty: &[()], slice: &[], $($tts)*);
+ };
+ (slice: &mut [], $($tts:tt)*) => {
+ take_tests!(ty: &mut [()], slice: &mut [], $($tts)*);
+ };
+ (slice: &$slice:expr, $($tts:tt)*) => {
+ take_tests!(ty: &[_], slice: &$slice, $($tts)*);
+ };
+ (slice: &mut $slice:expr, $($tts:tt)*) => {
+ take_tests!(ty: &mut [_], slice: &mut $slice, $($tts)*);
+ };
+ (ty: $ty:ty, slice: $slice:expr, method: $method:ident, $(($test_name:ident, ($($args:expr),*), $output:expr, $remaining:expr),)*) => {
+ $(
+ #[test]
+ fn $test_name() {
+ let mut slice: $ty = $slice;
+ assert_eq!($output, slice.$method($($args)*));
+ let remaining: $ty = $remaining;
+ assert_eq!(remaining, slice);
+ }
+ )*
+ };
+}
+
+take_tests! {
+ slice: &[0, 1, 2, 3], method: take,
+ (take_in_bounds_range_to, (..1), Some(&[0] as _), &[1, 2, 3]),
+ (take_in_bounds_range_to_inclusive, (..=0), Some(&[0] as _), &[1, 2, 3]),
+ (take_in_bounds_range_from, (2..), Some(&[2, 3] as _), &[0, 1]),
+ (take_oob_range_to, (..5), None, &[0, 1, 2, 3]),
+ (take_oob_range_to_inclusive, (..=4), None, &[0, 1, 2, 3]),
+ (take_oob_range_from, (5..), None, &[0, 1, 2, 3]),
+}
+
+take_tests! {
+ slice: &mut [0, 1, 2, 3], method: take_mut,
+ (take_mut_in_bounds_range_to, (..1), Some(&mut [0] as _), &mut [1, 2, 3]),
+ (take_mut_in_bounds_range_to_inclusive, (..=0), Some(&mut [0] as _), &mut [1, 2, 3]),
+ (take_mut_in_bounds_range_from, (2..), Some(&mut [2, 3] as _), &mut [0, 1]),
+ (take_mut_oob_range_to, (..5), None, &mut [0, 1, 2, 3]),
+ (take_mut_oob_range_to_inclusive, (..=4), None, &mut [0, 1, 2, 3]),
+ (take_mut_oob_range_from, (5..), None, &mut [0, 1, 2, 3]),
+}
+
+take_tests! {
+ slice: &[1, 2], method: take_first,
+ (take_first_nonempty, (), Some(&1), &[2]),
+}
+
+take_tests! {
+ slice: &mut [1, 2], method: take_first_mut,
+ (take_first_mut_nonempty, (), Some(&mut 1), &mut [2]),
+}
+
+take_tests! {
+ slice: &[1, 2], method: take_last,
+ (take_last_nonempty, (), Some(&2), &[1]),
+}
+
+take_tests! {
+ slice: &mut [1, 2], method: take_last_mut,
+ (take_last_mut_nonempty, (), Some(&mut 2), &mut [1]),
+}
+
+take_tests! {
+ slice: &[], method: take_first,
+ (take_first_empty, (), None, &[]),
+}
+
+take_tests! {
+ slice: &mut [], method: take_first_mut,
+ (take_first_mut_empty, (), None, &mut []),
+}
+
+take_tests! {
+ slice: &[], method: take_last,
+ (take_last_empty, (), None, &[]),
+}
+
+take_tests! {
+ slice: &mut [], method: take_last_mut,
+ (take_last_mut_empty, (), None, &mut []),
+}
+
+const EMPTY_MAX: &'static [()] = &[(); usize::MAX];
+
+// can't be a constant due to const mutability rules
+macro_rules! empty_max_mut {
+ () => {
+ &mut [(); usize::MAX] as _
+ };
+}
+
+#[cfg(not(miri))] // Comparing usize::MAX many elements takes forever in Miri (and in rustc without optimizations)
+take_tests! {
+ slice: &[(); usize::MAX], method: take,
+ (take_in_bounds_max_range_to, (..usize::MAX), Some(EMPTY_MAX), &[(); 0]),
+ (take_oob_max_range_to_inclusive, (..=usize::MAX), None, EMPTY_MAX),
+ (take_in_bounds_max_range_from, (usize::MAX..), Some(&[] as _), EMPTY_MAX),
+}
+
+#[cfg(not(miri))] // Comparing usize::MAX many elements takes forever in Miri (and in rustc without optimizations)
+take_tests! {
+ slice: &mut [(); usize::MAX], method: take_mut,
+ (take_mut_in_bounds_max_range_to, (..usize::MAX), Some(empty_max_mut!()), &mut [(); 0]),
+ (take_mut_oob_max_range_to_inclusive, (..=usize::MAX), None, empty_max_mut!()),
+ (take_mut_in_bounds_max_range_from, (usize::MAX..), Some(&mut [] as _), empty_max_mut!()),
+}
diff --git a/library/panic_abort/src/lib.rs b/library/panic_abort/src/lib.rs
index dec5e0b2123..5c5632a9d01 100644
--- a/library/panic_abort/src/lib.rs
+++ b/library/panic_abort/src/lib.rs
@@ -14,7 +14,6 @@
#![feature(std_internals)]
#![feature(staged_api)]
#![feature(rustc_attrs)]
-#![feature(asm)]
#![feature(c_unwind)]
#[cfg(target_os = "android")]
@@ -69,11 +68,11 @@ pub unsafe extern "C-unwind" fn __rust_start_panic(_payload: *mut &mut dyn BoxMe
const FAST_FAIL_FATAL_APP_EXIT: usize = 7;
cfg_if::cfg_if! {
if #[cfg(any(target_arch = "x86", target_arch = "x86_64"))] {
- asm!("int $$0x29", in("ecx") FAST_FAIL_FATAL_APP_EXIT);
+ core::arch::asm!("int $$0x29", in("ecx") FAST_FAIL_FATAL_APP_EXIT);
} else if #[cfg(all(target_arch = "arm", target_feature = "thumb-mode"))] {
- asm!(".inst 0xDEFB", in("r0") FAST_FAIL_FATAL_APP_EXIT);
+ core::arch::asm!(".inst 0xDEFB", in("r0") FAST_FAIL_FATAL_APP_EXIT);
} else if #[cfg(target_arch = "aarch64")] {
- asm!("brk 0xF003", in("x0") FAST_FAIL_FATAL_APP_EXIT);
+ core::arch::asm!("brk 0xF003", in("x0") FAST_FAIL_FATAL_APP_EXIT);
} else {
core::intrinsics::abort();
}
diff --git a/library/panic_unwind/src/emcc.rs b/library/panic_unwind/src/emcc.rs
index e428f2fdaaa..12f0fe9c3c3 100644
--- a/library/panic_unwind/src/emcc.rs
+++ b/library/panic_unwind/src/emcc.rs
@@ -49,7 +49,7 @@ static EXCEPTION_TYPE_INFO: TypeInfo = TypeInfo {
};
struct Exception {
- // This is necessary because C++ code can capture our execption with
+ // This is necessary because C++ code can capture our exception with
// std::exception_ptr and rethrow it multiple times, possibly even in
// another thread.
caught: AtomicBool,
diff --git a/library/portable-simd/CONTRIBUTING.md b/library/portable-simd/CONTRIBUTING.md
index f9ba12d3a1b..9612fe871c6 100644
--- a/library/portable-simd/CONTRIBUTING.md
+++ b/library/portable-simd/CONTRIBUTING.md
@@ -15,7 +15,7 @@ SIMD can be quite complex, and even a "simple" issue can be huge. If an issue is
## CI
-We currently have 2 CI matrices through Travis CI and GitHub Actions that will automatically build and test your change in order to verify that `std::simd`'s portable API is, in fact, portable. If your change builds locally, but does not build on either, this is likely due to a platform-specific concern that your code has not addressed. Please consult the build logs and address the error, or ask for help if you need it.
+We currently use GitHub Actions which will automatically build and test your change in order to verify that `std::simd`'s portable API is, in fact, portable. If your change builds locally, but does not build in CI, this is likely due to a platform-specific concern that your code has not addressed. Please consult the build logs and address the error, or ask for help if you need it.
## Beyond stdsimd
diff --git a/library/portable-simd/README.md b/library/portable-simd/README.md
index da536a4d6f2..db0af2da606 100644
--- a/library/portable-simd/README.md
+++ b/library/portable-simd/README.md
@@ -1,5 +1,5 @@
# The Rust standard library's portable SIMD API
-[![Build Status](https://travis-ci.com/rust-lang/portable-simd.svg?branch=master)](https://travis-ci.com/rust-lang/portable-simd)
+![Build Status](https://github.com/rust-lang/portable-simd/actions/workflows/ci.yml/badge.svg?branch=master)
Code repository for the [Portable SIMD Project Group](https://github.com/rust-lang/project-portable-simd).
Please refer to [CONTRIBUTING.md](./CONTRIBUTING.md) for our contributing guidelines.
diff --git a/library/portable-simd/crates/core_simd/examples/nbody.rs b/library/portable-simd/crates/core_simd/examples/nbody.rs
index 779575985ed..43280feebbd 100644
--- a/library/portable-simd/crates/core_simd/examples/nbody.rs
+++ b/library/portable-simd/crates/core_simd/examples/nbody.rs
@@ -97,7 +97,7 @@ mod nbody {
let sun = &mut sun[0];
for body in rest {
let m_ratio = body.mass / SOLAR_MASS;
- sun.v -= body.v * m_ratio;
+ sun.v -= body.v * Simd::splat(m_ratio);
}
}
@@ -143,14 +143,14 @@ mod nbody {
let mut i = 0;
for j in 0..N_BODIES {
for k in j + 1..N_BODIES {
- let f = r[i] * mag[i];
- bodies[j].v -= f * bodies[k].mass;
- bodies[k].v += f * bodies[j].mass;
+ let f = r[i] * Simd::splat(mag[i]);
+ bodies[j].v -= f * Simd::splat(bodies[k].mass);
+ bodies[k].v += f * Simd::splat(bodies[j].mass);
i += 1
}
}
for body in bodies {
- body.x += dt * body.v
+ body.x += Simd::splat(dt) * body.v
}
}
diff --git a/library/portable-simd/crates/core_simd/src/comparisons.rs b/library/portable-simd/crates/core_simd/src/comparisons.rs
index 8c51baca8ed..edef5af3687 100644
--- a/library/portable-simd/crates/core_simd/src/comparisons.rs
+++ b/library/portable-simd/crates/core_simd/src/comparisons.rs
@@ -8,12 +8,14 @@ where
{
/// Test if each lane is equal to the corresponding lane in `other`.
#[inline]
+ #[must_use = "method returns a new mask and does not mutate the original value"]
pub fn lanes_eq(self, other: Self) -> Mask<T::Mask, LANES> {
unsafe { Mask::from_int_unchecked(intrinsics::simd_eq(self, other)) }
}
/// Test if each lane is not equal to the corresponding lane in `other`.
#[inline]
+ #[must_use = "method returns a new mask and does not mutate the original value"]
pub fn lanes_ne(self, other: Self) -> Mask<T::Mask, LANES> {
unsafe { Mask::from_int_unchecked(intrinsics::simd_ne(self, other)) }
}
@@ -26,24 +28,28 @@ where
{
/// Test if each lane is less than the corresponding lane in `other`.
#[inline]
+ #[must_use = "method returns a new mask and does not mutate the original value"]
pub fn lanes_lt(self, other: Self) -> Mask<T::Mask, LANES> {
unsafe { Mask::from_int_unchecked(intrinsics::simd_lt(self, other)) }
}
/// Test if each lane is greater than the corresponding lane in `other`.
#[inline]
+ #[must_use = "method returns a new mask and does not mutate the original value"]
pub fn lanes_gt(self, other: Self) -> Mask<T::Mask, LANES> {
unsafe { Mask::from_int_unchecked(intrinsics::simd_gt(self, other)) }
}
/// Test if each lane is less than or equal to the corresponding lane in `other`.
#[inline]
+ #[must_use = "method returns a new mask and does not mutate the original value"]
pub fn lanes_le(self, other: Self) -> Mask<T::Mask, LANES> {
unsafe { Mask::from_int_unchecked(intrinsics::simd_le(self, other)) }
}
/// Test if each lane is greater than or equal to the corresponding lane in `other`.
#[inline]
+ #[must_use = "method returns a new mask and does not mutate the original value"]
pub fn lanes_ge(self, other: Self) -> Mask<T::Mask, LANES> {
unsafe { Mask::from_int_unchecked(intrinsics::simd_ge(self, other)) }
}
diff --git a/library/portable-simd/crates/core_simd/src/lane_count.rs b/library/portable-simd/crates/core_simd/src/lane_count.rs
index b017e7d137e..3b316f12b3e 100644
--- a/library/portable-simd/crates/core_simd/src/lane_count.rs
+++ b/library/portable-simd/crates/core_simd/src/lane_count.rs
@@ -15,34 +15,28 @@ impl<const LANES: usize> LaneCount<LANES> {
pub trait SupportedLaneCount: Sealed {
#[doc(hidden)]
type BitMask: Copy + Default + AsRef<[u8]> + AsMut<[u8]>;
-
- #[doc(hidden)]
- type IntBitMask;
}
impl<const LANES: usize> Sealed for LaneCount<LANES> {}
impl SupportedLaneCount for LaneCount<1> {
type BitMask = [u8; 1];
- type IntBitMask = u8;
}
impl SupportedLaneCount for LaneCount<2> {
type BitMask = [u8; 1];
- type IntBitMask = u8;
}
impl SupportedLaneCount for LaneCount<4> {
type BitMask = [u8; 1];
- type IntBitMask = u8;
}
impl SupportedLaneCount for LaneCount<8> {
type BitMask = [u8; 1];
- type IntBitMask = u8;
}
impl SupportedLaneCount for LaneCount<16> {
type BitMask = [u8; 2];
- type IntBitMask = u16;
}
impl SupportedLaneCount for LaneCount<32> {
type BitMask = [u8; 4];
- type IntBitMask = u32;
+}
+impl SupportedLaneCount for LaneCount<64> {
+ type BitMask = [u8; 8];
}
diff --git a/library/portable-simd/crates/core_simd/src/masks.rs b/library/portable-simd/crates/core_simd/src/masks.rs
index d460da0d04f..191e9690313 100644
--- a/library/portable-simd/crates/core_simd/src/masks.rs
+++ b/library/portable-simd/crates/core_simd/src/masks.rs
@@ -129,6 +129,7 @@ where
/// # Safety
/// All lanes must be either 0 or -1.
#[inline]
+ #[must_use = "method returns a new mask and does not mutate the original value"]
pub unsafe fn from_int_unchecked(value: Simd<T, LANES>) -> Self {
unsafe { Self(mask_impl::Mask::from_int_unchecked(value)) }
}
@@ -139,6 +140,7 @@ where
/// # Panics
/// Panics if any lane is not 0 or -1.
#[inline]
+ #[must_use = "method returns a new mask and does not mutate the original value"]
pub fn from_int(value: Simd<T, LANES>) -> Self {
assert!(T::valid(value), "all values must be either 0 or -1",);
unsafe { Self::from_int_unchecked(value) }
@@ -147,6 +149,7 @@ where
/// Converts the mask to a vector of integers, where 0 represents `false` and -1
/// represents `true`.
#[inline]
+ #[must_use = "method returns a new vector and does not mutate the original value"]
pub fn to_int(self) -> Simd<T, LANES> {
self.0.to_int()
}
@@ -156,6 +159,7 @@ where
/// # Safety
/// `lane` must be less than `LANES`.
#[inline]
+ #[must_use = "method returns a new bool and does not mutate the original value"]
pub unsafe fn test_unchecked(&self, lane: usize) -> bool {
unsafe { self.0.test_unchecked(lane) }
}
@@ -165,6 +169,7 @@ where
/// # Panics
/// Panics if `lane` is greater than or equal to the number of lanes in the vector.
#[inline]
+ #[must_use = "method returns a new bool and does not mutate the original value"]
pub fn test(&self, lane: usize) -> bool {
assert!(lane < LANES, "lane index out of range");
unsafe { self.test_unchecked(lane) }
@@ -195,24 +200,30 @@ where
/// Convert this mask to a bitmask, with one bit set per lane.
#[cfg(feature = "generic_const_exprs")]
+ #[inline]
+ #[must_use = "method returns a new array and does not mutate the original value"]
pub fn to_bitmask(self) -> [u8; LaneCount::<LANES>::BITMASK_LEN] {
self.0.to_bitmask()
}
/// Convert a bitmask to a mask.
#[cfg(feature = "generic_const_exprs")]
+ #[inline]
+ #[must_use = "method returns a new mask and does not mutate the original value"]
pub fn from_bitmask(bitmask: [u8; LaneCount::<LANES>::BITMASK_LEN]) -> Self {
Self(mask_impl::Mask::from_bitmask(bitmask))
}
/// Returns true if any lane is set, or false otherwise.
#[inline]
+ #[must_use = "method returns a new bool and does not mutate the original value"]
pub fn any(self) -> bool {
self.0.any()
}
/// Returns true if all lanes are set, or false otherwise.
#[inline]
+ #[must_use = "method returns a new bool and does not mutate the original value"]
pub fn all(self) -> bool {
self.0.all()
}
@@ -245,6 +256,7 @@ where
LaneCount<LANES>: SupportedLaneCount,
{
#[inline]
+ #[must_use = "method returns a defaulted mask with all lanes set to false (0)"]
fn default() -> Self {
Self::splat(false)
}
@@ -256,6 +268,7 @@ where
LaneCount<LANES>: SupportedLaneCount,
{
#[inline]
+ #[must_use = "method returns a new bool and does not mutate the original value"]
fn eq(&self, other: &Self) -> bool {
self.0 == other.0
}
@@ -267,6 +280,7 @@ where
LaneCount<LANES>: SupportedLaneCount,
{
#[inline]
+ #[must_use = "method returns a new Ordering and does not mutate the original value"]
fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
self.0.partial_cmp(&other.0)
}
@@ -291,6 +305,7 @@ where
{
type Output = Self;
#[inline]
+ #[must_use = "method returns a new mask and does not mutate the original value"]
fn bitand(self, rhs: Self) -> Self {
Self(self.0 & rhs.0)
}
@@ -303,6 +318,7 @@ where
{
type Output = Self;
#[inline]
+ #[must_use = "method returns a new mask and does not mutate the original value"]
fn bitand(self, rhs: bool) -> Self {
self & Self::splat(rhs)
}
@@ -315,6 +331,7 @@ where
{
type Output = Mask<T, LANES>;
#[inline]
+ #[must_use = "method returns a new mask and does not mutate the original value"]
fn bitand(self, rhs: Mask<T, LANES>) -> Mask<T, LANES> {
Mask::splat(self) & rhs
}
@@ -327,6 +344,7 @@ where
{
type Output = Self;
#[inline]
+ #[must_use = "method returns a new mask and does not mutate the original value"]
fn bitor(self, rhs: Self) -> Self {
Self(self.0 | rhs.0)
}
@@ -339,6 +357,7 @@ where
{
type Output = Self;
#[inline]
+ #[must_use = "method returns a new mask and does not mutate the original value"]
fn bitor(self, rhs: bool) -> Self {
self | Self::splat(rhs)
}
@@ -351,6 +370,7 @@ where
{
type Output = Mask<T, LANES>;
#[inline]
+ #[must_use = "method returns a new mask and does not mutate the original value"]
fn bitor(self, rhs: Mask<T, LANES>) -> Mask<T, LANES> {
Mask::splat(self) | rhs
}
@@ -363,6 +383,7 @@ where
{
type Output = Self;
#[inline]
+ #[must_use = "method returns a new mask and does not mutate the original value"]
fn bitxor(self, rhs: Self) -> Self::Output {
Self(self.0 ^ rhs.0)
}
@@ -375,6 +396,7 @@ where
{
type Output = Self;
#[inline]
+ #[must_use = "method returns a new mask and does not mutate the original value"]
fn bitxor(self, rhs: bool) -> Self::Output {
self ^ Self::splat(rhs)
}
@@ -387,6 +409,7 @@ where
{
type Output = Mask<T, LANES>;
#[inline]
+ #[must_use = "method returns a new mask and does not mutate the original value"]
fn bitxor(self, rhs: Mask<T, LANES>) -> Self::Output {
Mask::splat(self) ^ rhs
}
@@ -399,6 +422,7 @@ where
{
type Output = Mask<T, LANES>;
#[inline]
+ #[must_use = "method returns a new mask and does not mutate the original value"]
fn not(self) -> Self::Output {
Self(!self.0)
}
diff --git a/library/portable-simd/crates/core_simd/src/masks/bitmask.rs b/library/portable-simd/crates/core_simd/src/masks/bitmask.rs
index 2689e1a88a8..4c964cb52e1 100644
--- a/library/portable-simd/crates/core_simd/src/masks/bitmask.rs
+++ b/library/portable-simd/crates/core_simd/src/masks/bitmask.rs
@@ -1,3 +1,4 @@
+#![allow(unused_imports)]
use super::MaskElement;
use crate::simd::intrinsics;
use crate::simd::{LaneCount, Simd, SupportedLaneCount};
@@ -73,6 +74,7 @@ where
LaneCount<LANES>: SupportedLaneCount,
{
#[inline]
+ #[must_use = "method returns a new mask and does not mutate the original value"]
pub fn splat(value: bool) -> Self {
let mut mask = <LaneCount<LANES> as SupportedLaneCount>::BitMask::default();
if value {
@@ -87,6 +89,7 @@ where
}
#[inline]
+ #[must_use = "method returns a new bool and does not mutate the original value"]
pub unsafe fn test_unchecked(&self, lane: usize) -> bool {
(self.0.as_ref()[lane / 8] >> (lane % 8)) & 0x1 > 0
}
@@ -99,30 +102,26 @@ where
}
#[inline]
+ #[must_use = "method returns a new vector and does not mutate the original value"]
pub fn to_int(self) -> Simd<T, LANES> {
unsafe {
- let mask: <LaneCount<LANES> as SupportedLaneCount>::IntBitMask =
- core::mem::transmute_copy(&self);
- intrinsics::simd_select_bitmask(mask, Simd::splat(T::TRUE), Simd::splat(T::FALSE))
+ crate::intrinsics::simd_select_bitmask(
+ self.0,
+ Simd::splat(T::TRUE),
+ Simd::splat(T::FALSE),
+ )
}
}
#[inline]
+ #[must_use = "method returns a new mask and does not mutate the original value"]
pub unsafe fn from_int_unchecked(value: Simd<T, LANES>) -> Self {
- // TODO remove the transmute when rustc is more flexible
- assert_eq!(
- core::mem::size_of::<<LaneCount::<LANES> as SupportedLaneCount>::BitMask>(),
- core::mem::size_of::<<LaneCount::<LANES> as SupportedLaneCount>::IntBitMask>(),
- );
- unsafe {
- let mask: <LaneCount<LANES> as SupportedLaneCount>::IntBitMask =
- intrinsics::simd_bitmask(value);
- Self(core::mem::transmute_copy(&mask), PhantomData)
- }
+ unsafe { Self(crate::intrinsics::simd_bitmask(value), PhantomData) }
}
#[cfg(feature = "generic_const_exprs")]
#[inline]
+ #[must_use = "method returns a new array and does not mutate the original value"]
pub fn to_bitmask(self) -> [u8; LaneCount::<LANES>::BITMASK_LEN] {
// Safety: these are the same type and we are laundering the generic
unsafe { core::mem::transmute_copy(&self.0) }
@@ -130,12 +129,14 @@ where
#[cfg(feature = "generic_const_exprs")]
#[inline]
+ #[must_use = "method returns a new mask and does not mutate the original value"]
pub fn from_bitmask(bitmask: [u8; LaneCount::<LANES>::BITMASK_LEN]) -> Self {
// Safety: these are the same type and we are laundering the generic
Self(unsafe { core::mem::transmute_copy(&bitmask) }, PhantomData)
}
#[inline]
+ #[must_use = "method returns a new mask and does not mutate the original value"]
pub fn convert<U>(self) -> Mask<U, LANES>
where
U: MaskElement,
@@ -144,11 +145,13 @@ where
}
#[inline]
+ #[must_use = "method returns a new bool and does not mutate the original value"]
pub fn any(self) -> bool {
self != Self::splat(false)
}
#[inline]
+ #[must_use = "method returns a new bool and does not mutate the original value"]
pub fn all(self) -> bool {
self == Self::splat(true)
}
@@ -162,6 +165,7 @@ where
{
type Output = Self;
#[inline]
+ #[must_use = "method returns a new mask and does not mutate the original value"]
fn bitand(mut self, rhs: Self) -> Self {
for (l, r) in self.0.as_mut().iter_mut().zip(rhs.0.as_ref().iter()) {
*l &= r;
@@ -178,6 +182,7 @@ where
{
type Output = Self;
#[inline]
+ #[must_use = "method returns a new mask and does not mutate the original value"]
fn bitor(mut self, rhs: Self) -> Self {
for (l, r) in self.0.as_mut().iter_mut().zip(rhs.0.as_ref().iter()) {
*l |= r;
@@ -193,6 +198,7 @@ where
{
type Output = Self;
#[inline]
+ #[must_use = "method returns a new mask and does not mutate the original value"]
fn bitxor(mut self, rhs: Self) -> Self::Output {
for (l, r) in self.0.as_mut().iter_mut().zip(rhs.0.as_ref().iter()) {
*l ^= r;
@@ -208,6 +214,7 @@ where
{
type Output = Self;
#[inline]
+ #[must_use = "method returns a new mask and does not mutate the original value"]
fn not(mut self) -> Self::Output {
for x in self.0.as_mut() {
*x = !*x;
diff --git a/library/portable-simd/crates/core_simd/src/masks/full_masks.rs b/library/portable-simd/crates/core_simd/src/masks/full_masks.rs
index dd981cedb93..5421ccbe3d8 100644
--- a/library/portable-simd/crates/core_simd/src/masks/full_masks.rs
+++ b/library/portable-simd/crates/core_simd/src/masks/full_masks.rs
@@ -23,6 +23,7 @@ where
LaneCount<LANES>: SupportedLaneCount,
{
#[inline]
+ #[must_use = "method returns a new mask and does not mutate the original value"]
fn clone(&self) -> Self {
*self
}
@@ -70,11 +71,14 @@ where
T: MaskElement,
LaneCount<LANES>: SupportedLaneCount,
{
+ #[inline]
+ #[must_use = "method returns a new mask and does not mutate the original value"]
pub fn splat(value: bool) -> Self {
Self(Simd::splat(if value { T::TRUE } else { T::FALSE }))
}
#[inline]
+ #[must_use = "method returns a new bool and does not mutate the original value"]
pub unsafe fn test_unchecked(&self, lane: usize) -> bool {
T::eq(self.0[lane], T::TRUE)
}
@@ -85,16 +89,19 @@ where
}
#[inline]
+ #[must_use = "method returns a new vector and does not mutate the original value"]
pub fn to_int(self) -> Simd<T, LANES> {
self.0
}
#[inline]
+ #[must_use = "method returns a new mask and does not mutate the original value"]
pub unsafe fn from_int_unchecked(value: Simd<T, LANES>) -> Self {
Self(value)
}
#[inline]
+ #[must_use = "method returns a new mask and does not mutate the original value"]
pub fn convert<U>(self) -> Mask<U, LANES>
where
U: MaskElement,
@@ -104,17 +111,11 @@ where
#[cfg(feature = "generic_const_exprs")]
#[inline]
+ #[must_use = "method returns a new array and does not mutate the original value"]
pub fn to_bitmask(self) -> [u8; LaneCount::<LANES>::BITMASK_LEN] {
unsafe {
- // TODO remove the transmute when rustc can use arrays of u8 as bitmasks
- assert_eq!(
- core::mem::size_of::<<LaneCount::<LANES> as SupportedLaneCount>::IntBitMask>(),
- LaneCount::<LANES>::BITMASK_LEN,
- );
- let bitmask: <LaneCount<LANES> as SupportedLaneCount>::IntBitMask =
- intrinsics::simd_bitmask(self.0);
let mut bitmask: [u8; LaneCount::<LANES>::BITMASK_LEN] =
- core::mem::transmute_copy(&bitmask);
+ crate::intrinsics::simd_bitmask(self.0);
// There is a bug where LLVM appears to implement this operation with the wrong
// bit order.
@@ -131,6 +132,7 @@ where
#[cfg(feature = "generic_const_exprs")]
#[inline]
+ #[must_use = "method returns a new mask and does not mutate the original value"]
pub fn from_bitmask(mut bitmask: [u8; LaneCount::<LANES>::BITMASK_LEN]) -> Self {
unsafe {
// There is a bug where LLVM appears to implement this operation with the wrong
@@ -142,15 +144,7 @@ where
}
}
- // TODO remove the transmute when rustc can use arrays of u8 as bitmasks
- assert_eq!(
- core::mem::size_of::<<LaneCount::<LANES> as SupportedLaneCount>::IntBitMask>(),
- LaneCount::<LANES>::BITMASK_LEN,
- );
- let bitmask: <LaneCount<LANES> as SupportedLaneCount>::IntBitMask =
- core::mem::transmute_copy(&bitmask);
-
- Self::from_int_unchecked(intrinsics::simd_select_bitmask(
+ Self::from_int_unchecked(crate::intrinsics::simd_select_bitmask(
bitmask,
Self::splat(true).to_int(),
Self::splat(false).to_int(),
@@ -159,11 +153,13 @@ where
}
#[inline]
+ #[must_use = "method returns a new bool and does not mutate the original value"]
pub fn any(self) -> bool {
unsafe { intrinsics::simd_reduce_any(self.to_int()) }
}
#[inline]
+ #[must_use = "method returns a new vector and does not mutate the original value"]
pub fn all(self) -> bool {
unsafe { intrinsics::simd_reduce_all(self.to_int()) }
}
@@ -186,6 +182,7 @@ where
{
type Output = Self;
#[inline]
+ #[must_use = "method returns a new mask and does not mutate the original value"]
fn bitand(self, rhs: Self) -> Self {
unsafe { Self(intrinsics::simd_and(self.0, rhs.0)) }
}
@@ -198,6 +195,7 @@ where
{
type Output = Self;
#[inline]
+ #[must_use = "method returns a new mask and does not mutate the original value"]
fn bitor(self, rhs: Self) -> Self {
unsafe { Self(intrinsics::simd_or(self.0, rhs.0)) }
}
@@ -210,6 +208,7 @@ where
{
type Output = Self;
#[inline]
+ #[must_use = "method returns a new mask and does not mutate the original value"]
fn bitxor(self, rhs: Self) -> Self {
unsafe { Self(intrinsics::simd_xor(self.0, rhs.0)) }
}
@@ -222,6 +221,7 @@ where
{
type Output = Self;
#[inline]
+ #[must_use = "method returns a new mask and does not mutate the original value"]
fn not(self) -> Self::Output {
Self::splat(true) ^ self
}
diff --git a/library/portable-simd/crates/core_simd/src/math.rs b/library/portable-simd/crates/core_simd/src/math.rs
index 2bae414ebfb..7435b6df918 100644
--- a/library/portable-simd/crates/core_simd/src/math.rs
+++ b/library/portable-simd/crates/core_simd/src/math.rs
@@ -17,7 +17,7 @@ macro_rules! impl_uint_arith {
/// let max = Simd::splat(MAX);
/// let unsat = x + max;
/// let sat = x.saturating_add(max);
- /// assert_eq!(x - 1, unsat);
+ /// assert_eq!(unsat, Simd::from_array([1, 0, MAX, MAX - 1]));
/// assert_eq!(sat, max);
/// ```
#[inline]
@@ -37,7 +37,7 @@ macro_rules! impl_uint_arith {
/// let max = Simd::splat(MAX);
/// let unsat = x - max;
/// let sat = x.saturating_sub(max);
- /// assert_eq!(unsat, x + 1);
+ /// assert_eq!(unsat, Simd::from_array([3, 2, 1, 0]));
/// assert_eq!(sat, Simd::splat(0));
#[inline]
pub fn saturating_sub(self, second: Self) -> Self {
@@ -105,7 +105,7 @@ macro_rules! impl_int_arith {
#[inline]
pub fn abs(self) -> Self {
const SHR: $ty = <$ty>::BITS as $ty - 1;
- let m = self >> SHR;
+ let m = self >> Simd::splat(SHR);
(self^m) - m
}
@@ -128,7 +128,7 @@ macro_rules! impl_int_arith {
pub fn saturating_abs(self) -> Self {
// arith shift for -1 or 0 mask based on sign bit, giving 2s complement
const SHR: $ty = <$ty>::BITS as $ty - 1;
- let m = self >> SHR;
+ let m = self >> Simd::splat(SHR);
(self^m).saturating_sub(m)
}
diff --git a/library/portable-simd/crates/core_simd/src/ops.rs b/library/portable-simd/crates/core_simd/src/ops.rs
index 5d7af474caf..3582c57870b 100644
--- a/library/portable-simd/crates/core_simd/src/ops.rs
+++ b/library/portable-simd/crates/core_simd/src/ops.rs
@@ -1,5 +1,13 @@
use crate::simd::intrinsics;
use crate::simd::{LaneCount, Simd, SimdElement, SupportedLaneCount};
+use core::ops::{Add, Mul};
+use core::ops::{BitAnd, BitOr, BitXor};
+use core::ops::{Div, Rem, Sub};
+use core::ops::{Shl, Shr};
+
+mod assign;
+mod deref;
+mod unary;
impl<I, T, const LANES: usize> core::ops::Index<I> for Simd<T, LANES>
where
@@ -57,166 +65,44 @@ macro_rules! impl_ref_ops {
$(#[$attrs])*
fn $fn($self_tok, $rhs_arg: $rhs_arg_ty) -> Self::Output $body
}
-
- impl<const $lanes: usize> core::ops::$trait<&'_ $rhs> for $type
- where
- LaneCount<$lanes2>: SupportedLaneCount,
- {
- type Output = <$type as core::ops::$trait<$rhs>>::Output;
-
- $(#[$attrs])*
- fn $fn($self_tok, $rhs_arg: &$rhs) -> Self::Output {
- core::ops::$trait::$fn($self_tok, *$rhs_arg)
- }
- }
-
- impl<const $lanes: usize> core::ops::$trait<$rhs> for &'_ $type
- where
- LaneCount<$lanes2>: SupportedLaneCount,
- {
- type Output = <$type as core::ops::$trait<$rhs>>::Output;
-
- $(#[$attrs])*
- fn $fn($self_tok, $rhs_arg: $rhs) -> Self::Output {
- core::ops::$trait::$fn(*$self_tok, $rhs_arg)
- }
- }
-
- impl<const $lanes: usize> core::ops::$trait<&'_ $rhs> for &'_ $type
- where
- LaneCount<$lanes2>: SupportedLaneCount,
- {
- type Output = <$type as core::ops::$trait<$rhs>>::Output;
-
- $(#[$attrs])*
- fn $fn($self_tok, $rhs_arg: &$rhs) -> Self::Output {
- core::ops::$trait::$fn(*$self_tok, *$rhs_arg)
- }
- }
};
-
- // binary assignment op
- {
- impl<const $lanes:ident: usize> core::ops::$trait:ident<$rhs:ty> for $type:ty
- where
- LaneCount<$lanes2:ident>: SupportedLaneCount,
- {
- $(#[$attrs:meta])*
- fn $fn:ident(&mut $self_tok:ident, $rhs_arg:ident: $rhs_arg_ty:ty) $body:tt
- }
- } => {
- impl<const $lanes: usize> core::ops::$trait<$rhs> for $type
- where
- LaneCount<$lanes2>: SupportedLaneCount,
- {
- $(#[$attrs])*
- fn $fn(&mut $self_tok, $rhs_arg: $rhs_arg_ty) $body
- }
-
- impl<const $lanes: usize> core::ops::$trait<&'_ $rhs> for $type
- where
- LaneCount<$lanes2>: SupportedLaneCount,
- {
- $(#[$attrs])*
- fn $fn(&mut $self_tok, $rhs_arg: &$rhs_arg_ty) {
- core::ops::$trait::$fn($self_tok, *$rhs_arg)
- }
- }
- };
-
- // unary op
- {
- impl<const $lanes:ident: usize> core::ops::$trait:ident for $type:ty
- where
- LaneCount<$lanes2:ident>: SupportedLaneCount,
- {
- type Output = $output:ty;
- fn $fn:ident($self_tok:ident) -> Self::Output $body:tt
- }
- } => {
- impl<const $lanes: usize> core::ops::$trait for $type
- where
- LaneCount<$lanes2>: SupportedLaneCount,
- {
- type Output = $output;
- fn $fn($self_tok) -> Self::Output $body
- }
-
- impl<const $lanes: usize> core::ops::$trait for &'_ $type
- where
- LaneCount<$lanes2>: SupportedLaneCount,
- {
- type Output = <$type as core::ops::$trait>::Output;
- fn $fn($self_tok) -> Self::Output {
- core::ops::$trait::$fn(*$self_tok)
- }
- }
- }
}
/// Automatically implements operators over vectors and scalars for a particular vector.
macro_rules! impl_op {
{ impl Add for $scalar:ty } => {
- impl_op! { @binary $scalar, Add::add, AddAssign::add_assign, simd_add }
+ impl_op! { @binary $scalar, Add::add, simd_add }
};
{ impl Sub for $scalar:ty } => {
- impl_op! { @binary $scalar, Sub::sub, SubAssign::sub_assign, simd_sub }
+ impl_op! { @binary $scalar, Sub::sub, simd_sub }
};
{ impl Mul for $scalar:ty } => {
- impl_op! { @binary $scalar, Mul::mul, MulAssign::mul_assign, simd_mul }
+ impl_op! { @binary $scalar, Mul::mul, simd_mul }
};
{ impl Div for $scalar:ty } => {
- impl_op! { @binary $scalar, Div::div, DivAssign::div_assign, simd_div }
+ impl_op! { @binary $scalar, Div::div, simd_div }
};
{ impl Rem for $scalar:ty } => {
- impl_op! { @binary $scalar, Rem::rem, RemAssign::rem_assign, simd_rem }
+ impl_op! { @binary $scalar, Rem::rem, simd_rem }
};
{ impl Shl for $scalar:ty } => {
- impl_op! { @binary $scalar, Shl::shl, ShlAssign::shl_assign, simd_shl }
+ impl_op! { @binary $scalar, Shl::shl, simd_shl }
};
{ impl Shr for $scalar:ty } => {
- impl_op! { @binary $scalar, Shr::shr, ShrAssign::shr_assign, simd_shr }
+ impl_op! { @binary $scalar, Shr::shr, simd_shr }
};
{ impl BitAnd for $scalar:ty } => {
- impl_op! { @binary $scalar, BitAnd::bitand, BitAndAssign::bitand_assign, simd_and }
+ impl_op! { @binary $scalar, BitAnd::bitand, simd_and }
};
{ impl BitOr for $scalar:ty } => {
- impl_op! { @binary $scalar, BitOr::bitor, BitOrAssign::bitor_assign, simd_or }
+ impl_op! { @binary $scalar, BitOr::bitor, simd_or }
};
{ impl BitXor for $scalar:ty } => {
- impl_op! { @binary $scalar, BitXor::bitxor, BitXorAssign::bitxor_assign, simd_xor }
- };
-
- { impl Not for $scalar:ty } => {
- impl_ref_ops! {
- impl<const LANES: usize> core::ops::Not for Simd<$scalar, LANES>
- where
- LaneCount<LANES>: SupportedLaneCount,
- {
- type Output = Self;
- fn not(self) -> Self::Output {
- self ^ Self::splat(!<$scalar>::default())
- }
- }
- }
- };
-
- { impl Neg for $scalar:ty } => {
- impl_ref_ops! {
- impl<const LANES: usize> core::ops::Neg for Simd<$scalar, LANES>
- where
- LaneCount<LANES>: SupportedLaneCount,
- {
- type Output = Self;
- fn neg(self) -> Self::Output {
- unsafe { intrinsics::simd_neg(self) }
- }
- }
- }
+ impl_op! { @binary $scalar, BitXor::bitxor, simd_xor }
};
// generic binary op with assignment when output is `Self`
- { @binary $scalar:ty, $trait:ident :: $trait_fn:ident, $assign_trait:ident :: $assign_trait_fn:ident, $intrinsic:ident } => {
+ { @binary $scalar:ty, $trait:ident :: $trait_fn:ident, $intrinsic:ident } => {
impl_ref_ops! {
impl<const LANES: usize> core::ops::$trait<Self> for Simd<$scalar, LANES>
where
@@ -232,60 +118,6 @@ macro_rules! impl_op {
}
}
}
-
- impl_ref_ops! {
- impl<const LANES: usize> core::ops::$trait<$scalar> for Simd<$scalar, LANES>
- where
- LaneCount<LANES>: SupportedLaneCount,
- {
- type Output = Self;
-
- #[inline]
- fn $trait_fn(self, rhs: $scalar) -> Self::Output {
- core::ops::$trait::$trait_fn(self, Self::splat(rhs))
- }
- }
- }
-
- impl_ref_ops! {
- impl<const LANES: usize> core::ops::$trait<Simd<$scalar, LANES>> for $scalar
- where
- LaneCount<LANES>: SupportedLaneCount,
- {
- type Output = Simd<$scalar, LANES>;
-
- #[inline]
- fn $trait_fn(self, rhs: Simd<$scalar, LANES>) -> Self::Output {
- core::ops::$trait::$trait_fn(Simd::splat(self), rhs)
- }
- }
- }
-
- impl_ref_ops! {
- impl<const LANES: usize> core::ops::$assign_trait<Self> for Simd<$scalar, LANES>
- where
- LaneCount<LANES>: SupportedLaneCount,
- {
- #[inline]
- fn $assign_trait_fn(&mut self, rhs: Self) {
- unsafe {
- *self = intrinsics::$intrinsic(*self, rhs);
- }
- }
- }
- }
-
- impl_ref_ops! {
- impl<const LANES: usize> core::ops::$assign_trait<$scalar> for Simd<$scalar, LANES>
- where
- LaneCount<LANES>: SupportedLaneCount,
- {
- #[inline]
- fn $assign_trait_fn(&mut self, rhs: $scalar) {
- core::ops::$assign_trait::$assign_trait_fn(self, Self::splat(rhs));
- }
- }
- }
};
}
@@ -298,7 +130,6 @@ macro_rules! impl_float_ops {
impl_op! { impl Mul for $scalar }
impl_op! { impl Div for $scalar }
impl_op! { impl Rem for $scalar }
- impl_op! { impl Neg for $scalar }
)*
};
}
@@ -313,7 +144,6 @@ macro_rules! impl_unsigned_int_ops {
impl_op! { impl BitAnd for $scalar }
impl_op! { impl BitOr for $scalar }
impl_op! { impl BitXor for $scalar }
- impl_op! { impl Not for $scalar }
// Integers panic on divide by 0
impl_ref_ops! {
@@ -344,67 +174,6 @@ macro_rules! impl_unsigned_int_ops {
}
}
- impl_ref_ops! {
- impl<const LANES: usize> core::ops::Div<$scalar> for Simd<$scalar, LANES>
- where
- LaneCount<LANES>: SupportedLaneCount,
- {
- type Output = Self;
-
- #[inline]
- fn div(self, rhs: $scalar) -> Self::Output {
- if rhs == 0 {
- panic!("attempt to divide by zero");
- }
- if <$scalar>::MIN != 0 &&
- self.as_array().iter().any(|x| *x == <$scalar>::MIN) &&
- rhs == -1 as _ {
- panic!("attempt to divide with overflow");
- }
- let rhs = Self::splat(rhs);
- unsafe { intrinsics::simd_div(self, rhs) }
- }
- }
- }
-
- impl_ref_ops! {
- impl<const LANES: usize> core::ops::Div<Simd<$scalar, LANES>> for $scalar
- where
- LaneCount<LANES>: SupportedLaneCount,
- {
- type Output = Simd<$scalar, LANES>;
-
- #[inline]
- fn div(self, rhs: Simd<$scalar, LANES>) -> Self::Output {
- Simd::splat(self) / rhs
- }
- }
- }
-
- impl_ref_ops! {
- impl<const LANES: usize> core::ops::DivAssign<Self> for Simd<$scalar, LANES>
- where
- LaneCount<LANES>: SupportedLaneCount,
- {
- #[inline]
- fn div_assign(&mut self, rhs: Self) {
- *self = *self / rhs;
- }
- }
- }
-
- impl_ref_ops! {
- impl<const LANES: usize> core::ops::DivAssign<$scalar> for Simd<$scalar, LANES>
- where
- LaneCount<LANES>: SupportedLaneCount,
- {
- #[inline]
- fn div_assign(&mut self, rhs: $scalar) {
- *self = *self / rhs;
- }
- }
- }
-
// remainder panics on zero divisor
impl_ref_ops! {
impl<const LANES: usize> core::ops::Rem<Self> for Simd<$scalar, LANES>
@@ -434,67 +203,6 @@ macro_rules! impl_unsigned_int_ops {
}
}
- impl_ref_ops! {
- impl<const LANES: usize> core::ops::Rem<$scalar> for Simd<$scalar, LANES>
- where
- LaneCount<LANES>: SupportedLaneCount,
- {
- type Output = Self;
-
- #[inline]
- fn rem(self, rhs: $scalar) -> Self::Output {
- if rhs == 0 {
- panic!("attempt to calculate the remainder with a divisor of zero");
- }
- if <$scalar>::MIN != 0 &&
- self.as_array().iter().any(|x| *x == <$scalar>::MIN) &&
- rhs == -1 as _ {
- panic!("attempt to calculate the remainder with overflow");
- }
- let rhs = Self::splat(rhs);
- unsafe { intrinsics::simd_rem(self, rhs) }
- }
- }
- }
-
- impl_ref_ops! {
- impl<const LANES: usize> core::ops::Rem<Simd<$scalar, LANES>> for $scalar
- where
- LaneCount<LANES>: SupportedLaneCount,
- {
- type Output = Simd<$scalar, LANES>;
-
- #[inline]
- fn rem(self, rhs: Simd<$scalar, LANES>) -> Self::Output {
- Simd::splat(self) % rhs
- }
- }
- }
-
- impl_ref_ops! {
- impl<const LANES: usize> core::ops::RemAssign<Self> for Simd<$scalar, LANES>
- where
- LaneCount<LANES>: SupportedLaneCount,
- {
- #[inline]
- fn rem_assign(&mut self, rhs: Self) {
- *self = *self % rhs;
- }
- }
- }
-
- impl_ref_ops! {
- impl<const LANES: usize> core::ops::RemAssign<$scalar> for Simd<$scalar, LANES>
- where
- LaneCount<LANES>: SupportedLaneCount,
- {
- #[inline]
- fn rem_assign(&mut self, rhs: $scalar) {
- *self = *self % rhs;
- }
- }
- }
-
// shifts panic on overflow
impl_ref_ops! {
impl<const LANES: usize> core::ops::Shl<Self> for Simd<$scalar, LANES>
@@ -519,49 +227,6 @@ macro_rules! impl_unsigned_int_ops {
}
impl_ref_ops! {
- impl<const LANES: usize> core::ops::Shl<$scalar> for Simd<$scalar, LANES>
- where
- LaneCount<LANES>: SupportedLaneCount,
- {
- type Output = Self;
-
- #[inline]
- fn shl(self, rhs: $scalar) -> Self::Output {
- if invalid_shift_rhs(rhs) {
- panic!("attempt to shift left with overflow");
- }
- let rhs = Self::splat(rhs);
- unsafe { intrinsics::simd_shl(self, rhs) }
- }
- }
- }
-
-
- impl_ref_ops! {
- impl<const LANES: usize> core::ops::ShlAssign<Self> for Simd<$scalar, LANES>
- where
- LaneCount<LANES>: SupportedLaneCount,
- {
- #[inline]
- fn shl_assign(&mut self, rhs: Self) {
- *self = *self << rhs;
- }
- }
- }
-
- impl_ref_ops! {
- impl<const LANES: usize> core::ops::ShlAssign<$scalar> for Simd<$scalar, LANES>
- where
- LaneCount<LANES>: SupportedLaneCount,
- {
- #[inline]
- fn shl_assign(&mut self, rhs: $scalar) {
- *self = *self << rhs;
- }
- }
- }
-
- impl_ref_ops! {
impl<const LANES: usize> core::ops::Shr<Self> for Simd<$scalar, LANES>
where
LaneCount<LANES>: SupportedLaneCount,
@@ -582,49 +247,6 @@ macro_rules! impl_unsigned_int_ops {
}
}
}
-
- impl_ref_ops! {
- impl<const LANES: usize> core::ops::Shr<$scalar> for Simd<$scalar, LANES>
- where
- LaneCount<LANES>: SupportedLaneCount,
- {
- type Output = Self;
-
- #[inline]
- fn shr(self, rhs: $scalar) -> Self::Output {
- if invalid_shift_rhs(rhs) {
- panic!("attempt to shift with overflow");
- }
- let rhs = Self::splat(rhs);
- unsafe { intrinsics::simd_shr(self, rhs) }
- }
- }
- }
-
-
- impl_ref_ops! {
- impl<const LANES: usize> core::ops::ShrAssign<Self> for Simd<$scalar, LANES>
- where
- LaneCount<LANES>: SupportedLaneCount,
- {
- #[inline]
- fn shr_assign(&mut self, rhs: Self) {
- *self = *self >> rhs;
- }
- }
- }
-
- impl_ref_ops! {
- impl<const LANES: usize> core::ops::ShrAssign<$scalar> for Simd<$scalar, LANES>
- where
- LaneCount<LANES>: SupportedLaneCount,
- {
- #[inline]
- fn shr_assign(&mut self, rhs: $scalar) {
- *self = *self >> rhs;
- }
- }
- }
)*
};
}
@@ -633,9 +255,6 @@ macro_rules! impl_unsigned_int_ops {
macro_rules! impl_signed_int_ops {
{ $($scalar:ty),* } => {
impl_unsigned_int_ops! { $($scalar),* }
- $( // scalar
- impl_op! { impl Neg for $scalar }
- )*
};
}
diff --git a/library/portable-simd/crates/core_simd/src/ops/assign.rs b/library/portable-simd/crates/core_simd/src/ops/assign.rs
new file mode 100644
index 00000000000..d2b48614fc9
--- /dev/null
+++ b/library/portable-simd/crates/core_simd/src/ops/assign.rs
@@ -0,0 +1,124 @@
+//! Assignment operators
+use super::*;
+use core::ops::{AddAssign, MulAssign}; // commutative binary op-assignment
+use core::ops::{BitAndAssign, BitOrAssign, BitXorAssign}; // commutative bit binary op-assignment
+use core::ops::{DivAssign, RemAssign, SubAssign}; // non-commutative binary op-assignment
+use core::ops::{ShlAssign, ShrAssign}; // non-commutative bit binary op-assignment
+
+// Arithmetic
+
+macro_rules! assign_ops {
+ ($(impl<T, U, const LANES: usize> $assignTrait:ident<U> for Simd<T, LANES>
+ where
+ Self: $trait:ident,
+ {
+ fn $assign_call:ident(rhs: U) {
+ $call:ident
+ }
+ })*) => {
+ $(impl<T, U, const LANES: usize> $assignTrait<U> for Simd<T, LANES>
+ where
+ Self: $trait<U, Output = Self>,
+ T: SimdElement,
+ LaneCount<LANES>: SupportedLaneCount,
+ {
+ #[inline]
+ fn $assign_call(&mut self, rhs: U) {
+ *self = self.$call(rhs);
+ }
+ })*
+ }
+}
+
+assign_ops! {
+ // Arithmetic
+ impl<T, U, const LANES: usize> AddAssign<U> for Simd<T, LANES>
+ where
+ Self: Add,
+ {
+ fn add_assign(rhs: U) {
+ add
+ }
+ }
+
+ impl<T, U, const LANES: usize> MulAssign<U> for Simd<T, LANES>
+ where
+ Self: Mul,
+ {
+ fn mul_assign(rhs: U) {
+ mul
+ }
+ }
+
+ impl<T, U, const LANES: usize> SubAssign<U> for Simd<T, LANES>
+ where
+ Self: Sub,
+ {
+ fn sub_assign(rhs: U) {
+ sub
+ }
+ }
+
+ impl<T, U, const LANES: usize> DivAssign<U> for Simd<T, LANES>
+ where
+ Self: Div,
+ {
+ fn div_assign(rhs: U) {
+ div
+ }
+ }
+ impl<T, U, const LANES: usize> RemAssign<U> for Simd<T, LANES>
+ where
+ Self: Rem,
+ {
+ fn rem_assign(rhs: U) {
+ rem
+ }
+ }
+
+ // Bitops
+ impl<T, U, const LANES: usize> BitAndAssign<U> for Simd<T, LANES>
+ where
+ Self: BitAnd,
+ {
+ fn bitand_assign(rhs: U) {
+ bitand
+ }
+ }
+
+ impl<T, U, const LANES: usize> BitOrAssign<U> for Simd<T, LANES>
+ where
+ Self: BitOr,
+ {
+ fn bitor_assign(rhs: U) {
+ bitor
+ }
+ }
+
+ impl<T, U, const LANES: usize> BitXorAssign<U> for Simd<T, LANES>
+ where
+ Self: BitXor,
+ {
+ fn bitxor_assign(rhs: U) {
+ bitxor
+ }
+ }
+
+ impl<T, U, const LANES: usize> ShlAssign<U> for Simd<T, LANES>
+ where
+ Self: Shl,
+ {
+ fn shl_assign(rhs: U) {
+ shl
+ }
+ }
+
+ impl<T, U, const LANES: usize> ShrAssign<U> for Simd<T, LANES>
+ where
+ Self: Shr,
+ {
+ fn shr_assign(rhs: U) {
+ shr
+ }
+ }
+}
diff --git a/library/portable-simd/crates/core_simd/src/ops/deref.rs b/library/portable-simd/crates/core_simd/src/ops/deref.rs
new file mode 100644
index 00000000000..9883a74c92d
--- /dev/null
+++ b/library/portable-simd/crates/core_simd/src/ops/deref.rs
@@ -0,0 +1,124 @@
+//! This module hacks in "implicit deref" for Simd's operators.
+//! Ideally, Rust would take care of this itself,
+//! and method calls usually handle the LHS implicitly.
+//! But this is not the case with arithmetic ops.
+use super::*;
+
+macro_rules! deref_lhs {
+ (impl<T, const LANES: usize> $trait:ident for $simd:ty {
+ fn $call:ident
+ }) => {
+ impl<T, const LANES: usize> $trait<$simd> for &$simd
+ where
+ T: SimdElement,
+ $simd: $trait<$simd, Output = $simd>,
+ LaneCount<LANES>: SupportedLaneCount,
+ {
+ type Output = Simd<T, LANES>;
+
+ #[inline]
+ #[must_use = "operator returns a new vector without mutating the inputs"]
+ fn $call(self, rhs: $simd) -> Self::Output {
+ (*self).$call(rhs)
+ }
+ }
+ };
+}
+
+macro_rules! deref_rhs {
+ (impl<T, const LANES: usize> $trait:ident for $simd:ty {
+ fn $call:ident
+ }) => {
+ impl<T, const LANES: usize> $trait<&$simd> for $simd
+ where
+ T: SimdElement,
+ $simd: $trait<$simd, Output = $simd>,
+ LaneCount<LANES>: SupportedLaneCount,
+ {
+ type Output = Simd<T, LANES>;
+
+ #[inline]
+ #[must_use = "operator returns a new vector without mutating the inputs"]
+ fn $call(self, rhs: &$simd) -> Self::Output {
+ self.$call(*rhs)
+ }
+ }
+ };
+}
+
+macro_rules! deref_ops {
+ ($(impl<T, const LANES: usize> $trait:ident for $simd:ty {
+ fn $call:ident
+ })*) => {
+ $(
+ deref_rhs! {
+ impl<T, const LANES: usize> $trait for $simd {
+ fn $call
+ }
+ }
+ deref_lhs! {
+ impl<T, const LANES: usize> $trait for $simd {
+ fn $call
+ }
+ }
+ impl<'lhs, 'rhs, T, const LANES: usize> $trait<&'rhs $simd> for &'lhs $simd
+ where
+ T: SimdElement,
+ $simd: $trait<$simd, Output = $simd>,
+ LaneCount<LANES>: SupportedLaneCount,
+ {
+ type Output = $simd;
+
+ #[inline]
+ #[must_use = "operator returns a new vector without mutating the inputs"]
+ fn $call(self, rhs: &$simd) -> Self::Output {
+ (*self).$call(*rhs)
+ }
+ }
+ )*
+ }
+}
+
+deref_ops! {
+ // Arithmetic
+ impl<T, const LANES: usize> Add for Simd<T, LANES> {
+ fn add
+ }
+
+ impl<T, const LANES: usize> Mul for Simd<T, LANES> {
+ fn mul
+ }
+
+ impl<T, const LANES: usize> Sub for Simd<T, LANES> {
+ fn sub
+ }
+
+ impl<T, const LANES: usize> Div for Simd<T, LANES> {
+ fn div
+ }
+
+ impl<T, const LANES: usize> Rem for Simd<T, LANES> {
+ fn rem
+ }
+
+ // Bitops
+ impl<T, const LANES: usize> BitAnd for Simd<T, LANES> {
+ fn bitand
+ }
+
+ impl<T, const LANES: usize> BitOr for Simd<T, LANES> {
+ fn bitor
+ }
+
+ impl<T, const LANES: usize> BitXor for Simd<T, LANES> {
+ fn bitxor
+ }
+
+ impl<T, const LANES: usize> Shl for Simd<T, LANES> {
+ fn shl
+ }
+
+ impl<T, const LANES: usize> Shr for Simd<T, LANES> {
+ fn shr
+ }
+}
diff --git a/library/portable-simd/crates/core_simd/src/ops/unary.rs b/library/portable-simd/crates/core_simd/src/ops/unary.rs
new file mode 100644
index 00000000000..4ebea560fc6
--- /dev/null
+++ b/library/portable-simd/crates/core_simd/src/ops/unary.rs
@@ -0,0 +1,77 @@
+use crate::simd::intrinsics;
+use crate::simd::{LaneCount, Simd, SimdElement, SupportedLaneCount};
+use core::ops::{Neg, Not}; // unary ops
+
+macro_rules! neg {
+ ($(impl<const LANES: usize> Neg for Simd<$scalar:ty, LANES>)*) => {
+ $(impl<const LANES: usize> Neg for Simd<$scalar, LANES>
+ where
+ $scalar: SimdElement,
+ LaneCount<LANES>: SupportedLaneCount,
+ {
+ type Output = Self;
+
+ #[inline]
+ #[must_use = "operator returns a new vector without mutating the input"]
+ fn neg(self) -> Self::Output {
+ unsafe { intrinsics::simd_neg(self) }
+ }
+ })*
+ }
+}
+
+neg! {
+ impl<const LANES: usize> Neg for Simd<f32, LANES>
+
+ impl<const LANES: usize> Neg for Simd<f64, LANES>
+
+ impl<const LANES: usize> Neg for Simd<i8, LANES>
+
+ impl<const LANES: usize> Neg for Simd<i16, LANES>
+
+ impl<const LANES: usize> Neg for Simd<i32, LANES>
+
+ impl<const LANES: usize> Neg for Simd<i64, LANES>
+
+ impl<const LANES: usize> Neg for Simd<isize, LANES>
+}
+
+macro_rules! not {
+ ($(impl<const LANES: usize> Not for Simd<$scalar:ty, LANES>)*) => {
+ $(impl<const LANES: usize> Not for Simd<$scalar, LANES>
+ where
+ $scalar: SimdElement,
+ LaneCount<LANES>: SupportedLaneCount,
+ {
+ type Output = Self;
+
+ #[inline]
+ #[must_use = "operator returns a new vector without mutating the input"]
+ fn not(self) -> Self::Output {
+ self ^ (Simd::splat(!(0 as $scalar)))
+ }
+ })*
+ }
+}
+
+not! {
+ impl<const LANES: usize> Not for Simd<i8, LANES>
+
+ impl<const LANES: usize> Not for Simd<i16, LANES>
+
+ impl<const LANES: usize> Not for Simd<i32, LANES>
+
+ impl<const LANES: usize> Not for Simd<i64, LANES>
+
+ impl<const LANES: usize> Not for Simd<isize, LANES>
+
+ impl<const LANES: usize> Not for Simd<u8, LANES>
+
+ impl<const LANES: usize> Not for Simd<u16, LANES>
+
+ impl<const LANES: usize> Not for Simd<u32, LANES>
+
+ impl<const LANES: usize> Not for Simd<u64, LANES>
+
+ impl<const LANES: usize> Not for Simd<usize, LANES>
+}
diff --git a/library/portable-simd/crates/core_simd/src/reduction.rs b/library/portable-simd/crates/core_simd/src/reduction.rs
index db0640aae79..e79a185816b 100644
--- a/library/portable-simd/crates/core_simd/src/reduction.rs
+++ b/library/portable-simd/crates/core_simd/src/reduction.rs
@@ -2,7 +2,8 @@ use crate::simd::intrinsics::{
simd_reduce_add_ordered, simd_reduce_and, simd_reduce_max, simd_reduce_min,
simd_reduce_mul_ordered, simd_reduce_or, simd_reduce_xor,
};
-use crate::simd::{LaneCount, Simd, SupportedLaneCount};
+use crate::simd::{LaneCount, Simd, SimdElement, SupportedLaneCount};
+use core::ops::{BitAnd, BitOr, BitXor};
macro_rules! impl_integer_reductions {
{ $scalar:ty } => {
@@ -22,27 +23,6 @@ macro_rules! impl_integer_reductions {
unsafe { simd_reduce_mul_ordered(self, 1) }
}
- /// Horizontal bitwise "and". Returns the cumulative bitwise "and" across the lanes of
- /// the vector.
- #[inline]
- pub fn horizontal_and(self) -> $scalar {
- unsafe { simd_reduce_and(self) }
- }
-
- /// Horizontal bitwise "or". Returns the cumulative bitwise "or" across the lanes of
- /// the vector.
- #[inline]
- pub fn horizontal_or(self) -> $scalar {
- unsafe { simd_reduce_or(self) }
- }
-
- /// Horizontal bitwise "xor". Returns the cumulative bitwise "xor" across the lanes of
- /// the vector.
- #[inline]
- pub fn horizontal_xor(self) -> $scalar {
- unsafe { simd_reduce_xor(self) }
- }
-
/// Horizontal maximum. Returns the maximum lane in the vector.
#[inline]
pub fn horizontal_max(self) -> $scalar {
@@ -121,3 +101,45 @@ macro_rules! impl_float_reductions {
impl_float_reductions! { f32 }
impl_float_reductions! { f64 }
+
+impl<T, const LANES: usize> Simd<T, LANES>
+where
+ Self: BitAnd<Self, Output = Self>,
+ T: SimdElement + BitAnd<T, Output = T>,
+ LaneCount<LANES>: SupportedLaneCount,
+{
+ /// Horizontal bitwise "and". Returns the cumulative bitwise "and" across the lanes of
+ /// the vector.
+ #[inline]
+ pub fn horizontal_and(self) -> T {
+ unsafe { simd_reduce_and(self) }
+ }
+}
+
+impl<T, const LANES: usize> Simd<T, LANES>
+where
+ Self: BitOr<Self, Output = Self>,
+ T: SimdElement + BitOr<T, Output = T>,
+ LaneCount<LANES>: SupportedLaneCount,
+{
+ /// Horizontal bitwise "or". Returns the cumulative bitwise "or" across the lanes of
+ /// the vector.
+ #[inline]
+ pub fn horizontal_or(self) -> T {
+ unsafe { simd_reduce_or(self) }
+ }
+}
+
+impl<T, const LANES: usize> Simd<T, LANES>
+where
+ Self: BitXor<Self, Output = Self>,
+ T: SimdElement + BitXor<T, Output = T>,
+ LaneCount<LANES>: SupportedLaneCount,
+{
+ /// Horizontal bitwise "xor". Returns the cumulative bitwise "xor" across the lanes of
+ /// the vector.
+ #[inline]
+ pub fn horizontal_xor(self) -> T {
+ unsafe { simd_reduce_xor(self) }
+ }
+}
diff --git a/library/portable-simd/crates/core_simd/src/select.rs b/library/portable-simd/crates/core_simd/src/select.rs
index d976231a03a..5d696ebf76e 100644
--- a/library/portable-simd/crates/core_simd/src/select.rs
+++ b/library/portable-simd/crates/core_simd/src/select.rs
@@ -17,6 +17,7 @@ where
LaneCount<LANES>: SupportedLaneCount,
{
#[inline]
+ #[must_use = "method returns a new vector and does not mutate the original inputs"]
fn select(mask: Mask<T::Mask, LANES>, true_values: Self, false_values: Self) -> Self {
unsafe { intrinsics::simd_select(mask.to_int(), true_values, false_values) }
}
@@ -35,6 +36,7 @@ where
LaneCount<LANES>: SupportedLaneCount,
{
#[inline]
+ #[must_use = "method returns a new vector and does not mutate the original inputs"]
fn select(mask: Self, true_values: Self, false_values: Self) -> Self {
mask & true_values | !mask & false_values
}
@@ -80,6 +82,7 @@ where
/// assert_eq!(c.to_array(), [true, false, true, false]);
/// ```
#[inline]
+ #[must_use = "method returns a new vector and does not mutate the original inputs"]
pub fn select<S: Select<Self>>(self, true_values: S, false_values: S) -> S {
S::select(self, true_values, false_values)
}
diff --git a/library/portable-simd/crates/core_simd/src/swizzle.rs b/library/portable-simd/crates/core_simd/src/swizzle.rs
index 62cda68f0a9..bdc489774a5 100644
--- a/library/portable-simd/crates/core_simd/src/swizzle.rs
+++ b/library/portable-simd/crates/core_simd/src/swizzle.rs
@@ -87,6 +87,8 @@ pub trait Swizzle<const INPUT_LANES: usize, const OUTPUT_LANES: usize> {
/// Create a new vector from the lanes of `vector`.
///
/// Lane `i` of the output is `vector[Self::INDEX[i]]`.
+ #[inline]
+ #[must_use = "method returns a new vector and does not mutate the original inputs"]
fn swizzle<T>(vector: Simd<T, INPUT_LANES>) -> Simd<T, OUTPUT_LANES>
where
T: SimdElement,
@@ -106,6 +108,8 @@ pub trait Swizzle2<const INPUT_LANES: usize, const OUTPUT_LANES: usize> {
///
/// Lane `i` is `first[j]` when `Self::INDEX[i]` is `First(j)`, or `second[j]` when it is
/// `Second(j)`.
+ #[inline]
+ #[must_use = "method returns a new vector and does not mutate the original inputs"]
fn swizzle2<T>(
first: Simd<T, INPUT_LANES>,
second: Simd<T, INPUT_LANES>,
@@ -182,6 +186,7 @@ where
{
/// Reverse the order of the lanes in the vector.
#[inline]
+ #[must_use = "method returns a new vector and does not mutate the original inputs"]
pub fn reverse(self) -> Self {
const fn reverse_index<const LANES: usize>() -> [usize; LANES] {
let mut index = [0; LANES];
@@ -206,6 +211,7 @@ where
/// while the last `LANES - OFFSET` elements move to the front. After calling `rotate_lanes_left`,
/// the element previously in lane `OFFSET` will become the first element in the slice.
#[inline]
+ #[must_use = "method returns a new vector and does not mutate the original inputs"]
pub fn rotate_lanes_left<const OFFSET: usize>(self) -> Self {
const fn rotate_index<const OFFSET: usize, const LANES: usize>() -> [usize; LANES] {
let offset = OFFSET % LANES;
@@ -231,6 +237,7 @@ where
/// the end while the last `OFFSET` elements move to the front. After calling `rotate_lanes_right`,
/// the element previously at index `LANES - OFFSET` will become the first element in the slice.
#[inline]
+ #[must_use = "method returns a new vector and does not mutate the original inputs"]
pub fn rotate_lanes_right<const OFFSET: usize>(self) -> Self {
const fn rotate_index<const OFFSET: usize, const LANES: usize>() -> [usize; LANES] {
let offset = LANES - OFFSET % LANES;
@@ -273,6 +280,7 @@ where
/// assert_eq!(y.to_array(), [2, 6, 3, 7]);
/// ```
#[inline]
+ #[must_use = "method returns a new vector and does not mutate the original inputs"]
pub fn interleave(self, other: Self) -> (Self, Self) {
const fn lo<const LANES: usize>() -> [Which; LANES] {
let mut idx = [Which::First(0); LANES];
@@ -336,6 +344,7 @@ where
/// assert_eq!(y.to_array(), [4, 5, 6, 7]);
/// ```
#[inline]
+ #[must_use = "method returns a new vector and does not mutate the original inputs"]
pub fn deinterleave(self, other: Self) -> (Self, Self) {
const fn even<const LANES: usize>() -> [Which; LANES] {
let mut idx = [Which::First(0); LANES];
diff --git a/library/portable-simd/crates/core_simd/src/vector/float.rs b/library/portable-simd/crates/core_simd/src/vector/float.rs
index c09d0ac84d2..4a4b23238c4 100644
--- a/library/portable-simd/crates/core_simd/src/vector/float.rs
+++ b/library/portable-simd/crates/core_simd/src/vector/float.rs
@@ -15,6 +15,7 @@ macro_rules! impl_float_vector {
/// Raw transmutation to an unsigned integer vector type with the
/// same size and number of lanes.
#[inline]
+ #[must_use = "method returns a new vector and does not mutate the original value"]
pub fn to_bits(self) -> Simd<$bits_ty, LANES> {
assert_eq!(core::mem::size_of::<Self>(), core::mem::size_of::<Simd<$bits_ty, LANES>>());
unsafe { core::mem::transmute_copy(&self) }
@@ -23,6 +24,7 @@ macro_rules! impl_float_vector {
/// Raw transmutation from an unsigned integer vector type with the
/// same size and number of lanes.
#[inline]
+ #[must_use = "method returns a new vector and does not mutate the original value"]
pub fn from_bits(bits: Simd<$bits_ty, LANES>) -> Self {
assert_eq!(core::mem::size_of::<Self>(), core::mem::size_of::<Simd<$bits_ty, LANES>>());
unsafe { core::mem::transmute_copy(&bits) }
@@ -31,6 +33,7 @@ macro_rules! impl_float_vector {
/// Produces a vector where every lane has the absolute value of the
/// equivalently-indexed lane in `self`.
#[inline]
+ #[must_use = "method returns a new vector and does not mutate the original value"]
pub fn abs(self) -> Self {
unsafe { intrinsics::simd_fabs(self) }
}
@@ -44,6 +47,7 @@ macro_rules! impl_float_vector {
/// hardware in mind.
#[cfg(feature = "std")]
#[inline]
+ #[must_use = "method returns a new vector and does not mutate the original value"]
pub fn mul_add(self, a: Self, b: Self) -> Self {
unsafe { intrinsics::simd_fma(self, a, b) }
}
@@ -51,6 +55,7 @@ macro_rules! impl_float_vector {
/// Produces a vector where every lane has the square root value
/// of the equivalently-indexed lane in `self`
#[inline]
+ #[must_use = "method returns a new vector and does not mutate the original value"]
#[cfg(feature = "std")]
pub fn sqrt(self) -> Self {
unsafe { intrinsics::simd_fsqrt(self) }
@@ -58,12 +63,14 @@ macro_rules! impl_float_vector {
/// Takes the reciprocal (inverse) of each lane, `1/x`.
#[inline]
+ #[must_use = "method returns a new vector and does not mutate the original value"]
pub fn recip(self) -> Self {
Self::splat(1.0) / self
}
/// Converts each lane from radians to degrees.
#[inline]
+ #[must_use = "method returns a new vector and does not mutate the original value"]
pub fn to_degrees(self) -> Self {
// to_degrees uses a special constant for better precision, so extract that constant
self * Self::splat(<$type>::to_degrees(1.))
@@ -71,6 +78,7 @@ macro_rules! impl_float_vector {
/// Converts each lane from degrees to radians.
#[inline]
+ #[must_use = "method returns a new vector and does not mutate the original value"]
pub fn to_radians(self) -> Self {
self * Self::splat(<$type>::to_radians(1.))
}
@@ -78,6 +86,7 @@ macro_rules! impl_float_vector {
/// Returns true for each lane if it has a positive sign, including
/// `+0.0`, `NaN`s with positive sign bit and positive infinity.
#[inline]
+ #[must_use = "method returns a new mask and does not mutate the original value"]
pub fn is_sign_positive(self) -> Mask<$mask_ty, LANES> {
!self.is_sign_negative()
}
@@ -85,6 +94,7 @@ macro_rules! impl_float_vector {
/// Returns true for each lane if it has a negative sign, including
/// `-0.0`, `NaN`s with negative sign bit and negative infinity.
#[inline]
+ #[must_use = "method returns a new mask and does not mutate the original value"]
pub fn is_sign_negative(self) -> Mask<$mask_ty, LANES> {
let sign_bits = self.to_bits() & Simd::splat((!0 >> 1) + 1);
sign_bits.lanes_gt(Simd::splat(0))
@@ -92,24 +102,28 @@ macro_rules! impl_float_vector {
/// Returns true for each lane if its value is `NaN`.
#[inline]
+ #[must_use = "method returns a new mask and does not mutate the original value"]
pub fn is_nan(self) -> Mask<$mask_ty, LANES> {
self.lanes_ne(self)
}
/// Returns true for each lane if its value is positive infinity or negative infinity.
#[inline]
+ #[must_use = "method returns a new mask and does not mutate the original value"]
pub fn is_infinite(self) -> Mask<$mask_ty, LANES> {
self.abs().lanes_eq(Self::splat(<$type>::INFINITY))
}
/// Returns true for each lane if its value is neither infinite nor `NaN`.
#[inline]
+ #[must_use = "method returns a new mask and does not mutate the original value"]
pub fn is_finite(self) -> Mask<$mask_ty, LANES> {
self.abs().lanes_lt(Self::splat(<$type>::INFINITY))
}
/// Returns true for each lane if its value is subnormal.
#[inline]
+ #[must_use = "method returns a new mask and does not mutate the original value"]
pub fn is_subnormal(self) -> Mask<$mask_ty, LANES> {
self.abs().lanes_ne(Self::splat(0.0)) & (self.to_bits() & Self::splat(<$type>::INFINITY).to_bits()).lanes_eq(Simd::splat(0))
}
@@ -117,6 +131,7 @@ macro_rules! impl_float_vector {
/// Returns true for each lane if its value is neither neither zero, infinite,
/// subnormal, or `NaN`.
#[inline]
+ #[must_use = "method returns a new mask and does not mutate the original value"]
pub fn is_normal(self) -> Mask<$mask_ty, LANES> {
!(self.abs().lanes_eq(Self::splat(0.0)) | self.is_nan() | self.is_subnormal() | self.is_infinite())
}
@@ -127,6 +142,7 @@ macro_rules! impl_float_vector {
/// * `-1.0` if the number is negative, `-0.0`, or `NEG_INFINITY`
/// * `NAN` if the number is `NAN`
#[inline]
+ #[must_use = "method returns a new vector and does not mutate the original value"]
pub fn signum(self) -> Self {
self.is_nan().select(Self::splat(<$type>::NAN), Self::splat(1.0).copysign(self))
}
@@ -135,6 +151,7 @@ macro_rules! impl_float_vector {
///
/// If any lane is a `NAN`, then a `NAN` with the sign of `sign` is returned.
#[inline]
+ #[must_use = "method returns a new vector and does not mutate the original value"]
pub fn copysign(self, sign: Self) -> Self {
let sign_bit = sign.to_bits() & Self::splat(-0.).to_bits();
let magnitude = self.to_bits() & !Self::splat(-0.).to_bits();
@@ -145,6 +162,7 @@ macro_rules! impl_float_vector {
///
/// If one of the values is `NAN`, then the other value is returned.
#[inline]
+ #[must_use = "method returns a new vector and does not mutate the original value"]
pub fn min(self, other: Self) -> Self {
// TODO consider using an intrinsic
self.is_nan().select(
@@ -157,6 +175,7 @@ macro_rules! impl_float_vector {
///
/// If one of the values is `NAN`, then the other value is returned.
#[inline]
+ #[must_use = "method returns a new vector and does not mutate the original value"]
pub fn max(self, other: Self) -> Self {
// TODO consider using an intrinsic
self.is_nan().select(
@@ -171,6 +190,7 @@ macro_rules! impl_float_vector {
/// greater than `max`, and the corresponding lane in `min` if the lane is less
/// than `min`. Otherwise returns the lane in `self`.
#[inline]
+ #[must_use = "method returns a new vector and does not mutate the original value"]
pub fn clamp(self, min: Self, max: Self) -> Self {
assert!(
min.lanes_le(max).all(),
diff --git a/library/portable-simd/crates/core_simd/src/vector/ptr.rs b/library/portable-simd/crates/core_simd/src/vector/ptr.rs
index ac9b98ca031..c668d9a6eae 100644
--- a/library/portable-simd/crates/core_simd/src/vector/ptr.rs
+++ b/library/portable-simd/crates/core_simd/src/vector/ptr.rs
@@ -23,7 +23,7 @@ where
pub fn wrapping_add(self, addend: Simd<usize, LANES>) -> Self {
unsafe {
let x: Simd<usize, LANES> = mem::transmute_copy(&self);
- mem::transmute_copy(&{ x + (addend * mem::size_of::<T>()) })
+ mem::transmute_copy(&{ x + (addend * Simd::splat(mem::size_of::<T>())) })
}
}
}
@@ -49,7 +49,7 @@ where
pub fn wrapping_add(self, addend: Simd<usize, LANES>) -> Self {
unsafe {
let x: Simd<usize, LANES> = mem::transmute_copy(&self);
- mem::transmute_copy(&{ x + (addend * mem::size_of::<T>()) })
+ mem::transmute_copy(&{ x + (addend * Simd::splat(mem::size_of::<T>())) })
}
}
}
diff --git a/library/portable-simd/crates/core_simd/src/vendor/x86.rs b/library/portable-simd/crates/core_simd/src/vendor/x86.rs
index d3c19ccc539..0dd47015ed2 100644
--- a/library/portable-simd/crates/core_simd/src/vendor/x86.rs
+++ b/library/portable-simd/crates/core_simd/src/vendor/x86.rs
@@ -8,10 +8,10 @@ use core::arch::x86_64::*;
from_transmute! { unsafe u8x16 => __m128i }
from_transmute! { unsafe u8x32 => __m256i }
-//from_transmute! { unsafe u8x64 => __m512i }
+from_transmute! { unsafe u8x64 => __m512i }
from_transmute! { unsafe i8x16 => __m128i }
from_transmute! { unsafe i8x32 => __m256i }
-//from_transmute! { unsafe i8x64 => __m512i }
+from_transmute! { unsafe i8x64 => __m512i }
from_transmute! { unsafe u16x8 => __m128i }
from_transmute! { unsafe u16x16 => __m256i }
diff --git a/library/portable-simd/crates/core_simd/tests/autoderef.rs b/library/portable-simd/crates/core_simd/tests/autoderef.rs
new file mode 100644
index 00000000000..9359da16ee5
--- /dev/null
+++ b/library/portable-simd/crates/core_simd/tests/autoderef.rs
@@ -0,0 +1,22 @@
+// Test that we handle all our "auto-deref" cases correctly.
+#![feature(portable_simd)]
+use core_simd::f32x4;
+
+#[cfg(target_arch = "wasm32")]
+use wasm_bindgen_test::*;
+
+#[cfg(target_arch = "wasm32")]
+wasm_bindgen_test_configure!(run_in_browser);
+
+#[test]
+#[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
+fn deref() {
+ let x = f32x4::splat(1.0);
+ let y = f32x4::splat(2.0);
+ let a = &x;
+ let b = &y;
+ assert_eq!(f32x4::splat(3.0), x + y);
+ assert_eq!(f32x4::splat(3.0), x + b);
+ assert_eq!(f32x4::splat(3.0), a + y);
+ assert_eq!(f32x4::splat(3.0), a + b);
+}
diff --git a/library/portable-simd/crates/core_simd/tests/ops_macros.rs b/library/portable-simd/crates/core_simd/tests/ops_macros.rs
index 31b7ee20695..43ddde4c55e 100644
--- a/library/portable-simd/crates/core_simd/tests/ops_macros.rs
+++ b/library/portable-simd/crates/core_simd/tests/ops_macros.rs
@@ -38,22 +38,6 @@ macro_rules! impl_binary_op_test {
);
}
- fn scalar_rhs<const LANES: usize>() {
- test_helpers::test_binary_scalar_rhs_elementwise(
- &<Simd<$scalar, LANES> as core::ops::$trait<$scalar>>::$fn,
- &$scalar_fn,
- &|_, _| true,
- );
- }
-
- fn scalar_lhs<const LANES: usize>() {
- test_helpers::test_binary_scalar_lhs_elementwise(
- &<$scalar as core::ops::$trait<Simd<$scalar, LANES>>>::$fn,
- &$scalar_fn,
- &|_, _| true,
- );
- }
-
fn assign<const LANES: usize>() {
test_helpers::test_binary_elementwise(
&|mut a, b| { <Simd<$scalar, LANES> as core::ops::$trait_assign>::$fn_assign(&mut a, b); a },
@@ -61,14 +45,6 @@ macro_rules! impl_binary_op_test {
&|_, _| true,
);
}
-
- fn assign_scalar_rhs<const LANES: usize>() {
- test_helpers::test_binary_scalar_rhs_elementwise(
- &|mut a, b| { <Simd<$scalar, LANES> as core::ops::$trait_assign<$scalar>>::$fn_assign(&mut a, b); a },
- &$scalar_fn,
- &|_, _| true,
- );
- }
}
}
};
@@ -99,22 +75,6 @@ macro_rules! impl_binary_checked_op_test {
);
}
- fn scalar_rhs<const LANES: usize>() {
- test_helpers::test_binary_scalar_rhs_elementwise(
- &<Simd<$scalar, LANES> as core::ops::$trait<$scalar>>::$fn,
- &$scalar_fn,
- &|x, y| x.iter().all(|x| $check_fn(*x, y)),
- );
- }
-
- fn scalar_lhs<const LANES: usize>() {
- test_helpers::test_binary_scalar_lhs_elementwise(
- &<$scalar as core::ops::$trait<Simd<$scalar, LANES>>>::$fn,
- &$scalar_fn,
- &|x, y| y.iter().all(|y| $check_fn(x, *y)),
- );
- }
-
fn assign<const LANES: usize>() {
test_helpers::test_binary_elementwise(
&|mut a, b| { <Simd<$scalar, LANES> as core::ops::$trait_assign>::$fn_assign(&mut a, b); a },
@@ -122,14 +82,6 @@ macro_rules! impl_binary_checked_op_test {
&|x, y| x.iter().zip(y.iter()).all(|(x, y)| $check_fn(*x, *y)),
)
}
-
- fn assign_scalar_rhs<const LANES: usize>() {
- test_helpers::test_binary_scalar_rhs_elementwise(
- &|mut a, b| { <Simd<$scalar, LANES> as core::ops::$trait_assign<$scalar>>::$fn_assign(&mut a, b); a },
- &$scalar_fn,
- &|x, y| x.iter().all(|x| $check_fn(*x, y)),
- )
- }
}
}
};
diff --git a/library/portable-simd/crates/test_helpers/src/lib.rs b/library/portable-simd/crates/test_helpers/src/lib.rs
index 5c6478876f3..7edd6096381 100644
--- a/library/portable-simd/crates/test_helpers/src/lib.rs
+++ b/library/portable-simd/crates/test_helpers/src/lib.rs
@@ -376,6 +376,12 @@ macro_rules! test_lanes {
fn lanes_32() {
implementation::<32>();
}
+
+ #[test]
+ #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test::wasm_bindgen_test)]
+ fn lanes_64() {
+ implementation::<64>();
+ }
}
)*
}
@@ -431,6 +437,12 @@ macro_rules! test_lanes_panic {
fn lanes_32() {
implementation::<32>();
}
+
+ #[test]
+ #[should_panic]
+ fn lanes_64() {
+ implementation::<64>();
+ }
}
)*
}
diff --git a/library/proc_macro/src/bridge/client.rs b/library/proc_macro/src/bridge/client.rs
index 8ae7b6de1a6..83a2ac6f0d4 100644
--- a/library/proc_macro/src/bridge/client.rs
+++ b/library/proc_macro/src/bridge/client.rs
@@ -78,7 +78,7 @@ macro_rules! define_handles {
}
}
- impl<S: server::Types> Decode<'_, 's, HandleStore<server::MarkedTypes<S>>>
+ impl<'s, S: server::Types> Decode<'_, 's, HandleStore<server::MarkedTypes<S>>>
for &'s Marked<S::$oty, $oty>
{
fn decode(r: &mut Reader<'_>, s: &'s HandleStore<server::MarkedTypes<S>>) -> Self {
@@ -92,7 +92,7 @@ macro_rules! define_handles {
}
}
- impl<S: server::Types> DecodeMut<'_, 's, HandleStore<server::MarkedTypes<S>>>
+ impl<'s, S: server::Types> DecodeMut<'_, 's, HandleStore<server::MarkedTypes<S>>>
for &'s mut Marked<S::$oty, $oty>
{
fn decode(
diff --git a/library/proc_macro/src/bridge/mod.rs b/library/proc_macro/src/bridge/mod.rs
index 2df287f7d93..fbeb585095b 100644
--- a/library/proc_macro/src/bridge/mod.rs
+++ b/library/proc_macro/src/bridge/mod.rs
@@ -295,13 +295,13 @@ impl<T, M> Unmark for Marked<T, M> {
self.value
}
}
-impl<T, M> Unmark for &'a Marked<T, M> {
+impl<'a, T, M> Unmark for &'a Marked<T, M> {
type Unmarked = &'a T;
fn unmark(self) -> Self::Unmarked {
&self.value
}
}
-impl<T, M> Unmark for &'a mut Marked<T, M> {
+impl<'a, T, M> Unmark for &'a mut Marked<T, M> {
type Unmarked = &'a mut T;
fn unmark(self) -> Self::Unmarked {
&mut self.value
@@ -356,8 +356,8 @@ mark_noop! {
(),
bool,
char,
- &'a [u8],
- &'a str,
+ &'_ [u8],
+ &'_ str,
String,
usize,
Delimiter,
diff --git a/library/proc_macro/src/bridge/rpc.rs b/library/proc_macro/src/bridge/rpc.rs
index 42432563faf..d50564d01a5 100644
--- a/library/proc_macro/src/bridge/rpc.rs
+++ b/library/proc_macro/src/bridge/rpc.rs
@@ -79,7 +79,7 @@ macro_rules! rpc_encode_decode {
}
}
- impl<S, $($($T: for<'s> DecodeMut<'a, 's, S>),+)?> DecodeMut<'a, '_, S>
+ impl<'a, S, $($($T: for<'s> DecodeMut<'a, 's, S>),+)?> DecodeMut<'a, '_, S>
for $name $(<$($T),+>)?
{
fn decode(r: &mut Reader<'a>, s: &mut S) -> Self {
@@ -176,7 +176,7 @@ impl<S, A: Encode<S>, B: Encode<S>> Encode<S> for (A, B) {
}
}
-impl<S, A: for<'s> DecodeMut<'a, 's, S>, B: for<'s> DecodeMut<'a, 's, S>> DecodeMut<'a, '_, S>
+impl<'a, S, A: for<'s> DecodeMut<'a, 's, S>, B: for<'s> DecodeMut<'a, 's, S>> DecodeMut<'a, '_, S>
for (A, B)
{
fn decode(r: &mut Reader<'a>, s: &mut S) -> Self {
@@ -213,7 +213,7 @@ impl<S> Encode<S> for &[u8] {
}
}
-impl<S> DecodeMut<'a, '_, S> for &'a [u8] {
+impl<'a, S> DecodeMut<'a, '_, S> for &'a [u8] {
fn decode(r: &mut Reader<'a>, s: &mut S) -> Self {
let len = usize::decode(r, s);
let xs = &r[..len];
@@ -228,7 +228,7 @@ impl<S> Encode<S> for &str {
}
}
-impl<S> DecodeMut<'a, '_, S> for &'a str {
+impl<'a, S> DecodeMut<'a, '_, S> for &'a str {
fn decode(r: &mut Reader<'a>, s: &mut S) -> Self {
str::from_utf8(<&[u8]>::decode(r, s)).unwrap()
}
diff --git a/library/proc_macro/src/lib.rs b/library/proc_macro/src/lib.rs
index ef96d72a38b..69af598f91e 100644
--- a/library/proc_macro/src/lib.rs
+++ b/library/proc_macro/src/lib.rs
@@ -25,7 +25,6 @@
#![feature(allow_internal_unstable)]
#![feature(decl_macro)]
#![feature(extern_types)]
-#![feature(in_band_lifetimes)]
#![feature(negative_impls)]
#![feature(auto_traits)]
#![feature(restricted_std)]
diff --git a/library/std/Cargo.toml b/library/std/Cargo.toml
index 8f43e902a87..232ccdf39d4 100644
--- a/library/std/Cargo.toml
+++ b/library/std/Cargo.toml
@@ -4,7 +4,7 @@ version = "0.0.0"
license = "MIT OR Apache-2.0"
repository = "https://github.com/rust-lang/rust.git"
description = "The Rust Standard Library"
-edition = "2018"
+edition = "2021"
[lib]
crate-type = ["dylib", "rlib"]
@@ -15,8 +15,8 @@ cfg-if = { version = "0.1.8", features = ['rustc-dep-of-std'] }
panic_unwind = { path = "../panic_unwind", optional = true }
panic_abort = { path = "../panic_abort" }
core = { path = "../core" }
-libc = { version = "0.2.106", default-features = false, features = ['rustc-dep-of-std'] }
-compiler_builtins = { version = "0.1.52" }
+libc = { version = "0.2.108", default-features = false, features = ['rustc-dep-of-std'] }
+compiler_builtins = { version = "0.1.66" }
profiler_builtins = { path = "../profiler_builtins", optional = true }
unwind = { path = "../unwind" }
hashbrown = { version = "0.11", default-features = false, features = ['rustc-dep-of-std'] }
diff --git a/library/std/src/collections/hash/map.rs b/library/std/src/collections/hash/map.rs
index 12246b5173d..35f17aa781f 100644
--- a/library/std/src/collections/hash/map.rs
+++ b/library/std/src/collections/hash/map.rs
@@ -334,10 +334,11 @@ impl<K, V, S> HashMap<K, V, S> {
/// ```
/// use std::collections::HashMap;
///
- /// let mut map = HashMap::new();
- /// map.insert("a", 1);
- /// map.insert("b", 2);
- /// map.insert("c", 3);
+ /// let map = HashMap::from([
+ /// ("a", 1),
+ /// ("b", 2),
+ /// ("c", 3),
+ /// ]);
///
/// for key in map.keys() {
/// println!("{}", key);
@@ -356,10 +357,11 @@ impl<K, V, S> HashMap<K, V, S> {
/// ```
/// use std::collections::HashMap;
///
- /// let mut map = HashMap::new();
- /// map.insert("a", 1);
- /// map.insert("b", 2);
- /// map.insert("c", 3);
+ /// let map = HashMap::from([
+ /// ("a", 1),
+ /// ("b", 2),
+ /// ("c", 3),
+ /// ]);
///
/// for val in map.values() {
/// println!("{}", val);
@@ -378,11 +380,11 @@ impl<K, V, S> HashMap<K, V, S> {
/// ```
/// use std::collections::HashMap;
///
- /// let mut map = HashMap::new();
- ///
- /// map.insert("a", 1);
- /// map.insert("b", 2);
- /// map.insert("c", 3);
+ /// let mut map = HashMap::from([
+ /// ("a", 1),
+ /// ("b", 2),
+ /// ("c", 3),
+ /// ]);
///
/// for val in map.values_mut() {
/// *val = *val + 10;
@@ -405,10 +407,11 @@ impl<K, V, S> HashMap<K, V, S> {
/// ```
/// use std::collections::HashMap;
///
- /// let mut map = HashMap::new();
- /// map.insert("a", 1);
- /// map.insert("b", 2);
- /// map.insert("c", 3);
+ /// let map = HashMap::from([
+ /// ("a", 1),
+ /// ("b", 2),
+ /// ("c", 3),
+ /// ]);
///
/// for (key, val) in map.iter() {
/// println!("key: {} val: {}", key, val);
@@ -428,10 +431,11 @@ impl<K, V, S> HashMap<K, V, S> {
/// ```
/// use std::collections::HashMap;
///
- /// let mut map = HashMap::new();
- /// map.insert("a", 1);
- /// map.insert("b", 2);
- /// map.insert("c", 3);
+ /// let mut map = HashMap::from([
+ /// ("a", 1),
+ /// ("b", 2),
+ /// ("c", 3),
+ /// ]);
///
/// // Update all values
/// for (_, val) in map.iter_mut() {
@@ -966,10 +970,11 @@ where
/// ```
/// use std::collections::HashMap;
///
- /// let mut map = HashMap::new();
- /// map.insert("a", 1);
- /// map.insert("b", 2);
- /// map.insert("c", 3);
+ /// let map = HashMap::from([
+ /// ("a", 1),
+ /// ("b", 2),
+ /// ("c", 3),
+ /// ]);
///
/// let mut vec: Vec<&str> = map.into_keys().collect();
/// // The `IntoKeys` iterator produces keys in arbitrary order, so the
@@ -992,10 +997,11 @@ where
/// ```
/// use std::collections::HashMap;
///
- /// let mut map = HashMap::new();
- /// map.insert("a", 1);
- /// map.insert("b", 2);
- /// map.insert("c", 3);
+ /// let map = HashMap::from([
+ /// ("a", 1),
+ /// ("b", 2),
+ /// ("c", 3),
+ /// ]);
///
/// let mut vec: Vec<i32> = map.into_values().collect();
/// // The `IntoValues` iterator produces values in arbitrary order, so
@@ -1186,7 +1192,7 @@ where
/// assert_eq!(map1, map2);
/// ```
fn from(arr: [(K, V); N]) -> Self {
- crate::array::IntoIter::new(arr).collect()
+ Self::from_iter(arr)
}
}
@@ -1202,8 +1208,9 @@ where
/// ```
/// use std::collections::HashMap;
///
-/// let mut map = HashMap::new();
-/// map.insert("a", 1);
+/// let map = HashMap::from([
+/// ("a", 1),
+/// ]);
/// let iter = map.iter();
/// ```
#[stable(feature = "rust1", since = "1.0.0")]
@@ -1239,8 +1246,9 @@ impl<K: Debug, V: Debug> fmt::Debug for Iter<'_, K, V> {
/// ```
/// use std::collections::HashMap;
///
-/// let mut map = HashMap::new();
-/// map.insert("a", 1);
+/// let mut map = HashMap::from([
+/// ("a", 1),
+/// ]);
/// let iter = map.iter_mut();
/// ```
#[stable(feature = "rust1", since = "1.0.0")]
@@ -1269,8 +1277,9 @@ impl<'a, K, V> IterMut<'a, K, V> {
/// ```
/// use std::collections::HashMap;
///
-/// let mut map = HashMap::new();
-/// map.insert("a", 1);
+/// let map = HashMap::from([
+/// ("a", 1),
+/// ]);
/// let iter = map.into_iter();
/// ```
#[stable(feature = "rust1", since = "1.0.0")]
@@ -1298,8 +1307,9 @@ impl<K, V> IntoIter<K, V> {
/// ```
/// use std::collections::HashMap;
///
-/// let mut map = HashMap::new();
-/// map.insert("a", 1);
+/// let map = HashMap::from([
+/// ("a", 1),
+/// ]);
/// let iter_keys = map.keys();
/// ```
#[stable(feature = "rust1", since = "1.0.0")]
@@ -1335,8 +1345,9 @@ impl<K: Debug, V> fmt::Debug for Keys<'_, K, V> {
/// ```
/// use std::collections::HashMap;
///
-/// let mut map = HashMap::new();
-/// map.insert("a", 1);
+/// let map = HashMap::from([
+/// ("a", 1),
+/// ]);
/// let iter_values = map.values();
/// ```
#[stable(feature = "rust1", since = "1.0.0")]
@@ -1372,8 +1383,9 @@ impl<K, V: Debug> fmt::Debug for Values<'_, K, V> {
/// ```
/// use std::collections::HashMap;
///
-/// let mut map = HashMap::new();
-/// map.insert("a", 1);
+/// let mut map = HashMap::from([
+/// ("a", 1),
+/// ]);
/// let iter = map.drain();
/// ```
#[stable(feature = "drain", since = "1.6.0")]
@@ -1402,8 +1414,9 @@ impl<'a, K, V> Drain<'a, K, V> {
///
/// use std::collections::HashMap;
///
-/// let mut map = HashMap::new();
-/// map.insert("a", 1);
+/// let mut map = HashMap::from([
+/// ("a", 1),
+/// ]);
/// let iter = map.drain_filter(|_k, v| *v % 2 == 0);
/// ```
#[unstable(feature = "hash_drain_filter", issue = "59618")]
@@ -1426,8 +1439,9 @@ where
/// ```
/// use std::collections::HashMap;
///
-/// let mut map = HashMap::new();
-/// map.insert("a", 1);
+/// let mut map = HashMap::from([
+/// ("a", 1),
+/// ]);
/// let iter_values = map.values_mut();
/// ```
#[stable(feature = "map_values_mut", since = "1.10.0")]
@@ -1447,8 +1461,9 @@ pub struct ValuesMut<'a, K: 'a, V: 'a> {
/// ```
/// use std::collections::HashMap;
///
-/// let mut map = HashMap::new();
-/// map.insert("a", 1);
+/// let map = HashMap::from([
+/// ("a", 1),
+/// ]);
/// let iter_keys = map.into_keys();
/// ```
#[stable(feature = "map_into_keys_values", since = "1.54.0")]
@@ -1468,8 +1483,9 @@ pub struct IntoKeys<K, V> {
/// ```
/// use std::collections::HashMap;
///
-/// let mut map = HashMap::new();
-/// map.insert("a", 1);
+/// let map = HashMap::from([
+/// ("a", 1),
+/// ]);
/// let iter_keys = map.into_values();
/// ```
#[stable(feature = "map_into_keys_values", since = "1.54.0")]
@@ -2004,10 +2020,11 @@ impl<K, V, S> IntoIterator for HashMap<K, V, S> {
/// ```
/// use std::collections::HashMap;
///
- /// let mut map = HashMap::new();
- /// map.insert("a", 1);
- /// map.insert("b", 2);
- /// map.insert("c", 3);
+ /// let map = HashMap::from([
+ /// ("a", 1),
+ /// ("b", 2),
+ /// ("c", 3),
+ /// ]);
///
/// // Not possible with .iter()
/// let vec: Vec<(&str, i32)> = map.into_iter().collect();
diff --git a/library/std/src/collections/hash/set.rs b/library/std/src/collections/hash/set.rs
index 1fc1d39b181..a1e28c0b0a6 100644
--- a/library/std/src/collections/hash/set.rs
+++ b/library/std/src/collections/hash/set.rs
@@ -233,7 +233,7 @@ impl<T, S> HashSet<T, S> {
/// ```
/// use std::collections::HashSet;
///
- /// let mut set: HashSet<_> = [1, 2, 3].iter().cloned().collect();
+ /// let mut set = HashSet::from([1, 2, 3]);
/// assert!(!set.is_empty());
///
/// // print 1, 2, 3 in an arbitrary order
@@ -489,8 +489,8 @@ where
///
/// ```
/// use std::collections::HashSet;
- /// let a: HashSet<_> = [1, 2, 3].iter().cloned().collect();
- /// let b: HashSet<_> = [4, 2, 3, 4].iter().cloned().collect();
+ /// let a = HashSet::from([1, 2, 3]);
+ /// let b = HashSet::from([4, 2, 3, 4]);
///
/// // Can be seen as `a - b`.
/// for x in a.difference(&b) {
@@ -518,8 +518,8 @@ where
///
/// ```
/// use std::collections::HashSet;
- /// let a: HashSet<_> = [1, 2, 3].iter().cloned().collect();
- /// let b: HashSet<_> = [4, 2, 3, 4].iter().cloned().collect();
+ /// let a = HashSet::from([1, 2, 3]);
+ /// let b = HashSet::from([4, 2, 3, 4]);
///
/// // Print 1, 4 in arbitrary order.
/// for x in a.symmetric_difference(&b) {
@@ -548,8 +548,8 @@ where
///
/// ```
/// use std::collections::HashSet;
- /// let a: HashSet<_> = [1, 2, 3].iter().cloned().collect();
- /// let b: HashSet<_> = [4, 2, 3, 4].iter().cloned().collect();
+ /// let a = HashSet::from([1, 2, 3]);
+ /// let b = HashSet::from([4, 2, 3, 4]);
///
/// // Print 2, 3 in arbitrary order.
/// for x in a.intersection(&b) {
@@ -576,8 +576,8 @@ where
///
/// ```
/// use std::collections::HashSet;
- /// let a: HashSet<_> = [1, 2, 3].iter().cloned().collect();
- /// let b: HashSet<_> = [4, 2, 3, 4].iter().cloned().collect();
+ /// let a = HashSet::from([1, 2, 3]);
+ /// let b = HashSet::from([4, 2, 3, 4]);
///
/// // Print 1, 2, 3, 4 in arbitrary order.
/// for x in a.union(&b) {
@@ -608,7 +608,7 @@ where
/// ```
/// use std::collections::HashSet;
///
- /// let set: HashSet<_> = [1, 2, 3].iter().cloned().collect();
+ /// let set = HashSet::from([1, 2, 3]);
/// assert_eq!(set.contains(&1), true);
/// assert_eq!(set.contains(&4), false);
/// ```
@@ -633,7 +633,7 @@ where
/// ```
/// use std::collections::HashSet;
///
- /// let set: HashSet<_> = [1, 2, 3].iter().cloned().collect();
+ /// let set = HashSet::from([1, 2, 3]);
/// assert_eq!(set.get(&2), Some(&2));
/// assert_eq!(set.get(&4), None);
/// ```
@@ -657,7 +657,7 @@ where
///
/// use std::collections::HashSet;
///
- /// let mut set: HashSet<_> = [1, 2, 3].iter().cloned().collect();
+ /// let mut set = HashSet::from([1, 2, 3]);
/// assert_eq!(set.len(), 3);
/// assert_eq!(set.get_or_insert(2), &2);
/// assert_eq!(set.get_or_insert(100), &100);
@@ -744,7 +744,7 @@ where
/// ```
/// use std::collections::HashSet;
///
- /// let a: HashSet<_> = [1, 2, 3].iter().cloned().collect();
+ /// let a = HashSet::from([1, 2, 3]);
/// let mut b = HashSet::new();
///
/// assert_eq!(a.is_disjoint(&b), true);
@@ -770,7 +770,7 @@ where
/// ```
/// use std::collections::HashSet;
///
- /// let sup: HashSet<_> = [1, 2, 3].iter().cloned().collect();
+ /// let sup = HashSet::from([1, 2, 3]);
/// let mut set = HashSet::new();
///
/// assert_eq!(set.is_subset(&sup), true);
@@ -792,7 +792,7 @@ where
/// ```
/// use std::collections::HashSet;
///
- /// let sub: HashSet<_> = [1, 2].iter().cloned().collect();
+ /// let sub = HashSet::from([1, 2]);
/// let mut set = HashSet::new();
///
/// assert_eq!(set.is_superset(&sub), false);
@@ -893,7 +893,7 @@ where
/// ```
/// use std::collections::HashSet;
///
- /// let mut set: HashSet<_> = [1, 2, 3].iter().cloned().collect();
+ /// let mut set = HashSet::from([1, 2, 3]);
/// assert_eq!(set.take(&2), Some(2));
/// assert_eq!(set.take(&2), None);
/// ```
@@ -917,8 +917,7 @@ where
/// ```
/// use std::collections::HashSet;
///
- /// let xs = [1, 2, 3, 4, 5, 6];
- /// let mut set: HashSet<i32> = xs.iter().cloned().collect();
+ /// let mut set = HashSet::from([1, 2, 3, 4, 5, 6]);
/// set.retain(|&k| k % 2 == 0);
/// assert_eq!(set.len(), 3);
/// ```
@@ -1022,7 +1021,7 @@ where
/// assert_eq!(set1, set2);
/// ```
fn from(arr: [T; N]) -> Self {
- crate::array::IntoIter::new(arr).collect()
+ Self::from_iter(arr)
}
}
@@ -1097,8 +1096,8 @@ where
/// ```
/// use std::collections::HashSet;
///
- /// let a: HashSet<_> = vec![1, 2, 3].into_iter().collect();
- /// let b: HashSet<_> = vec![3, 4, 5].into_iter().collect();
+ /// let a = HashSet::from([1, 2, 3]);
+ /// let b = HashSet::from([3, 4, 5]);
///
/// let set = &a | &b;
///
@@ -1130,8 +1129,8 @@ where
/// ```
/// use std::collections::HashSet;
///
- /// let a: HashSet<_> = vec![1, 2, 3].into_iter().collect();
- /// let b: HashSet<_> = vec![2, 3, 4].into_iter().collect();
+ /// let a = HashSet::from([1, 2, 3]);
+ /// let b = HashSet::from([2, 3, 4]);
///
/// let set = &a & &b;
///
@@ -1163,8 +1162,8 @@ where
/// ```
/// use std::collections::HashSet;
///
- /// let a: HashSet<_> = vec![1, 2, 3].into_iter().collect();
- /// let b: HashSet<_> = vec![3, 4, 5].into_iter().collect();
+ /// let a = HashSet::from([1, 2, 3]);
+ /// let b = HashSet::from([3, 4, 5]);
///
/// let set = &a ^ &b;
///
@@ -1196,8 +1195,8 @@ where
/// ```
/// use std::collections::HashSet;
///
- /// let a: HashSet<_> = vec![1, 2, 3].into_iter().collect();
- /// let b: HashSet<_> = vec![3, 4, 5].into_iter().collect();
+ /// let a = HashSet::from([1, 2, 3]);
+ /// let b = HashSet::from([3, 4, 5]);
///
/// let set = &a - &b;
///
@@ -1226,7 +1225,7 @@ where
/// ```
/// use std::collections::HashSet;
///
-/// let a: HashSet<u32> = vec![1, 2, 3].into_iter().collect();
+/// let a = HashSet::from([1, 2, 3]);
///
/// let mut iter = a.iter();
/// ```
@@ -1248,7 +1247,7 @@ pub struct Iter<'a, K: 'a> {
/// ```
/// use std::collections::HashSet;
///
-/// let a: HashSet<u32> = vec![1, 2, 3].into_iter().collect();
+/// let a = HashSet::from([1, 2, 3]);
///
/// let mut iter = a.into_iter();
/// ```
@@ -1269,7 +1268,7 @@ pub struct IntoIter<K> {
/// ```
/// use std::collections::HashSet;
///
-/// let mut a: HashSet<u32> = vec![1, 2, 3].into_iter().collect();
+/// let mut a = HashSet::from([1, 2, 3]);
///
/// let mut drain = a.drain();
/// ```
@@ -1291,7 +1290,7 @@ pub struct Drain<'a, K: 'a> {
///
/// use std::collections::HashSet;
///
-/// let mut a: HashSet<u32> = vec![1, 2, 3].into_iter().collect();
+/// let mut a = HashSet::from([1, 2, 3]);
///
/// let mut drain_filtered = a.drain_filter(|v| v % 2 == 0);
/// ```
@@ -1315,8 +1314,8 @@ where
/// ```
/// use std::collections::HashSet;
///
-/// let a: HashSet<u32> = vec![1, 2, 3].into_iter().collect();
-/// let b: HashSet<_> = [4, 2, 3, 4].iter().cloned().collect();
+/// let a = HashSet::from([1, 2, 3]);
+/// let b = HashSet::from([4, 2, 3, 4]);
///
/// let mut intersection = a.intersection(&b);
/// ```
@@ -1342,8 +1341,8 @@ pub struct Intersection<'a, T: 'a, S: 'a> {
/// ```
/// use std::collections::HashSet;
///
-/// let a: HashSet<u32> = vec![1, 2, 3].into_iter().collect();
-/// let b: HashSet<_> = [4, 2, 3, 4].iter().cloned().collect();
+/// let a = HashSet::from([1, 2, 3]);
+/// let b = HashSet::from([4, 2, 3, 4]);
///
/// let mut difference = a.difference(&b);
/// ```
@@ -1369,8 +1368,8 @@ pub struct Difference<'a, T: 'a, S: 'a> {
/// ```
/// use std::collections::HashSet;
///
-/// let a: HashSet<u32> = vec![1, 2, 3].into_iter().collect();
-/// let b: HashSet<_> = [4, 2, 3, 4].iter().cloned().collect();
+/// let a = HashSet::from([1, 2, 3]);
+/// let b = HashSet::from([4, 2, 3, 4]);
///
/// let mut intersection = a.symmetric_difference(&b);
/// ```
@@ -1393,8 +1392,8 @@ pub struct SymmetricDifference<'a, T: 'a, S: 'a> {
/// ```
/// use std::collections::HashSet;
///
-/// let a: HashSet<u32> = vec![1, 2, 3].into_iter().collect();
-/// let b: HashSet<_> = [4, 2, 3, 4].iter().cloned().collect();
+/// let a = HashSet::from([1, 2, 3]);
+/// let b = HashSet::from([4, 2, 3, 4]);
///
/// let mut union_iter = a.union(&b);
/// ```
diff --git a/library/std/src/env.rs b/library/std/src/env.rs
index c6af708f6cd..c06928647d3 100644
--- a/library/std/src/env.rs
+++ b/library/std/src/env.rs
@@ -583,28 +583,25 @@ pub fn home_dir() -> Option<PathBuf> {
/// may result in "insecure temporary file" security vulnerabilities. Consider
/// using a crate that securely creates temporary files or directories.
///
-/// # Unix
+/// # Platform-specific behavior
///
-/// Returns the value of the `TMPDIR` environment variable if it is
+/// On Unix, returns the value of the `TMPDIR` environment variable if it is
/// set, otherwise for non-Android it returns `/tmp`. If Android, since there
/// is no global temporary folder (it is usually allocated per-app), it returns
/// `/data/local/tmp`.
+/// On Windows, the behavior is equivalent to that of [`GetTempPath2`][GetTempPath2] /
+/// [`GetTempPath`][GetTempPath], which this function uses internally.
+/// Note that, this [may change in the future][changes].
///
-/// # Windows
-///
-/// Returns the value of, in order, the `TMP`, `TEMP`,
-/// `USERPROFILE` environment variable if any are set and not the empty
-/// string. Otherwise, `temp_dir` returns the path of the Windows directory.
-/// This behavior is identical to that of [`GetTempPath`][msdn], which this
-/// function uses internally.
-///
-/// [msdn]: https://docs.microsoft.com/en-us/windows/win32/api/fileapi/nf-fileapi-gettemppatha
+/// [changes]: io#platform-specific-behavior
+/// [GetTempPath2]: https://docs.microsoft.com/en-us/windows/win32/api/fileapi/nf-fileapi-gettemppath2a
+/// [GetTempPath]: https://docs.microsoft.com/en-us/windows/win32/api/fileapi/nf-fileapi-gettemppatha
///
/// ```no_run
/// use std::env;
///
/// fn main() {
-/// let mut dir = env::temp_dir();
+/// let dir = env::temp_dir();
/// println!("Temporary directory: {}", dir.display());
/// }
/// ```
diff --git a/library/std/src/ffi/c_str.rs b/library/std/src/ffi/c_str.rs
index 465bbae8631..9c1b79d6966 100644
--- a/library/std/src/ffi/c_str.rs
+++ b/library/std/src/ffi/c_str.rs
@@ -1259,7 +1259,7 @@ impl CStr {
#[inline]
#[must_use]
#[stable(feature = "cstr_from_bytes", since = "1.10.0")]
- #[rustc_const_unstable(feature = "const_cstr_unchecked", issue = "90343")]
+ #[rustc_const_stable(feature = "const_cstr_unchecked", since = "1.59.0")]
pub const unsafe fn from_bytes_with_nul_unchecked(bytes: &[u8]) -> &CStr {
// SAFETY: Casting to CStr is safe because its internal representation
// is a [u8] too (safe only inside std).
diff --git a/library/std/src/ffi/mod.rs b/library/std/src/ffi/mod.rs
index 7f3bb836754..019b64c395e 100644
--- a/library/std/src/ffi/mod.rs
+++ b/library/std/src/ffi/mod.rs
@@ -81,9 +81,9 @@
//! [`OsStr`] and Rust strings work similarly to those for [`CString`]
//! and [`CStr`].
//!
-//! * [`OsString`] represents an owned string in whatever
-//! representation the operating system prefers. In the Rust standard
-//! library, various APIs that transfer strings to/from the operating
+//! * [`OsString`] losslessly represents an owned platform string. However, this
+//! representation is not necessarily in a form native to the platform.
+//! In the Rust standard library, various APIs that transfer strings to/from the operating
//! system use [`OsString`] instead of plain strings. For example,
//! [`env::var_os()`] is used to query environment variables; it
//! returns an <code>[Option]<[OsString]></code>. If the environment variable
@@ -92,9 +92,9 @@
//! your code can detect errors in case the environment variable did
//! not in fact contain valid Unicode data.
//!
-//! * [`OsStr`] represents a borrowed reference to a string in a
-//! format that can be passed to the operating system. It can be
-//! converted into a UTF-8 Rust string slice in a similar way to
+//! * [`OsStr`] losslessly represents a borrowed reference to a platform string.
+//! However, this representation is not necessarily in a form native to the platform.
+//! It can be converted into a UTF-8 Rust string slice in a similar way to
//! [`OsString`].
//!
//! # Conversions
@@ -113,16 +113,19 @@
//!
//! ## On Windows
//!
+//! An [`OsStr`] can be losslessly converted to a native Windows string. And
+//! a native Windows string can be losslessly converted to an [`OsString`].
+//!
//! On Windows, [`OsStr`] implements the
//! <code>std::os::windows::ffi::[OsStrExt][windows.OsStrExt]</code> trait,
//! which provides an [`encode_wide`] method. This provides an
-//! iterator that can be [`collect`]ed into a vector of [`u16`].
+//! iterator that can be [`collect`]ed into a vector of [`u16`]. After a nul
+//! characters is appended, this is the same as a native Windows string.
//!
//! Additionally, on Windows [`OsString`] implements the
//! <code>std::os::windows:ffi::[OsStringExt][windows.OsStringExt]</code>
-//! trait, which provides a [`from_wide`] method. The result of this
-//! method is an [`OsString`] which can be round-tripped to a Windows
-//! string losslessly.
+//! trait, which provides a [`from_wide`] method to convert a native Windows
+//! string (without the terminating nul character) to an [`OsString`].
//!
//! [Unicode scalar value]: https://www.unicode.org/glossary/#unicode_scalar_value
//! [Unicode code point]: https://www.unicode.org/glossary/#code_point
diff --git a/library/std/src/fs.rs b/library/std/src/fs.rs
index a14f1e2ecb2..dae85027b6c 100644
--- a/library/std/src/fs.rs
+++ b/library/std/src/fs.rs
@@ -13,7 +13,7 @@ mod tests;
use crate::ffi::OsString;
use crate::fmt;
-use crate::io::{self, Initializer, IoSlice, IoSliceMut, Read, Seek, SeekFrom, Write};
+use crate::io::{self, IoSlice, IoSliceMut, Read, ReadBuf, Seek, SeekFrom, Write};
use crate::path::{Path, PathBuf};
use crate::sys::fs as fs_imp;
use crate::sys_common::{AsInner, AsInnerMut, FromInner, IntoInner};
@@ -623,15 +623,13 @@ impl Read for File {
self.inner.read_vectored(bufs)
}
- #[inline]
- fn is_read_vectored(&self) -> bool {
- self.inner.is_read_vectored()
+ fn read_buf(&mut self, buf: &mut ReadBuf<'_>) -> io::Result<()> {
+ self.inner.read_buf(buf)
}
#[inline]
- unsafe fn initializer(&self) -> Initializer {
- // SAFETY: Read is guaranteed to work on uninitialized memory
- unsafe { Initializer::nop() }
+ fn is_read_vectored(&self) -> bool {
+ self.inner.is_read_vectored()
}
// Reserves space in the buffer based on the file size when available.
@@ -677,6 +675,10 @@ impl Read for &File {
self.inner.read(buf)
}
+ fn read_buf(&mut self, buf: &mut ReadBuf<'_>) -> io::Result<()> {
+ self.inner.read_buf(buf)
+ }
+
fn read_vectored(&mut self, bufs: &mut [IoSliceMut<'_>]) -> io::Result<usize> {
self.inner.read_vectored(bufs)
}
@@ -686,12 +688,6 @@ impl Read for &File {
self.inner.is_read_vectored()
}
- #[inline]
- unsafe fn initializer(&self) -> Initializer {
- // SAFETY: Read is guaranteed to work on uninitialized memory
- unsafe { Initializer::nop() }
- }
-
// Reserves space in the buffer based on the file size when available.
fn read_to_end(&mut self, buf: &mut Vec<u8>) -> io::Result<usize> {
buf.reserve(buffer_capacity_required(self));
@@ -1062,7 +1058,7 @@ impl Metadata {
/// }
/// ```
#[must_use]
- #[stable(feature = "is_symlink", since = "1.57.0")]
+ #[stable(feature = "is_symlink", since = "1.58.0")]
pub fn is_symlink(&self) -> bool {
self.file_type().is_symlink()
}
diff --git a/library/std/src/fs/tests.rs b/library/std/src/fs/tests.rs
index 9a8f1e44f1f..749d51d4981 100644
--- a/library/std/src/fs/tests.rs
+++ b/library/std/src/fs/tests.rs
@@ -38,10 +38,9 @@ macro_rules! error {
($e:expr, $s:expr) => {
match $e {
Ok(_) => panic!("Unexpected success. Should've been: {:?}", $s),
- Err(ref err) => assert!(
- err.raw_os_error() == Some($s),
- format!("`{}` did not have a code of `{}`", err, $s)
- ),
+ Err(ref err) => {
+ assert!(err.raw_os_error() == Some($s), "`{}` did not have a code of `{}`", err, $s)
+ }
}
};
}
@@ -58,7 +57,7 @@ macro_rules! error_contains {
match $e {
Ok(_) => panic!("Unexpected success. Should've been: {:?}", $s),
Err(ref err) => {
- assert!(err.to_string().contains($s), format!("`{}` did not contain `{}`", err, $s))
+ assert!(err.to_string().contains($s), "`{}` did not contain `{}`", err, $s)
}
}
};
@@ -1369,7 +1368,7 @@ fn symlink_hard_link() {
// "hard_link" should appear as a symlink.
assert!(check!(fs::symlink_metadata(tmpdir.join("hard_link"))).file_type().is_symlink());
- // We sould be able to open "file" via any of the above names.
+ // We should be able to open "file" via any of the above names.
let _ = check!(fs::File::open(tmpdir.join("file")));
assert!(fs::File::open(tmpdir.join("file.renamed")).is_err());
let _ = check!(fs::File::open(tmpdir.join("symlink")));
diff --git a/library/std/src/io/buffered/bufreader.rs b/library/std/src/io/buffered/bufreader.rs
index 2864e94f60f..b56dc65f0b2 100644
--- a/library/std/src/io/buffered/bufreader.rs
+++ b/library/std/src/io/buffered/bufreader.rs
@@ -1,8 +1,9 @@
use crate::cmp;
use crate::fmt;
use crate::io::{
- self, BufRead, Initializer, IoSliceMut, Read, Seek, SeekFrom, SizeHint, DEFAULT_BUF_SIZE,
+ self, BufRead, IoSliceMut, Read, ReadBuf, Seek, SeekFrom, SizeHint, DEFAULT_BUF_SIZE,
};
+use crate::mem::MaybeUninit;
/// The `BufReader<R>` struct adds buffering to any reader.
///
@@ -47,9 +48,10 @@ use crate::io::{
#[stable(feature = "rust1", since = "1.0.0")]
pub struct BufReader<R> {
inner: R,
- buf: Box<[u8]>,
+ buf: Box<[MaybeUninit<u8>]>,
pos: usize,
cap: usize,
+ init: usize,
}
impl<R: Read> BufReader<R> {
@@ -91,11 +93,8 @@ impl<R: Read> BufReader<R> {
/// ```
#[stable(feature = "rust1", since = "1.0.0")]
pub fn with_capacity(capacity: usize, inner: R) -> BufReader<R> {
- unsafe {
- let mut buf = Box::new_uninit_slice(capacity).assume_init();
- inner.initializer().initialize(&mut buf);
- BufReader { inner, buf, pos: 0, cap: 0 }
- }
+ let buf = Box::new_uninit_slice(capacity);
+ BufReader { inner, buf, pos: 0, cap: 0, init: 0 }
}
}
@@ -171,7 +170,8 @@ impl<R> BufReader<R> {
/// ```
#[stable(feature = "bufreader_buffer", since = "1.37.0")]
pub fn buffer(&self) -> &[u8] {
- &self.buf[self.pos..self.cap]
+ // SAFETY: self.cap is always <= self.init, so self.buf[self.pos..self.cap] is always init
+ unsafe { MaybeUninit::slice_assume_init_ref(&self.buf[self.pos..self.cap]) }
}
/// Returns the number of bytes the internal buffer can hold at once.
@@ -271,6 +271,25 @@ impl<R: Read> Read for BufReader<R> {
Ok(nread)
}
+ fn read_buf(&mut self, buf: &mut ReadBuf<'_>) -> io::Result<()> {
+ // If we don't have any buffered data and we're doing a massive read
+ // (larger than our internal buffer), bypass our internal buffer
+ // entirely.
+ if self.pos == self.cap && buf.remaining() >= self.buf.len() {
+ self.discard_buffer();
+ return self.inner.read_buf(buf);
+ }
+
+ let prev = buf.filled_len();
+
+ let mut rem = self.fill_buf()?;
+ rem.read_buf(buf)?;
+
+ self.consume(buf.filled_len() - prev); //slice impl of read_buf known to never unfill buf
+
+ Ok(())
+ }
+
// Small read_exacts from a BufReader are extremely common when used with a deserializer.
// The default implementation calls read in a loop, which results in surprisingly poor code
// generation for the common path where the buffer has enough bytes to fill the passed-in
@@ -303,16 +322,11 @@ impl<R: Read> Read for BufReader<R> {
self.inner.is_read_vectored()
}
- // we can't skip unconditionally because of the large buffer case in read.
- unsafe fn initializer(&self) -> Initializer {
- self.inner.initializer()
- }
-
// The inner reader might have an optimized `read_to_end`. Drain our buffer and then
// delegate to the inner implementation.
fn read_to_end(&mut self, buf: &mut Vec<u8>) -> io::Result<usize> {
let nread = self.cap - self.pos;
- buf.extend_from_slice(&self.buf[self.pos..self.cap]);
+ buf.extend_from_slice(&self.buffer());
self.discard_buffer();
Ok(nread + self.inner.read_to_end(buf)?)
}
@@ -363,10 +377,23 @@ impl<R: Read> BufRead for BufReader<R> {
// to tell the compiler that the pos..cap slice is always valid.
if self.pos >= self.cap {
debug_assert!(self.pos == self.cap);
- self.cap = self.inner.read(&mut self.buf)?;
+
+ let mut readbuf = ReadBuf::uninit(&mut self.buf);
+
+ // SAFETY: `self.init` is either 0 or set to `readbuf.initialized_len()`
+ // from the last time this function was called
+ unsafe {
+ readbuf.assume_init(self.init);
+ }
+
+ self.inner.read_buf(&mut readbuf)?;
+
+ self.cap = readbuf.filled_len();
+ self.init = readbuf.initialized_len();
+
self.pos = 0;
}
- Ok(&self.buf[self.pos..self.cap])
+ Ok(self.buffer())
}
fn consume(&mut self, amt: usize) {
diff --git a/library/std/src/io/buffered/tests.rs b/library/std/src/io/buffered/tests.rs
index feb149c07a5..9d429e7090e 100644
--- a/library/std/src/io/buffered/tests.rs
+++ b/library/std/src/io/buffered/tests.rs
@@ -1,5 +1,6 @@
use crate::io::prelude::*;
-use crate::io::{self, BufReader, BufWriter, ErrorKind, IoSlice, LineWriter, SeekFrom};
+use crate::io::{self, BufReader, BufWriter, ErrorKind, IoSlice, LineWriter, ReadBuf, SeekFrom};
+use crate::mem::MaybeUninit;
use crate::panic;
use crate::sync::atomic::{AtomicUsize, Ordering};
use crate::thread;
@@ -56,6 +57,55 @@ fn test_buffered_reader() {
}
#[test]
+fn test_buffered_reader_read_buf() {
+ let inner: &[u8] = &[5, 6, 7, 0, 1, 2, 3, 4];
+ let mut reader = BufReader::with_capacity(2, inner);
+
+ let mut buf = [MaybeUninit::uninit(); 3];
+ let mut buf = ReadBuf::uninit(&mut buf);
+
+ reader.read_buf(&mut buf).unwrap();
+
+ assert_eq!(buf.filled(), [5, 6, 7]);
+ assert_eq!(reader.buffer(), []);
+
+ let mut buf = [MaybeUninit::uninit(); 2];
+ let mut buf = ReadBuf::uninit(&mut buf);
+
+ reader.read_buf(&mut buf).unwrap();
+
+ assert_eq!(buf.filled(), [0, 1]);
+ assert_eq!(reader.buffer(), []);
+
+ let mut buf = [MaybeUninit::uninit(); 1];
+ let mut buf = ReadBuf::uninit(&mut buf);
+
+ reader.read_buf(&mut buf).unwrap();
+
+ assert_eq!(buf.filled(), [2]);
+ assert_eq!(reader.buffer(), [3]);
+
+ let mut buf = [MaybeUninit::uninit(); 3];
+ let mut buf = ReadBuf::uninit(&mut buf);
+
+ reader.read_buf(&mut buf).unwrap();
+
+ assert_eq!(buf.filled(), [3]);
+ assert_eq!(reader.buffer(), []);
+
+ reader.read_buf(&mut buf).unwrap();
+
+ assert_eq!(buf.filled(), [3, 4]);
+ assert_eq!(reader.buffer(), []);
+
+ buf.clear();
+
+ reader.read_buf(&mut buf).unwrap();
+
+ assert_eq!(buf.filled_len(), 0);
+}
+
+#[test]
fn test_buffered_reader_seek() {
let inner: &[u8] = &[5, 6, 7, 0, 1, 2, 3, 4];
let mut reader = BufReader::with_capacity(2, io::Cursor::new(inner));
diff --git a/library/std/src/io/copy.rs b/library/std/src/io/copy.rs
index eb60df214c4..6ab96662305 100644
--- a/library/std/src/io/copy.rs
+++ b/library/std/src/io/copy.rs
@@ -1,4 +1,4 @@
-use super::{BufWriter, ErrorKind, Read, Result, Write, DEFAULT_BUF_SIZE};
+use super::{BufWriter, ErrorKind, Read, ReadBuf, Result, Write, DEFAULT_BUF_SIZE};
use crate::mem::MaybeUninit;
/// Copies the entire contents of a reader into a writer.
@@ -82,33 +82,30 @@ impl<I: Write> BufferedCopySpec for BufWriter<I> {
return stack_buffer_copy(reader, writer);
}
- // FIXME: #42788
- //
- // - This creates a (mut) reference to a slice of
- // _uninitialized_ integers, which is **undefined behavior**
- //
- // - Only the standard library gets to soundly "ignore" this,
- // based on its privileged knowledge of unstable rustc
- // internals;
- unsafe {
- let spare_cap = writer.buffer_mut().spare_capacity_mut();
- reader.initializer().initialize(MaybeUninit::slice_assume_init_mut(spare_cap));
- }
-
let mut len = 0;
+ let mut init = 0;
loop {
let buf = writer.buffer_mut();
- let spare_cap = buf.spare_capacity_mut();
-
- if spare_cap.len() >= DEFAULT_BUF_SIZE {
- match reader.read(unsafe { MaybeUninit::slice_assume_init_mut(spare_cap) }) {
- Ok(0) => return Ok(len), // EOF reached
- Ok(bytes_read) => {
- assert!(bytes_read <= spare_cap.len());
- // SAFETY: The initializer contract guarantees that either it or `read`
- // will have initialized these bytes. And we just checked that the number
- // of bytes is within the buffer capacity.
+ let mut read_buf = ReadBuf::uninit(buf.spare_capacity_mut());
+
+ // SAFETY: init is either 0 or the initialized_len of the previous iteration
+ unsafe {
+ read_buf.assume_init(init);
+ }
+
+ if read_buf.capacity() >= DEFAULT_BUF_SIZE {
+ match reader.read_buf(&mut read_buf) {
+ Ok(()) => {
+ let bytes_read = read_buf.filled_len();
+
+ if bytes_read == 0 {
+ return Ok(len);
+ }
+
+ init = read_buf.initialized_len() - bytes_read;
+
+ // SAFETY: ReadBuf guarantees all of its filled bytes are init
unsafe { buf.set_len(buf.len() + bytes_read) };
len += bytes_read as u64;
// Read again if the buffer still has enough capacity, as BufWriter itself would do
@@ -129,28 +126,26 @@ fn stack_buffer_copy<R: Read + ?Sized, W: Write + ?Sized>(
reader: &mut R,
writer: &mut W,
) -> Result<u64> {
- let mut buf = MaybeUninit::<[u8; DEFAULT_BUF_SIZE]>::uninit();
- // FIXME: #42788
- //
- // - This creates a (mut) reference to a slice of
- // _uninitialized_ integers, which is **undefined behavior**
- //
- // - Only the standard library gets to soundly "ignore" this,
- // based on its privileged knowledge of unstable rustc
- // internals;
- unsafe {
- reader.initializer().initialize(buf.assume_init_mut());
- }
+ let mut buf = [MaybeUninit::uninit(); DEFAULT_BUF_SIZE];
+ let mut buf = ReadBuf::uninit(&mut buf);
+
+ let mut len = 0;
- let mut written = 0;
loop {
- let len = match reader.read(unsafe { buf.assume_init_mut() }) {
- Ok(0) => return Ok(written),
- Ok(len) => len,
- Err(ref e) if e.kind() == ErrorKind::Interrupted => continue,
+ match reader.read_buf(&mut buf) {
+ Ok(()) => {}
+ Err(e) if e.kind() == ErrorKind::Interrupted => continue,
Err(e) => return Err(e),
};
- writer.write_all(unsafe { &buf.assume_init_ref()[..len] })?;
- written += len as u64;
+
+ if buf.filled().is_empty() {
+ break;
+ }
+
+ len += buf.filled().len() as u64;
+ writer.write_all(buf.filled())?;
+ buf.clear();
}
+
+ Ok(len)
}
diff --git a/library/std/src/io/cursor.rs b/library/std/src/io/cursor.rs
index 980b2531192..416cc906e65 100644
--- a/library/std/src/io/cursor.rs
+++ b/library/std/src/io/cursor.rs
@@ -4,7 +4,7 @@ mod tests;
use crate::io::prelude::*;
use crate::cmp;
-use crate::io::{self, Error, ErrorKind, Initializer, IoSlice, IoSliceMut, SeekFrom};
+use crate::io::{self, Error, ErrorKind, IoSlice, IoSliceMut, ReadBuf, SeekFrom};
use core::convert::TryInto;
@@ -324,6 +324,16 @@ where
Ok(n)
}
+ fn read_buf(&mut self, buf: &mut ReadBuf<'_>) -> io::Result<()> {
+ let prev_filled = buf.filled_len();
+
+ Read::read_buf(&mut self.fill_buf()?, buf)?;
+
+ self.pos += (buf.filled_len() - prev_filled) as u64;
+
+ Ok(())
+ }
+
fn read_vectored(&mut self, bufs: &mut [IoSliceMut<'_>]) -> io::Result<usize> {
let mut nread = 0;
for buf in bufs {
@@ -346,11 +356,6 @@ where
self.pos += n as u64;
Ok(())
}
-
- #[inline]
- unsafe fn initializer(&self) -> Initializer {
- Initializer::nop()
- }
}
#[stable(feature = "rust1", since = "1.0.0")]
diff --git a/library/std/src/io/error.rs b/library/std/src/io/error.rs
index d93c6172cfc..210a9ec7183 100644
--- a/library/std/src/io/error.rs
+++ b/library/std/src/io/error.rs
@@ -417,6 +417,33 @@ impl Error {
Self::_new(kind, error.into())
}
+ /// Creates a new I/O error from an arbitrary error payload.
+ ///
+ /// This function is used to generically create I/O errors which do not
+ /// originate from the OS itself. It is a shortcut for [`Error::new`]
+ /// with [`ErrorKind::Other`].
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// #![feature(io_error_other)]
+ ///
+ /// use std::io::Error;
+ ///
+ /// // errors can be created from strings
+ /// let custom_error = Error::other("oh no!");
+ ///
+ /// // errors can also be created from other errors
+ /// let custom_error2 = Error::other(custom_error);
+ /// ```
+ #[unstable(feature = "io_error_other", issue = "91946")]
+ pub fn other<E>(error: E) -> Error
+ where
+ E: Into<Box<dyn error::Error + Send + Sync>>,
+ {
+ Self::_new(ErrorKind::Other, error.into())
+ }
+
fn _new(kind: ErrorKind, error: Box<dyn error::Error + Send + Sync>) -> Error {
Error { repr: Repr::Custom(Box::new(Custom { kind, error })) }
}
@@ -440,12 +467,18 @@ impl Error {
/// `GetLastError` on Windows) and will return a corresponding instance of
/// [`Error`] for the error code.
///
+ /// This should be called immediately after a call to a platform function,
+ /// otherwise the state of the error value is indeterminate. In particular,
+ /// other standard library functions may call platform functions that may
+ /// (or may not) reset the error value even if they succeed.
+ ///
/// # Examples
///
/// ```
/// use std::io::Error;
///
- /// println!("last OS error: {:?}", Error::last_os_error());
+ /// let os_error = Error::last_os_error();
+ /// println!("last OS error: {:?}", os_error);
/// ```
#[stable(feature = "rust1", since = "1.0.0")]
#[must_use]
diff --git a/library/std/src/io/impls.rs b/library/std/src/io/impls.rs
index 7a2a49ba7d7..23201f9fc5c 100644
--- a/library/std/src/io/impls.rs
+++ b/library/std/src/io/impls.rs
@@ -5,7 +5,7 @@ use crate::alloc::Allocator;
use crate::cmp;
use crate::fmt;
use crate::io::{
- self, BufRead, Error, ErrorKind, Initializer, IoSlice, IoSliceMut, Read, Seek, SeekFrom, Write,
+ self, BufRead, Error, ErrorKind, IoSlice, IoSliceMut, Read, ReadBuf, Seek, SeekFrom, Write,
};
use crate::mem;
@@ -20,6 +20,11 @@ impl<R: Read + ?Sized> Read for &mut R {
}
#[inline]
+ fn read_buf(&mut self, buf: &mut ReadBuf<'_>) -> io::Result<()> {
+ (**self).read_buf(buf)
+ }
+
+ #[inline]
fn read_vectored(&mut self, bufs: &mut [IoSliceMut<'_>]) -> io::Result<usize> {
(**self).read_vectored(bufs)
}
@@ -30,11 +35,6 @@ impl<R: Read + ?Sized> Read for &mut R {
}
#[inline]
- unsafe fn initializer(&self) -> Initializer {
- (**self).initializer()
- }
-
- #[inline]
fn read_to_end(&mut self, buf: &mut Vec<u8>) -> io::Result<usize> {
(**self).read_to_end(buf)
}
@@ -124,6 +124,11 @@ impl<R: Read + ?Sized> Read for Box<R> {
}
#[inline]
+ fn read_buf(&mut self, buf: &mut ReadBuf<'_>) -> io::Result<()> {
+ (**self).read_buf(buf)
+ }
+
+ #[inline]
fn read_vectored(&mut self, bufs: &mut [IoSliceMut<'_>]) -> io::Result<usize> {
(**self).read_vectored(bufs)
}
@@ -134,11 +139,6 @@ impl<R: Read + ?Sized> Read for Box<R> {
}
#[inline]
- unsafe fn initializer(&self) -> Initializer {
- (**self).initializer()
- }
-
- #[inline]
fn read_to_end(&mut self, buf: &mut Vec<u8>) -> io::Result<usize> {
(**self).read_to_end(buf)
}
@@ -248,6 +248,17 @@ impl Read for &[u8] {
}
#[inline]
+ fn read_buf(&mut self, buf: &mut ReadBuf<'_>) -> io::Result<()> {
+ let amt = cmp::min(buf.remaining(), self.len());
+ let (a, b) = self.split_at(amt);
+
+ buf.append(a);
+
+ *self = b;
+ Ok(())
+ }
+
+ #[inline]
fn read_vectored(&mut self, bufs: &mut [IoSliceMut<'_>]) -> io::Result<usize> {
let mut nread = 0;
for buf in bufs {
@@ -266,11 +277,6 @@ impl Read for &[u8] {
}
#[inline]
- unsafe fn initializer(&self) -> Initializer {
- Initializer::nop()
- }
-
- #[inline]
fn read_exact(&mut self, buf: &mut [u8]) -> io::Result<()> {
if buf.len() > self.len() {
return Err(Error::new_const(ErrorKind::UnexpectedEof, &"failed to fill whole buffer"));
diff --git a/library/std/src/io/mod.rs b/library/std/src/io/mod.rs
index 8cc91566418..ecc9e91b6bd 100644
--- a/library/std/src/io/mod.rs
+++ b/library/std/src/io/mod.rs
@@ -256,7 +256,6 @@ use crate::convert::TryInto;
use crate::fmt;
use crate::mem::replace;
use crate::ops::{Deref, DerefMut};
-use crate::ptr;
use crate::slice;
use crate::str;
use crate::sys;
@@ -288,12 +287,16 @@ pub use self::stdio::{_eprint, _print};
#[stable(feature = "rust1", since = "1.0.0")]
pub use self::util::{empty, repeat, sink, Empty, Repeat, Sink};
+#[unstable(feature = "read_buf", issue = "78485")]
+pub use self::readbuf::ReadBuf;
+
mod buffered;
pub(crate) mod copy;
mod cursor;
mod error;
mod impls;
pub mod prelude;
+mod readbuf;
mod stdio;
mod util;
@@ -355,52 +358,43 @@ where
// of data to return. Simply tacking on an extra DEFAULT_BUF_SIZE space every
// time is 4,500 times (!) slower than a default reservation size of 32 if the
// reader has a very small amount of data to return.
-//
-// Because we're extending the buffer with uninitialized data for trusted
-// readers, we need to make sure to truncate that if any of this panics.
pub(crate) fn default_read_to_end<R: Read + ?Sized>(r: &mut R, buf: &mut Vec<u8>) -> Result<usize> {
let start_len = buf.len();
let start_cap = buf.capacity();
- let mut g = Guard { len: buf.len(), buf };
+
+ let mut initialized = 0; // Extra initialized bytes from previous loop iteration
loop {
- // If we've read all the way up to the capacity, reserve more space.
- if g.len == g.buf.capacity() {
- g.buf.reserve(32);
+ if buf.len() == buf.capacity() {
+ buf.reserve(32); // buf is full, need more space
}
- // Initialize any excess capacity and adjust the length so we can write
- // to it.
- if g.buf.len() < g.buf.capacity() {
- unsafe {
- // FIXME(danielhenrymantilla): #42788
- //
- // - This creates a (mut) reference to a slice of
- // _uninitialized_ integers, which is **undefined behavior**
- //
- // - Only the standard library gets to soundly "ignore" this,
- // based on its privileged knowledge of unstable rustc
- // internals;
- let capacity = g.buf.capacity();
- g.buf.set_len(capacity);
- r.initializer().initialize(&mut g.buf[g.len..]);
- }
+ let mut read_buf = ReadBuf::uninit(buf.spare_capacity_mut());
+
+ // SAFETY: These bytes were initialized but not filled in the previous loop
+ unsafe {
+ read_buf.assume_init(initialized);
}
- let buf = &mut g.buf[g.len..];
- match r.read(buf) {
- Ok(0) => return Ok(g.len - start_len),
- Ok(n) => {
- // We can't allow bogus values from read. If it is too large, the returned vec could have its length
- // set past its capacity, or if it overflows the vec could be shortened which could create an invalid
- // string if this is called via read_to_string.
- assert!(n <= buf.len());
- g.len += n;
- }
- Err(ref e) if e.kind() == ErrorKind::Interrupted => continue,
+ match r.read_buf(&mut read_buf) {
+ Ok(()) => {}
+ Err(e) if e.kind() == ErrorKind::Interrupted => continue,
Err(e) => return Err(e),
}
- if g.len == g.buf.capacity() && g.buf.capacity() == start_cap {
+ if read_buf.filled_len() == 0 {
+ return Ok(buf.len() - start_len);
+ }
+
+ // store how much was initialized but not filled
+ initialized = read_buf.initialized_len() - read_buf.filled_len();
+ let new_len = read_buf.filled_len() + buf.len();
+
+ // SAFETY: ReadBuf's invariants mean this much memory is init
+ unsafe {
+ buf.set_len(new_len);
+ }
+
+ if buf.len() == buf.capacity() && buf.capacity() == start_cap {
// The buffer might be an exact fit. Let's read into a probe buffer
// and see if it returns `Ok(0)`. If so, we've avoided an
// unnecessary doubling of the capacity. But if not, append the
@@ -409,10 +403,9 @@ pub(crate) fn default_read_to_end<R: Read + ?Sized>(r: &mut R, buf: &mut Vec<u8>
loop {
match r.read(&mut probe) {
- Ok(0) => return Ok(g.len - start_len),
+ Ok(0) => return Ok(buf.len() - start_len),
Ok(n) => {
- g.buf.extend_from_slice(&probe[..n]);
- g.len += n;
+ buf.extend_from_slice(&probe[..n]);
break;
}
Err(ref e) if e.kind() == ErrorKind::Interrupted => continue,
@@ -474,6 +467,15 @@ pub(crate) fn default_read_exact<R: Read + ?Sized>(this: &mut R, mut buf: &mut [
}
}
+pub(crate) fn default_read_buf<F>(read: F, buf: &mut ReadBuf<'_>) -> Result<()>
+where
+ F: FnOnce(&mut [u8]) -> Result<usize>,
+{
+ let n = read(buf.initialize_unfilled())?;
+ buf.add_filled(n);
+ Ok(())
+}
+
/// The `Read` trait allows for reading bytes from a source.
///
/// Implementors of the `Read` trait are called 'readers'.
@@ -656,31 +658,6 @@ pub trait Read {
false
}
- /// Determines if this `Read`er can work with buffers of uninitialized
- /// memory.
- ///
- /// The default implementation returns an initializer which will zero
- /// buffers.
- ///
- /// If a `Read`er guarantees that it can work properly with uninitialized
- /// memory, it should call [`Initializer::nop()`]. See the documentation for
- /// [`Initializer`] for details.
- ///
- /// The behavior of this method must be independent of the state of the
- /// `Read`er - the method only takes `&self` so that it can be used through
- /// trait objects.
- ///
- /// # Safety
- ///
- /// This method is unsafe because a `Read`er could otherwise return a
- /// non-zeroing `Initializer` from another `Read` type without an `unsafe`
- /// block.
- #[unstable(feature = "read_initializer", issue = "42788")]
- #[inline]
- unsafe fn initializer(&self) -> Initializer {
- Initializer::zeroing()
- }
-
/// Read all bytes until EOF in this source, placing them into `buf`.
///
/// All bytes read from this source will be appended to the specified buffer
@@ -830,7 +807,40 @@ pub trait Read {
default_read_exact(self, buf)
}
- /// Creates a "by reference" adapter for this instance of `Read`.
+ /// Pull some bytes from this source into the specified buffer.
+ ///
+ /// This is equivalent to the [`read`](Read::read) method, except that it is passed a [`ReadBuf`] rather than `[u8]` to allow use
+ /// with uninitialized buffers. The new data will be appended to any existing contents of `buf`.
+ ///
+ /// The default implementation delegates to `read`.
+ #[unstable(feature = "read_buf", issue = "78485")]
+ fn read_buf(&mut self, buf: &mut ReadBuf<'_>) -> Result<()> {
+ default_read_buf(|b| self.read(b), buf)
+ }
+
+ /// Read the exact number of bytes required to fill `buf`.
+ ///
+ /// This is equivalent to the [`read_exact`](Read::read_exact) method, except that it is passed a [`ReadBuf`] rather than `[u8]` to
+ /// allow use with uninitialized buffers.
+ #[unstable(feature = "read_buf", issue = "78485")]
+ fn read_buf_exact(&mut self, buf: &mut ReadBuf<'_>) -> Result<()> {
+ while buf.remaining() > 0 {
+ let prev_filled = buf.filled().len();
+ match self.read_buf(buf) {
+ Ok(()) => {}
+ Err(e) if e.kind() == ErrorKind::Interrupted => continue,
+ Err(e) => return Err(e),
+ }
+
+ if buf.filled().len() == prev_filled {
+ return Err(Error::new(ErrorKind::UnexpectedEof, "failed to fill buffer"));
+ }
+ }
+
+ Ok(())
+ }
+
+ /// Creates a "by reference" adaptor for this instance of `Read`.
///
/// The returned adapter also implements `Read` and will simply borrow this
/// current reader.
@@ -1300,53 +1310,6 @@ impl<'a> Deref for IoSlice<'a> {
}
}
-/// A type used to conditionally initialize buffers passed to `Read` methods.
-#[unstable(feature = "read_initializer", issue = "42788")]
-#[derive(Debug)]
-pub struct Initializer(bool);
-
-impl Initializer {
- /// Returns a new `Initializer` which will zero out buffers.
- #[unstable(feature = "read_initializer", issue = "42788")]
- #[must_use]
- #[inline]
- pub fn zeroing() -> Initializer {
- Initializer(true)
- }
-
- /// Returns a new `Initializer` which will not zero out buffers.
- ///
- /// # Safety
- ///
- /// This may only be called by `Read`ers which guarantee that they will not
- /// read from buffers passed to `Read` methods, and that the return value of
- /// the method accurately reflects the number of bytes that have been
- /// written to the head of the buffer.
- #[unstable(feature = "read_initializer", issue = "42788")]
- #[must_use]
- #[inline]
- pub unsafe fn nop() -> Initializer {
- Initializer(false)
- }
-
- /// Indicates if a buffer should be initialized.
- #[unstable(feature = "read_initializer", issue = "42788")]
- #[must_use]
- #[inline]
- pub fn should_initialize(&self) -> bool {
- self.0
- }
-
- /// Initializes a buffer if necessary.
- #[unstable(feature = "read_initializer", issue = "42788")]
- #[inline]
- pub fn initialize(&self, buf: &mut [u8]) {
- if self.should_initialize() {
- unsafe { ptr::write_bytes(buf.as_mut_ptr(), 0, buf.len()) }
- }
- }
-}
-
/// A trait for objects which are byte-oriented sinks.
///
/// Implementors of the `Write` trait are sometimes called 'writers'.
@@ -2403,11 +2366,6 @@ impl<T: Read, U: Read> Read for Chain<T, U> {
}
self.second.read_vectored(bufs)
}
-
- unsafe fn initializer(&self) -> Initializer {
- let initializer = self.first.initializer();
- if initializer.should_initialize() { initializer } else { self.second.initializer() }
- }
}
#[stable(feature = "chain_bufread", since = "1.9.0")]
@@ -2610,8 +2568,53 @@ impl<T: Read> Read for Take<T> {
Ok(n)
}
- unsafe fn initializer(&self) -> Initializer {
- self.inner.initializer()
+ fn read_buf(&mut self, buf: &mut ReadBuf<'_>) -> Result<()> {
+ // Don't call into inner reader at all at EOF because it may still block
+ if self.limit == 0 {
+ return Ok(());
+ }
+
+ let prev_filled = buf.filled_len();
+
+ if self.limit <= buf.remaining() as u64 {
+ // if we just use an as cast to convert, limit may wrap around on a 32 bit target
+ let limit = cmp::min(self.limit, usize::MAX as u64) as usize;
+
+ let extra_init = cmp::min(limit as usize, buf.initialized_len() - buf.filled_len());
+
+ // SAFETY: no uninit data is written to ibuf
+ let ibuf = unsafe { &mut buf.unfilled_mut()[..limit] };
+
+ let mut sliced_buf = ReadBuf::uninit(ibuf);
+
+ // SAFETY: extra_init bytes of ibuf are known to be initialized
+ unsafe {
+ sliced_buf.assume_init(extra_init);
+ }
+
+ self.inner.read_buf(&mut sliced_buf)?;
+
+ let new_init = sliced_buf.initialized_len();
+ let filled = sliced_buf.filled_len();
+
+ // sliced_buf / ibuf must drop here
+
+ // SAFETY: new_init bytes of buf's unfilled buffer have been initialized
+ unsafe {
+ buf.assume_init(new_init);
+ }
+
+ buf.add_filled(filled);
+
+ self.limit -= filled as u64;
+ } else {
+ self.inner.read_buf(buf)?;
+
+ //inner may unfill
+ self.limit -= buf.filled_len().saturating_sub(prev_filled) as u64;
+ }
+
+ Ok(())
}
}
diff --git a/library/std/src/io/readbuf.rs b/library/std/src/io/readbuf.rs
new file mode 100644
index 00000000000..d84a500e078
--- /dev/null
+++ b/library/std/src/io/readbuf.rs
@@ -0,0 +1,245 @@
+#![unstable(feature = "read_buf", issue = "78485")]
+
+#[cfg(test)]
+mod tests;
+
+use crate::cmp;
+use crate::fmt::{self, Debug, Formatter};
+use crate::mem::MaybeUninit;
+
+/// A wrapper around a byte buffer that is incrementally filled and initialized.
+///
+/// This type is a sort of "double cursor". It tracks three regions in the buffer: a region at the beginning of the
+/// buffer that has been logically filled with data, a region that has been initialized at some point but not yet
+/// logically filled, and a region at the end that is fully uninitialized. The filled region is guaranteed to be a
+/// subset of the initialized region.
+///
+/// In summary, the contents of the buffer can be visualized as:
+/// ```not_rust
+/// [ capacity ]
+/// [ filled | unfilled ]
+/// [ initialized | uninitialized ]
+/// ```
+pub struct ReadBuf<'a> {
+ buf: &'a mut [MaybeUninit<u8>],
+ filled: usize,
+ initialized: usize,
+}
+
+impl Debug for ReadBuf<'_> {
+ fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
+ f.debug_struct("ReadBuf")
+ .field("init", &self.initialized())
+ .field("filled", &self.filled)
+ .field("capacity", &self.capacity())
+ .finish()
+ }
+}
+
+impl<'a> ReadBuf<'a> {
+ /// Creates a new `ReadBuf` from a fully initialized buffer.
+ #[inline]
+ pub fn new(buf: &'a mut [u8]) -> ReadBuf<'a> {
+ let len = buf.len();
+
+ ReadBuf {
+ //SAFETY: initialized data never becoming uninitialized is an invariant of ReadBuf
+ buf: unsafe { (buf as *mut [u8]).as_uninit_slice_mut().unwrap() },
+ filled: 0,
+ initialized: len,
+ }
+ }
+
+ /// Creates a new `ReadBuf` from a fully uninitialized buffer.
+ ///
+ /// Use `assume_init` if part of the buffer is known to be already inintialized.
+ #[inline]
+ pub fn uninit(buf: &'a mut [MaybeUninit<u8>]) -> ReadBuf<'a> {
+ ReadBuf { buf, filled: 0, initialized: 0 }
+ }
+
+ /// Returns the total capacity of the buffer.
+ #[inline]
+ pub fn capacity(&self) -> usize {
+ self.buf.len()
+ }
+
+ /// Returns a shared reference to the filled portion of the buffer.
+ #[inline]
+ pub fn filled(&self) -> &[u8] {
+ //SAFETY: We only slice the filled part of the buffer, which is always valid
+ unsafe { MaybeUninit::slice_assume_init_ref(&self.buf[0..self.filled]) }
+ }
+
+ /// Returns a mutable reference to the filled portion of the buffer.
+ #[inline]
+ pub fn filled_mut(&mut self) -> &mut [u8] {
+ //SAFETY: We only slice the filled part of the buffer, which is always valid
+ unsafe { MaybeUninit::slice_assume_init_mut(&mut self.buf[0..self.filled]) }
+ }
+
+ /// Returns a shared reference to the initialized portion of the buffer.
+ ///
+ /// This includes the filled portion.
+ #[inline]
+ pub fn initialized(&self) -> &[u8] {
+ //SAFETY: We only slice the initialized part of the buffer, which is always valid
+ unsafe { MaybeUninit::slice_assume_init_ref(&self.buf[0..self.initialized]) }
+ }
+
+ /// Returns a mutable reference to the initialized portion of the buffer.
+ ///
+ /// This includes the filled portion.
+ #[inline]
+ pub fn initialized_mut(&mut self) -> &mut [u8] {
+ //SAFETY: We only slice the initialized part of the buffer, which is always valid
+ unsafe { MaybeUninit::slice_assume_init_mut(&mut self.buf[0..self.initialized]) }
+ }
+
+ /// Returns a mutable reference to the unfilled part of the buffer without ensuring that it has been fully
+ /// initialized.
+ ///
+ /// # Safety
+ ///
+ /// The caller must not de-initialize portions of the buffer that have already been initialized.
+ #[inline]
+ pub unsafe fn unfilled_mut(&mut self) -> &mut [MaybeUninit<u8>] {
+ &mut self.buf[self.filled..]
+ }
+
+ /// Returns a mutable reference to the uninitialized part of the buffer.
+ ///
+ /// It is safe to uninitialize any of these bytes.
+ #[inline]
+ pub fn uninitialized_mut(&mut self) -> &mut [MaybeUninit<u8>] {
+ &mut self.buf[self.initialized..]
+ }
+
+ /// Returns a mutable reference to the unfilled part of the buffer, ensuring it is fully initialized.
+ ///
+ /// Since `ReadBuf` tracks the region of the buffer that has been initialized, this is effectively "free" after
+ /// the first use.
+ #[inline]
+ pub fn initialize_unfilled(&mut self) -> &mut [u8] {
+ // should optimize out the assertion
+ self.initialize_unfilled_to(self.remaining())
+ }
+
+ /// Returns a mutable reference to the first `n` bytes of the unfilled part of the buffer, ensuring it is
+ /// fully initialized.
+ ///
+ /// # Panics
+ ///
+ /// Panics if `self.remaining()` is less than `n`.
+ #[inline]
+ pub fn initialize_unfilled_to(&mut self, n: usize) -> &mut [u8] {
+ assert!(self.remaining() >= n);
+
+ let extra_init = self.initialized - self.filled;
+ // If we don't have enough initialized, do zeroing
+ if n > extra_init {
+ let uninit = n - extra_init;
+ let unfilled = &mut self.uninitialized_mut()[0..uninit];
+
+ for byte in unfilled.iter_mut() {
+ byte.write(0);
+ }
+
+ // SAFETY: we just inintialized uninit bytes, and the previous bytes were already init
+ unsafe {
+ self.assume_init(n);
+ }
+ }
+
+ let filled = self.filled;
+
+ &mut self.initialized_mut()[filled..filled + n]
+ }
+
+ /// Returns the number of bytes at the end of the slice that have not yet been filled.
+ #[inline]
+ pub fn remaining(&self) -> usize {
+ self.capacity() - self.filled
+ }
+
+ /// Clears the buffer, resetting the filled region to empty.
+ ///
+ /// The number of initialized bytes is not changed, and the contents of the buffer are not modified.
+ #[inline]
+ pub fn clear(&mut self) {
+ self.set_filled(0); // The assertion in `set_filled` is optimized out
+ }
+
+ /// Increases the size of the filled region of the buffer.
+ ///
+ /// The number of initialized bytes is not changed.
+ ///
+ /// # Panics
+ ///
+ /// Panics if the filled region of the buffer would become larger than the initialized region.
+ #[inline]
+ pub fn add_filled(&mut self, n: usize) {
+ self.set_filled(self.filled + n);
+ }
+
+ /// Sets the size of the filled region of the buffer.
+ ///
+ /// The number of initialized bytes is not changed.
+ ///
+ /// Note that this can be used to *shrink* the filled region of the buffer in addition to growing it (for
+ /// example, by a `Read` implementation that compresses data in-place).
+ ///
+ /// # Panics
+ ///
+ /// Panics if the filled region of the buffer would become larger than the initialized region.
+ #[inline]
+ pub fn set_filled(&mut self, n: usize) {
+ assert!(n <= self.initialized);
+
+ self.filled = n;
+ }
+
+ /// Asserts that the first `n` unfilled bytes of the buffer are initialized.
+ ///
+ /// `ReadBuf` assumes that bytes are never de-initialized, so this method does nothing when called with fewer
+ /// bytes than are already known to be initialized.
+ ///
+ /// # Safety
+ ///
+ /// The caller must ensure that the first `n` unfilled bytes of the buffer have already been initialized.
+ #[inline]
+ pub unsafe fn assume_init(&mut self, n: usize) {
+ self.initialized = cmp::max(self.initialized, self.filled + n);
+ }
+
+ /// Appends data to the buffer, advancing the written position and possibly also the initialized position.
+ ///
+ /// # Panics
+ ///
+ /// Panics if `self.remaining()` is less than `buf.len()`.
+ #[inline]
+ pub fn append(&mut self, buf: &[u8]) {
+ assert!(self.remaining() >= buf.len());
+
+ // SAFETY: we do not de-initialize any of the elements of the slice
+ unsafe {
+ MaybeUninit::write_slice(&mut self.unfilled_mut()[..buf.len()], buf);
+ }
+
+ // SAFETY: We just added the entire contents of buf to the filled section.
+ unsafe { self.assume_init(buf.len()) }
+ self.add_filled(buf.len());
+ }
+
+ /// Returns the amount of bytes that have been filled.
+ #[inline]
+ pub fn filled_len(&self) -> usize {
+ self.filled
+ }
+
+ /// Returns the amount of bytes that have been initialized.
+ #[inline]
+ pub fn initialized_len(&self) -> usize {
+ self.initialized
+ }
+}
diff --git a/library/std/src/io/readbuf/tests.rs b/library/std/src/io/readbuf/tests.rs
new file mode 100644
index 00000000000..3b7a5a56d22
--- /dev/null
+++ b/library/std/src/io/readbuf/tests.rs
@@ -0,0 +1,181 @@
+use super::ReadBuf;
+use crate::mem::MaybeUninit;
+
+/// Test that ReadBuf has the correct numbers when created with new
+#[test]
+fn new() {
+ let mut buf = [0; 16];
+ let rbuf = ReadBuf::new(&mut buf);
+
+ assert_eq!(rbuf.filled_len(), 0);
+ assert_eq!(rbuf.initialized_len(), 16);
+ assert_eq!(rbuf.capacity(), 16);
+ assert_eq!(rbuf.remaining(), 16);
+}
+
+/// Test that ReadBuf has the correct numbers when created with uninit
+#[test]
+fn uninit() {
+ let mut buf = [MaybeUninit::uninit(); 16];
+ let rbuf = ReadBuf::uninit(&mut buf);
+
+ assert_eq!(rbuf.filled_len(), 0);
+ assert_eq!(rbuf.initialized_len(), 0);
+ assert_eq!(rbuf.capacity(), 16);
+ assert_eq!(rbuf.remaining(), 16);
+}
+
+#[test]
+fn initialize_unfilled() {
+ let mut buf = [MaybeUninit::uninit(); 16];
+ let mut rbuf = ReadBuf::uninit(&mut buf);
+
+ rbuf.initialize_unfilled();
+
+ assert_eq!(rbuf.initialized_len(), 16);
+}
+
+#[test]
+fn initialize_unfilled_to() {
+ let mut buf = [MaybeUninit::uninit(); 16];
+ let mut rbuf = ReadBuf::uninit(&mut buf);
+
+ rbuf.initialize_unfilled_to(8);
+
+ assert_eq!(rbuf.initialized_len(), 8);
+
+ rbuf.initialize_unfilled_to(4);
+
+ assert_eq!(rbuf.initialized_len(), 8);
+
+ rbuf.set_filled(8);
+
+ rbuf.initialize_unfilled_to(6);
+
+ assert_eq!(rbuf.initialized_len(), 14);
+
+ rbuf.initialize_unfilled_to(8);
+
+ assert_eq!(rbuf.initialized_len(), 16);
+}
+
+#[test]
+fn add_filled() {
+ let mut buf = [0; 16];
+ let mut rbuf = ReadBuf::new(&mut buf);
+
+ rbuf.add_filled(1);
+
+ assert_eq!(rbuf.filled_len(), 1);
+ assert_eq!(rbuf.remaining(), 15);
+}
+
+#[test]
+#[should_panic]
+fn add_filled_panic() {
+ let mut buf = [MaybeUninit::uninit(); 16];
+ let mut rbuf = ReadBuf::uninit(&mut buf);
+
+ rbuf.add_filled(1);
+}
+
+#[test]
+fn set_filled() {
+ let mut buf = [0; 16];
+ let mut rbuf = ReadBuf::new(&mut buf);
+
+ rbuf.set_filled(16);
+
+ assert_eq!(rbuf.filled_len(), 16);
+ assert_eq!(rbuf.remaining(), 0);
+
+ rbuf.set_filled(6);
+
+ assert_eq!(rbuf.filled_len(), 6);
+ assert_eq!(rbuf.remaining(), 10);
+}
+
+#[test]
+#[should_panic]
+fn set_filled_panic() {
+ let mut buf = [MaybeUninit::uninit(); 16];
+ let mut rbuf = ReadBuf::uninit(&mut buf);
+
+ rbuf.set_filled(16);
+}
+
+#[test]
+fn clear() {
+ let mut buf = [255; 16];
+ let mut rbuf = ReadBuf::new(&mut buf);
+
+ rbuf.set_filled(16);
+
+ assert_eq!(rbuf.filled_len(), 16);
+ assert_eq!(rbuf.remaining(), 0);
+
+ rbuf.clear();
+
+ assert_eq!(rbuf.filled_len(), 0);
+ assert_eq!(rbuf.remaining(), 16);
+
+ assert_eq!(rbuf.initialized(), [255; 16]);
+}
+
+#[test]
+fn assume_init() {
+ let mut buf = [MaybeUninit::uninit(); 16];
+ let mut rbuf = ReadBuf::uninit(&mut buf);
+
+ unsafe {
+ rbuf.assume_init(8);
+ }
+
+ assert_eq!(rbuf.initialized_len(), 8);
+
+ rbuf.add_filled(4);
+
+ unsafe {
+ rbuf.assume_init(2);
+ }
+
+ assert_eq!(rbuf.initialized_len(), 8);
+
+ unsafe {
+ rbuf.assume_init(8);
+ }
+
+ assert_eq!(rbuf.initialized_len(), 12);
+}
+
+#[test]
+fn append() {
+ let mut buf = [MaybeUninit::new(255); 16];
+ let mut rbuf = ReadBuf::uninit(&mut buf);
+
+ rbuf.append(&[0; 8]);
+
+ assert_eq!(rbuf.initialized_len(), 8);
+ assert_eq!(rbuf.filled_len(), 8);
+ assert_eq!(rbuf.filled(), [0; 8]);
+
+ rbuf.clear();
+
+ rbuf.append(&[1; 16]);
+
+ assert_eq!(rbuf.initialized_len(), 16);
+ assert_eq!(rbuf.filled_len(), 16);
+ assert_eq!(rbuf.filled(), [1; 16]);
+}
+
+#[test]
+fn filled_mut() {
+ let mut buf = [0; 16];
+ let mut rbuf = ReadBuf::new(&mut buf);
+
+ rbuf.add_filled(8);
+
+ let filled = rbuf.filled().to_vec();
+
+ assert_eq!(&*filled, &*rbuf.filled_mut());
+}
diff --git a/library/std/src/io/stdio.rs b/library/std/src/io/stdio.rs
index f7fc23c1e82..c072f0cafe4 100644
--- a/library/std/src/io/stdio.rs
+++ b/library/std/src/io/stdio.rs
@@ -7,7 +7,7 @@ use crate::io::prelude::*;
use crate::cell::{Cell, RefCell};
use crate::fmt;
-use crate::io::{self, BufReader, Initializer, IoSlice, IoSliceMut, LineWriter, Lines, Split};
+use crate::io::{self, BufReader, IoSlice, IoSliceMut, LineWriter, Lines, Split};
use crate::lazy::SyncOnceCell;
use crate::pin::Pin;
use crate::sync::atomic::{AtomicBool, Ordering};
@@ -108,11 +108,6 @@ impl Read for StdinRaw {
self.0.is_read_vectored()
}
- #[inline]
- unsafe fn initializer(&self) -> Initializer {
- Initializer::nop()
- }
-
fn read_to_end(&mut self, buf: &mut Vec<u8>) -> io::Result<usize> {
handle_ebadf(self.0.read_to_end(buf), 0)
}
@@ -514,10 +509,6 @@ impl Read for Stdin {
fn is_read_vectored(&self) -> bool {
self.lock().is_read_vectored()
}
- #[inline]
- unsafe fn initializer(&self) -> Initializer {
- Initializer::nop()
- }
fn read_to_end(&mut self, buf: &mut Vec<u8>) -> io::Result<usize> {
self.lock().read_to_end(buf)
}
@@ -552,11 +543,6 @@ impl Read for StdinLock<'_> {
self.inner.is_read_vectored()
}
- #[inline]
- unsafe fn initializer(&self) -> Initializer {
- Initializer::nop()
- }
-
fn read_to_end(&mut self, buf: &mut Vec<u8>) -> io::Result<usize> {
self.inner.read_to_end(buf)
}
@@ -1193,7 +1179,7 @@ where
})
}) == Ok(Some(()))
{
- // Succesfully wrote to capture buffer.
+ // Successfully wrote to capture buffer.
return;
}
diff --git a/library/std/src/io/tests.rs b/library/std/src/io/tests.rs
index 0321a2b60b1..ea49bfe3421 100644
--- a/library/std/src/io/tests.rs
+++ b/library/std/src/io/tests.rs
@@ -1,7 +1,8 @@
-use super::{repeat, Cursor, SeekFrom};
+use super::{repeat, Cursor, ReadBuf, SeekFrom};
use crate::cmp::{self, min};
use crate::io::{self, IoSlice, IoSliceMut};
use crate::io::{BufRead, BufReader, Read, Seek, Write};
+use crate::mem::MaybeUninit;
use crate::ops::Deref;
#[test]
@@ -157,6 +158,28 @@ fn read_exact_slice() {
}
#[test]
+fn read_buf_exact() {
+ let mut buf = [0; 4];
+ let mut buf = ReadBuf::new(&mut buf);
+
+ let mut c = Cursor::new(&b""[..]);
+ assert_eq!(c.read_buf_exact(&mut buf).unwrap_err().kind(), io::ErrorKind::UnexpectedEof);
+
+ let mut c = Cursor::new(&b"123456789"[..]);
+ c.read_buf_exact(&mut buf).unwrap();
+ assert_eq!(buf.filled(), b"1234");
+
+ buf.clear();
+
+ c.read_buf_exact(&mut buf).unwrap();
+ assert_eq!(buf.filled(), b"5678");
+
+ buf.clear();
+
+ assert_eq!(c.read_buf_exact(&mut buf).unwrap_err().kind(), io::ErrorKind::UnexpectedEof);
+}
+
+#[test]
fn take_eof() {
struct R;
@@ -559,3 +582,23 @@ fn test_write_all_vectored() {
}
}
}
+
+#[bench]
+fn bench_take_read(b: &mut test::Bencher) {
+ b.iter(|| {
+ let mut buf = [0; 64];
+
+ [255; 128].take(64).read(&mut buf).unwrap();
+ });
+}
+
+#[bench]
+fn bench_take_read_buf(b: &mut test::Bencher) {
+ b.iter(|| {
+ let mut buf = [MaybeUninit::uninit(); 64];
+
+ let mut rbuf = ReadBuf::uninit(&mut buf);
+
+ [255; 128].take(64).read_buf(&mut rbuf).unwrap();
+ });
+}
diff --git a/library/std/src/io/util.rs b/library/std/src/io/util.rs
index 9cd7c514849..c1300cd67c0 100644
--- a/library/std/src/io/util.rs
+++ b/library/std/src/io/util.rs
@@ -5,7 +5,7 @@ mod tests;
use crate::fmt;
use crate::io::{
- self, BufRead, Initializer, IoSlice, IoSliceMut, Read, Seek, SeekFrom, SizeHint, Write,
+ self, BufRead, IoSlice, IoSliceMut, Read, ReadBuf, Seek, SeekFrom, SizeHint, Write,
};
/// A reader which is always at EOF.
@@ -47,8 +47,8 @@ impl Read for Empty {
}
#[inline]
- unsafe fn initializer(&self) -> Initializer {
- Initializer::nop()
+ fn read_buf(&mut self, _buf: &mut ReadBuf<'_>) -> io::Result<()> {
+ Ok(())
}
}
#[stable(feature = "rust1", since = "1.0.0")]
@@ -130,6 +130,24 @@ impl Read for Repeat {
Ok(buf.len())
}
+ fn read_buf(&mut self, buf: &mut ReadBuf<'_>) -> io::Result<()> {
+ // SAFETY: No uninit bytes are being written
+ for slot in unsafe { buf.unfilled_mut() } {
+ slot.write(self.byte);
+ }
+
+ let remaining = buf.remaining();
+
+ // SAFETY: the entire unfilled portion of buf has been initialized
+ unsafe {
+ buf.assume_init(remaining);
+ }
+
+ buf.add_filled(remaining);
+
+ Ok(())
+ }
+
#[inline]
fn read_vectored(&mut self, bufs: &mut [IoSliceMut<'_>]) -> io::Result<usize> {
let mut nwritten = 0;
@@ -143,11 +161,6 @@ impl Read for Repeat {
fn is_read_vectored(&self) -> bool {
true
}
-
- #[inline]
- unsafe fn initializer(&self) -> Initializer {
- Initializer::nop()
- }
}
impl SizeHint for Repeat {
diff --git a/library/std/src/io/util/tests.rs b/library/std/src/io/util/tests.rs
index 7632eaf872a..08972a59a83 100644
--- a/library/std/src/io/util/tests.rs
+++ b/library/std/src/io/util/tests.rs
@@ -1,9 +1,12 @@
use crate::cmp::{max, min};
use crate::io::prelude::*;
use crate::io::{
- copy, empty, repeat, sink, BufWriter, Empty, Repeat, Result, SeekFrom, Sink, DEFAULT_BUF_SIZE,
+ copy, empty, repeat, sink, BufWriter, Empty, ReadBuf, Repeat, Result, SeekFrom, Sink,
+ DEFAULT_BUF_SIZE,
};
+use crate::mem::MaybeUninit;
+
#[test]
fn copy_copies() {
let mut r = repeat(0).take(4);
@@ -75,6 +78,30 @@ fn empty_reads() {
assert_eq!(e.read(&mut [0]).unwrap(), 0);
assert_eq!(e.read(&mut [0; 1024]).unwrap(), 0);
assert_eq!(e.by_ref().read(&mut [0; 1024]).unwrap(), 0);
+
+ let mut buf = [];
+ let mut buf = ReadBuf::uninit(&mut buf);
+ e.read_buf(&mut buf).unwrap();
+ assert_eq!(buf.filled_len(), 0);
+ assert_eq!(buf.initialized_len(), 0);
+
+ let mut buf = [MaybeUninit::uninit()];
+ let mut buf = ReadBuf::uninit(&mut buf);
+ e.read_buf(&mut buf).unwrap();
+ assert_eq!(buf.filled_len(), 0);
+ assert_eq!(buf.initialized_len(), 0);
+
+ let mut buf = [MaybeUninit::uninit(); 1024];
+ let mut buf = ReadBuf::uninit(&mut buf);
+ e.read_buf(&mut buf).unwrap();
+ assert_eq!(buf.filled_len(), 0);
+ assert_eq!(buf.initialized_len(), 0);
+
+ let mut buf = [MaybeUninit::uninit(); 1024];
+ let mut buf = ReadBuf::uninit(&mut buf);
+ e.by_ref().read_buf(&mut buf).unwrap();
+ assert_eq!(buf.filled_len(), 0);
+ assert_eq!(buf.initialized_len(), 0);
}
#[test]
diff --git a/library/std/src/lib.rs b/library/std/src/lib.rs
index afd8d8edaa1..22e721d79bf 100644
--- a/library/std/src/lib.rs
+++ b/library/std/src/lib.rs
@@ -216,10 +216,7 @@
// std may use features in a platform-specific way
#![allow(unused_features)]
#![feature(rustc_allow_const_fn_unstable)]
-#![cfg_attr(
- test,
- feature(internal_output_capture, print_internals, update_panic_count, thread_local_const_init)
-)]
+#![cfg_attr(test, feature(internal_output_capture, print_internals, update_panic_count))]
#![cfg_attr(
all(target_vendor = "fortanix", target_env = "sgx"),
feature(slice_index_methods, coerce_unsized, sgx_platform)
@@ -236,7 +233,6 @@
#![feature(allow_internal_unstable)]
#![feature(arbitrary_self_types)]
#![feature(array_error_internals)]
-#![feature(asm)]
#![feature(assert_matches)]
#![feature(associated_type_bounds)]
#![feature(async_stream)]
@@ -253,8 +249,8 @@
#![feature(cfg_target_thread_local)]
#![feature(char_error_internals)]
#![feature(char_internals)]
+#![cfg_attr(not(bootstrap), feature(concat_bytes))]
#![feature(concat_idents)]
-#![feature(const_cstr_unchecked)]
#![feature(const_fn_floating_point_arithmetic)]
#![feature(const_fn_fn_ptr_basics)]
#![feature(const_fn_trait_bound)]
@@ -264,8 +260,7 @@
#![feature(const_ipv4)]
#![feature(const_ipv6)]
#![feature(const_option)]
-#![cfg_attr(bootstrap, feature(const_raw_ptr_deref))]
-#![cfg_attr(not(bootstrap), feature(const_mut_refs))]
+#![feature(const_mut_refs)]
#![feature(const_socketaddr)]
#![feature(const_trait_impl)]
#![feature(container_error_extra)]
@@ -275,10 +270,9 @@
#![feature(decl_macro)]
#![feature(doc_cfg)]
#![feature(doc_cfg_hide)]
-#![feature(doc_keyword)]
+#![feature(rustdoc_internals)]
#![feature(doc_masked)]
#![feature(doc_notable_trait)]
-#![feature(doc_primitive)]
#![feature(dropck_eyepatch)]
#![feature(duration_checked_float)]
#![feature(duration_constants)]
@@ -292,14 +286,12 @@
#![feature(gen_future)]
#![feature(generator_trait)]
#![feature(get_mut_unchecked)]
-#![feature(global_asm)]
#![feature(hashmap_internals)]
#![feature(int_error_internals)]
#![feature(integer_atomics)]
#![feature(int_log)]
#![feature(into_future)]
#![feature(intra_doc_pointers)]
-#![feature(iter_zip)]
#![feature(lang_items)]
#![feature(linkage)]
#![feature(llvm_asm)]
@@ -308,6 +300,7 @@
#![feature(maybe_uninit_extra)]
#![feature(maybe_uninit_slice)]
#![feature(maybe_uninit_uninit_array)]
+#![feature(maybe_uninit_write_slice)]
#![feature(min_specialization)]
#![feature(mixed_integer_ops)]
#![feature(must_not_suspend)]
@@ -322,8 +315,9 @@
#![feature(panic_internals)]
#![feature(panic_unwind)]
#![feature(pin_static_ref)]
-#![cfg_attr(not(bootstrap), feature(portable_simd))]
+#![feature(portable_simd)]
#![feature(prelude_import)]
+#![feature(ptr_as_uninit)]
#![feature(ptr_internals)]
#![feature(rustc_attrs)]
#![feature(rustc_private)]
@@ -475,7 +469,6 @@ pub use core::ptr;
#[stable(feature = "rust1", since = "1.0.0")]
pub use core::result;
#[unstable(feature = "portable_simd", issue = "86656")]
-#[cfg(not(bootstrap))]
pub use core::simd;
#[unstable(feature = "async_stream", issue = "79024")]
pub use core::stream;
@@ -582,6 +575,14 @@ pub use core::{
log_syntax, module_path, option_env, stringify, trace_macros,
};
+#[unstable(
+ feature = "concat_bytes",
+ issue = "87555",
+ reason = "`concat_bytes` is not stable enough for use and is subject to change"
+)]
+#[cfg(not(bootstrap))]
+pub use core::concat_bytes;
+
#[stable(feature = "core_primitive", since = "1.43.0")]
pub use core::primitive;
diff --git a/library/std/src/net/ip/tests.rs b/library/std/src/net/ip/tests.rs
index 17581f33026..632d4683b41 100644
--- a/library/std/src/net/ip/tests.rs
+++ b/library/std/src/net/ip/tests.rs
@@ -749,7 +749,7 @@ fn ipv4_from_constructors() {
}
#[test]
-fn ipv6_from_contructors() {
+fn ipv6_from_constructors() {
assert_eq!(Ipv6Addr::LOCALHOST, Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 1));
assert!(Ipv6Addr::LOCALHOST.is_loopback());
assert_eq!(Ipv6Addr::UNSPECIFIED, Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 0));
diff --git a/library/std/src/net/tcp.rs b/library/std/src/net/tcp.rs
index 5738862fb58..1ba54d892e3 100644
--- a/library/std/src/net/tcp.rs
+++ b/library/std/src/net/tcp.rs
@@ -6,7 +6,7 @@ mod tests;
use crate::io::prelude::*;
use crate::fmt;
-use crate::io::{self, Initializer, IoSlice, IoSliceMut};
+use crate::io::{self, IoSlice, IoSliceMut};
use crate::net::{Shutdown, SocketAddr, ToSocketAddrs};
use crate::sys_common::net as net_imp;
use crate::sys_common::{AsInner, FromInner, IntoInner};
@@ -626,12 +626,6 @@ impl Read for TcpStream {
fn is_read_vectored(&self) -> bool {
self.0.is_read_vectored()
}
-
- #[inline]
- unsafe fn initializer(&self) -> Initializer {
- // SAFETY: Read is guaranteed to work on uninitialized memory
- unsafe { Initializer::nop() }
- }
}
#[stable(feature = "rust1", since = "1.0.0")]
impl Write for TcpStream {
@@ -666,12 +660,6 @@ impl Read for &TcpStream {
fn is_read_vectored(&self) -> bool {
self.0.is_read_vectored()
}
-
- #[inline]
- unsafe fn initializer(&self) -> Initializer {
- // SAFETY: Read is guaranteed to work on uninitialized memory
- unsafe { Initializer::nop() }
- }
}
#[stable(feature = "rust1", since = "1.0.0")]
impl Write for &TcpStream {
diff --git a/library/std/src/os/fortanix_sgx/arch.rs b/library/std/src/os/fortanix_sgx/arch.rs
index 4ce482e23cb..8358cb9e81b 100644
--- a/library/std/src/os/fortanix_sgx/arch.rs
+++ b/library/std/src/os/fortanix_sgx/arch.rs
@@ -5,6 +5,7 @@
#![unstable(feature = "sgx_platform", issue = "56975")]
use crate::mem::MaybeUninit;
+use core::arch::asm;
/// Wrapper struct to force 16-byte alignment.
#[repr(align(16))]
diff --git a/library/std/src/os/raw/mod.rs b/library/std/src/os/raw/mod.rs
index 01392ffab79..f0b38d29845 100644
--- a/library/std/src/os/raw/mod.rs
+++ b/library/std/src/os/raw/mod.rs
@@ -69,7 +69,8 @@ type_alias! { "char.md", c_char = u8, NonZero_c_char = NonZeroU8;
target_arch = "aarch64",
target_arch = "arm",
target_arch = "powerpc",
- target_arch = "powerpc64"
+ target_arch = "powerpc64",
+ target_arch = "riscv64"
)
),
all(
@@ -112,7 +113,8 @@ type_alias! { "char.md", c_char = i8, NonZero_c_char = NonZeroI8;
target_arch = "aarch64",
target_arch = "arm",
target_arch = "powerpc",
- target_arch = "powerpc64"
+ target_arch = "powerpc64",
+ target_arch = "riscv64"
)
),
all(
diff --git a/library/std/src/os/unix/net/stream.rs b/library/std/src/os/unix/net/stream.rs
index 6120d557227..583f861a925 100644
--- a/library/std/src/os/unix/net/stream.rs
+++ b/library/std/src/os/unix/net/stream.rs
@@ -11,7 +11,7 @@
use super::{recv_vectored_with_ancillary_from, send_vectored_with_ancillary_to, SocketAncillary};
use super::{sockaddr_un, SocketAddr};
use crate::fmt;
-use crate::io::{self, Initializer, IoSlice, IoSliceMut};
+use crate::io::{self, IoSlice, IoSliceMut};
use crate::net::Shutdown;
use crate::os::unix::io::{AsFd, AsRawFd, BorrowedFd, FromRawFd, IntoRawFd, OwnedFd, RawFd};
#[cfg(any(
@@ -624,11 +624,6 @@ impl io::Read for UnixStream {
fn is_read_vectored(&self) -> bool {
io::Read::is_read_vectored(&&*self)
}
-
- #[inline]
- unsafe fn initializer(&self) -> Initializer {
- Initializer::nop()
- }
}
#[stable(feature = "unix_socket", since = "1.10.0")]
@@ -645,11 +640,6 @@ impl<'a> io::Read for &'a UnixStream {
fn is_read_vectored(&self) -> bool {
self.0.is_read_vectored()
}
-
- #[inline]
- unsafe fn initializer(&self) -> Initializer {
- Initializer::nop()
- }
}
#[stable(feature = "unix_socket", since = "1.10.0")]
diff --git a/library/std/src/os/windows/fs.rs b/library/std/src/os/windows/fs.rs
index be35ab0ca1e..31d1e3c1e42 100644
--- a/library/std/src/os/windows/fs.rs
+++ b/library/std/src/os/windows/fs.rs
@@ -543,6 +543,16 @@ impl FileTypeExt for fs::FileType {
/// Ok(())
/// }
/// ```
+///
+/// # Limitations
+///
+/// Windows treats symlink creation as a [privileged action][symlink-security],
+/// therefore this function is likely to fail unless the user makes changes to
+/// their system to permit symlink creation. Users can try enabling Developer
+/// Mode, granting the `SeCreateSymbolicLinkPrivilege` privilege, or running
+/// the process as an administrator.
+///
+/// [symlink-security]: https://docs.microsoft.com/en-us/windows/security/threat-protection/security-policy-settings/create-symbolic-links
#[stable(feature = "symlink", since = "1.1.0")]
pub fn symlink_file<P: AsRef<Path>, Q: AsRef<Path>>(original: P, link: Q) -> io::Result<()> {
sys::fs::symlink_inner(original.as_ref(), link.as_ref(), false)
@@ -572,6 +582,16 @@ pub fn symlink_file<P: AsRef<Path>, Q: AsRef<Path>>(original: P, link: Q) -> io:
/// Ok(())
/// }
/// ```
+///
+/// # Limitations
+///
+/// Windows treats symlink creation as a [privileged action][symlink-security],
+/// therefore this function is likely to fail unless the user makes changes to
+/// their system to permit symlink creation. Users can try enabling Developer
+/// Mode, granting the `SeCreateSymbolicLinkPrivilege` privilege, or running
+/// the process as an administrator.
+///
+/// [symlink-security]: https://docs.microsoft.com/en-us/windows/security/threat-protection/security-policy-settings/create-symbolic-links
#[stable(feature = "symlink", since = "1.1.0")]
pub fn symlink_dir<P: AsRef<Path>, Q: AsRef<Path>>(original: P, link: Q) -> io::Result<()> {
sys::fs::symlink_inner(original.as_ref(), link.as_ref(), true)
diff --git a/library/std/src/panicking.rs b/library/std/src/panicking.rs
index 6fc6b8daec0..87854fe4f29 100644
--- a/library/std/src/panicking.rs
+++ b/library/std/src/panicking.rs
@@ -365,7 +365,7 @@ pub unsafe fn r#try<R, F: FnOnce() -> R>(f: F) -> Result<R, Box<dyn Any + Send>>
// 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
+ // See their safety preconditions for more information
unsafe {
return if intrinsics::r#try(do_call::<F, R>, data_ptr, do_catch::<F, R>) == 0 {
Ok(ManuallyDrop::into_inner(data.r))
@@ -398,7 +398,7 @@ pub unsafe fn r#try<R, F: FnOnce() -> R>(f: F) -> Result<R, Box<dyn Any + Send>>
// 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.
+ // SAFETY: this is the responsibility of the caller, see above.
unsafe {
let data = data as *mut Data<F, R>;
let data = &mut (*data);
@@ -420,7 +420,7 @@ pub unsafe fn r#try<R, F: FnOnce() -> R>(f: F) -> Result<R, Box<dyn Any + Send>>
// 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.
+ // SAFETY: this is the responsibility 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
diff --git a/library/std/src/path.rs b/library/std/src/path.rs
index cf2cd5adc48..7d401cff591 100644
--- a/library/std/src/path.rs
+++ b/library/std/src/path.rs
@@ -12,6 +12,13 @@
//! [`PathBuf`]; note that the paths may differ syntactically by the
//! normalization described in the documentation for the [`components`] method.
//!
+//! ## Case sensitivity
+//!
+//! Unless otherwise indicated path methods that do not access the filesystem,
+//! such as [`Path::starts_with`] and [`Path::ends_with`], are case sensitive no
+//! matter the platform or filesystem. An exception to this is made for Windows
+//! drive letters.
+//!
//! ## Simple usage
//!
//! Path manipulation includes both parsing components from slices and building
@@ -2810,7 +2817,7 @@ impl Path {
/// check errors, call [`fs::symlink_metadata`] and handle its [`Result`]. Then call
/// [`fs::Metadata::is_symlink`] if it was [`Ok`].
#[must_use]
- #[stable(feature = "is_symlink", since = "1.57.0")]
+ #[stable(feature = "is_symlink", since = "1.58.0")]
pub fn is_symlink(&self) -> bool {
fs::symlink_metadata(self).map(|m| m.is_symlink()).unwrap_or(false)
}
diff --git a/library/std/src/prelude/v1.rs b/library/std/src/prelude/v1.rs
index 772044f0149..743dd51333d 100644
--- a/library/std/src/prelude/v1.rs
+++ b/library/std/src/prelude/v1.rs
@@ -46,20 +46,13 @@ pub use core::prelude::v1::{
};
#[unstable(
- feature = "asm",
- issue = "72016",
- reason = "inline assembly is not stable enough for use and is subject to change"
+ feature = "concat_bytes",
+ issue = "87555",
+ reason = "`concat_bytes` is not stable enough for use and is subject to change"
)]
+#[cfg(not(bootstrap))]
#[doc(no_inline)]
-pub use core::prelude::v1::asm;
-
-#[unstable(
- feature = "global_asm",
- issue = "35119",
- reason = "`global_asm!` is not stable enough for use and is subject to change"
-)]
-#[doc(no_inline)]
-pub use core::prelude::v1::global_asm;
+pub use core::prelude::v1::concat_bytes;
// FIXME: Attribute and internal derive macros are not documented because for them rustdoc generates
// dead links which fail link checker testing.
diff --git a/library/std/src/primitive_docs.rs b/library/std/src/primitive_docs.rs
index f47a30c9b5d..8fcd8cdeb10 100644
--- a/library/std/src/primitive_docs.rs
+++ b/library/std/src/primitive_docs.rs
@@ -606,8 +606,7 @@ mod prim_pointer {}
/// println!("array[{}] = {}", i, x);
/// }
///
-/// // You can explicitly iterate an array by value using
-/// // `IntoIterator::into_iter` or `std::array::IntoIter::new`:
+/// // You can explicitly iterate an array by value using `IntoIterator::into_iter`
/// for item in IntoIterator::into_iter(array).enumerate() {
/// let (i, x): (usize, i32) = item;
/// println!("array[{}] = {}", i, x);
diff --git a/library/std/src/process.rs b/library/std/src/process.rs
index 4e9fd51f282..e012594dd46 100644
--- a/library/std/src/process.rs
+++ b/library/std/src/process.rs
@@ -110,7 +110,7 @@ use crate::convert::Infallible;
use crate::ffi::OsStr;
use crate::fmt;
use crate::fs;
-use crate::io::{self, Initializer, IoSlice, IoSliceMut};
+use crate::io::{self, IoSlice, IoSliceMut};
use crate::num::NonZeroI32;
use crate::path::Path;
use crate::str;
@@ -362,12 +362,6 @@ impl Read for ChildStdout {
fn is_read_vectored(&self) -> bool {
self.inner.is_read_vectored()
}
-
- #[inline]
- unsafe fn initializer(&self) -> Initializer {
- // SAFETY: Read is guaranteed to work on uninitialized memory
- unsafe { Initializer::nop() }
- }
}
impl AsInner<AnonPipe> for ChildStdout {
@@ -429,12 +423,6 @@ impl Read for ChildStderr {
fn is_read_vectored(&self) -> bool {
self.inner.is_read_vectored()
}
-
- #[inline]
- unsafe fn initializer(&self) -> Initializer {
- // SAFETY: Read is guaranteed to work on uninitialized memory
- unsafe { Initializer::nop() }
- }
}
impl AsInner<AnonPipe> for ChildStderr {
@@ -1612,7 +1600,6 @@ impl ExitStatusError {
/// ```
/// #![feature(exit_status_error)]
/// # if cfg!(unix) {
- /// use std::convert::TryFrom;
/// use std::num::NonZeroI32;
/// use std::process::Command;
///
diff --git a/library/std/src/process/tests.rs b/library/std/src/process/tests.rs
index 094d2efbdd5..67b747e4107 100644
--- a/library/std/src/process/tests.rs
+++ b/library/std/src/process/tests.rs
@@ -4,15 +4,23 @@ use super::{Command, Output, Stdio};
use crate::io::ErrorKind;
use crate::str;
-// FIXME(#10380) these tests should not all be ignored on android.
+#[cfg(target_os = "android")]
+fn shell_cmd() -> Command {
+ Command::new("/system/bin/sh")
+}
+
+#[cfg(not(target_os = "android"))]
+fn shell_cmd() -> Command {
+ Command::new("/bin/sh")
+}
#[test]
-#[cfg_attr(any(target_os = "vxworks", target_os = "android"), ignore)]
+#[cfg_attr(any(target_os = "vxworks"), ignore)]
fn smoke() {
let p = if cfg!(target_os = "windows") {
Command::new("cmd").args(&["/C", "exit 0"]).spawn()
} else {
- Command::new("true").spawn()
+ shell_cmd().arg("-c").arg("true").spawn()
};
assert!(p.is_ok());
let mut p = p.unwrap();
@@ -29,12 +37,12 @@ fn smoke_failure() {
}
#[test]
-#[cfg_attr(any(target_os = "vxworks", target_os = "android"), ignore)]
+#[cfg_attr(any(target_os = "vxworks"), ignore)]
fn exit_reported_right() {
let p = if cfg!(target_os = "windows") {
Command::new("cmd").args(&["/C", "exit 1"]).spawn()
} else {
- Command::new("false").spawn()
+ shell_cmd().arg("-c").arg("false").spawn()
};
assert!(p.is_ok());
let mut p = p.unwrap();
@@ -44,12 +52,11 @@ fn exit_reported_right() {
#[test]
#[cfg(unix)]
-#[cfg_attr(any(target_os = "vxworks", target_os = "android"), ignore)]
+#[cfg_attr(any(target_os = "vxworks"), ignore)]
fn signal_reported_right() {
use crate::os::unix::process::ExitStatusExt;
- let mut p =
- Command::new("/bin/sh").arg("-c").arg("read a").stdin(Stdio::piped()).spawn().unwrap();
+ let mut p = shell_cmd().arg("-c").arg("read a").stdin(Stdio::piped()).spawn().unwrap();
p.kill().unwrap();
match p.wait().unwrap().signal() {
Some(9) => {}
@@ -69,31 +76,31 @@ pub fn run_output(mut cmd: Command) -> String {
}
#[test]
-#[cfg_attr(any(target_os = "vxworks", target_os = "android"), ignore)]
+#[cfg_attr(any(target_os = "vxworks"), ignore)]
fn stdout_works() {
if cfg!(target_os = "windows") {
let mut cmd = Command::new("cmd");
cmd.args(&["/C", "echo foobar"]).stdout(Stdio::piped());
assert_eq!(run_output(cmd), "foobar\r\n");
} else {
- let mut cmd = Command::new("echo");
- cmd.arg("foobar").stdout(Stdio::piped());
+ let mut cmd = shell_cmd();
+ cmd.arg("-c").arg("echo foobar").stdout(Stdio::piped());
assert_eq!(run_output(cmd), "foobar\n");
}
}
#[test]
-#[cfg_attr(any(windows, target_os = "android", target_os = "vxworks"), ignore)]
+#[cfg_attr(any(windows, target_os = "vxworks"), ignore)]
fn set_current_dir_works() {
- let mut cmd = Command::new("/bin/sh");
+ let mut cmd = shell_cmd();
cmd.arg("-c").arg("pwd").current_dir("/").stdout(Stdio::piped());
assert_eq!(run_output(cmd), "/\n");
}
#[test]
-#[cfg_attr(any(windows, target_os = "android", target_os = "vxworks"), ignore)]
+#[cfg_attr(any(windows, target_os = "vxworks"), ignore)]
fn stdin_works() {
- let mut p = Command::new("/bin/sh")
+ let mut p = shell_cmd()
.arg("-c")
.arg("read line; echo $line")
.stdin(Stdio::piped())
@@ -109,19 +116,19 @@ fn stdin_works() {
}
#[test]
-#[cfg_attr(any(target_os = "vxworks", target_os = "android"), ignore)]
+#[cfg_attr(any(target_os = "vxworks"), ignore)]
fn test_process_status() {
let mut status = if cfg!(target_os = "windows") {
Command::new("cmd").args(&["/C", "exit 1"]).status().unwrap()
} else {
- Command::new("false").status().unwrap()
+ shell_cmd().arg("-c").arg("false").status().unwrap()
};
assert!(status.code() == Some(1));
status = if cfg!(target_os = "windows") {
Command::new("cmd").args(&["/C", "exit 0"]).status().unwrap()
} else {
- Command::new("true").status().unwrap()
+ shell_cmd().arg("-c").arg("true").status().unwrap()
};
assert!(status.success());
}
@@ -135,12 +142,12 @@ fn test_process_output_fail_to_start() {
}
#[test]
-#[cfg_attr(any(target_os = "vxworks", target_os = "android"), ignore)]
+#[cfg_attr(any(target_os = "vxworks"), ignore)]
fn test_process_output_output() {
let Output { status, stdout, stderr } = if cfg!(target_os = "windows") {
Command::new("cmd").args(&["/C", "echo hello"]).output().unwrap()
} else {
- Command::new("echo").arg("hello").output().unwrap()
+ shell_cmd().arg("-c").arg("echo hello").output().unwrap()
};
let output_str = str::from_utf8(&stdout).unwrap();
@@ -150,7 +157,7 @@ fn test_process_output_output() {
}
#[test]
-#[cfg_attr(any(target_os = "vxworks", target_os = "android"), ignore)]
+#[cfg_attr(any(target_os = "vxworks"), ignore)]
fn test_process_output_error() {
let Output { status, stdout, stderr } = if cfg!(target_os = "windows") {
Command::new("cmd").args(&["/C", "mkdir ."]).output().unwrap()
@@ -158,41 +165,42 @@ fn test_process_output_error() {
Command::new("mkdir").arg("./").output().unwrap()
};
- assert!(status.code() == Some(1));
+ assert!(status.code().is_some());
+ assert!(status.code() != Some(0));
assert_eq!(stdout, Vec::new());
assert!(!stderr.is_empty());
}
#[test]
-#[cfg_attr(any(target_os = "vxworks", target_os = "android"), ignore)]
+#[cfg_attr(any(target_os = "vxworks"), ignore)]
fn test_finish_once() {
let mut prog = if cfg!(target_os = "windows") {
Command::new("cmd").args(&["/C", "exit 1"]).spawn().unwrap()
} else {
- Command::new("false").spawn().unwrap()
+ shell_cmd().arg("-c").arg("false").spawn().unwrap()
};
assert!(prog.wait().unwrap().code() == Some(1));
}
#[test]
-#[cfg_attr(any(target_os = "vxworks", target_os = "android"), ignore)]
+#[cfg_attr(any(target_os = "vxworks"), ignore)]
fn test_finish_twice() {
let mut prog = if cfg!(target_os = "windows") {
Command::new("cmd").args(&["/C", "exit 1"]).spawn().unwrap()
} else {
- Command::new("false").spawn().unwrap()
+ shell_cmd().arg("-c").arg("false").spawn().unwrap()
};
assert!(prog.wait().unwrap().code() == Some(1));
assert!(prog.wait().unwrap().code() == Some(1));
}
#[test]
-#[cfg_attr(any(target_os = "vxworks", target_os = "android"), ignore)]
+#[cfg_attr(any(target_os = "vxworks"), ignore)]
fn test_wait_with_output_once() {
let prog = if cfg!(target_os = "windows") {
Command::new("cmd").args(&["/C", "echo hello"]).stdout(Stdio::piped()).spawn().unwrap()
} else {
- Command::new("echo").arg("hello").stdout(Stdio::piped()).spawn().unwrap()
+ shell_cmd().arg("-c").arg("echo hello").stdout(Stdio::piped()).spawn().unwrap()
};
let Output { status, stdout, stderr } = prog.wait_with_output().unwrap();
diff --git a/library/std/src/sys/hermit/fd.rs b/library/std/src/sys/hermit/fd.rs
index c400f5f2c2e..1179a49c22f 100644
--- a/library/std/src/sys/hermit/fd.rs
+++ b/library/std/src/sys/hermit/fd.rs
@@ -1,6 +1,6 @@
#![unstable(reason = "not public", issue = "none", feature = "fd")]
-use crate::io::{self, Read};
+use crate::io::{self, Read, ReadBuf};
use crate::mem;
use crate::sys::cvt;
use crate::sys::hermit::abi;
diff --git a/library/std/src/sys/hermit/fs.rs b/library/std/src/sys/hermit/fs.rs
index be019d4435d..974c44eb8dd 100644
--- a/library/std/src/sys/hermit/fs.rs
+++ b/library/std/src/sys/hermit/fs.rs
@@ -2,7 +2,7 @@ use crate::ffi::{CStr, CString, OsString};
use crate::fmt;
use crate::hash::{Hash, Hasher};
use crate::io::{self, Error, ErrorKind};
-use crate::io::{IoSlice, IoSliceMut, SeekFrom};
+use crate::io::{IoSlice, IoSliceMut, ReadBuf, SeekFrom};
use crate::os::unix::ffi::OsStrExt;
use crate::path::{Path, PathBuf};
use crate::sys::cvt;
@@ -312,6 +312,10 @@ impl File {
false
}
+ pub fn read_buf(&self, buf: &mut ReadBuf<'_>) -> io::Result<()> {
+ crate::io::default_read_buf(|buf| self.read(buf), buf)
+ }
+
pub fn write(&self, buf: &[u8]) -> io::Result<usize> {
self.0.write(buf)
}
diff --git a/library/std/src/sys/hermit/mutex.rs b/library/std/src/sys/hermit/mutex.rs
index 691e7e07902..415cbba101c 100644
--- a/library/std/src/sys/hermit/mutex.rs
+++ b/library/std/src/sys/hermit/mutex.rs
@@ -46,8 +46,17 @@ impl<T> Spinlock<T> {
#[inline]
fn obtain_lock(&self) {
let ticket = self.queue.fetch_add(1, Ordering::SeqCst) + 1;
+ let mut counter: u16 = 0;
while self.dequeue.load(Ordering::SeqCst) != ticket {
- hint::spin_loop();
+ counter += 1;
+ if counter < 100 {
+ hint::spin_loop();
+ } else {
+ counter = 0;
+ unsafe {
+ abi::yield_now();
+ }
+ }
}
}
diff --git a/library/std/src/sys/itron/thread.rs b/library/std/src/sys/itron/thread.rs
index bb9fa54d02e..ebcc9ab26e0 100644
--- a/library/std/src/sys/itron/thread.rs
+++ b/library/std/src/sys/itron/thread.rs
@@ -126,7 +126,7 @@ impl Thread {
// In this case, `inner`'s ownership has been moved to us,
// And we are responsible for dropping it. The acquire
// ordering is not necessary because the parent thread made
- // no memory acccess needing synchronization since the call
+ // no memory access needing synchronization since the call
// to `acre_tsk`.
// Safety: See above.
let _ = unsafe { Box::from_raw(inner as *const _ as *mut ThreadInner) };
@@ -264,7 +264,7 @@ impl Drop for Thread {
// one will ever join it.
// The ownership of `self.inner` is moved to the child thread.
// However, the release ordering is not necessary because we
- // made no memory acccess needing synchronization since the call
+ // made no memory access needing synchronization since the call
// to `acre_tsk`.
}
LIFECYCLE_FINISHED => {
diff --git a/library/std/src/sys/sgx/abi/mem.rs b/library/std/src/sys/sgx/abi/mem.rs
index 52e8bec937c..18e6d5b3fa2 100644
--- a/library/std/src/sys/sgx/abi/mem.rs
+++ b/library/std/src/sys/sgx/abi/mem.rs
@@ -1,3 +1,5 @@
+use core::arch::asm;
+
// Do not remove inline: will result in relocation failure
#[inline(always)]
pub(crate) unsafe fn rel_ptr<T>(offset: u64) -> *const T {
diff --git a/library/std/src/sys/sgx/abi/mod.rs b/library/std/src/sys/sgx/abi/mod.rs
index 231cc15b849..5df08a4ff59 100644
--- a/library/std/src/sys/sgx/abi/mod.rs
+++ b/library/std/src/sys/sgx/abi/mod.rs
@@ -1,6 +1,7 @@
#![cfg_attr(test, allow(unused))] // RT initialization logic is not compiled for test
use crate::io::Write;
+use core::arch::global_asm;
use core::sync::atomic::{AtomicUsize, Ordering};
// runtime features
diff --git a/library/std/src/sys/solid/abi/mod.rs b/library/std/src/sys/solid/abi/mod.rs
index 3205f0db85f..1afc83f766d 100644
--- a/library/std/src/sys/solid/abi/mod.rs
+++ b/library/std/src/sys/solid/abi/mod.rs
@@ -10,9 +10,9 @@ pub fn breakpoint_program_exited(tid: usize) {
match () {
// SOLID_BP_PROGRAM_EXITED = 15
#[cfg(target_arch = "arm")]
- () => asm!("bkpt #15", in("r0") tid),
+ () => core::arch::asm!("bkpt #15", in("r0") tid),
#[cfg(target_arch = "aarch64")]
- () => asm!("hlt #15", in("x0") tid),
+ () => core::arch::asm!("hlt #15", in("x0") tid),
}
}
}
@@ -23,9 +23,9 @@ pub fn breakpoint_abort() {
match () {
// SOLID_BP_CSABORT = 16
#[cfg(target_arch = "arm")]
- () => asm!("bkpt #16"),
+ () => core::arch::asm!("bkpt #16"),
#[cfg(target_arch = "aarch64")]
- () => asm!("hlt #16"),
+ () => core::arch::asm!("hlt #16"),
}
}
}
diff --git a/library/std/src/sys/unix/android.rs b/library/std/src/sys/unix/android.rs
index 6a46525f682..73ff10ab8a2 100644
--- a/library/std/src/sys/unix/android.rs
+++ b/library/std/src/sys/unix/android.rs
@@ -18,11 +18,9 @@
#![cfg(target_os = "android")]
-use libc::{c_int, c_void, sighandler_t, size_t, ssize_t};
-use libc::{ftruncate, pread, pwrite};
+use libc::{c_int, sighandler_t};
-use super::{cvt, cvt_r, weak::weak};
-use crate::io;
+use super::weak::weak;
// The `log2` and `log2f` functions apparently appeared in android-18, or at
// least you can see they're not present in the android-17 header [1] and they
@@ -81,87 +79,3 @@ pub unsafe fn signal(signum: c_int, handler: sighandler_t) -> sighandler_t {
let f = f.expect("neither `signal` nor `bsd_signal` symbols found");
f(signum, handler)
}
-
-// The `ftruncate64` symbol apparently appeared in android-12, so we do some
-// dynamic detection to see if we can figure out whether `ftruncate64` exists.
-//
-// If it doesn't we just fall back to `ftruncate`, generating an error for
-// too-large values.
-#[cfg(target_pointer_width = "32")]
-pub fn ftruncate64(fd: c_int, size: u64) -> io::Result<()> {
- weak!(fn ftruncate64(c_int, i64) -> c_int);
-
- unsafe {
- match ftruncate64.get() {
- Some(f) => cvt_r(|| f(fd, size as i64)).map(drop),
- None => {
- if size > i32::MAX as u64 {
- Err(io::Error::new_const(io::ErrorKind::InvalidInput, &"cannot truncate >2GB"))
- } else {
- cvt_r(|| ftruncate(fd, size as i32)).map(drop)
- }
- }
- }
- }
-}
-
-#[cfg(target_pointer_width = "64")]
-pub fn ftruncate64(fd: c_int, size: u64) -> io::Result<()> {
- unsafe { cvt_r(|| ftruncate(fd, size as i64)).map(drop) }
-}
-
-#[cfg(target_pointer_width = "32")]
-pub unsafe fn cvt_pread64(
- fd: c_int,
- buf: *mut c_void,
- count: size_t,
- offset: i64,
-) -> io::Result<ssize_t> {
- use crate::convert::TryInto;
- weak!(fn pread64(c_int, *mut c_void, size_t, i64) -> ssize_t);
- pread64.get().map(|f| cvt(f(fd, buf, count, offset))).unwrap_or_else(|| {
- if let Ok(o) = offset.try_into() {
- cvt(pread(fd, buf, count, o))
- } else {
- Err(io::Error::new_const(io::ErrorKind::InvalidInput, &"cannot pread >2GB"))
- }
- })
-}
-
-#[cfg(target_pointer_width = "32")]
-pub unsafe fn cvt_pwrite64(
- fd: c_int,
- buf: *const c_void,
- count: size_t,
- offset: i64,
-) -> io::Result<ssize_t> {
- use crate::convert::TryInto;
- weak!(fn pwrite64(c_int, *const c_void, size_t, i64) -> ssize_t);
- pwrite64.get().map(|f| cvt(f(fd, buf, count, offset))).unwrap_or_else(|| {
- if let Ok(o) = offset.try_into() {
- cvt(pwrite(fd, buf, count, o))
- } else {
- Err(io::Error::new_const(io::ErrorKind::InvalidInput, &"cannot pwrite >2GB"))
- }
- })
-}
-
-#[cfg(target_pointer_width = "64")]
-pub unsafe fn cvt_pread64(
- fd: c_int,
- buf: *mut c_void,
- count: size_t,
- offset: i64,
-) -> io::Result<ssize_t> {
- cvt(pread(fd, buf, count, offset))
-}
-
-#[cfg(target_pointer_width = "64")]
-pub unsafe fn cvt_pwrite64(
- fd: c_int,
- buf: *const c_void,
- count: size_t,
- offset: i64,
-) -> io::Result<ssize_t> {
- cvt(pwrite(fd, buf, count, offset))
-}
diff --git a/library/std/src/sys/unix/fd.rs b/library/std/src/sys/unix/fd.rs
index 0956726084e..2362bff913f 100644
--- a/library/std/src/sys/unix/fd.rs
+++ b/library/std/src/sys/unix/fd.rs
@@ -4,7 +4,7 @@
mod tests;
use crate::cmp;
-use crate::io::{self, Initializer, IoSlice, IoSliceMut, Read};
+use crate::io::{self, IoSlice, IoSliceMut, Read, ReadBuf};
use crate::os::unix::io::{AsFd, AsRawFd, BorrowedFd, FromRawFd, IntoRawFd, OwnedFd, RawFd};
use crate::sys::cvt;
use crate::sys_common::{AsInner, FromInner, IntoInner};
@@ -99,34 +99,39 @@ impl FileDesc {
}
pub fn read_at(&self, buf: &mut [u8], offset: u64) -> io::Result<usize> {
- #[cfg(target_os = "android")]
- use super::android::cvt_pread64;
-
- #[cfg(not(target_os = "android"))]
- unsafe fn cvt_pread64(
- fd: c_int,
- buf: *mut c_void,
- count: usize,
- offset: i64,
- ) -> io::Result<isize> {
- #[cfg(not(target_os = "linux"))]
- use libc::pread as pread64;
- #[cfg(target_os = "linux")]
- use libc::pread64;
- cvt(pread64(fd, buf, count, offset))
- }
+ #[cfg(not(any(target_os = "linux", target_os = "android")))]
+ use libc::pread as pread64;
+ #[cfg(any(target_os = "linux", target_os = "android"))]
+ use libc::pread64;
unsafe {
- cvt_pread64(
+ cvt(pread64(
self.as_raw_fd(),
buf.as_mut_ptr() as *mut c_void,
cmp::min(buf.len(), READ_LIMIT),
offset as i64,
- )
+ ))
.map(|n| n as usize)
}
}
+ pub fn read_buf(&self, buf: &mut ReadBuf<'_>) -> io::Result<()> {
+ let ret = cvt(unsafe {
+ libc::read(
+ self.as_raw_fd(),
+ buf.unfilled_mut().as_mut_ptr() as *mut c_void,
+ cmp::min(buf.remaining(), READ_LIMIT),
+ )
+ })?;
+
+ // Safety: `ret` bytes were written to the initialized portion of the buffer
+ unsafe {
+ buf.assume_init(ret as usize);
+ }
+ buf.add_filled(ret as usize);
+ Ok(())
+ }
+
pub fn write(&self, buf: &[u8]) -> io::Result<usize> {
let ret = cvt(unsafe {
libc::write(
@@ -161,30 +166,18 @@ impl FileDesc {
}
pub fn write_at(&self, buf: &[u8], offset: u64) -> io::Result<usize> {
- #[cfg(target_os = "android")]
- use super::android::cvt_pwrite64;
-
- #[cfg(not(target_os = "android"))]
- unsafe fn cvt_pwrite64(
- fd: c_int,
- buf: *const c_void,
- count: usize,
- offset: i64,
- ) -> io::Result<isize> {
- #[cfg(not(target_os = "linux"))]
- use libc::pwrite as pwrite64;
- #[cfg(target_os = "linux")]
- use libc::pwrite64;
- cvt(pwrite64(fd, buf, count, offset))
- }
+ #[cfg(not(any(target_os = "linux", target_os = "android")))]
+ use libc::pwrite as pwrite64;
+ #[cfg(any(target_os = "linux", target_os = "android"))]
+ use libc::pwrite64;
unsafe {
- cvt_pwrite64(
+ cvt(pwrite64(
self.as_raw_fd(),
buf.as_ptr() as *const c_void,
cmp::min(buf.len(), READ_LIMIT),
offset as i64,
- )
+ ))
.map(|n| n as usize)
}
}
@@ -289,11 +282,6 @@ impl<'a> Read for &'a FileDesc {
fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
(**self).read(buf)
}
-
- #[inline]
- unsafe fn initializer(&self) -> Initializer {
- Initializer::nop()
- }
}
impl AsInner<OwnedFd> for FileDesc {
diff --git a/library/std/src/sys/unix/fs.rs b/library/std/src/sys/unix/fs.rs
index a4fff9b2e64..bcf2be0e95f 100644
--- a/library/std/src/sys/unix/fs.rs
+++ b/library/std/src/sys/unix/fs.rs
@@ -2,7 +2,7 @@ use crate::os::unix::prelude::*;
use crate::ffi::{CStr, CString, OsStr, OsString};
use crate::fmt;
-use crate::io::{self, Error, IoSlice, IoSliceMut, SeekFrom};
+use crate::io::{self, Error, IoSlice, IoSliceMut, ReadBuf, SeekFrom};
use crate::mem;
use crate::os::unix::io::{AsFd, AsRawFd, BorrowedFd, FromRawFd, IntoRawFd};
use crate::path::{Path, PathBuf};
@@ -46,8 +46,8 @@ use libc::fstatat64;
use libc::readdir_r as readdir64_r;
#[cfg(target_os = "android")]
use libc::{
- dirent as dirent64, fstat as fstat64, fstatat as fstatat64, lseek64, lstat as lstat64,
- open as open64, stat as stat64,
+ dirent as dirent64, fstat as fstat64, fstatat as fstatat64, ftruncate64, lseek64,
+ lstat as lstat64, off64_t, open as open64, stat as stat64,
};
#[cfg(not(any(
target_os = "linux",
@@ -835,16 +835,10 @@ impl File {
}
pub fn truncate(&self, size: u64) -> io::Result<()> {
- #[cfg(target_os = "android")]
- return crate::sys::android::ftruncate64(self.as_raw_fd(), size);
-
- #[cfg(not(target_os = "android"))]
- {
- use crate::convert::TryInto;
- let size: off64_t =
- size.try_into().map_err(|e| io::Error::new(io::ErrorKind::InvalidInput, e))?;
- cvt_r(|| unsafe { ftruncate64(self.as_raw_fd(), size) }).map(drop)
- }
+ use crate::convert::TryInto;
+ let size: off64_t =
+ size.try_into().map_err(|e| io::Error::new(io::ErrorKind::InvalidInput, e))?;
+ cvt_r(|| unsafe { ftruncate64(self.as_raw_fd(), size) }).map(drop)
}
pub fn read(&self, buf: &mut [u8]) -> io::Result<usize> {
@@ -864,6 +858,10 @@ impl File {
self.0.read_at(buf, offset)
}
+ pub fn read_buf(&self, buf: &mut ReadBuf<'_>) -> io::Result<()> {
+ self.0.read_buf(buf)
+ }
+
pub fn write(&self, buf: &[u8]) -> io::Result<usize> {
self.0.write(buf)
}
@@ -1154,7 +1152,7 @@ pub fn link(original: &Path, link: &Path) -> io::Result<()> {
} else if #[cfg(target_os = "macos")] {
// On MacOS, older versions (<=10.9) lack support for linkat while newer
// versions have it. We want to use linkat if it is available, so we use weak!
- // to check. `linkat` is preferable to `link` ecause it gives us a flag to
+ // to check. `linkat` is preferable to `link` because it gives us a flag to
// specify how symlinks should be handled. We pass 0 as the flags argument,
// meaning it shouldn't follow symlinks.
weak!(fn linkat(c_int, *const c_char, c_int, *const c_char, c_int) -> c_int);
diff --git a/library/std/src/sys/unix/kernel_copy.rs b/library/std/src/sys/unix/kernel_copy.rs
index a6b43229ba6..e85e4c5d618 100644
--- a/library/std/src/sys/unix/kernel_copy.rs
+++ b/library/std/src/sys/unix/kernel_copy.rs
@@ -104,7 +104,7 @@ impl FdMeta {
fn potential_sendfile_source(&self) -> bool {
match self {
- // procfs erronously shows 0 length on non-empty readable files.
+ // procfs erroneously shows 0 length on non-empty readable files.
// and if a file is truly empty then a `read` syscall will determine that and skip the write syscall
// thus there would be benefit from attempting sendfile
FdMeta::Metadata(meta)
@@ -576,7 +576,7 @@ pub(super) fn copy_regular_files(reader: RawFd, writer: RawFd, max_len: u64) ->
return match err.raw_os_error() {
// when file offset + max_length > u64::MAX
Some(EOVERFLOW) => CopyResult::Fallback(written),
- Some(ENOSYS | EXDEV | EINVAL | EPERM | EOPNOTSUPP | EBADF) => {
+ Some(ENOSYS | EXDEV | EINVAL | EPERM | EOPNOTSUPP | EBADF) if written == 0 => {
// Try fallback io::copy if either:
// - Kernel version is < 4.5 (ENOSYS¹)
// - Files are mounted on different fs (EXDEV)
@@ -584,12 +584,14 @@ pub(super) fn copy_regular_files(reader: RawFd, writer: RawFd, max_len: u64) ->
// - copy_file_range file is immutable or syscall is blocked by seccomp¹ (EPERM)
// - copy_file_range cannot be used with pipes or device nodes (EINVAL)
// - the writer fd was opened with O_APPEND (EBADF²)
+ // and no bytes were written successfully yet. (All these errnos should
+ // not be returned if something was already written, but they happen in
+ // the wild, see #91152.)
//
// ¹ these cases should be detected by the initial probe but we handle them here
// anyway in case syscall interception changes during runtime
// ² actually invalid file descriptors would cause this too, but in that case
// the fallback code path is expected to encounter the same error again
- assert_eq!(written, 0);
CopyResult::Fallback(0)
}
_ => CopyResult::Error(err, written),
@@ -612,6 +614,9 @@ fn sendfile_splice(mode: SpliceMode, reader: RawFd, writer: RawFd, len: u64) ->
static HAS_SENDFILE: AtomicBool = AtomicBool::new(true);
static HAS_SPLICE: AtomicBool = AtomicBool::new(true);
+ // Android builds use feature level 14, but the libc wrapper for splice is
+ // gated on feature level 21+, so we have to invoke the syscall directly.
+ #[cfg(target_os = "android")]
syscall! {
fn splice(
srcfd: libc::c_int,
@@ -623,6 +628,9 @@ fn sendfile_splice(mode: SpliceMode, reader: RawFd, writer: RawFd, len: u64) ->
) -> libc::ssize_t
}
+ #[cfg(target_os = "linux")]
+ use libc::splice;
+
match mode {
SpliceMode::Sendfile if !HAS_SENDFILE.load(Ordering::Relaxed) => {
return CopyResult::Fallback(0);
diff --git a/library/std/src/sys/unix/net.rs b/library/std/src/sys/unix/net.rs
index 9ae6d12dcb9..a82a0172126 100644
--- a/library/std/src/sys/unix/net.rs
+++ b/library/std/src/sys/unix/net.rs
@@ -501,7 +501,7 @@ impl FromRawFd for Socket {
// res_init unconditionally, we call it only when we detect we're linking
// against glibc version < 2.26. (That is, when we both know its needed and
// believe it's thread-safe).
-#[cfg(all(target_env = "gnu", not(target_os = "vxworks")))]
+#[cfg(all(target_os = "linux", target_env = "gnu"))]
fn on_resolver_failure() {
use crate::sys;
@@ -513,5 +513,5 @@ fn on_resolver_failure() {
}
}
-#[cfg(any(not(target_env = "gnu"), target_os = "vxworks"))]
+#[cfg(not(all(target_os = "linux", target_env = "gnu")))]
fn on_resolver_failure() {}
diff --git a/library/std/src/sys/unix/os.rs b/library/std/src/sys/unix/os.rs
index 87893d26912..8a028d99306 100644
--- a/library/std/src/sys/unix/os.rs
+++ b/library/std/src/sys/unix/os.rs
@@ -2,7 +2,7 @@
#![allow(unused_imports)] // lots of cfg code here
-#[cfg(all(test, target_env = "gnu"))]
+#[cfg(test)]
mod tests;
use crate::os::unix::prelude::*;
@@ -97,6 +97,7 @@ pub fn errno() -> i32 {
}
#[cfg(target_os = "dragonfly")]
+#[allow(dead_code)]
pub fn set_errno(e: i32) {
extern "C" {
#[thread_local]
@@ -472,10 +473,7 @@ impl Iterator for Env {
#[cfg(target_os = "macos")]
pub unsafe fn environ() -> *mut *const *const c_char {
- extern "C" {
- fn _NSGetEnviron() -> *mut *const *const c_char;
- }
- _NSGetEnviron()
+ libc::_NSGetEnviron() as *mut *const *const c_char
}
#[cfg(not(target_os = "macos"))]
@@ -636,22 +634,14 @@ pub fn getppid() -> u32 {
unsafe { libc::getppid() as u32 }
}
-#[cfg(all(target_env = "gnu", not(target_os = "vxworks")))]
+#[cfg(all(target_os = "linux", target_env = "gnu"))]
pub fn glibc_version() -> Option<(usize, usize)> {
- if let Some(Ok(version_str)) = glibc_version_cstr().map(CStr::to_str) {
- parse_glibc_version(version_str)
- } else {
- None
- }
-}
-
-#[cfg(all(target_env = "gnu", not(target_os = "vxworks")))]
-fn glibc_version_cstr() -> Option<&'static CStr> {
- weak! {
- fn gnu_get_libc_version() -> *const libc::c_char
+ extern "C" {
+ fn gnu_get_libc_version() -> *const libc::c_char;
}
- if let Some(f) = gnu_get_libc_version.get() {
- unsafe { Some(CStr::from_ptr(f())) }
+ let version_cstr = unsafe { CStr::from_ptr(gnu_get_libc_version()) };
+ if let Ok(version_str) = version_cstr.to_str() {
+ parse_glibc_version(version_str)
} else {
None
}
@@ -659,7 +649,7 @@ fn glibc_version_cstr() -> Option<&'static CStr> {
// Returns Some((major, minor)) if the string is a valid "x.y" version,
// ignoring any extra dot-separated parts. Otherwise return None.
-#[cfg(all(target_env = "gnu", not(target_os = "vxworks")))]
+#[cfg(all(target_os = "linux", target_env = "gnu"))]
fn parse_glibc_version(version: &str) -> Option<(usize, usize)> {
let mut parsed_ints = version.split('.').map(str::parse::<usize>).fuse();
match (parsed_ints.next(), parsed_ints.next()) {
diff --git a/library/std/src/sys/unix/os/tests.rs b/library/std/src/sys/unix/os/tests.rs
index c445acf2722..efc29955b05 100644
--- a/library/std/src/sys/unix/os/tests.rs
+++ b/library/std/src/sys/unix/os/tests.rs
@@ -1,14 +1,12 @@
-use super::*;
-
#[test]
-#[cfg(not(target_os = "vxworks"))]
+#[cfg(all(target_os = "linux", target_env = "gnu"))]
fn test_glibc_version() {
// This mostly just tests that the weak linkage doesn't panic wildly...
- glibc_version();
+ super::glibc_version();
}
#[test]
-#[cfg(not(target_os = "vxworks"))]
+#[cfg(all(target_os = "linux", target_env = "gnu"))]
fn test_parse_glibc_version() {
let cases = [
("0.0", Some((0, 0))),
@@ -20,6 +18,6 @@ fn test_parse_glibc_version() {
("foo.1", None),
];
for &(version_str, parsed) in cases.iter() {
- assert_eq!(parsed, parse_glibc_version(version_str));
+ assert_eq!(parsed, super::parse_glibc_version(version_str));
}
}
diff --git a/library/std/src/sys/unix/process/process_fuchsia.rs b/library/std/src/sys/unix/process/process_fuchsia.rs
index 507abb27871..ce77c210a62 100644
--- a/library/std/src/sys/unix/process/process_fuchsia.rs
+++ b/library/std/src/sys/unix/process/process_fuchsia.rs
@@ -284,7 +284,7 @@ impl ExitStatus {
//
// The other view would be to say that the caller on Fuchsia ought to know that `into_raw`
// will give a raw Fuchsia status (whatever that is - I don't know, personally). That is
- // not possible here becaause we must return a c_int because that's what Unix (including
+ // not possible here because we must return a c_int because that's what Unix (including
// SuS and POSIX) say a wait status is, but Fuchsia apparently uses a u64, so it won't
// necessarily fit.
//
diff --git a/library/std/src/sys/unix/process/process_unix.rs b/library/std/src/sys/unix/process/process_unix.rs
index 3bf1493f3b8..bce35b380e6 100644
--- a/library/std/src/sys/unix/process/process_unix.rs
+++ b/library/std/src/sys/unix/process/process_unix.rs
@@ -13,7 +13,7 @@ use crate::sys::process::process_common::*;
use crate::os::linux::process::PidFd;
#[cfg(target_os = "linux")]
-use crate::sys::weak::syscall;
+use crate::sys::weak::raw_syscall;
#[cfg(any(
target_os = "macos",
@@ -162,7 +162,7 @@ impl Command {
cgroup: u64,
}
- syscall! {
+ raw_syscall! {
fn clone3(cl_args: *mut clone_args, len: libc::size_t) -> libc::c_long
}
diff --git a/library/std/src/sys/unix/thread.rs b/library/std/src/sys/unix/thread.rs
index b99eb2e553f..9e02966b57c 100644
--- a/library/std/src/sys/unix/thread.rs
+++ b/library/std/src/sys/unix/thread.rs
@@ -7,7 +7,9 @@ use crate::ptr;
use crate::sys::{os, stack_overflow};
use crate::time::Duration;
-#[cfg(any(target_os = "linux", target_os = "solaris", target_os = "illumos"))]
+#[cfg(all(target_os = "linux", target_env = "gnu"))]
+use crate::sys::weak::dlsym;
+#[cfg(any(target_os = "solaris", target_os = "illumos"))]
use crate::sys::weak::weak;
#[cfg(not(any(target_os = "l4re", target_os = "vxworks", target_os = "espidf")))]
pub const DEFAULT_MIN_STACK_SIZE: usize = 2 * 1024 * 1024;
@@ -627,10 +629,12 @@ pub mod guard {
// We need that information to avoid blowing up when a small stack
// is created in an application with big thread-local storage requirements.
// See #6233 for rationale and details.
-#[cfg(target_os = "linux")]
-#[allow(deprecated)]
+#[cfg(all(target_os = "linux", target_env = "gnu"))]
fn min_stack_size(attr: *const libc::pthread_attr_t) -> usize {
- weak!(fn __pthread_get_minstack(*const libc::pthread_attr_t) -> libc::size_t);
+ // We use dlsym to avoid an ELF version dependency on GLIBC_PRIVATE. (#23628)
+ // We shouldn't really be using such an internal symbol, but there's currently
+ // no other way to account for the TLS size.
+ dlsym!(fn __pthread_get_minstack(*const libc::pthread_attr_t) -> libc::size_t);
match __pthread_get_minstack.get() {
None => libc::PTHREAD_STACK_MIN,
@@ -638,9 +642,8 @@ fn min_stack_size(attr: *const libc::pthread_attr_t) -> usize {
}
}
-// No point in looking up __pthread_get_minstack() on non-glibc
-// platforms.
-#[cfg(all(not(target_os = "linux"), not(target_os = "netbsd")))]
+// No point in looking up __pthread_get_minstack() on non-glibc platforms.
+#[cfg(all(not(all(target_os = "linux", target_env = "gnu")), not(target_os = "netbsd")))]
fn min_stack_size(_: *const libc::pthread_attr_t) -> usize {
libc::PTHREAD_STACK_MIN
}
diff --git a/library/std/src/sys/unix/weak.rs b/library/std/src/sys/unix/weak.rs
index ba432ec5494..55719b87c7e 100644
--- a/library/std/src/sys/unix/weak.rs
+++ b/library/std/src/sys/unix/weak.rs
@@ -6,7 +6,7 @@
//! detection.
//!
//! One option to use here is weak linkage, but that is unfortunately only
-//! really workable on Linux. Hence, use dlsym to get the symbol value at
+//! really workable with ELF. Otherwise, use dlsym to get the symbol value at
//! runtime. This is also done for compatibility with older versions of glibc,
//! and to avoid creating dependencies on GLIBC_PRIVATE symbols. It assumes that
//! we've been dynamically linked to the library the symbol comes from, but that
@@ -14,7 +14,8 @@
//!
//! A long time ago this used weak linkage for the __pthread_get_minstack
//! symbol, but that caused Debian to detect an unnecessarily strict versioned
-//! dependency on libc6 (#23628).
+//! dependency on libc6 (#23628) because it is GLIBC_PRIVATE. We now use `dlsym`
+//! for a runtime lookup of that symbol to avoid the ELF versioned dependency.
// There are a variety of `#[cfg]`s controlling which targets are involved in
// each instance of `weak!` and `syscall!`. Rather than trying to unify all of
@@ -22,31 +23,75 @@
#![allow(dead_code, unused_macros)]
use crate::ffi::CStr;
-use crate::marker;
+use crate::marker::PhantomData;
use crate::mem;
use crate::sync::atomic::{self, AtomicUsize, Ordering};
+// We can use true weak linkage on ELF targets.
+#[cfg(not(any(target_os = "macos", target_os = "ios")))]
pub(crate) macro weak {
(fn $name:ident($($t:ty),*) -> $ret:ty) => (
- #[allow(non_upper_case_globals)]
- static $name: crate::sys::weak::Weak<unsafe extern "C" fn($($t),*) -> $ret> =
- crate::sys::weak::Weak::new(concat!(stringify!($name), '\0'));
+ let ref $name: ExternWeak<unsafe extern "C" fn($($t),*) -> $ret> = {
+ extern "C" {
+ #[linkage = "extern_weak"]
+ static $name: *const libc::c_void;
+ }
+ #[allow(unused_unsafe)]
+ ExternWeak::new(unsafe { $name })
+ };
)
}
-pub struct Weak<F> {
+// On non-ELF targets, use the dlsym approximation of weak linkage.
+#[cfg(any(target_os = "macos", target_os = "ios"))]
+pub(crate) use self::dlsym as weak;
+
+pub(crate) struct ExternWeak<F> {
+ weak_ptr: *const libc::c_void,
+ _marker: PhantomData<F>,
+}
+
+impl<F> ExternWeak<F> {
+ #[inline]
+ pub(crate) fn new(weak_ptr: *const libc::c_void) -> Self {
+ ExternWeak { weak_ptr, _marker: PhantomData }
+ }
+}
+
+impl<F> ExternWeak<F> {
+ #[inline]
+ pub(crate) fn get(&self) -> Option<F> {
+ unsafe {
+ if self.weak_ptr.is_null() {
+ None
+ } else {
+ Some(mem::transmute_copy::<*const libc::c_void, F>(&self.weak_ptr))
+ }
+ }
+ }
+}
+
+pub(crate) macro dlsym {
+ (fn $name:ident($($t:ty),*) -> $ret:ty) => (
+ static DLSYM: DlsymWeak<unsafe extern "C" fn($($t),*) -> $ret> =
+ DlsymWeak::new(concat!(stringify!($name), '\0'));
+ let $name = &DLSYM;
+ )
+}
+
+pub(crate) struct DlsymWeak<F> {
name: &'static str,
addr: AtomicUsize,
- _marker: marker::PhantomData<F>,
+ _marker: PhantomData<F>,
}
-impl<F> Weak<F> {
- pub const fn new(name: &'static str) -> Weak<F> {
- Weak { name, addr: AtomicUsize::new(1), _marker: marker::PhantomData }
+impl<F> DlsymWeak<F> {
+ pub(crate) const fn new(name: &'static str) -> Self {
+ DlsymWeak { name, addr: AtomicUsize::new(1), _marker: PhantomData }
}
- pub fn get(&self) -> Option<F> {
- assert_eq!(mem::size_of::<F>(), mem::size_of::<usize>());
+ #[inline]
+ pub(crate) fn get(&self) -> Option<F> {
unsafe {
// Relaxed is fine here because we fence before reading through the
// pointer (see the comment below).
@@ -79,9 +124,11 @@ impl<F> Weak<F> {
}
}
- // Cold because it should only happen during first-time initalization.
+ // Cold because it should only happen during first-time initialization.
#[cold]
unsafe fn initialize(&self) -> Option<F> {
+ assert_eq!(mem::size_of::<F>(), mem::size_of::<usize>());
+
let val = fetch(self.name);
// This synchronizes with the acquire fence in `get`.
self.addr.store(val, Ordering::Release);
@@ -105,14 +152,12 @@ unsafe fn fetch(name: &str) -> usize {
pub(crate) macro syscall {
(fn $name:ident($($arg_name:ident: $t:ty),*) -> $ret:ty) => (
unsafe fn $name($($arg_name: $t),*) -> $ret {
- use super::os;
-
weak! { fn $name($($t),*) -> $ret }
if let Some(fun) = $name.get() {
fun($($arg_name),*)
} else {
- os::set_errno(libc::ENOSYS);
+ super::os::set_errno(libc::ENOSYS);
-1
}
}
@@ -123,11 +168,6 @@ pub(crate) macro syscall {
pub(crate) macro syscall {
(fn $name:ident($($arg_name:ident: $t:ty),*) -> $ret:ty) => (
unsafe fn $name($($arg_name:$t),*) -> $ret {
- use weak;
- // This looks like a hack, but concat_idents only accepts idents
- // (not paths).
- use libc::*;
-
weak! { fn $name($($t),*) -> $ret }
// Use a weak symbol from libc when possible, allowing `LD_PRELOAD`
@@ -135,6 +175,10 @@ pub(crate) macro syscall {
if let Some(fun) = $name.get() {
fun($($arg_name),*)
} else {
+ // This looks like a hack, but concat_idents only accepts idents
+ // (not paths).
+ use libc::*;
+
syscall(
concat_idents!(SYS_, $name),
$($arg_name),*
@@ -143,3 +187,19 @@ pub(crate) macro syscall {
}
)
}
+
+#[cfg(any(target_os = "linux", target_os = "android"))]
+pub(crate) macro raw_syscall {
+ (fn $name:ident($($arg_name:ident: $t:ty),*) -> $ret:ty) => (
+ unsafe fn $name($($arg_name:$t),*) -> $ret {
+ // This looks like a hack, but concat_idents only accepts idents
+ // (not paths).
+ use libc::*;
+
+ syscall(
+ concat_idents!(SYS_, $name),
+ $($arg_name),*
+ ) as $ret
+ }
+ )
+}
diff --git a/library/std/src/sys/unsupported/fs.rs b/library/std/src/sys/unsupported/fs.rs
index 6b45e29c145..d1d2847cd33 100644
--- a/library/std/src/sys/unsupported/fs.rs
+++ b/library/std/src/sys/unsupported/fs.rs
@@ -1,7 +1,7 @@
use crate::ffi::OsString;
use crate::fmt;
use crate::hash::{Hash, Hasher};
-use crate::io::{self, IoSlice, IoSliceMut, SeekFrom};
+use crate::io::{self, IoSlice, IoSliceMut, ReadBuf, SeekFrom};
use crate::path::{Path, PathBuf};
use crate::sys::time::SystemTime;
use crate::sys::unsupported;
@@ -206,6 +206,10 @@ impl File {
self.0
}
+ pub fn read_buf(&self, _buf: &mut ReadBuf<'_>) -> io::Result<()> {
+ self.0
+ }
+
pub fn write(&self, _buf: &[u8]) -> io::Result<usize> {
self.0
}
diff --git a/library/std/src/sys/wasi/fs.rs b/library/std/src/sys/wasi/fs.rs
index 984dda8dc0b..1a3da3746ac 100644
--- a/library/std/src/sys/wasi/fs.rs
+++ b/library/std/src/sys/wasi/fs.rs
@@ -3,7 +3,7 @@
use super::fd::WasiFd;
use crate::ffi::{CStr, CString, OsStr, OsString};
use crate::fmt;
-use crate::io::{self, IoSlice, IoSliceMut, SeekFrom};
+use crate::io::{self, IoSlice, IoSliceMut, ReadBuf, SeekFrom};
use crate::iter;
use crate::mem::{self, ManuallyDrop};
use crate::os::raw::c_int;
@@ -411,6 +411,10 @@ impl File {
true
}
+ pub fn read_buf(&self, buf: &mut ReadBuf<'_>) -> io::Result<()> {
+ crate::io::default_read_buf(|buf| self.read(buf), buf)
+ }
+
pub fn write(&self, buf: &[u8]) -> io::Result<usize> {
self.write_vectored(&[IoSlice::new(buf)])
}
diff --git a/library/std/src/sys/wasm/alloc.rs b/library/std/src/sys/wasm/alloc.rs
index 3223e894102..6dceb1689a8 100644
--- a/library/std/src/sys/wasm/alloc.rs
+++ b/library/std/src/sys/wasm/alloc.rs
@@ -24,7 +24,7 @@ static mut DLMALLOC: dlmalloc::Dlmalloc = dlmalloc::Dlmalloc::new();
unsafe impl GlobalAlloc for System {
#[inline]
unsafe fn alloc(&self, layout: Layout) -> *mut u8 {
- // SAFETY: DLMALLOC access is guranteed to be safe because the lock gives us unique and non-reentrant access.
+ // SAFETY: DLMALLOC access is guaranteed to be safe because the lock gives us unique and non-reentrant access.
// Calling malloc() is safe because preconditions on this function match the trait method preconditions.
let _lock = lock::lock();
unsafe { DLMALLOC.malloc(layout.size(), layout.align()) }
@@ -32,7 +32,7 @@ unsafe impl GlobalAlloc for System {
#[inline]
unsafe fn alloc_zeroed(&self, layout: Layout) -> *mut u8 {
- // SAFETY: DLMALLOC access is guranteed to be safe because the lock gives us unique and non-reentrant access.
+ // SAFETY: DLMALLOC access is guaranteed to be safe because the lock gives us unique and non-reentrant access.
// Calling calloc() is safe because preconditions on this function match the trait method preconditions.
let _lock = lock::lock();
unsafe { DLMALLOC.calloc(layout.size(), layout.align()) }
@@ -40,7 +40,7 @@ unsafe impl GlobalAlloc for System {
#[inline]
unsafe fn dealloc(&self, ptr: *mut u8, layout: Layout) {
- // SAFETY: DLMALLOC access is guranteed to be safe because the lock gives us unique and non-reentrant access.
+ // SAFETY: DLMALLOC access is guaranteed to be safe because the lock gives us unique and non-reentrant access.
// Calling free() is safe because preconditions on this function match the trait method preconditions.
let _lock = lock::lock();
unsafe { DLMALLOC.free(ptr, layout.size(), layout.align()) }
@@ -48,7 +48,7 @@ unsafe impl GlobalAlloc for System {
#[inline]
unsafe fn realloc(&self, ptr: *mut u8, layout: Layout, new_size: usize) -> *mut u8 {
- // SAFETY: DLMALLOC access is guranteed to be safe because the lock gives us unique and non-reentrant access.
+ // SAFETY: DLMALLOC access is guaranteed to be safe because the lock gives us unique and non-reentrant access.
// Calling realloc() is safe because preconditions on this function match the trait method preconditions.
let _lock = lock::lock();
unsafe { DLMALLOC.realloc(ptr, layout.size(), layout.align(), new_size) }
diff --git a/library/std/src/sys/wasm/atomics/mutex.rs b/library/std/src/sys/wasm/atomics/mutex.rs
index 5ff0ec052b6..3a09f0bf9bb 100644
--- a/library/std/src/sys/wasm/atomics/mutex.rs
+++ b/library/std/src/sys/wasm/atomics/mutex.rs
@@ -73,7 +73,7 @@ pub struct ReentrantMutex {
unsafe impl Send for ReentrantMutex {}
unsafe impl Sync for ReentrantMutex {}
-// Reentrant mutexes are similarly implemented to mutexs above except that
+// Reentrant mutexes are similarly implemented to mutexes above except that
// instead of "1" meaning unlocked we use the id of a thread to represent
// whether it has locked a mutex. That way we have an atomic counter which
// always holds the id of the thread that currently holds the lock (or 0 if the
@@ -96,7 +96,7 @@ impl ReentrantMutex {
pub unsafe fn lock(&self) {
let me = thread::my_id();
while let Err(owner) = self._try_lock(me) {
- // SAFETY: the caller must gurantee that `self.ptr()` and `owner` are valid i32.
+ // SAFETY: the caller must guarantee that `self.ptr()` and `owner` are valid i32.
let val = unsafe { wasm32::memory_atomic_wait32(self.ptr(), owner as i32, -1) };
debug_assert!(val == 0 || val == 1);
}
@@ -136,7 +136,7 @@ impl ReentrantMutex {
match *self.recursions.get() {
0 => {
self.owner.swap(0, SeqCst);
- // SAFETY: the caller must gurantee that `self.ptr()` is valid i32.
+ // SAFETY: the caller must guarantee that `self.ptr()` is valid i32.
unsafe {
wasm32::memory_atomic_notify(self.ptr() as *mut i32, 1);
} // wake up one waiter, if any
diff --git a/library/std/src/sys/windows/c.rs b/library/std/src/sys/windows/c.rs
index 50c4547de85..b87b6b5d88e 100644
--- a/library/std/src/sys/windows/c.rs
+++ b/library/std/src/sys/windows/c.rs
@@ -1110,6 +1110,12 @@ compat_fn! {
-> () {
GetSystemTimeAsFileTime(lpSystemTimeAsFileTime)
}
+
+ // >= Win11 / Server 2022
+ // https://docs.microsoft.com/en-us/windows/win32/api/fileapi/nf-fileapi-gettemppath2a
+ pub fn GetTempPath2W(nBufferLength: DWORD, lpBuffer: LPCWSTR) -> DWORD {
+ GetTempPathW(nBufferLength, lpBuffer)
+ }
}
compat_fn! {
diff --git a/library/std/src/sys/windows/fs.rs b/library/std/src/sys/windows/fs.rs
index 9859000c8d4..b258fc0478b 100644
--- a/library/std/src/sys/windows/fs.rs
+++ b/library/std/src/sys/windows/fs.rs
@@ -2,7 +2,7 @@ use crate::os::windows::prelude::*;
use crate::ffi::OsString;
use crate::fmt;
-use crate::io::{self, Error, IoSlice, IoSliceMut, SeekFrom};
+use crate::io::{self, Error, IoSlice, IoSliceMut, ReadBuf, SeekFrom};
use crate::mem;
use crate::os::windows::io::{AsHandle, BorrowedHandle};
use crate::path::{Path, PathBuf};
@@ -420,6 +420,10 @@ impl File {
self.handle.read_at(buf, offset)
}
+ pub fn read_buf(&self, buf: &mut ReadBuf<'_>) -> io::Result<()> {
+ self.handle.read_buf(buf)
+ }
+
pub fn write(&self, buf: &[u8]) -> io::Result<usize> {
self.handle.write(buf)
}
diff --git a/library/std/src/sys/windows/handle.rs b/library/std/src/sys/windows/handle.rs
index 21d86b00226..c3a3482f910 100644
--- a/library/std/src/sys/windows/handle.rs
+++ b/library/std/src/sys/windows/handle.rs
@@ -1,7 +1,7 @@
#![unstable(issue = "none", feature = "windows_handle")]
use crate::cmp;
-use crate::io::{self, ErrorKind, IoSlice, IoSliceMut, Read};
+use crate::io::{self, ErrorKind, IoSlice, IoSliceMut, Read, ReadBuf};
use crate::mem;
use crate::os::windows::io::{
AsHandle, AsRawHandle, BorrowedHandle, FromRawHandle, IntoRawHandle, OwnedHandle, RawHandle,
@@ -130,6 +130,39 @@ impl Handle {
}
}
+ pub fn read_buf(&self, buf: &mut ReadBuf<'_>) -> io::Result<()> {
+ let mut read = 0;
+ let len = cmp::min(buf.remaining(), <c::DWORD>::MAX as usize) as c::DWORD;
+ let res = cvt(unsafe {
+ c::ReadFile(
+ self.as_raw_handle(),
+ buf.unfilled_mut().as_mut_ptr() as c::LPVOID,
+ len,
+ &mut read,
+ ptr::null_mut(),
+ )
+ });
+
+ match res {
+ Ok(_) => {
+ // Safety: `read` bytes were written to the initialized portion of the buffer
+ unsafe {
+ buf.assume_init(read as usize);
+ }
+ buf.add_filled(read as usize);
+ Ok(())
+ }
+
+ // The special treatment of BrokenPipe is to deal with Windows
+ // pipe semantics, which yields this error when *reading* from
+ // a pipe after the other end has closed; we interpret that as
+ // EOF on the pipe.
+ Err(ref e) if e.kind() == ErrorKind::BrokenPipe => Ok(()),
+
+ Err(e) => Err(e),
+ }
+ }
+
pub unsafe fn read_overlapped(
&self,
buf: &mut [u8],
diff --git a/library/std/src/sys/windows/mod.rs b/library/std/src/sys/windows/mod.rs
index 28fec817f86..084af4325e7 100644
--- a/library/std/src/sys/windows/mod.rs
+++ b/library/std/src/sys/windows/mod.rs
@@ -288,13 +288,13 @@ pub fn abort_internal() -> ! {
unsafe {
cfg_if::cfg_if! {
if #[cfg(any(target_arch = "x86", target_arch = "x86_64"))] {
- asm!("int $$0x29", in("ecx") FAST_FAIL_FATAL_APP_EXIT);
+ core::arch::asm!("int $$0x29", in("ecx") FAST_FAIL_FATAL_APP_EXIT);
crate::intrinsics::unreachable();
} else if #[cfg(all(target_arch = "arm", target_feature = "thumb-mode"))] {
- asm!(".inst 0xDEFB", in("r0") FAST_FAIL_FATAL_APP_EXIT);
+ core::arch::asm!(".inst 0xDEFB", in("r0") FAST_FAIL_FATAL_APP_EXIT);
crate::intrinsics::unreachable();
} else if #[cfg(target_arch = "aarch64")] {
- asm!("brk 0xF003", in("x0") FAST_FAIL_FATAL_APP_EXIT);
+ core::arch::asm!("brk 0xF003", in("x0") FAST_FAIL_FATAL_APP_EXIT);
crate::intrinsics::unreachable();
}
}
diff --git a/library/std/src/sys/windows/os.rs b/library/std/src/sys/windows/os.rs
index b5209aa690b..5f8556c3bc3 100644
--- a/library/std/src/sys/windows/os.rs
+++ b/library/std/src/sys/windows/os.rs
@@ -275,7 +275,7 @@ pub fn unsetenv(n: &OsStr) -> io::Result<()> {
}
pub fn temp_dir() -> PathBuf {
- super::fill_utf16_buf(|buf, sz| unsafe { c::GetTempPathW(sz, buf) }, super::os2path).unwrap()
+ super::fill_utf16_buf(|buf, sz| unsafe { c::GetTempPath2W(sz, buf) }, super::os2path).unwrap()
}
#[cfg(not(target_vendor = "uwp"))]
diff --git a/library/std/src/sys/windows/stdio.rs b/library/std/src/sys/windows/stdio.rs
index a4fe5f67f69..eb0925b3fda 100644
--- a/library/std/src/sys/windows/stdio.rs
+++ b/library/std/src/sys/windows/stdio.rs
@@ -124,7 +124,7 @@ fn write(
//
// If the data is not valid UTF-8 we write out as many bytes as are valid.
// If the first byte is invalid it is either first byte of a multi-byte sequence but the
- // provided byte slice is too short or it is the first byte of an invalide multi-byte sequence.
+ // provided byte slice is too short or it is the first byte of an invalid multi-byte sequence.
let len = cmp::min(data.len(), MAX_BUFFER_SIZE / 2);
let utf8 = match str::from_utf8(&data[..len]) {
Ok(s) => s,
diff --git a/library/std/src/sys/windows/thread_parker.rs b/library/std/src/sys/windows/thread_parker.rs
index 4f59d4dd452..5a8011a9588 100644
--- a/library/std/src/sys/windows/thread_parker.rs
+++ b/library/std/src/sys/windows/thread_parker.rs
@@ -22,7 +22,7 @@
//
// Unlike WaitOnAddress, NtWaitForKeyedEvent/NtReleaseKeyedEvent operate on a
// HANDLE (created with NtCreateKeyedEvent). This means that we can be sure
-// a succesfully awoken park() was awoken by unpark() and not a
+// a successfully awoken park() was awoken by unpark() and not a
// NtReleaseKeyedEvent call from some other code, as these events are not only
// matched by the key (address of the parker (state)), but also by this HANDLE.
// We lazily allocate this handle the first time it is needed.
diff --git a/library/std/src/sys_common/thread_parker/generic.rs b/library/std/src/sys_common/thread_parker/generic.rs
index 14cfa958e5e..d99e901bb5f 100644
--- a/library/std/src/sys_common/thread_parker/generic.rs
+++ b/library/std/src/sys_common/thread_parker/generic.rs
@@ -1,4 +1,4 @@
-//! Parker implementaiton based on a Mutex and Condvar.
+//! Parker implementation based on a Mutex and Condvar.
use crate::sync::atomic::AtomicUsize;
use crate::sync::atomic::Ordering::SeqCst;
@@ -20,7 +20,7 @@ impl Parker {
Parker { state: AtomicUsize::new(EMPTY), lock: Mutex::new(()), cvar: Condvar::new() }
}
- // This implementaiton doesn't require `unsafe`, but other implementations
+ // This implementation doesn't require `unsafe`, but other implementations
// may assume this is only called by the thread that owns the Parker.
pub unsafe fn park(&self) {
// If we were previously notified then we consume this notification and
@@ -55,7 +55,7 @@ impl Parker {
}
}
- // This implementaiton doesn't require `unsafe`, but other implementations
+ // This implementation doesn't require `unsafe`, but other implementations
// may assume this is only called by the thread that owns the Parker.
pub unsafe fn park_timeout(&self, dur: Duration) {
// Like `park` above we have a fast path for an already-notified thread, and
diff --git a/library/std/src/thread/local.rs b/library/std/src/thread/local.rs
index 4da59577d78..1d2f6e97680 100644
--- a/library/std/src/thread/local.rs
+++ b/library/std/src/thread/local.rs
@@ -76,7 +76,21 @@ use crate::fmt;
/// destroyed, but not all platforms have this guard. Those platforms that do
/// not guard typically have a synthetic limit after which point no more
/// destructors are run.
+/// 3. When the process exits on Windows systems, TLS destructors may only be
+/// run on the thread that causes the process to exit. This is because the
+/// other threads may be forcibly terminated.
///
+/// ## Synchronization in thread-local destructors
+///
+/// On Windows, synchronization operations (such as [`JoinHandle::join`]) in
+/// thread local destructors are prone to deadlocks and so should be avoided.
+/// This is because the [loader lock] is held while a destructor is run. The
+/// lock is acquired whenever a thread starts or exits or when a DLL is loaded
+/// or unloaded. Therefore these events are blocked for as long as a thread
+/// local destructor is running.
+///
+/// [loader lock]: https://docs.microsoft.com/en-us/windows/win32/dlls/dynamic-link-library-best-practices
+/// [`JoinHandle::join`]: crate::thread::JoinHandle::join
/// [`with`]: LocalKey::with
#[stable(feature = "rust1", since = "1.0.0")]
pub struct LocalKey<T: 'static> {
@@ -164,7 +178,6 @@ macro_rules! __thread_local_inner {
(@key $t:ty, const $init:expr) => {{
#[cfg_attr(not(windows), inline)] // see comments below
unsafe fn __getit() -> $crate::option::Option<&'static $t> {
- const _REQUIRE_UNSTABLE: () = $crate::thread::require_unstable_const_init_thread_local();
const INIT_EXPR: $t = $init;
// wasm without atomics maps directly to `static mut`, and dtors
@@ -569,7 +582,7 @@ pub mod fast {
Key { inner: LazyKeyInner::new(), dtor_state: Cell::new(DtorState::Unregistered) }
}
- // note that this is just a publically-callable function only for the
+ // note that this is just a publicly-callable function only for the
// const-initialized form of thread locals, basically a way to call the
// free `register_dtor` function defined elsewhere in libstd.
pub unsafe fn register_dtor(a: *mut u8, dtor: unsafe extern "C" fn(*mut u8)) {
@@ -580,7 +593,7 @@ pub mod fast {
pub unsafe fn get<F: FnOnce() -> T>(&self, init: F) -> Option<&'static T> {
// SAFETY: See the definitions of `LazyKeyInner::get` and
- // `try_initialize` for more informations.
+ // `try_initialize` for more information.
//
// The caller must ensure no mutable references are ever active to
// the inner cell or the inner T when this is called.
diff --git a/library/std/src/thread/mod.rs b/library/std/src/thread/mod.rs
index 39b53b51bfa..64f6c7fa022 100644
--- a/library/std/src/thread/mod.rs
+++ b/library/std/src/thread/mod.rs
@@ -204,13 +204,6 @@ pub use self::local::os::Key as __OsLocalKeyInner;
#[doc(hidden)]
pub use self::local::statik::Key as __StaticLocalKeyInner;
-// This is only used to make thread locals with `const { .. }` initialization
-// expressions unstable. If and/or when that syntax is stabilized with thread
-// locals this will simply be removed.
-#[doc(hidden)]
-#[unstable(feature = "thread_local_const_init", issue = "84223")]
-pub const fn require_unstable_const_init_thread_local() {}
-
////////////////////////////////////////////////////////////////////////////////
// Builder
////////////////////////////////////////////////////////////////////////////////
@@ -1460,9 +1453,12 @@ fn _assert_sync_and_send() {
/// The purpose of this API is to provide an easy and portable way to query
/// the default amount of parallelism the program should use. Among other things it
/// does not expose information on NUMA regions, does not account for
-/// differences in (co)processor capabilities, and will not modify the program's
-/// global state in order to more accurately query the amount of available
-/// parallelism.
+/// differences in (co)processor capabilities or current system load,
+/// and will not modify the program's global state in order to more accurately
+/// query the amount of available parallelism.
+///
+/// Where both fixed steady-state and burst limits are available the steady-state
+/// capacity will be used to ensure more predictable latencies.
///
/// Resource limits can be changed during the runtime of a program, therefore the value is
/// not cached and instead recomputed every time this function is called. It should not be
diff --git a/library/std/src/thread/tests.rs b/library/std/src/thread/tests.rs
index ca0d88135a5..4f2c81731a3 100644
--- a/library/std/src/thread/tests.rs
+++ b/library/std/src/thread/tests.rs
@@ -1,6 +1,7 @@
use super::Builder;
use crate::any::Any;
use crate::mem;
+use crate::panic::panic_any;
use crate::result;
use crate::sync::{
mpsc::{channel, Sender},
@@ -183,7 +184,7 @@ fn test_simple_newsched_spawn() {
}
#[test]
-fn test_try_panic_message_static_str() {
+fn test_try_panic_message_string_literal() {
match thread::spawn(move || {
panic!("static string");
})
@@ -199,9 +200,9 @@ fn test_try_panic_message_static_str() {
}
#[test]
-fn test_try_panic_message_owned_str() {
+fn test_try_panic_any_message_owned_str() {
match thread::spawn(move || {
- panic!("owned string".to_string());
+ panic_any("owned string".to_string());
})
.join()
{
@@ -215,9 +216,9 @@ fn test_try_panic_message_owned_str() {
}
#[test]
-fn test_try_panic_message_any() {
+fn test_try_panic_any_message_any() {
match thread::spawn(move || {
- panic!(box 413u16 as Box<dyn Any + Send>);
+ panic_any(box 413u16 as Box<dyn Any + Send>);
})
.join()
{
@@ -233,10 +234,10 @@ fn test_try_panic_message_any() {
}
#[test]
-fn test_try_panic_message_unit_struct() {
+fn test_try_panic_any_message_unit_struct() {
struct Juju;
- match thread::spawn(move || panic!(Juju)).join() {
+ match thread::spawn(move || panic_any(Juju)).join() {
Err(ref e) if e.is::<Juju>() => {}
Err(_) | Ok(()) => panic!(),
}
diff --git a/library/std/src/time.rs b/library/std/src/time.rs
index a5e3bd0c290..86cc93c4453 100644
--- a/library/std/src/time.rs
+++ b/library/std/src/time.rs
@@ -273,7 +273,7 @@ impl Instant {
// While issues have been seen on arm64 platforms the Arm architecture
// requires that the counter monotonically increases and that it must
// provide a uniform view of system time (e.g. it must not be possible
- // for a core to recieve a message from another core with a time stamp
+ // for a core to receive a message from another core with a time stamp
// and observe time going backwards (ARM DDI 0487G.b D11.1.2). While
// there have been a few 64bit SoCs that have bugs which cause time to
// not monoticially increase, these have been fixed in the Linux kernel
diff --git a/library/stdarch b/library/stdarch
-Subproject cfba59fccd90b3b52a614120834320f764ab08d
+Subproject 0716b22e902207efabe46879cbf28d0189ab792
diff --git a/library/unwind/build.rs b/library/unwind/build.rs
index 1d0b4a59a28..a3f5224151d 100644
--- a/library/unwind/build.rs
+++ b/library/unwind/build.rs
@@ -17,6 +17,9 @@ fn main() {
} else {
println!("cargo:rustc-link-lib=gcc");
}
+
+ // Android's unwinding library depends on dl_iterate_phdr in `libdl`.
+ println!("cargo:rustc-link-lib=dl");
} else if target.contains("freebsd") {
println!("cargo:rustc-link-lib=gcc_s");
} else if target.contains("netbsd") {
diff --git a/src/bootstrap/bootstrap.py b/src/bootstrap/bootstrap.py
index 22f2e405a1e..5df3d0bde6d 100644
--- a/src/bootstrap/bootstrap.py
+++ b/src/bootstrap/bootstrap.py
@@ -189,11 +189,11 @@ def default_build_triple(verbose):
host = next(x for x in version.split('\n') if x.startswith("host: "))
triple = host.split("host: ")[1]
if verbose:
- print("detected default triple {}".format(triple))
+ print("detected default triple {} from pre-installed rustc".format(triple))
return triple
except Exception as e:
if verbose:
- print("rustup not detected: {}".format(e))
+ print("pre-installed rustc not detected: {}".format(e))
print("falling back to auto-detect")
required = sys.platform != 'win32'
@@ -265,7 +265,7 @@ def default_build_triple(verbose):
err = "unknown OS type: {}".format(ostype)
sys.exit(err)
- if cputype == 'powerpc' and ostype == 'unknown-freebsd':
+ if cputype in ['powerpc', 'riscv'] and ostype == 'unknown-freebsd':
cputype = subprocess.check_output(
['uname', '-p']).strip().decode(default_encoding)
cputype_mapper = {
@@ -726,12 +726,15 @@ class RustBuild(object):
status = subprocess.call(["git", "diff-index", "--quiet", commit, "--", compiler, library])
if status != 0:
if download_rustc == "if-unchanged":
+ if self.verbose:
+ print("warning: saw changes to compiler/ or library/ since {}; " \
+ "ignoring `download-rustc`".format(commit))
return None
- print("warning: `download-rustc` is enabled, but there are changes to \
- compiler/ or library/")
+ print("warning: `download-rustc` is enabled, but there are changes to " \
+ "compiler/ or library/")
if self.verbose:
- print("using downloaded stage1 artifacts from CI (commit {})".format(commit))
+ print("using downloaded stage2 artifacts from CI (commit {})".format(commit))
self.rustc_commit = commit
# FIXME: support downloading artifacts from the beta channel
self.download_toolchain(False, "nightly")
diff --git a/src/bootstrap/builder.rs b/src/bootstrap/builder.rs
index 6ba1b1b6036..bbd2c087cca 100644
--- a/src/bootstrap/builder.rs
+++ b/src/bootstrap/builder.rs
@@ -1176,6 +1176,7 @@ impl<'a> Builder<'a> {
rustflags.arg("-Zosx-rpath-install-name");
Some("-Wl,-rpath,@loader_path/../lib")
} else if !target.contains("windows") {
+ rustflags.arg("-Clink-args=-Wl,-z,origin");
Some("-Wl,-rpath,$ORIGIN/../lib")
} else {
None
@@ -1578,11 +1579,11 @@ impl<'a> Builder<'a> {
panic!("{}", out);
}
if let Some(out) = self.cache.get(&step) {
- self.verbose(&format!("{}c {:?}", " ".repeat(stack.len()), step));
+ self.verbose_than(1, &format!("{}c {:?}", " ".repeat(stack.len()), step));
return out;
}
- self.verbose(&format!("{}> {:?}", " ".repeat(stack.len()), step));
+ self.verbose_than(1, &format!("{}> {:?}", " ".repeat(stack.len()), step));
stack.push(Box::new(step.clone()));
}
@@ -1605,7 +1606,7 @@ impl<'a> Builder<'a> {
let cur_step = stack.pop().expect("step stack empty");
assert_eq!(cur_step.downcast_ref(), Some(&step));
}
- self.verbose(&format!("{}< {:?}", " ".repeat(self.stack.borrow().len()), step));
+ self.verbose_than(1, &format!("{}< {:?}", " ".repeat(self.stack.borrow().len()), step));
self.cache.put(step, out.clone());
out
}
diff --git a/src/bootstrap/clean.rs b/src/bootstrap/clean.rs
index 3216c1af267..3b73dc1c7df 100644
--- a/src/bootstrap/clean.rs
+++ b/src/bootstrap/clean.rs
@@ -75,10 +75,10 @@ fn rm_rf(path: &Path) {
do_op(path, "remove dir", |p| {
fs::remove_dir(p).or_else(|e| {
// Check for dir not empty on Windows
+ // FIXME: Once `ErrorKind::DirectoryNotEmpty` is stabilized,
+ // match on `e.kind()` instead.
#[cfg(windows)]
- if matches!(e.kind(), std::io::ErrorKind::Other)
- && e.raw_os_error() == Some(145)
- {
+ if e.raw_os_error() == Some(145) {
return Ok(());
}
diff --git a/src/bootstrap/compile.rs b/src/bootstrap/compile.rs
index 007ca9f7f5a..6a734ab5177 100644
--- a/src/bootstrap/compile.rs
+++ b/src/bootstrap/compile.rs
@@ -28,6 +28,7 @@ use crate::dist;
use crate::native;
use crate::tool::SourceType;
use crate::util::{exe, is_debug_info, is_dylib, symlink_dir};
+use crate::LLVM_TOOLS;
use crate::{Compiler, DependencyType, GitRepo, Mode};
#[derive(Debug, PartialOrd, Ord, Copy, Clone, PartialEq, Eq, Hash)]
@@ -1164,6 +1165,21 @@ impl Step for Assemble {
let llvm_bin_dir = output(Command::new(llvm_config_bin).arg("--bindir"));
let llvm_bin_dir = Path::new(llvm_bin_dir.trim());
builder.copy(&llvm_bin_dir.join(&src_exe), &libdir_bin.join(&dst_exe));
+
+ // Since we've already built the LLVM tools, install them to the sysroot.
+ // This is the equivalent of installing the `llvm-tools-preview` component via
+ // rustup, and lets developers use a locally built toolchain to
+ // build projects that expect llvm tools to be present in the sysroot
+ // (e.g. the `bootimage` crate).
+ for tool in LLVM_TOOLS {
+ let tool_exe = exe(tool, target_compiler.host);
+ let src_path = llvm_bin_dir.join(&tool_exe);
+ // When using `donwload-ci-llvm`, some of the tools
+ // may not exist, so skip trying to copy them.
+ if src_path.exists() {
+ builder.copy(&src_path, &libdir_bin.join(&tool_exe));
+ }
+ }
}
}
diff --git a/src/bootstrap/defaults/config.tools.toml b/src/bootstrap/defaults/config.tools.toml
index 182fb0fb067..88359fff191 100644
--- a/src/bootstrap/defaults/config.tools.toml
+++ b/src/bootstrap/defaults/config.tools.toml
@@ -11,6 +11,10 @@ incremental = true
# This cuts compile times by almost 60x, but means you can't modify the compiler.
download-rustc = "if-unchanged"
+[build]
+# Document with the in-tree rustdoc by default, since `download-rustc` makes it quick to compile.
+doc-stage = 2
+
[llvm]
# Will download LLVM from CI if available on your platform.
download-ci-llvm = "if-available"
diff --git a/src/bootstrap/dist.rs b/src/bootstrap/dist.rs
index 09ea84a083e..dd179df3948 100644
--- a/src/bootstrap/dist.rs
+++ b/src/bootstrap/dist.rs
@@ -1564,7 +1564,9 @@ impl Step for Extended {
builder.install(&etc.join("gfx/rust-logo.ico"), &exe, 0o644);
// Generate msi installer
- let wix = PathBuf::from(env::var_os("WIX").unwrap());
+ let wix_path = env::var_os("WIX")
+ .expect("`WIX` environment variable must be set for generating MSI installer(s).");
+ let wix = PathBuf::from(wix_path);
let heat = wix.join("bin/heat.exe");
let candle = wix.join("bin/candle.exe");
let light = wix.join("bin/light.exe");
@@ -2085,6 +2087,13 @@ impl Step for RustDev {
] {
tarball.add_file(src_bindir.join(exe(bin, target)), "bin", 0o755);
}
+
+ // We don't build LLD on some platforms, so only add it if it exists
+ let lld_path = builder.lld_out(target).join("bin").join(exe("lld", target));
+ if lld_path.exists() {
+ tarball.add_file(lld_path, "bin", 0o755);
+ }
+
tarball.add_file(&builder.llvm_filecheck(target), "bin", 0o755);
// Copy the include directory as well; needed mostly to build
diff --git a/src/bootstrap/download-ci-llvm-stamp b/src/bootstrap/download-ci-llvm-stamp
index 19e5fffcc2d..ef635ee26df 100644
--- a/src/bootstrap/download-ci-llvm-stamp
+++ b/src/bootstrap/download-ci-llvm-stamp
@@ -1,4 +1,4 @@
Change this file to make users of the `download-ci-llvm` configuration download
a new version of LLVM from CI, even if the LLVM submodule hasn’t changed.
-Last change is for: https://github.com/rust-lang/rust/pull/88069
+Last change is for: https://github.com/rust-lang/rust/pull/91229
diff --git a/src/bootstrap/lib.rs b/src/bootstrap/lib.rs
index 3b3c8a9227d..82462f9758e 100644
--- a/src/bootstrap/lib.rs
+++ b/src/bootstrap/lib.rs
@@ -493,7 +493,7 @@ impl Build {
// NOTE: The check for the empty directory is here because when running x.py the first time,
// the submodule won't be checked out. Check it out now so we can build it.
- if !channel::GitInfo::new(false, relative_path).is_git() && !dir_is_empty(&absolute_path) {
+ if !channel::GitInfo::new(false, &absolute_path).is_git() && !dir_is_empty(&absolute_path) {
return;
}
@@ -1043,7 +1043,7 @@ impl Build {
options[1] = Some(format!("-Clink-arg=-Wl,{}", threads));
}
- std::array::IntoIter::new(options).flatten()
+ IntoIterator::into_iter(options).flatten()
}
/// Returns if this target should statically link the C runtime, if specified
diff --git a/src/bootstrap/native.rs b/src/bootstrap/native.rs
index 37578e30f6d..4a754e6da12 100644
--- a/src/bootstrap/native.rs
+++ b/src/bootstrap/native.rs
@@ -249,9 +249,14 @@ impl Step for Llvm {
}
}
- if target.starts_with("riscv") {
- // In RISC-V, using C++ atomics require linking to `libatomic` but the LLVM build
- // system check cannot detect this. Therefore it is set manually here.
+ if !target.contains("freebsd") && target.starts_with("riscv") {
+ // RISC-V GCC erroneously requires linking against
+ // `libatomic` when using 1-byte and 2-byte C++
+ // atomics but the LLVM build system check cannot
+ // detect this. Therefore it is set manually here.
+ // FreeBSD uses Clang as its system compiler and
+ // provides no libatomic in its base system so does
+ // not want this.
if !builder.config.llvm_tools_enabled {
cfg.define("CMAKE_EXE_LINKER_FLAGS", "-latomic");
} else {
diff --git a/src/ci/docker/host-x86_64/dist-aarch64-linux/Dockerfile b/src/ci/docker/host-x86_64/dist-aarch64-linux/Dockerfile
index e6b6b6e53b9..ab588ccc249 100644
--- a/src/ci/docker/host-x86_64/dist-aarch64-linux/Dockerfile
+++ b/src/ci/docker/host-x86_64/dist-aarch64-linux/Dockerfile
@@ -1,5 +1,18 @@
+FROM ubuntu:20.04
+RUN apt-get update && \
+ apt-get install -y --no-install-recommends \
+ curl \
+ ca-certificates
+WORKDIR /tmp
+RUN curl -f https://curl.se/ca/cacert.pem -o cacert.pem
+
FROM ubuntu:16.04
+# The ca-certificates in ubuntu-16 is too old, so update the certificates
+# with something more recent.
+COPY --from=0 /tmp/cacert.pem /tmp/cacert.pem
+ENV CURL_CA_BUNDLE /tmp/cacert.pem
+
COPY scripts/cross-apt-packages.sh /scripts/
RUN sh /scripts/cross-apt-packages.sh
diff --git a/src/ci/docker/host-x86_64/dist-arm-linux/Dockerfile b/src/ci/docker/host-x86_64/dist-arm-linux/Dockerfile
index 61cc000dca5..ee4fd759b46 100644
--- a/src/ci/docker/host-x86_64/dist-arm-linux/Dockerfile
+++ b/src/ci/docker/host-x86_64/dist-arm-linux/Dockerfile
@@ -1,5 +1,18 @@
+FROM ubuntu:20.04
+RUN apt-get update && \
+ apt-get install -y --no-install-recommends \
+ curl \
+ ca-certificates
+WORKDIR /tmp
+RUN curl -f https://curl.se/ca/cacert.pem -o cacert.pem
+
FROM ubuntu:16.04
+# The ca-certificates in ubuntu-16 is too old, so update the certificates
+# with something more recent.
+COPY --from=0 /tmp/cacert.pem /tmp/cacert.pem
+ENV CURL_CA_BUNDLE /tmp/cacert.pem
+
COPY scripts/cross-apt-packages.sh /scripts/
RUN sh /scripts/cross-apt-packages.sh
diff --git a/src/ci/docker/host-x86_64/dist-armhf-linux/Dockerfile b/src/ci/docker/host-x86_64/dist-armhf-linux/Dockerfile
index 66eb4137a87..b11a1d3feb2 100644
--- a/src/ci/docker/host-x86_64/dist-armhf-linux/Dockerfile
+++ b/src/ci/docker/host-x86_64/dist-armhf-linux/Dockerfile
@@ -1,5 +1,18 @@
+FROM ubuntu:20.04
+RUN apt-get update && \
+ apt-get install -y --no-install-recommends \
+ curl \
+ ca-certificates
+WORKDIR /tmp
+RUN curl -f https://curl.se/ca/cacert.pem -o cacert.pem
+
FROM ubuntu:16.04
+# The ca-certificates in ubuntu-16 is too old, so update the certificates
+# with something more recent.
+COPY --from=0 /tmp/cacert.pem /tmp/cacert.pem
+ENV CURL_CA_BUNDLE /tmp/cacert.pem
+
COPY scripts/cross-apt-packages.sh /scripts/
RUN sh /scripts/cross-apt-packages.sh
diff --git a/src/ci/docker/host-x86_64/dist-armv7-linux/Dockerfile b/src/ci/docker/host-x86_64/dist-armv7-linux/Dockerfile
index c13f63911f8..55ca23b293d 100644
--- a/src/ci/docker/host-x86_64/dist-armv7-linux/Dockerfile
+++ b/src/ci/docker/host-x86_64/dist-armv7-linux/Dockerfile
@@ -1,5 +1,18 @@
+FROM ubuntu:20.04
+RUN apt-get update && \
+ apt-get install -y --no-install-recommends \
+ curl \
+ ca-certificates
+WORKDIR /tmp
+RUN curl -f https://curl.se/ca/cacert.pem -o cacert.pem
+
FROM ubuntu:16.04
+# The ca-certificates in ubuntu-16 is too old, so update the certificates
+# with something more recent.
+COPY --from=0 /tmp/cacert.pem /tmp/cacert.pem
+ENV CURL_CA_BUNDLE /tmp/cacert.pem
+
COPY scripts/cross-apt-packages.sh /scripts/
RUN sh /scripts/cross-apt-packages.sh
diff --git a/src/ci/docker/host-x86_64/x86_64-gnu-tools/Dockerfile b/src/ci/docker/host-x86_64/x86_64-gnu-tools/Dockerfile
index ba4e1ca3114..6e77bb0a09b 100644
--- a/src/ci/docker/host-x86_64/x86_64-gnu-tools/Dockerfile
+++ b/src/ci/docker/host-x86_64/x86_64-gnu-tools/Dockerfile
@@ -72,7 +72,7 @@ ENV PATH="/node-v14.4.0-linux-x64/bin:${PATH}"
# https://github.com/puppeteer/puppeteer/issues/375
#
# We also specify the version in case we need to update it to go around cache limitations.
-RUN npm install -g browser-ui-test@0.4.5 --unsafe-perm=true
+RUN npm install -g browser-ui-test@0.5.1 --unsafe-perm=true
ENV RUST_CONFIGURE_ARGS \
--build=x86_64-unknown-linux-gnu \
diff --git a/src/ci/docker/scripts/freebsd-toolchain.sh b/src/ci/docker/scripts/freebsd-toolchain.sh
index de6b52a5e00..2f7c57bcdc4 100755
--- a/src/ci/docker/scripts/freebsd-toolchain.sh
+++ b/src/ci/docker/scripts/freebsd-toolchain.sh
@@ -53,7 +53,7 @@ files_to_extract=(
for lib in c cxxrt gcc_s m thr util; do
files_to_extract=("${files_to_extract[@]}" "./lib/lib${lib}.*" "./usr/lib/lib${lib}.*")
done
-for lib in c++ c_nonshared compiler_rt execinfo gcc pthread rt ssp_nonshared procstat kvm; do
+for lib in c++ c_nonshared compiler_rt execinfo gcc pthread rt ssp_nonshared procstat devstat kvm; do
files_to_extract=("${files_to_extract[@]}" "./usr/lib/lib${lib}.*")
done
diff --git a/src/doc/book b/src/doc/book
-Subproject 5c5dbc5b196c9564422b3193264f3288d2a051c
+Subproject 5f9358faeb1f46e19b8a23a21e79fd7fe150491
diff --git a/src/doc/edition-guide b/src/doc/edition-guide
-Subproject 27f4a84d3852e9416cae5861254fa53a825c56b
+Subproject beea0a3cdc3885375342fd010f9ad658e6a5e09
diff --git a/src/doc/embedded-book b/src/doc/embedded-book
-Subproject 51739471276b1776dea27cf562b974ef07e2468
+Subproject 8c395bdd8073deb20ca67e1ed4b14a3a7e315a3
diff --git a/src/doc/nomicon b/src/doc/nomicon
-Subproject c6b4bf831e9a40aec34f53067d20634839a6778
+Subproject 49681ea4a9fa81173dbe9ffed74b4d4a35eae9e
diff --git a/src/doc/reference b/src/doc/reference
-Subproject a01d151a7250a540a9cb7ccce5956f020c677c2
+Subproject 954f3d441ad880737a13e241108f791a4d2a38c
diff --git a/src/doc/rust-by-example b/src/doc/rust-by-example
-Subproject e9d45342d7a6c1def4731f1782d87ea317ba30c
+Subproject 1ca6a7bd1d73edc4a3e6c7d6a40f5d4b66c1e51
diff --git a/src/doc/rustc-dev-guide b/src/doc/rustc-dev-guide
-Subproject 196ef69aa68f2cef44f37566ee7db37daf00301
+Subproject a374e7d8bb6b79de45b92295d06b4ac0ef35bc0
diff --git a/src/doc/rustc/src/platform-support.md b/src/doc/rustc/src/platform-support.md
index 4da3491c586..f4f659ffa27 100644
--- a/src/doc/rustc/src/platform-support.md
+++ b/src/doc/rustc/src/platform-support.md
@@ -267,6 +267,7 @@ target | std | host | notes
`riscv32gc-unknown-linux-gnu` | | | RISC-V Linux (kernel 5.4, glibc 2.33)
`riscv32gc-unknown-linux-musl` | | | RISC-V Linux (kernel 5.4, musl + RISCV32 support patches)
`riscv32imc-esp-espidf` | ✓ | | RISC-V ESP-IDF
+`riscv64gc-unknown-freebsd` | | | RISC-V FreeBSD
`riscv64gc-unknown-linux-musl` | | | RISC-V Linux (kernel 4.20, musl 1.2.0)
`s390x-unknown-linux-musl` | | | S390x Linux (kernel 2.6.32, MUSL)
`sparc-unknown-linux-gnu` | ✓ | | 32-bit SPARC Linux
diff --git a/src/doc/rustdoc/src/command-line-arguments.md b/src/doc/rustdoc/src/command-line-arguments.md
index d6948622662..9de2e733de7 100644
--- a/src/doc/rustdoc/src/command-line-arguments.md
+++ b/src/doc/rustdoc/src/command-line-arguments.md
@@ -57,13 +57,13 @@ release: 1.17.0
LLVM version: 3.9
```
-## `-o`/`--output`: output path
+## `-o`/`--out-dir`: output directory path
Using this flag looks like this:
```bash
$ rustdoc src/lib.rs -o target/doc
-$ rustdoc src/lib.rs --output target/doc
+$ rustdoc src/lib.rs --out-dir target/doc
```
By default, `rustdoc`'s output appears in a directory named `doc` in
diff --git a/src/doc/rustdoc/src/documentation-tests.md b/src/doc/rustdoc/src/documentation-tests.md
index 70900a0bab9..aea55d4f4b6 100644
--- a/src/doc/rustdoc/src/documentation-tests.md
+++ b/src/doc/rustdoc/src/documentation-tests.md
@@ -261,6 +261,16 @@ conversion, so type inference fails because the type is not unique. Please note
that you must write the `(())` in one sequence without intermediate whitespace
so that `rustdoc` understands you want an implicit `Result`-returning function.
+## Showing warnings in doctests
+
+You can show warnings in doctests by running `rustdoc --test --test-args=--show-output`
+(or, if you're using cargo, `cargo test --doc -- --show-output`).
+By default, this will still hide `unused` warnings, since so many examples use private functions;
+you can add `#![warn(unused)]` to the top of your example if you want to see unused variables or dead code warnings.
+You can also use [`#![doc(test(attr(warn(unused))))]`][test-attr] in the crate root to enable warnings globally.
+
+[test-attr]: ./the-doc-attribute.md#testattr
+
## Documenting macros
Here’s an example of documenting a macro:
@@ -349,9 +359,8 @@ are added.
# fn foo() {}
```
-`edition2018` tells `rustdoc` that the code sample should be compiled using
-the 2018 edition of Rust. Similarly, you can specify `edition2015` to compile
-the code with the 2015 edition.
+`edition2015`, `edition2018` and `edition2021` tell `rustdoc`
+that the code sample should be compiled using the respective edition of Rust.
```rust
/// Only runs on the 2018 edition.
diff --git a/src/doc/rustdoc/src/unstable-features.md b/src/doc/rustdoc/src/unstable-features.md
index 8da1d22a4d1..56ca7c03928 100644
--- a/src/doc/rustdoc/src/unstable-features.md
+++ b/src/doc/rustdoc/src/unstable-features.md
@@ -138,7 +138,8 @@ This is for Rust compiler internal use only.
Since primitive types are defined in the compiler, there's no place to attach documentation
attributes. The `#[doc(primitive)]` attribute is used by the standard library to provide a way
-to generate documentation for primitive types, and requires `#![feature(doc_primitive)]` to enable.
+to generate documentation for primitive types, and requires `#![feature(rustdoc_internals)]` to
+enable.
## Document keywords
@@ -149,7 +150,7 @@ Rust keywords are documented in the standard library (look for `match` for examp
To do so, the `#[doc(keyword = "...")]` attribute is used. Example:
```rust
-#![feature(doc_keyword)]
+#![feature(rustdoc_internals)]
/// Some documentation about the keyword.
#[doc(keyword = "keyword")]
@@ -256,22 +257,6 @@ all these files are linked from every page, changing where they are can be cumbe
specially cache them. This flag will rename all these files in the output to include the suffix in
the filename. For example, `light.css` would become `light-suf.css` with the above command.
-### `--display-doctest-warnings`: display warnings when documenting or running documentation tests
-
-Using this flag looks like this:
-
-```bash
-$ rustdoc src/lib.rs -Z unstable-options --display-doctest-warnings
-$ rustdoc --test src/lib.rs -Z unstable-options --display-doctest-warnings
-```
-
-The intent behind this flag is to allow the user to see warnings that occur within their library or
-their documentation tests, which are usually suppressed. However, [due to a
-bug][issue-display-warnings], this flag doesn't 100% work as intended. See the linked issue for
-details.
-
-[issue-display-warnings]: https://github.com/rust-lang/rust/issues/41574
-
### `--extern-html-root-url`: control how rustdoc links to non-local crates
Using this flag looks like this:
@@ -411,7 +396,7 @@ Note that the third item is the crate root, which in this case is undocumented.
### `-w`/`--output-format`: output format
`--output-format json` emits documentation in the experimental
-[JSON format](https://github.com/rust-lang/rfcs/pull/2963). `--output-format html` has no effect,
+[JSON format](https://doc.rust-lang.org/nightly/nightly-rustc/rustdoc_json_types/). `--output-format html` has no effect,
and is also accepted on stable toolchains.
It can also be used with `--show-coverage`. Take a look at its
diff --git a/src/doc/unstable-book/src/compiler-flags/instrument-coverage.md b/src/doc/unstable-book/src/compiler-flags/instrument-coverage.md
index f7c2a26f018..f4d1ca0ec69 100644
--- a/src/doc/unstable-book/src/compiler-flags/instrument-coverage.md
+++ b/src/doc/unstable-book/src/compiler-flags/instrument-coverage.md
@@ -20,7 +20,7 @@ This document describes how to enable and use the LLVM instrumentation-based cov
When `-Z instrument-coverage` is enabled, the Rust compiler enhances rust-based libraries and binaries by:
- Automatically injecting calls to an LLVM intrinsic ([`llvm.instrprof.increment`]), at functions and branches in compiled code, to increment counters when conditional sections of code are executed.
-- Embedding additional information in the data section of each library and binary (using the [LLVM Code Coverage Mapping Format] _Version 4_, supported _only_ in LLVM 11 and up), to define the code regions (start and end positions in the source code) being counted.
+- Embedding additional information in the data section of each library and binary (using the [LLVM Code Coverage Mapping Format] _Version 5_, if compiling with LLVM 12, or _Version 6_, if compiling with LLVM 13 or higher), to define the code regions (start and end positions in the source code) being counted.
When running a coverage-instrumented program, the counter values are written to a `profraw` file at program termination. LLVM bundles tools that read the counter results, combine those results with the coverage map (embedded in the program binary), and generate coverage reports in multiple formats.
@@ -123,7 +123,7 @@ If `LLVM_PROFILE_FILE` contains a path to a non-existent directory, the missing
## Installing LLVM coverage tools
-LLVM's supplies two tools—`llvm-profdata` and `llvm-cov`—that process coverage data and generate reports. There are several ways to find and/or install these tools, but note that the coverage mapping data generated by the Rust compiler requires LLVM version 11 or higher. (`llvm-cov --version` typically shows the tool's LLVM version number.):
+LLVM's supplies two tools—`llvm-profdata` and `llvm-cov`—that process coverage data and generate reports. There are several ways to find and/or install these tools, but note that the coverage mapping data generated by the Rust compiler requires LLVM version 12 or higher. (`llvm-cov --version` typically shows the tool's LLVM version number.):
- The LLVM tools may be installed (or installable) directly to your OS (such as via `apt-get`, for Linux).
- If you are building the Rust compiler from source, you can optionally use the bundled LLVM tools, built from source. Those tool binaries can typically be found in your build platform directory at something like: `rust/build/x86_64-unknown-linux-gnu/llvm/bin/llvm-*`.
diff --git a/src/doc/unstable-book/src/compiler-flags/sanitizer.md b/src/doc/unstable-book/src/compiler-flags/sanitizer.md
index b3dbc9a9956..d630f4ecb7b 100644
--- a/src/doc/unstable-book/src/compiler-flags/sanitizer.md
+++ b/src/doc/unstable-book/src/compiler-flags/sanitizer.md
@@ -199,8 +199,9 @@ LLVM CFI can be enabled with -Zsanitizer=cfi and requires LTO (i.e., -Clto).
## Example
```text
-#![feature(asm, naked_functions)]
+#![feature(naked_functions)]
+use std::arch::asm;
use std::mem;
fn add_one(x: i32) -> i32 {
diff --git a/src/doc/unstable-book/src/language-features/asm-const.md b/src/doc/unstable-book/src/language-features/asm-const.md
new file mode 100644
index 00000000000..1063c23b6df
--- /dev/null
+++ b/src/doc/unstable-book/src/language-features/asm-const.md
@@ -0,0 +1,11 @@
+# `asm_const`
+
+The tracking issue for this feature is: [#72016]
+
+[#72016]: https://github.com/rust-lang/rust/issues/72016
+
+------------------------
+
+This feature adds a `const <expr>` operand type to `asm!` and `global_asm!`.
+- `<expr>` must be an integer constant expression.
+- The value of the expression is formatted as a string and substituted directly into the asm template string.
diff --git a/src/doc/unstable-book/src/language-features/asm-experimental-arch.md b/src/doc/unstable-book/src/language-features/asm-experimental-arch.md
new file mode 100644
index 00000000000..ec97eaa8b2b
--- /dev/null
+++ b/src/doc/unstable-book/src/language-features/asm-experimental-arch.md
@@ -0,0 +1,117 @@
+# `asm_experimental_arch`
+
+The tracking issue for this feature is: [#72016]
+
+[#72016]: https://github.com/rust-lang/rust/issues/72016
+
+------------------------
+
+This feature tracks `asm!` and `global_asm!` support for the following architectures:
+- NVPTX
+- PowerPC
+- Hexagon
+- MIPS32r2 and MIPS64r2
+- wasm32
+- BPF
+- SPIR-V
+- AVR
+
+## Register classes
+
+| Architecture | Register class | Registers | LLVM constraint code |
+| ------------ | -------------- | ---------------------------------- | -------------------- |
+| MIPS | `reg` | `$[2-25]` | `r` |
+| MIPS | `freg` | `$f[0-31]` | `f` |
+| NVPTX | `reg16` | None\* | `h` |
+| NVPTX | `reg32` | None\* | `r` |
+| NVPTX | `reg64` | None\* | `l` |
+| Hexagon | `reg` | `r[0-28]` | `r` |
+| PowerPC | `reg` | `r[0-31]` | `r` |
+| PowerPC | `reg_nonzero` | `r[1-31]` | `b` |
+| PowerPC | `freg` | `f[0-31]` | `f` |
+| PowerPC | `cr` | `cr[0-7]`, `cr` | Only clobbers |
+| PowerPC | `xer` | `xer` | Only clobbers |
+| wasm32 | `local` | None\* | `r` |
+| BPF | `reg` | `r[0-10]` | `r` |
+| BPF | `wreg` | `w[0-10]` | `w` |
+| AVR | `reg` | `r[2-25]`, `XH`, `XL`, `ZH`, `ZL` | `r` |
+| AVR | `reg_upper` | `r[16-25]`, `XH`, `XL`, `ZH`, `ZL` | `d` |
+| AVR | `reg_pair` | `r3r2` .. `r25r24`, `X`, `Z` | `r` |
+| AVR | `reg_iw` | `r25r24`, `X`, `Z` | `w` |
+| AVR | `reg_ptr` | `X`, `Z` | `e` |
+
+> **Notes**:
+> - NVPTX doesn't have a fixed register set, so named registers are not supported.
+>
+> - WebAssembly doesn't have registers, so named registers are not supported.
+
+# Register class supported types
+
+| Architecture | Register class | Target feature | Allowed types |
+| ------------ | ------------------------------- | -------------- | --------------------------------------- |
+| MIPS32 | `reg` | None | `i8`, `i16`, `i32`, `f32` |
+| MIPS32 | `freg` | None | `f32`, `f64` |
+| MIPS64 | `reg` | None | `i8`, `i16`, `i32`, `i64`, `f32`, `f64` |
+| MIPS64 | `freg` | None | `f32`, `f64` |
+| NVPTX | `reg16` | None | `i8`, `i16` |
+| NVPTX | `reg32` | None | `i8`, `i16`, `i32`, `f32` |
+| NVPTX | `reg64` | None | `i8`, `i16`, `i32`, `f32`, `i64`, `f64` |
+| Hexagon | `reg` | None | `i8`, `i16`, `i32`, `f32` |
+| PowerPC | `reg` | None | `i8`, `i16`, `i32` |
+| PowerPC | `reg_nonzero` | None | `i8`, `i16`, `i32` |
+| PowerPC | `freg` | None | `f32`, `f64` |
+| PowerPC | `cr` | N/A | Only clobbers |
+| PowerPC | `xer` | N/A | Only clobbers |
+| wasm32 | `local` | None | `i8` `i16` `i32` `i64` `f32` `f64` |
+| BPF | `reg` | None | `i8` `i16` `i32` `i64` |
+| BPF | `wreg` | `alu32` | `i8` `i16` `i32` |
+| AVR | `reg`, `reg_upper` | None | `i8` |
+| AVR | `reg_pair`, `reg_iw`, `reg_ptr` | None | `i16` |
+
+## Register aliases
+
+| Architecture | Base register | Aliases |
+| ------------ | ------------- | --------- |
+| Hexagon | `r29` | `sp` |
+| Hexagon | `r30` | `fr` |
+| Hexagon | `r31` | `lr` |
+| BPF | `r[0-10]` | `w[0-10]` |
+| AVR | `XH` | `r27` |
+| AVR | `XL` | `r26` |
+| AVR | `ZH` | `r31` |
+| AVR | `ZL` | `r30` |
+
+## Unsupported registers
+
+| Architecture | Unsupported register | Reason |
+| ------------ | --------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
+| All | `sp` | The stack pointer must be restored to its original value at the end of an asm code block. |
+| All | `fr` (Hexagon), `$fp` (MIPS), `Y` (AVR) | The frame pointer cannot be used as an input or output. |
+| All | `r19` (Hexagon) | This is used internally by LLVM as a "base pointer" for functions with complex stack frames. |
+| MIPS | `$0` or `$zero` | This is a constant zero register which can't be modified. |
+| MIPS | `$1` or `$at` | Reserved for assembler. |
+| MIPS | `$26`/`$k0`, `$27`/`$k1` | OS-reserved registers. |
+| MIPS | `$28`/`$gp` | Global pointer cannot be used as inputs or outputs. |
+| MIPS | `$ra` | Return address cannot be used as inputs or outputs. |
+| Hexagon | `lr` | This is the link register which cannot be used as an input or output. |
+| AVR | `r0`, `r1`, `r1r0` | Due to an issue in LLVM, the `r0` and `r1` registers cannot be used as inputs or outputs. If modified, they must be restored to their original values before the end of the block. |
+
+## Template modifiers
+
+| Architecture | Register class | Modifier | Example output | LLVM modifier |
+| ------------ | -------------- | -------- | -------------- | ------------- |
+| MIPS | `reg` | None | `$2` | None |
+| MIPS | `freg` | None | `$f0` | None |
+| NVPTX | `reg16` | None | `rs0` | None |
+| NVPTX | `reg32` | None | `r0` | None |
+| NVPTX | `reg64` | None | `rd0` | None |
+| Hexagon | `reg` | None | `r0` | None |
+| PowerPC | `reg` | None | `0` | None |
+| PowerPC | `reg_nonzero` | None | `3` | `b` |
+| PowerPC | `freg` | None | `0` | None |
+
+# Flags covered by `preserves_flags`
+
+These flags registers must be restored upon exiting the asm block if the `preserves_flags` option is set:
+- AVR
+ - The status register `SREG`.
diff --git a/src/doc/unstable-book/src/language-features/asm-sym.md b/src/doc/unstable-book/src/language-features/asm-sym.md
new file mode 100644
index 00000000000..7544e20807e
--- /dev/null
+++ b/src/doc/unstable-book/src/language-features/asm-sym.md
@@ -0,0 +1,13 @@
+# `asm_sym`
+
+The tracking issue for this feature is: [#72016]
+
+[#72016]: https://github.com/rust-lang/rust/issues/72016
+
+------------------------
+
+This feature adds a `sym <path>` operand type to `asm!` and `global_asm!`.
+- `<path>` must refer to a `fn` or `static`.
+- A mangled symbol name referring to the item is substituted into the asm template string.
+- The substituted string does not include any modifiers (e.g. GOT, PLT, relocations, etc).
+- `<path>` is allowed to point to a `#[thread_local]` static, in which case the asm code can combine the symbol with relocations (e.g. `@plt`, `@TPOFF`) to read from thread-local data.
diff --git a/src/doc/unstable-book/src/language-features/asm-unwind.md b/src/doc/unstable-book/src/language-features/asm-unwind.md
new file mode 100644
index 00000000000..414193fe801
--- /dev/null
+++ b/src/doc/unstable-book/src/language-features/asm-unwind.md
@@ -0,0 +1,9 @@
+# `asm_unwind`
+
+The tracking issue for this feature is: [#72016]
+
+[#72016]: https://github.com/rust-lang/rust/issues/72016
+
+------------------------
+
+This feature adds a `may_unwind` option to `asm!` which allows an `asm` block to unwind stack and be part of the stack unwinding process. This option is only supported by the LLVM backend right now.
diff --git a/src/doc/unstable-book/src/language-features/inline-const-pat.md b/src/doc/unstable-book/src/language-features/inline-const-pat.md
new file mode 100644
index 00000000000..5f0f7547a0a
--- /dev/null
+++ b/src/doc/unstable-book/src/language-features/inline-const-pat.md
@@ -0,0 +1,24 @@
+# `inline_const_pat`
+
+The tracking issue for this feature is: [#76001]
+
+See also [`inline_const`](inline-const.md)
+
+------
+
+This feature allows you to use inline constant expressions in pattern position:
+
+```rust
+#![feature(inline_const_pat)]
+
+const fn one() -> i32 { 1 }
+
+let some_int = 3;
+match some_int {
+ const { 1 + 2 } => println!("Matched 1 + 2"),
+ const { one() } => println!("Matched const fn returning 1"),
+ _ => println!("Didn't match anything :("),
+}
+```
+
+[#76001]: https://github.com/rust-lang/rust/issues/76001
diff --git a/src/doc/unstable-book/src/language-features/inline-const.md b/src/doc/unstable-book/src/language-features/inline-const.md
index 00e1c79ca3f..7be70eed6ce 100644
--- a/src/doc/unstable-book/src/language-features/inline-const.md
+++ b/src/doc/unstable-book/src/language-features/inline-const.md
@@ -2,6 +2,8 @@
The tracking issue for this feature is: [#76001]
+See also [`inline_const_pat`](inline-const-pat.md)
+
------
This feature allows you to use inline constant expressions. For example, you can
@@ -27,19 +29,4 @@ fn main() {
}
```
-You can also use inline constant expressions in patterns:
-
-```rust
-#![feature(inline_const)]
-
-const fn one() -> i32 { 1 }
-
-let some_int = 3;
-match some_int {
- const { 1 + 2 } => println!("Matched 1 + 2"),
- const { one() } => println!("Matched const fn returning 1"),
- _ => println!("Didn't match anything :("),
-}
-```
-
[#76001]: https://github.com/rust-lang/rust/issues/76001
diff --git a/src/doc/unstable-book/src/library-features/asm.md b/src/doc/unstable-book/src/library-features/asm.md
deleted file mode 100644
index fac55b97888..00000000000
--- a/src/doc/unstable-book/src/library-features/asm.md
+++ /dev/null
@@ -1,896 +0,0 @@
-# `asm`
-
-The tracking issue for this feature is: [#72016]
-
-[#72016]: https://github.com/rust-lang/rust/issues/72016
-
-------------------------
-
-For extremely low-level manipulations and performance reasons, one
-might wish to control the CPU directly. Rust supports using inline
-assembly to do this via the `asm!` macro.
-
-# Guide-level explanation
-[guide-level-explanation]: #guide-level-explanation
-
-Rust provides support for inline assembly via the `asm!` macro.
-It can be used to embed handwritten assembly in the assembly output generated by the compiler.
-Generally this should not be necessary, but might be where the required performance or timing
-cannot be otherwise achieved. Accessing low level hardware primitives, e.g. in kernel code, may also demand this functionality.
-
-> **Note**: the examples here are given in x86/x86-64 assembly, but other architectures are also supported.
-
-Inline assembly is currently supported on the following architectures:
-- x86 and x86-64
-- ARM
-- AArch64
-- RISC-V
-- NVPTX
-- PowerPC
-- Hexagon
-- MIPS32r2 and MIPS64r2
-- wasm32
-- BPF
-- SPIR-V
-
-## Basic usage
-
-Let us start with the simplest possible example:
-
-```rust,allow_fail
-#![feature(asm)]
-unsafe {
- asm!("nop");
-}
-```
-
-This will insert a NOP (no operation) instruction into the assembly generated by the compiler.
-Note that all `asm!` invocations have to be inside an `unsafe` block, as they could insert
-arbitrary instructions and break various invariants. The instructions to be inserted are listed
-in the first argument of the `asm!` macro as a string literal.
-
-## Inputs and outputs
-
-Now inserting an instruction that does nothing is rather boring. Let us do something that
-actually acts on data:
-
-```rust,allow_fail
-#![feature(asm)]
-let x: u64;
-unsafe {
- asm!("mov {}, 5", out(reg) x);
-}
-assert_eq!(x, 5);
-```
-
-This will write the value `5` into the `u64` variable `x`.
-You can see that the string literal we use to specify instructions is actually a template string.
-It is governed by the same rules as Rust [format strings][format-syntax].
-The arguments that are inserted into the template however look a bit different than you may
-be familiar with. First we need to specify if the variable is an input or an output of the
-inline assembly. In this case it is an output. We declared this by writing `out`.
-We also need to specify in what kind of register the assembly expects the variable.
-In this case we put it in an arbitrary general purpose register by specifying `reg`.
-The compiler will choose an appropriate register to insert into
-the template and will read the variable from there after the inline assembly finishes executing.
-
-Let us see another example that also uses an input:
-
-```rust,allow_fail
-#![feature(asm)]
-let i: u64 = 3;
-let o: u64;
-unsafe {
- asm!(
- "mov {0}, {1}",
- "add {0}, {number}",
- out(reg) o,
- in(reg) i,
- number = const 5,
- );
-}
-assert_eq!(o, 8);
-```
-
-This will add `5` to the input in variable `i` and write the result to variable `o`.
-The particular way this assembly does this is first copying the value from `i` to the output,
-and then adding `5` to it.
-
-The example shows a few things:
-
-First, we can see that `asm!` allows multiple template string arguments; each
-one is treated as a separate line of assembly code, as if they were all joined
-together with newlines between them. This makes it easy to format assembly
-code.
-
-Second, we can see that inputs are declared by writing `in` instead of `out`.
-
-Third, one of our operands has a type we haven't seen yet, `const`.
-This tells the compiler to expand this argument to a value directly inside the assembly template.
-This is only possible for constants and literals.
-
-Fourth, we can see that we can specify an argument number, or name as in any format string.
-For inline assembly templates this is particularly useful as arguments are often used more than once.
-For more complex inline assembly using this facility is generally recommended, as it improves
-readability, and allows reordering instructions without changing the argument order.
-
-We can further refine the above example to avoid the `mov` instruction:
-
-```rust,allow_fail
-#![feature(asm)]
-let mut x: u64 = 3;
-unsafe {
- asm!("add {0}, {number}", inout(reg) x, number = const 5);
-}
-assert_eq!(x, 8);
-```
-
-We can see that `inout` is used to specify an argument that is both input and output.
-This is different from specifying an input and output separately in that it is guaranteed to assign both to the same register.
-
-It is also possible to specify different variables for the input and output parts of an `inout` operand:
-
-```rust,allow_fail
-#![feature(asm)]
-let x: u64 = 3;
-let y: u64;
-unsafe {
- asm!("add {0}, {number}", inout(reg) x => y, number = const 5);
-}
-assert_eq!(y, 8);
-```
-
-## Late output operands
-
-The Rust compiler is conservative with its allocation of operands. It is assumed that an `out`
-can be written at any time, and can therefore not share its location with any other argument.
-However, to guarantee optimal performance it is important to use as few registers as possible,
-so they won't have to be saved and reloaded around the inline assembly block.
-To achieve this Rust provides a `lateout` specifier. This can be used on any output that is
-written only after all inputs have been consumed.
-There is also a `inlateout` variant of this specifier.
-
-Here is an example where `inlateout` *cannot* be used:
-
-```rust,allow_fail
-#![feature(asm)]
-let mut a: u64 = 4;
-let b: u64 = 4;
-let c: u64 = 4;
-unsafe {
- asm!(
- "add {0}, {1}",
- "add {0}, {2}",
- inout(reg) a,
- in(reg) b,
- in(reg) c,
- );
-}
-assert_eq!(a, 12);
-```
-
-Here the compiler is free to allocate the same register for inputs `b` and `c` since it knows they have the same value. However it must allocate a separate register for `a` since it uses `inout` and not `inlateout`. If `inlateout` was used, then `a` and `c` could be allocated to the same register, in which case the first instruction to overwrite the value of `c` and cause the assembly code to produce the wrong result.
-
-However the following example can use `inlateout` since the output is only modified after all input registers have been read:
-
-```rust,allow_fail
-#![feature(asm)]
-let mut a: u64 = 4;
-let b: u64 = 4;
-unsafe {
- asm!("add {0}, {1}", inlateout(reg) a, in(reg) b);
-}
-assert_eq!(a, 8);
-```
-
-As you can see, this assembly fragment will still work correctly if `a` and `b` are assigned to the same register.
-
-## Explicit register operands
-
-Some instructions require that the operands be in a specific register.
-Therefore, Rust inline assembly provides some more specific constraint specifiers.
-While `reg` is generally available on any architecture, explicit registers are highly architecture specific. E.g. for x86 the general purpose registers `eax`, `ebx`, `ecx`, `edx`, `ebp`, `esi`, and `edi` among others can be addressed by their name.
-
-```rust,allow_fail,no_run
-#![feature(asm)]
-let cmd = 0xd1;
-unsafe {
- asm!("out 0x64, eax", in("eax") cmd);
-}
-```
-
-In this example we call the `out` instruction to output the content of the `cmd` variable to port `0x64`. Since the `out` instruction only accepts `eax` (and its sub registers) as operand we had to use the `eax` constraint specifier.
-
-> **Note**: unlike other operand types, explicit register operands cannot be used in the template string: you can't use `{}` and should write the register name directly instead. Also, they must appear at the end of the operand list after all other operand types.
-
-Consider this example which uses the x86 `mul` instruction:
-
-```rust,allow_fail
-#![feature(asm)]
-fn mul(a: u64, b: u64) -> u128 {
- let lo: u64;
- let hi: u64;
-
- unsafe {
- asm!(
- // The x86 mul instruction takes rax as an implicit input and writes
- // the 128-bit result of the multiplication to rax:rdx.
- "mul {}",
- in(reg) a,
- inlateout("rax") b => lo,
- lateout("rdx") hi
- );
- }
-
- ((hi as u128) << 64) + lo as u128
-}
-```
-
-This uses the `mul` instruction to multiply two 64-bit inputs with a 128-bit result.
-The only explicit operand is a register, that we fill from the variable `a`.
-The second operand is implicit, and must be the `rax` register, which we fill from the variable `b`.
-The lower 64 bits of the result are stored in `rax` from which we fill the variable `lo`.
-The higher 64 bits are stored in `rdx` from which we fill the variable `hi`.
-
-## Clobbered registers
-
-In many cases inline assembly will modify state that is not needed as an output.
-Usually this is either because we have to use a scratch register in the assembly or because instructions modify state that we don't need to further examine.
-This state is generally referred to as being "clobbered".
-We need to tell the compiler about this since it may need to save and restore this state around the inline assembly block.
-
-```rust,allow_fail
-#![feature(asm)]
-let ebx: u32;
-let ecx: u32;
-
-unsafe {
- asm!(
- "cpuid",
- // EAX 4 selects the "Deterministic Cache Parameters" CPUID leaf
- inout("eax") 4 => _,
- // ECX 0 selects the L0 cache information.
- inout("ecx") 0 => ecx,
- lateout("ebx") ebx,
- lateout("edx") _,
- );
-}
-
-println!(
- "L0 Cache: {}",
- ((ebx >> 22) + 1) * (((ebx >> 12) & 0x3ff) + 1) * ((ebx & 0xfff) + 1) * (ecx + 1)
-);
-```
-
-In the example above we use the `cpuid` instruction to get the L1 cache size.
-This instruction writes to `eax`, `ebx`, `ecx`, and `edx`, but for the cache size we only care about the contents of `ebx` and `ecx`.
-
-However we still need to tell the compiler that `eax` and `edx` have been modified so that it can save any values that were in these registers before the asm. This is done by declaring these as outputs but with `_` instead of a variable name, which indicates that the output value is to be discarded.
-
-This can also be used with a general register class (e.g. `reg`) to obtain a scratch register for use inside the asm code:
-
-```rust,allow_fail
-#![feature(asm)]
-// Multiply x by 6 using shifts and adds
-let mut x: u64 = 4;
-unsafe {
- asm!(
- "mov {tmp}, {x}",
- "shl {tmp}, 1",
- "shl {x}, 2",
- "add {x}, {tmp}",
- x = inout(reg) x,
- tmp = out(reg) _,
- );
-}
-assert_eq!(x, 4 * 6);
-```
-
-## Symbol operands and ABI clobbers
-
-A special operand type, `sym`, allows you to use the symbol name of a `fn` or `static` in inline assembly code.
-This allows you to call a function or access a global variable without needing to keep its address in a register.
-
-```rust,allow_fail
-#![feature(asm)]
-extern "C" fn foo(arg: i32) -> i32 {
- println!("arg = {}", arg);
- arg * 2
-}
-
-fn call_foo(arg: i32) -> i32 {
- unsafe {
- let result;
- asm!(
- "call {}",
- sym foo,
- // 1st argument in rdi
- in("rdi") arg,
- // Return value in rax
- out("rax") result,
- // Mark all registers which are not preserved by the "C" calling
- // convention as clobbered.
- clobber_abi("C"),
- );
- result
- }
-}
-```
-
-Note that the `fn` or `static` item does not need to be public or `#[no_mangle]`: the compiler will automatically insert the appropriate mangled symbol name into the assembly code.
-
-By default, `asm!` assumes that any register not specified as an output will have its contents preserved by the assembly code. The [`clobber_abi`](#abi-clobbers) argument to `asm!` tells the compiler to automatically insert the necessary clobber operands according to the given calling convention ABI: any register which is not fully preserved in that ABI will be treated as clobbered. Multiple `clobber_abi` arguments may be provided and all clobbers from all specified ABIs will be inserted.
-
-## Register template modifiers
-
-In some cases, fine control is needed over the way a register name is formatted when inserted into the template string. This is needed when an architecture's assembly language has several names for the same register, each typically being a "view" over a subset of the register (e.g. the low 32 bits of a 64-bit register).
-
-By default the compiler will always choose the name that refers to the full register size (e.g. `rax` on x86-64, `eax` on x86, etc).
-
-This default can be overriden by using modifiers on the template string operands, just like you would with format strings:
-
-```rust,allow_fail
-#![feature(asm)]
-let mut x: u16 = 0xab;
-
-unsafe {
- asm!("mov {0:h}, {0:l}", inout(reg_abcd) x);
-}
-
-assert_eq!(x, 0xabab);
-```
-
-In this example, we use the `reg_abcd` register class to restrict the register allocator to the 4 legacy x86 register (`ax`, `bx`, `cx`, `dx`) of which the first two bytes can be addressed independently.
-
-Let us assume that the register allocator has chosen to allocate `x` in the `ax` register.
-The `h` modifier will emit the register name for the high byte of that register and the `l` modifier will emit the register name for the low byte. The asm code will therefore be expanded as `mov ah, al` which copies the low byte of the value into the high byte.
-
-If you use a smaller data type (e.g. `u16`) with an operand and forget the use template modifiers, the compiler will emit a warning and suggest the correct modifier to use.
-
-## Memory address operands
-
-Sometimes assembly instructions require operands passed via memory addresses/memory locations.
-You have to manually use the memory address syntax specified by the target architecture.
-For example, on x86/x86_64 using intel assembly syntax, you should wrap inputs/outputs in `[]` to indicate they are memory operands:
-
-```rust,allow_fail
-#![feature(asm, llvm_asm)]
-# fn load_fpu_control_word(control: u16) {
-unsafe {
- asm!("fldcw [{}]", in(reg) &control, options(nostack));
-
- // Previously this would have been written with the deprecated `llvm_asm!` like this
- llvm_asm!("fldcw $0" :: "m" (control) :: "volatile");
-}
-# }
-```
-
-## Labels
-
-Any reuse of a named label, local or otherwise, can result in a assembler or linker error or may cause other strange behavior. Reuse of a named label can happen in a variety of ways including:
-
-- explicitly: using a label more than once in one `asm!` block, or multiple times across blocks
-- implicitly via inlining: the compiler is allowed to instantiate multiple copies of an `asm!` block, for example when the function containing it is inlined in multiple places.
-- implicitly via LTO: LTO can cause code from *other crates* to be placed in the same codegen unit, and so could bring in arbitrary labels
-
-As a consequence, you should only use GNU assembler **numeric** [local labels] inside inline assembly code. Defining symbols in assembly code may lead to assembler and/or linker errors due to duplicate symbol definitions.
-
-Moreover, on x86 when using the default intel syntax, due to [an llvm bug], you shouldn't use labels exclusively made of `0` and `1` digits, e.g. `0`, `11` or `101010`, as they may end up being interpreted as binary values. Using `options(att_syntax)` will avoid any ambiguity, but that affects the syntax of the _entire_ `asm!` block.
-
-```rust,allow_fail
-#![feature(asm)]
-
-let mut a = 0;
-unsafe {
- asm!(
- "mov {0}, 10",
- "2:",
- "sub {0}, 1",
- "cmp {0}, 3",
- "jle 2f",
- "jmp 2b",
- "2:",
- "add {0}, 2",
- out(reg) a
- );
-}
-assert_eq!(a, 5);
-```
-
-This will decrement the `{0}` register value from 10 to 3, then add 2 and store it in `a`.
-
-This example shows a few things:
-
-First that the same number can be used as a label multiple times in the same inline block.
-
-Second, that when a numeric label is used as a reference (as an instruction operand, for example), the suffixes b (“backward”) or f (“forward”) should be added to the numeric label. It will then refer to the nearest label defined by this number in this direction.
-
-[local labels]: https://sourceware.org/binutils/docs/as/Symbol-Names.html#Local-Labels
-[an llvm bug]: https://bugs.llvm.org/show_bug.cgi?id=36144
-
-## Options
-
-By default, an inline assembly block is treated the same way as an external FFI function call with a custom calling convention: it may read/write memory, have observable side effects, etc. However, in many cases it is desirable to give the compiler more information about what the assembly code is actually doing so that it can optimize better.
-
-Let's take our previous example of an `add` instruction:
-
-```rust,allow_fail
-#![feature(asm)]
-let mut a: u64 = 4;
-let b: u64 = 4;
-unsafe {
- asm!(
- "add {0}, {1}",
- inlateout(reg) a, in(reg) b,
- options(pure, nomem, nostack),
- );
-}
-assert_eq!(a, 8);
-```
-
-Options can be provided as an optional final argument to the `asm!` macro. We specified three options here:
-- `pure` means that the asm code has no observable side effects and that its output depends only on its inputs. This allows the compiler optimizer to call the inline asm fewer times or even eliminate it entirely.
-- `nomem` means that the asm code does not read or write to memory. By default the compiler will assume that inline assembly can read or write any memory address that is accessible to it (e.g. through a pointer passed as an operand, or a global).
-- `nostack` means that the asm code does not push any data onto the stack. This allows the compiler to use optimizations such as the stack red zone on x86-64 to avoid stack pointer adjustments.
-
-These allow the compiler to better optimize code using `asm!`, for example by eliminating pure `asm!` blocks whose outputs are not needed.
-
-See the reference for the full list of available options and their effects.
-
-# Reference-level explanation
-[reference-level-explanation]: #reference-level-explanation
-
-Inline assembler is implemented as an unsafe macro `asm!()`.
-The first argument to this macro is a template string literal used to build the final assembly.
-The following arguments specify input and output operands.
-When required, options are specified as the final argument.
-
-The following ABNF specifies the general syntax:
-
-```text
-dir_spec := "in" / "out" / "lateout" / "inout" / "inlateout"
-reg_spec := <register class> / "<explicit register>"
-operand_expr := expr / "_" / expr "=>" expr / expr "=>" "_"
-reg_operand := dir_spec "(" reg_spec ")" operand_expr
-operand := reg_operand / "const" const_expr / "sym" path
-clobber_abi := "clobber_abi(" <abi> *["," <abi>] [","] ")"
-option := "pure" / "nomem" / "readonly" / "preserves_flags" / "noreturn" / "nostack" / "att_syntax" / "raw"
-options := "options(" option *["," option] [","] ")"
-asm := "asm!(" format_string *("," format_string) *("," [ident "="] operand) *("," clobber_abi) *("," options) [","] ")"
-```
-
-Inline assembly is currently supported on the following architectures:
-- x86 and x86-64
-- ARM
-- AArch64
-- RISC-V
-- NVPTX
-- PowerPC
-- Hexagon
-- MIPS32r2 and MIPS64r2
-- wasm32
-- BPF
-- SPIR-V
-
-Support for more targets may be added in the future. The compiler will emit an error if `asm!` is used on an unsupported target.
-
-[format-syntax]: https://doc.rust-lang.org/std/fmt/#syntax
-
-## Template string arguments
-
-The assembler template uses the same syntax as [format strings][format-syntax] (i.e. placeholders are specified by curly braces). The corresponding arguments are accessed in order, by index, or by name. However, implicit named arguments (introduced by [RFC #2795][rfc-2795]) are not supported.
-
-An `asm!` invocation may have one or more template string arguments; an `asm!` with multiple template string arguments is treated as if all the strings were concatenated with a `\n` between them. The expected usage is for each template string argument to correspond to a line of assembly code. All template string arguments must appear before any other arguments.
-
-As with format strings, named arguments must appear after positional arguments. Explicit register operands must appear at the end of the operand list, after named arguments if any.
-
-Explicit register operands cannot be used by placeholders in the template string. All other named and positional operands must appear at least once in the template string, otherwise a compiler error is generated.
-
-The exact assembly code syntax is target-specific and opaque to the compiler except for the way operands are substituted into the template string to form the code passed to the assembler.
-
-The 5 targets specified in this RFC (x86, ARM, AArch64, RISC-V, Hexagon) all use the assembly code syntax of the GNU assembler (GAS). On x86, the `.intel_syntax noprefix` mode of GAS is used by default. On ARM, the `.syntax unified` mode is used. These targets impose an additional restriction on the assembly code: any assembler state (e.g. the current section which can be changed with `.section`) must be restored to its original value at the end of the asm string. Assembly code that does not conform to the GAS syntax will result in assembler-specific behavior.
-
-[rfc-2795]: https://github.com/rust-lang/rfcs/pull/2795
-
-## Operand type
-
-Several types of operands are supported:
-
-* `in(<reg>) <expr>`
- - `<reg>` can refer to a register class or an explicit register. The allocated register name is substituted into the asm template string.
- - The allocated register will contain the value of `<expr>` at the start of the asm code.
- - The allocated register must contain the same value at the end of the asm code (except if a `lateout` is allocated to the same register).
-* `out(<reg>) <expr>`
- - `<reg>` can refer to a register class or an explicit register. The allocated register name is substituted into the asm template string.
- - The allocated register will contain an undefined value at the start of the asm code.
- - `<expr>` must be a (possibly uninitialized) place expression, to which the contents of the allocated register is written to at the end of the asm code.
- - An underscore (`_`) may be specified instead of an expression, which will cause the contents of the register to be discarded at the end of the asm code (effectively acting as a clobber).
-* `lateout(<reg>) <expr>`
- - Identical to `out` except that the register allocator can reuse a register allocated to an `in`.
- - You should only write to the register after all inputs are read, otherwise you may clobber an input.
-* `inout(<reg>) <expr>`
- - `<reg>` can refer to a register class or an explicit register. The allocated register name is substituted into the asm template string.
- - The allocated register will contain the value of `<expr>` at the start of the asm code.
- - `<expr>` must be a mutable initialized place expression, to which the contents of the allocated register is written to at the end of the asm code.
-* `inout(<reg>) <in expr> => <out expr>`
- - Same as `inout` except that the initial value of the register is taken from the value of `<in expr>`.
- - `<out expr>` must be a (possibly uninitialized) place expression, to which the contents of the allocated register is written to at the end of the asm code.
- - An underscore (`_`) may be specified instead of an expression for `<out expr>`, which will cause the contents of the register to be discarded at the end of the asm code (effectively acting as a clobber).
- - `<in expr>` and `<out expr>` may have different types.
-* `inlateout(<reg>) <expr>` / `inlateout(<reg>) <in expr> => <out expr>`
- - Identical to `inout` except that the register allocator can reuse a register allocated to an `in` (this can happen if the compiler knows the `in` has the same initial value as the `inlateout`).
- - You should only write to the register after all inputs are read, otherwise you may clobber an input.
-* `const <expr>`
- - `<expr>` must be an integer constant expression.
- - The value of the expression is formatted as a string and substituted directly into the asm template string.
-* `sym <path>`
- - `<path>` must refer to a `fn` or `static`.
- - A mangled symbol name referring to the item is substituted into the asm template string.
- - The substituted string does not include any modifiers (e.g. GOT, PLT, relocations, etc).
- - `<path>` is allowed to point to a `#[thread_local]` static, in which case the asm code can combine the symbol with relocations (e.g. `@plt`, `@TPOFF`) to read from thread-local data.
-
-Operand expressions are evaluated from left to right, just like function call arguments. After the `asm!` has executed, outputs are written to in left to right order. This is significant if two outputs point to the same place: that place will contain the value of the rightmost output.
-
-## Register operands
-
-Input and output operands can be specified either as an explicit register or as a register class from which the register allocator can select a register. Explicit registers are specified as string literals (e.g. `"eax"`) while register classes are specified as identifiers (e.g. `reg`). Using string literals for register names enables support for architectures that use special characters in register names, such as MIPS (`$0`, `$1`, etc).
-
-Note that explicit registers treat register aliases (e.g. `r14` vs `lr` on ARM) and smaller views of a register (e.g. `eax` vs `rax`) as equivalent to the base register. It is a compile-time error to use the same explicit register for two input operands or two output operands. Additionally, it is also a compile-time error to use overlapping registers (e.g. ARM VFP) in input operands or in output operands.
-
-Only the following types are allowed as operands for inline assembly:
-- Integers (signed and unsigned)
-- Floating-point numbers
-- Pointers (thin only)
-- Function pointers
-- SIMD vectors (structs defined with `#[repr(simd)]` and which implement `Copy`). This includes architecture-specific vector types defined in `std::arch` such as `__m128` (x86) or `int8x16_t` (ARM).
-
-Here is the list of currently supported register classes:
-
-| Architecture | Register class | Registers | LLVM constraint code |
-| ------------ | -------------- | --------- | -------------------- |
-| x86 | `reg` | `ax`, `bx`, `cx`, `dx`, `si`, `di`, `bp`, `r[8-15]` (x86-64 only) | `r` |
-| x86 | `reg_abcd` | `ax`, `bx`, `cx`, `dx` | `Q` |
-| x86-32 | `reg_byte` | `al`, `bl`, `cl`, `dl`, `ah`, `bh`, `ch`, `dh` | `q` |
-| x86-64 | `reg_byte`\* | `al`, `bl`, `cl`, `dl`, `sil`, `dil`, `bpl`, `r[8-15]b` | `q` |
-| x86 | `xmm_reg` | `xmm[0-7]` (x86) `xmm[0-15]` (x86-64) | `x` |
-| x86 | `ymm_reg` | `ymm[0-7]` (x86) `ymm[0-15]` (x86-64) | `x` |
-| x86 | `zmm_reg` | `zmm[0-7]` (x86) `zmm[0-31]` (x86-64) | `v` |
-| x86 | `kreg` | `k[1-7]` | `Yk` |
-| x86 | `x87_reg` | `st([0-7])` | Only clobbers |
-| x86 | `mmx_reg` | `mm[0-7]` | Only clobbers |
-| AArch64 | `reg` | `x[0-30]` | `r` |
-| AArch64 | `vreg` | `v[0-31]` | `w` |
-| AArch64 | `vreg_low16` | `v[0-15]` | `x` |
-| AArch64 | `preg` | `p[0-15]`, `ffr` | Only clobbers |
-| ARM (ARM) | `reg` | `r[0-12]`, `r14` | `r` |
-| ARM (Thumb2) | `reg` | `r[0-12]`, `r14` | `r` |
-| ARM (Thumb1) | `reg` | `r[0-7]` | `r` |
-| ARM (ARM) | `reg_thumb` | `r[0-r12]`, `r14` | `l` |
-| ARM (Thumb2) | `reg_thumb` | `r[0-7]` | `l` |
-| ARM (Thumb1) | `reg_thumb` | `r[0-7]` | `l` |
-| ARM | `sreg` | `s[0-31]` | `t` |
-| ARM | `sreg_low16` | `s[0-15]` | `x` |
-| ARM | `dreg` | `d[0-31]` | `w` |
-| ARM | `dreg_low16` | `d[0-15]` | `t` |
-| ARM | `dreg_low8` | `d[0-8]` | `x` |
-| ARM | `qreg` | `q[0-15]` | `w` |
-| ARM | `qreg_low8` | `q[0-7]` | `t` |
-| ARM | `qreg_low4` | `q[0-3]` | `x` |
-| MIPS | `reg` | `$[2-25]` | `r` |
-| MIPS | `freg` | `$f[0-31]` | `f` |
-| NVPTX | `reg16` | None\* | `h` |
-| NVPTX | `reg32` | None\* | `r` |
-| NVPTX | `reg64` | None\* | `l` |
-| RISC-V | `reg` | `x1`, `x[5-7]`, `x[9-15]`, `x[16-31]` (non-RV32E) | `r` |
-| RISC-V | `freg` | `f[0-31]` | `f` |
-| RISC-V | `vreg` | `v[0-31]` | Only clobbers |
-| Hexagon | `reg` | `r[0-28]` | `r` |
-| PowerPC | `reg` | `r[0-31]` | `r` |
-| PowerPC | `reg_nonzero` | | `r[1-31]` | `b` |
-| PowerPC | `freg` | `f[0-31]` | `f` |
-| PowerPC | `cr` | `cr[0-7]`, `cr` | Only clobbers |
-| PowerPC | `xer` | `xer` | Only clobbers |
-| wasm32 | `local` | None\* | `r` |
-| BPF | `reg` | `r[0-10]` | `r` |
-| BPF | `wreg` | `w[0-10]` | `w` |
-
-> **Note**: On x86 we treat `reg_byte` differently from `reg` because the compiler can allocate `al` and `ah` separately whereas `reg` reserves the whole register.
->
-> Note #2: On x86-64 the high byte registers (e.g. `ah`) are not available in the `reg_byte` register class.
->
-> Note #3: NVPTX doesn't have a fixed register set, so named registers are not supported.
->
-> Note #4: WebAssembly doesn't have registers, so named registers are not supported.
->
-> Note #5: Some register classes are marked as "Only clobbers" which means that they cannot be used for inputs or outputs, only clobbers of the form `out("reg") _` or `lateout("reg") _`.
-
-Additional register classes may be added in the future based on demand (e.g. MMX, x87, etc).
-
-Each register class has constraints on which value types they can be used with. This is necessary because the way a value is loaded into a register depends on its type. For example, on big-endian systems, loading a `i32x4` and a `i8x16` into a SIMD register may result in different register contents even if the byte-wise memory representation of both values is identical. The availability of supported types for a particular register class may depend on what target features are currently enabled.
-
-| Architecture | Register class | Target feature | Allowed types |
-| ------------ | -------------- | -------------- | ------------- |
-| x86-32 | `reg` | None | `i16`, `i32`, `f32` |
-| x86-64 | `reg` | None | `i16`, `i32`, `f32`, `i64`, `f64` |
-| x86 | `reg_byte` | None | `i8` |
-| x86 | `xmm_reg` | `sse` | `i32`, `f32`, `i64`, `f64`, <br> `i8x16`, `i16x8`, `i32x4`, `i64x2`, `f32x4`, `f64x2` |
-| x86 | `ymm_reg` | `avx` | `i32`, `f32`, `i64`, `f64`, <br> `i8x16`, `i16x8`, `i32x4`, `i64x2`, `f32x4`, `f64x2` <br> `i8x32`, `i16x16`, `i32x8`, `i64x4`, `f32x8`, `f64x4` |
-| x86 | `zmm_reg` | `avx512f` | `i32`, `f32`, `i64`, `f64`, <br> `i8x16`, `i16x8`, `i32x4`, `i64x2`, `f32x4`, `f64x2` <br> `i8x32`, `i16x16`, `i32x8`, `i64x4`, `f32x8`, `f64x4` <br> `i8x64`, `i16x32`, `i32x16`, `i64x8`, `f32x16`, `f64x8` |
-| x86 | `kreg` | `avx512f` | `i8`, `i16` |
-| x86 | `kreg` | `avx512bw` | `i32`, `i64` |
-| x86 | `mmx_reg` | N/A | Only clobbers |
-| x86 | `x87_reg` | N/A | Only clobbers |
-| AArch64 | `reg` | None | `i8`, `i16`, `i32`, `f32`, `i64`, `f64` |
-| AArch64 | `vreg` | `fp` | `i8`, `i16`, `i32`, `f32`, `i64`, `f64`, <br> `i8x8`, `i16x4`, `i32x2`, `i64x1`, `f32x2`, `f64x1`, <br> `i8x16`, `i16x8`, `i32x4`, `i64x2`, `f32x4`, `f64x2` |
-| AArch64 | `preg` | N/A | Only clobbers |
-| ARM | `reg` | None | `i8`, `i16`, `i32`, `f32` |
-| ARM | `sreg` | `vfp2` | `i32`, `f32` |
-| ARM | `dreg` | `vfp2` | `i64`, `f64`, `i8x8`, `i16x4`, `i32x2`, `i64x1`, `f32x2` |
-| ARM | `qreg` | `neon` | `i8x16`, `i16x8`, `i32x4`, `i64x2`, `f32x4` |
-| MIPS32 | `reg` | None | `i8`, `i16`, `i32`, `f32` |
-| MIPS32 | `freg` | None | `f32`, `f64` |
-| MIPS64 | `reg` | None | `i8`, `i16`, `i32`, `i64`, `f32`, `f64` |
-| MIPS64 | `freg` | None | `f32`, `f64` |
-| NVPTX | `reg16` | None | `i8`, `i16` |
-| NVPTX | `reg32` | None | `i8`, `i16`, `i32`, `f32` |
-| NVPTX | `reg64` | None | `i8`, `i16`, `i32`, `f32`, `i64`, `f64` |
-| RISC-V32 | `reg` | None | `i8`, `i16`, `i32`, `f32` |
-| RISC-V64 | `reg` | None | `i8`, `i16`, `i32`, `f32`, `i64`, `f64` |
-| RISC-V | `freg` | `f` | `f32` |
-| RISC-V | `freg` | `d` | `f64` |
-| RISC-V | `vreg` | N/A | Only clobbers |
-| Hexagon | `reg` | None | `i8`, `i16`, `i32`, `f32` |
-| PowerPC | `reg` | None | `i8`, `i16`, `i32` |
-| PowerPC | `reg_nonzero` | None | `i8`, `i16`, `i32` |
-| PowerPC | `freg` | None | `f32`, `f64` |
-| PowerPC | `cr` | N/A | Only clobbers |
-| PowerPC | `xer` | N/A | Only clobbers |
-| wasm32 | `local` | None | `i8` `i16` `i32` `i64` `f32` `f64` |
-| BPF | `reg` | None | `i8` `i16` `i32` `i64` |
-| BPF | `wreg` | `alu32` | `i8` `i16` `i32` |
-
-> **Note**: For the purposes of the above table pointers, function pointers and `isize`/`usize` are treated as the equivalent integer type (`i16`/`i32`/`i64` depending on the target).
-
-If a value is of a smaller size than the register it is allocated in then the upper bits of that register will have an undefined value for inputs and will be ignored for outputs. The only exception is the `freg` register class on RISC-V where `f32` values are NaN-boxed in a `f64` as required by the RISC-V architecture.
-
-When separate input and output expressions are specified for an `inout` operand, both expressions must have the same type. The only exception is if both operands are pointers or integers, in which case they are only required to have the same size. This restriction exists because the register allocators in LLVM and GCC sometimes cannot handle tied operands with different types.
-
-## Register names
-
-Some registers have multiple names. These are all treated by the compiler as identical to the base register name. Here is the list of all supported register aliases:
-
-| Architecture | Base register | Aliases |
-| ------------ | ------------- | ------- |
-| x86 | `ax` | `eax`, `rax` |
-| x86 | `bx` | `ebx`, `rbx` |
-| x86 | `cx` | `ecx`, `rcx` |
-| x86 | `dx` | `edx`, `rdx` |
-| x86 | `si` | `esi`, `rsi` |
-| x86 | `di` | `edi`, `rdi` |
-| x86 | `bp` | `bpl`, `ebp`, `rbp` |
-| x86 | `sp` | `spl`, `esp`, `rsp` |
-| x86 | `ip` | `eip`, `rip` |
-| x86 | `st(0)` | `st` |
-| x86 | `r[8-15]` | `r[8-15]b`, `r[8-15]w`, `r[8-15]d` |
-| x86 | `xmm[0-31]` | `ymm[0-31]`, `zmm[0-31]` |
-| AArch64 | `x[0-30]` | `w[0-30]` |
-| AArch64 | `x29` | `fp` |
-| AArch64 | `x30` | `lr` |
-| AArch64 | `sp` | `wsp` |
-| AArch64 | `xzr` | `wzr` |
-| AArch64 | `v[0-31]` | `b[0-31]`, `h[0-31]`, `s[0-31]`, `d[0-31]`, `q[0-31]` |
-| ARM | `r[0-3]` | `a[1-4]` |
-| ARM | `r[4-9]` | `v[1-6]` |
-| ARM | `r9` | `rfp` |
-| ARM | `r10` | `sl` |
-| ARM | `r11` | `fp` |
-| ARM | `r12` | `ip` |
-| ARM | `r13` | `sp` |
-| ARM | `r14` | `lr` |
-| ARM | `r15` | `pc` |
-| RISC-V | `x0` | `zero` |
-| RISC-V | `x1` | `ra` |
-| RISC-V | `x2` | `sp` |
-| RISC-V | `x3` | `gp` |
-| RISC-V | `x4` | `tp` |
-| RISC-V | `x[5-7]` | `t[0-2]` |
-| RISC-V | `x8` | `fp`, `s0` |
-| RISC-V | `x9` | `s1` |
-| RISC-V | `x[10-17]` | `a[0-7]` |
-| RISC-V | `x[18-27]` | `s[2-11]` |
-| RISC-V | `x[28-31]` | `t[3-6]` |
-| RISC-V | `f[0-7]` | `ft[0-7]` |
-| RISC-V | `f[8-9]` | `fs[0-1]` |
-| RISC-V | `f[10-17]` | `fa[0-7]` |
-| RISC-V | `f[18-27]` | `fs[2-11]` |
-| RISC-V | `f[28-31]` | `ft[8-11]` |
-| Hexagon | `r29` | `sp` |
-| Hexagon | `r30` | `fr` |
-| Hexagon | `r31` | `lr` |
-| BPF | `r[0-10]` | `w[0-10]` |
-
-Some registers cannot be used for input or output operands:
-
-| Architecture | Unsupported register | Reason |
-| ------------ | -------------------- | ------ |
-| All | `sp` | The stack pointer must be restored to its original value at the end of an asm code block. |
-| All | `bp` (x86), `x29` (AArch64), `x8` (RISC-V), `fr` (Hexagon), `$fp` (MIPS) | The frame pointer cannot be used as an input or output. |
-| ARM | `r7` or `r11` | On ARM the frame pointer can be either `r7` or `r11` depending on the target. The frame pointer cannot be used as an input or output. |
-| All | `si` (x86-32), `bx` (x86-64), `r6` (ARM), `x19` (AArch64), `r19` (Hexagon), `x9` (RISC-V) | This is used internally by LLVM as a "base pointer" for functions with complex stack frames. |
-| x86 | `k0` | This is a constant zero register which can't be modified. |
-| x86 | `ip` | This is the program counter, not a real register. |
-| x86 | `mm[0-7]` | MMX registers are not currently supported (but may be in the future). |
-| x86 | `st([0-7])` | x87 registers are not currently supported (but may be in the future). |
-| AArch64 | `xzr` | This is a constant zero register which can't be modified. |
-| ARM | `pc` | This is the program counter, not a real register. |
-| ARM | `r9` | This is a reserved register on some ARM targets. |
-| MIPS | `$0` or `$zero` | This is a constant zero register which can't be modified. |
-| MIPS | `$1` or `$at` | Reserved for assembler. |
-| MIPS | `$26`/`$k0`, `$27`/`$k1` | OS-reserved registers. |
-| MIPS | `$28`/`$gp` | Global pointer cannot be used as inputs or outputs. |
-| MIPS | `$ra` | Return address cannot be used as inputs or outputs. |
-| RISC-V | `x0` | This is a constant zero register which can't be modified. |
-| RISC-V | `gp`, `tp` | These registers are reserved and cannot be used as inputs or outputs. |
-| Hexagon | `lr` | This is the link register which cannot be used as an input or output. |
-
-In some cases LLVM will allocate a "reserved register" for `reg` operands even though this register cannot be explicitly specified. Assembly code making use of reserved registers should be careful since `reg` operands may alias with those registers. Reserved registers are the frame pointer and base pointer
-- The frame pointer and LLVM base pointer on all architectures.
-- `r9` on ARM.
-- `x18` on AArch64.
-
-## Template modifiers
-
-The placeholders can be augmented by modifiers which are specified after the `:` in the curly braces. These modifiers do not affect register allocation, but change the way operands are formatted when inserted into the template string. Only one modifier is allowed per template placeholder.
-
-The supported modifiers are a subset of LLVM's (and GCC's) [asm template argument modifiers][llvm-argmod], but do not use the same letter codes.
-
-| Architecture | Register class | Modifier | Example output | LLVM modifier |
-| ------------ | -------------- | -------- | -------------- | ------------- |
-| x86-32 | `reg` | None | `eax` | `k` |
-| x86-64 | `reg` | None | `rax` | `q` |
-| x86-32 | `reg_abcd` | `l` | `al` | `b` |
-| x86-64 | `reg` | `l` | `al` | `b` |
-| x86 | `reg_abcd` | `h` | `ah` | `h` |
-| x86 | `reg` | `x` | `ax` | `w` |
-| x86 | `reg` | `e` | `eax` | `k` |
-| x86-64 | `reg` | `r` | `rax` | `q` |
-| x86 | `reg_byte` | None | `al` / `ah` | None |
-| x86 | `xmm_reg` | None | `xmm0` | `x` |
-| x86 | `ymm_reg` | None | `ymm0` | `t` |
-| x86 | `zmm_reg` | None | `zmm0` | `g` |
-| x86 | `*mm_reg` | `x` | `xmm0` | `x` |
-| x86 | `*mm_reg` | `y` | `ymm0` | `t` |
-| x86 | `*mm_reg` | `z` | `zmm0` | `g` |
-| x86 | `kreg` | None | `k1` | None |
-| AArch64 | `reg` | None | `x0` | `x` |
-| AArch64 | `reg` | `w` | `w0` | `w` |
-| AArch64 | `reg` | `x` | `x0` | `x` |
-| AArch64 | `vreg` | None | `v0` | None |
-| AArch64 | `vreg` | `v` | `v0` | None |
-| AArch64 | `vreg` | `b` | `b0` | `b` |
-| AArch64 | `vreg` | `h` | `h0` | `h` |
-| AArch64 | `vreg` | `s` | `s0` | `s` |
-| AArch64 | `vreg` | `d` | `d0` | `d` |
-| AArch64 | `vreg` | `q` | `q0` | `q` |
-| ARM | `reg` | None | `r0` | None |
-| ARM | `sreg` | None | `s0` | None |
-| ARM | `dreg` | None | `d0` | `P` |
-| ARM | `qreg` | None | `q0` | `q` |
-| ARM | `qreg` | `e` / `f` | `d0` / `d1` | `e` / `f` |
-| MIPS | `reg` | None | `$2` | None |
-| MIPS | `freg` | None | `$f0` | None |
-| NVPTX | `reg16` | None | `rs0` | None |
-| NVPTX | `reg32` | None | `r0` | None |
-| NVPTX | `reg64` | None | `rd0` | None |
-| RISC-V | `reg` | None | `x1` | None |
-| RISC-V | `freg` | None | `f0` | None |
-| Hexagon | `reg` | None | `r0` | None |
-| PowerPC | `reg` | None | `0` | None |
-| PowerPC | `reg_nonzero` | None | `3` | `b` |
-| PowerPC | `freg` | None | `0` | None |
-
-> Notes:
-> - on ARM `e` / `f`: this prints the low or high doubleword register name of a NEON quad (128-bit) register.
-> - on x86: our behavior for `reg` with no modifiers differs from what GCC does. GCC will infer the modifier based on the operand value type, while we default to the full register size.
-> - on x86 `xmm_reg`: the `x`, `t` and `g` LLVM modifiers are not yet implemented in LLVM (they are supported by GCC only), but this should be a simple change.
-
-As stated in the previous section, passing an input value smaller than the register width will result in the upper bits of the register containing undefined values. This is not a problem if the inline asm only accesses the lower bits of the register, which can be done by using a template modifier to use a subregister name in the asm code (e.g. `ax` instead of `rax`). Since this an easy pitfall, the compiler will suggest a template modifier to use where appropriate given the input type. If all references to an operand already have modifiers then the warning is suppressed for that operand.
-
-[llvm-argmod]: http://llvm.org/docs/LangRef.html#asm-template-argument-modifiers
-
-## ABI clobbers
-
-The `clobber_abi` keyword can be used to apply a default set of clobbers to an `asm` block. This will automatically insert the necessary clobber constraints as needed for calling a function with a particular calling convention: if the calling convention does not fully preserve the value of a register across a call then a `lateout("reg") _` is implicitly added to the operands list.
-
-`clobber_abi` may be specified any number of times. It will insert a clobber for all unique registers in the union of all specified calling conventions.
-
-Generic register class outputs are disallowed by the compiler when `clobber_abi` is used: all outputs must specify an explicit register. Explicit register outputs have precedence over the implicit clobbers inserted by `clobber_abi`: a clobber will only be inserted for a register if that register is not used as an output.
-The following ABIs can be used with `clobber_abi`:
-
-| Architecture | ABI name | Clobbered registers |
-| ------------ | -------- | ------------------- |
-| x86-32 | `"C"`, `"system"`, `"efiapi"`, `"cdecl"`, `"stdcall"`, `"fastcall"` | `ax`, `cx`, `dx`, `xmm[0-7]`, `mm[0-7]`, `k[1-7]`, `st([0-7])` |
-| x86-64 | `"C"`, `"system"` (on Windows), `"efiapi"`, `"win64"` | `ax`, `cx`, `dx`, `r[8-11]`, `xmm[0-31]`, `mm[0-7]`, `k[1-7]`, `st([0-7])` |
-| x86-64 | `"C"`, `"system"` (on non-Windows), `"sysv64"` | `ax`, `cx`, `dx`, `si`, `di`, `r[8-11]`, `xmm[0-31]`, `mm[0-7]`, `k[1-7]`, `st([0-7])` |
-| AArch64 | `"C"`, `"system"`, `"efiapi"` | `x[0-17]`, `x30`, `v[0-31]`, `p[0-15]`, `ffr` |
-| ARM | `"C"`, `"system"`, `"efiapi"`, `"aapcs"` | `r[0-3]`, `r12`, `r14`, `s[0-15]`, `d[0-7]`, `d[16-31]` |
-| RISC-V | `"C"`, `"system"`, `"efiapi"` | `x1`, `x[5-7]`, `x[10-17]`, `x[28-31]`, `f[0-7]`, `f[10-17]`, `f[28-31]`, `v[0-31]` |
-
-The list of clobbered registers for each ABI is updated in rustc as architectures gain new registers: this ensures that `asm` clobbers will continue to be correct when LLVM starts using these new registers in its generated code.
-
-## Options
-
-Flags are used to further influence the behavior of the inline assembly block.
-Currently the following options are defined:
-- `pure`: The `asm` block has no side effects, and its outputs depend only on its direct inputs (i.e. the values themselves, not what they point to) or values read from memory (unless the `nomem` options is also set). This allows the compiler to execute the `asm` block fewer times than specified in the program (e.g. by hoisting it out of a loop) or even eliminate it entirely if the outputs are not used.
-- `nomem`: The `asm` blocks does not read or write to any memory. This allows the compiler to cache the values of modified global variables in registers across the `asm` block since it knows that they are not read or written to by the `asm`.
-- `readonly`: The `asm` block does not write to any memory. This allows the compiler to cache the values of unmodified global variables in registers across the `asm` block since it knows that they are not written to by the `asm`.
-- `preserves_flags`: The `asm` block does not modify the flags register (defined in the rules below). This allows the compiler to avoid recomputing the condition flags after the `asm` block.
-- `noreturn`: The `asm` block never returns, and its return type is defined as `!` (never). Behavior is undefined if execution falls through past the end of the asm code. A `noreturn` asm block behaves just like a function which doesn't return; notably, local variables in scope are not dropped before it is invoked.
-- `nostack`: The `asm` block does not push data to the stack, or write to the stack red-zone (if supported by the target). If this option is *not* used then the stack pointer is guaranteed to be suitably aligned (according to the target ABI) for a function call.
-- `att_syntax`: This option is only valid on x86, and causes the assembler to use the `.att_syntax prefix` mode of the GNU assembler. Register operands are substituted in with a leading `%`.
-- `raw`: This causes the template string to be parsed as a raw assembly string, with no special handling for `{` and `}`. This is primarily useful when including raw assembly code from an external file using `include_str!`.
-
-The compiler performs some additional checks on options:
-- The `nomem` and `readonly` options are mutually exclusive: it is a compile-time error to specify both.
-- The `pure` option must be combined with either the `nomem` or `readonly` options, otherwise a compile-time error is emitted.
-- It is a compile-time error to specify `pure` on an asm block with no outputs or only discarded outputs (`_`).
-- It is a compile-time error to specify `noreturn` on an asm block with outputs.
-
-## Rules for inline assembly
-
-- Any registers not specified as inputs will contain an undefined value on entry to the asm block.
- - An "undefined value" in the context of inline assembly means that the register can (non-deterministically) have any one of the possible values allowed by the architecture. Notably it is not the same as an LLVM `undef` which can have a different value every time you read it (since such a concept does not exist in assembly code).
-- Any registers not specified as outputs must have the same value upon exiting the asm block as they had on entry, otherwise behavior is undefined.
- - This only applies to registers which can be specified as an input or output. Other registers follow target-specific rules.
- - Note that a `lateout` may be allocated to the same register as an `in`, in which case this rule does not apply. Code should not rely on this however since it depends on the results of register allocation.
-- Behavior is undefined if execution unwinds out of an asm block.
- - This also applies if the assembly code calls a function which then unwinds.
-- The set of memory locations that assembly code is allowed to read and write are the same as those allowed for an FFI function.
- - Refer to the unsafe code guidelines for the exact rules.
- - If the `readonly` option is set, then only memory reads are allowed.
- - If the `nomem` option is set then no reads or writes to memory are allowed.
- - These rules do not apply to memory which is private to the asm code, such as stack space allocated within the asm block.
-- The compiler cannot assume that the instructions in the asm are the ones that will actually end up executed.
- - This effectively means that the compiler must treat the `asm!` as a black box and only take the interface specification into account, not the instructions themselves.
- - Runtime code patching is allowed, via target-specific mechanisms (outside the scope of this RFC).
-- Unless the `nostack` option is set, asm code is allowed to use stack space below the stack pointer.
- - On entry to the asm block the stack pointer is guaranteed to be suitably aligned (according to the target ABI) for a function call.
- - You are responsible for making sure you don't overflow the stack (e.g. use stack probing to ensure you hit a guard page).
- - You should adjust the stack pointer when allocating stack memory as required by the target ABI.
- - The stack pointer must be restored to its original value before leaving the asm block.
-- If the `noreturn` option is set then behavior is undefined if execution falls through to the end of the asm block.
-- If the `pure` option is set then behavior is undefined if the `asm` has side-effects other than its direct outputs. Behavior is also undefined if two executions of the `asm` code with the same inputs result in different outputs.
- - When used with the `nomem` option, "inputs" are just the direct inputs of the `asm!`.
- - When used with the `readonly` option, "inputs" comprise the direct inputs of the `asm!` and any memory that the `asm!` block is allowed to read.
-- These flags registers must be restored upon exiting the asm block if the `preserves_flags` option is set:
- - x86
- - Status flags in `EFLAGS` (CF, PF, AF, ZF, SF, OF).
- - Floating-point status word (all).
- - Floating-point exception flags in `MXCSR` (PE, UE, OE, ZE, DE, IE).
- - ARM
- - Condition flags in `CPSR` (N, Z, C, V)
- - Saturation flag in `CPSR` (Q)
- - Greater than or equal flags in `CPSR` (GE).
- - Condition flags in `FPSCR` (N, Z, C, V)
- - Saturation flag in `FPSCR` (QC)
- - Floating-point exception flags in `FPSCR` (IDC, IXC, UFC, OFC, DZC, IOC).
- - AArch64
- - Condition flags (`NZCV` register).
- - Floating-point status (`FPSR` register).
- - RISC-V
- - Floating-point exception flags in `fcsr` (`fflags`).
- - Vector extension state (`vtype`, `vl`, `vcsr`).
-- On x86, the direction flag (DF in `EFLAGS`) is clear on entry to an asm block and must be clear on exit.
- - Behavior is undefined if the direction flag is set on exiting an asm block.
-- The requirement of restoring the stack pointer and non-output registers to their original value only applies when exiting an `asm!` block.
- - This means that `asm!` blocks that never return (even if not marked `noreturn`) don't need to preserve these registers.
- - When returning to a different `asm!` block than you entered (e.g. for context switching), these registers must contain the value they had upon entering the `asm!` block that you are *exiting*.
- - You cannot exit an `asm!` block that has not been entered. Neither can you exit an `asm!` block that has already been exited.
- - You are responsible for switching any target-specific state (e.g. thread-local storage, stack bounds).
- - The set of memory locations that you may access is the intersection of those allowed by the `asm!` blocks you entered and exited.
-- You cannot assume that an `asm!` block will appear exactly once in the output binary. The compiler is allowed to instantiate multiple copies of the `asm!` block, for example when the function containing it is inlined in multiple places.
-- On x86, inline assembly must not end with an instruction prefix (such as `LOCK`) that would apply to instructions generated by the compiler.
- - The compiler is currently unable to detect this due to the way inline assembly is compiled, but may catch and reject this in the future.
-
-> **Note**: As a general rule, the flags covered by `preserves_flags` are those which are *not* preserved when performing a function call.
diff --git a/src/doc/unstable-book/src/library-features/global-asm.md b/src/doc/unstable-book/src/library-features/global-asm.md
deleted file mode 100644
index 3f8e165841d..00000000000
--- a/src/doc/unstable-book/src/library-features/global-asm.md
+++ /dev/null
@@ -1,113 +0,0 @@
-# `global_asm`
-
-The tracking issue for this feature is: [#35119]
-
-[#35119]: https://github.com/rust-lang/rust/issues/35119
-
-------------------------
-
-The `global_asm!` macro allows the programmer to write arbitrary
-assembly outside the scope of a function body, passing it through
-`rustc` and `llvm` to the assembler. That is to say, `global_asm!` is
-equivalent to assembling the asm with an external assembler and then
-linking the resulting object file with the current crate.
-
-`global_asm!` fills a role not currently satisfied by either `asm!`
-or `#[naked]` functions. The programmer has _all_ features of the
-assembler at their disposal. The linker will expect to resolve any
-symbols defined in the inline assembly, modulo any symbols marked as
-external. It also means syntax for directives and assembly follow the
-conventions of the assembler in your toolchain.
-
-A simple usage looks like this:
-
-```rust,ignore (requires-external-file)
-#![feature(global_asm)]
-# // you also need relevant target_arch cfgs
-global_asm!(include_str!("something_neato.s"));
-```
-
-And a more complicated usage looks like this:
-
-```rust,no_run
-#![feature(global_asm)]
-# #[cfg(any(target_arch="x86", target_arch="x86_64"))]
-# mod x86 {
-
-pub mod sally {
- global_asm!(
- ".global foo",
- "foo:",
- "jmp baz",
- );
-
- #[no_mangle]
- pub unsafe extern "C" fn baz() {}
-}
-
-// the symbols `foo` and `bar` are global, no matter where
-// `global_asm!` was used.
-extern "C" {
- fn foo();
- fn bar();
-}
-
-pub mod harry {
- global_asm!(
- ".global bar",
- "bar:",
- "jmp quux",
- );
-
- #[no_mangle]
- pub unsafe extern "C" fn quux() {}
-}
-# }
-```
-
-You may use `global_asm!` multiple times, anywhere in your crate, in
-whatever way suits you. However, you should not rely on assembler state
-(e.g. assembler macros) defined in one `global_asm!` to be available in
-another one. It is implementation-defined whether the multiple usages
-are concatenated into one or assembled separately.
-
-`global_asm!` also supports `const` operands like `asm!`, which allows
-constants defined in Rust to be used in assembly code:
-
-```rust,no_run
-#![feature(global_asm, asm_const)]
-# #[cfg(any(target_arch="x86", target_arch="x86_64"))]
-# mod x86 {
-const C: i32 = 1234;
-global_asm!(
- ".global bar",
- "bar: .word {c}",
- c = const C,
-);
-# }
-```
-
-The syntax for passing operands is the same as `asm!` except that only
-`const` operands are allowed. Refer to the [asm](asm.md) documentation
-for more details.
-
-On x86, the assembly code will use intel syntax by default. You can
-override this by adding `options(att_syntax)` at the end of the macro
-arguments list:
-
-```rust,no_run
-#![feature(global_asm, asm_const)]
-# #[cfg(any(target_arch="x86", target_arch="x86_64"))]
-# mod x86 {
-global_asm!("movl ${}, %ecx", const 5, options(att_syntax));
-// is equivalent to
-global_asm!("mov ecx, {}", const 5);
-# }
-```
-
-------------------------
-
-If you don't need quite as much power and flexibility as
-`global_asm!` provides, and you don't mind restricting your inline
-assembly to `fn` bodies only, you might try the
-[asm](asm.md) feature instead.
diff --git a/src/doc/unstable-book/src/library-features/llvm-asm.md b/src/doc/unstable-book/src/library-features/llvm-asm.md
index 07fc16261d8..094124998b6 100644
--- a/src/doc/unstable-book/src/library-features/llvm-asm.md
+++ b/src/doc/unstable-book/src/library-features/llvm-asm.md
@@ -188,6 +188,3 @@ documentation as well][llvm-docs] for more information about clobbers,
constraints, etc.
[llvm-docs]: http://llvm.org/docs/LangRef.html#inline-assembler-expressions
-
-If you need more power and don't mind losing some of the niceties of
-`llvm_asm!`, check out [global_asm](global-asm.md).
diff --git a/src/etc/htmldocck.py b/src/etc/htmldocck.py
index 8647db5a45d..48a341ffe08 100644
--- a/src/etc/htmldocck.py
+++ b/src/etc/htmldocck.py
@@ -90,10 +90,20 @@ There are a number of supported commands:
highlights for example. If you want to simply check for the presence of
a given node or attribute, use an empty string (`""`) as a `PATTERN`.
-* `@count PATH XPATH COUNT' checks for the occurrence of the given XPath
+* `@count PATH XPATH COUNT` checks for the occurrence of the given XPath
in the specified file. The number of occurrences must match the given
count.
+* `@snapshot NAME PATH XPATH` creates a snapshot test named NAME.
+ A snapshot test captures a subtree of the DOM, at the location
+ determined by the XPath, and compares it to a pre-recorded value
+ in a file. The file's name is the test's name with the `.rs` extension
+ replaced with `.NAME.html`, where NAME is the snapshot's name.
+
+ htmldocck supports the `--bless` option to accept the current subtree
+ as expected, saving it to the file determined by the snapshot's name.
+ compiletest's `--bless` flag is forwarded to htmldocck.
+
* `@has-dir PATH` checks for the existence of the given directory.
All conditions can be negated with `!`. `@!has foo/type.NoSuch.html`
@@ -137,6 +147,10 @@ except NameError:
channel = os.environ["DOC_RUST_LANG_ORG_CHANNEL"]
+# Initialized in main
+rust_test_path = None
+bless = None
+
class CustomHTMLParser(HTMLParser):
"""simplified HTML parser.
@@ -387,6 +401,32 @@ def get_tree_count(tree, path):
return len(tree.findall(path))
+def check_snapshot(snapshot_name, tree):
+ assert rust_test_path.endswith('.rs')
+ snapshot_path = '{}.{}.{}'.format(rust_test_path[:-3], snapshot_name, 'html')
+ try:
+ with open(snapshot_path, 'r') as snapshot_file:
+ expected_str = snapshot_file.read()
+ except FileNotFoundError:
+ if bless:
+ expected_str = None
+ else:
+ raise FailedCheck('No saved snapshot value')
+
+ actual_str = ET.tostring(tree).decode('utf-8')
+
+ if expected_str != actual_str:
+ if bless:
+ with open(snapshot_path, 'w') as snapshot_file:
+ snapshot_file.write(actual_str)
+ else:
+ print('--- expected ---\n')
+ print(expected_str)
+ print('\n\n--- actual ---\n')
+ print(actual_str)
+ print()
+ raise FailedCheck('Actual snapshot value is different than expected')
+
def stderr(*args):
if sys.version_info.major < 3:
file = codecs.getwriter('utf-8')(sys.stderr)
@@ -448,6 +488,28 @@ def check_command(c, cache):
ret = expected == found
else:
raise InvalidCheck('Invalid number of @{} arguments'.format(c.cmd))
+
+ elif c.cmd == 'snapshot': # snapshot test
+ if len(c.args) == 3: # @snapshot <snapshot-name> <html-path> <xpath>
+ [snapshot_name, html_path, pattern] = c.args
+ tree = cache.get_tree(html_path)
+ xpath = normalize_xpath(pattern)
+ subtrees = tree.findall(xpath)
+ if len(subtrees) == 1:
+ [subtree] = subtrees
+ try:
+ check_snapshot(snapshot_name, subtree)
+ ret = True
+ except FailedCheck as err:
+ cerr = str(err)
+ ret = False
+ elif len(subtrees) == 0:
+ raise FailedCheck('XPATH did not match')
+ else:
+ raise FailedCheck('Expected 1 match, but found {}'.format(len(subtrees)))
+ else:
+ raise InvalidCheck('Invalid number of @{} arguments'.format(c.cmd))
+
elif c.cmd == 'has-dir': # has-dir test
if len(c.args) == 1: # @has-dir <path> = has-dir test
try:
@@ -458,11 +520,13 @@ def check_command(c, cache):
ret = False
else:
raise InvalidCheck('Invalid number of @{} arguments'.format(c.cmd))
+
elif c.cmd == 'valid-html':
raise InvalidCheck('Unimplemented @valid-html')
elif c.cmd == 'valid-links':
raise InvalidCheck('Unimplemented @valid-links')
+
else:
raise InvalidCheck('Unrecognized @{}'.format(c.cmd))
@@ -483,11 +547,19 @@ def check(target, commands):
if __name__ == '__main__':
- if len(sys.argv) != 3:
- stderr('Usage: {} <doc dir> <template>'.format(sys.argv[0]))
+ if len(sys.argv) not in [3, 4]:
+ stderr('Usage: {} <doc dir> <template> [--bless]'.format(sys.argv[0]))
raise SystemExit(1)
- check(sys.argv[1], get_commands(sys.argv[2]))
+ rust_test_path = sys.argv[2]
+ if len(sys.argv) > 3 and sys.argv[3] == '--bless':
+ bless = True
+ else:
+ # We only support `--bless` at the end of the arguments.
+ # This assert is to prevent silent failures.
+ assert '--bless' not in sys.argv
+ bless = False
+ check(sys.argv[1], get_commands(rust_test_path))
if ERR_COUNT:
stderr("\nEncountered {} errors".format(ERR_COUNT))
raise SystemExit(1)
diff --git a/src/librustdoc/clean/auto_trait.rs b/src/librustdoc/clean/auto_trait.rs
index 2ccf17387d1..09692d27e8f 100644
--- a/src/librustdoc/clean/auto_trait.rs
+++ b/src/librustdoc/clean/auto_trait.rs
@@ -100,9 +100,12 @@ impl<'a, 'tcx> AutoTraitFinder<'a, 'tcx> {
// Instead, we generate `impl !Send for Foo<T>`, which better
// expresses the fact that `Foo<T>` never implements `Send`,
// regardless of the choice of `T`.
- let params = (tcx.generics_of(item_def_id), ty::GenericPredicates::default())
- .clean(self.cx)
- .params;
+ let raw_generics = clean_ty_generics(
+ self.cx,
+ tcx.generics_of(item_def_id),
+ ty::GenericPredicates::default(),
+ );
+ let params = raw_generics.params;
Generics { params, where_predicates: Vec::new() }
}
@@ -451,10 +454,12 @@ impl<'a, 'tcx> AutoTraitFinder<'a, 'tcx> {
})
.map(|p| p.fold_with(&mut replacer));
- let mut generic_params =
- (tcx.generics_of(item_def_id), tcx.explicit_predicates_of(item_def_id))
- .clean(self.cx)
- .params;
+ let raw_generics = clean_ty_generics(
+ self.cx,
+ tcx.generics_of(item_def_id),
+ tcx.explicit_predicates_of(item_def_id),
+ );
+ let mut generic_params = raw_generics.params;
debug!("param_env_to_generics({:?}): generic_params={:?}", item_def_id, generic_params);
@@ -500,7 +505,7 @@ impl<'a, 'tcx> AutoTraitFinder<'a, 'tcx> {
.and_then(|trait_| {
ty_to_traits
.get(&ty)
- .map(|bounds| bounds.contains(&strip_path_generics(trait_.clone())))
+ .map(|bounds| bounds.contains(&strip_path_generics(trait_)))
})
.unwrap_or(false)
{
diff --git a/src/librustdoc/clean/blanket_impl.rs b/src/librustdoc/clean/blanket_impl.rs
index f44589f6067..dca02cb25bd 100644
--- a/src/librustdoc/clean/blanket_impl.rs
+++ b/src/librustdoc/clean/blanket_impl.rs
@@ -3,7 +3,7 @@ use rustc_hir as hir;
use rustc_infer::infer::{InferOk, TyCtxtInferExt};
use rustc_infer::traits;
use rustc_middle::ty::subst::Subst;
-use rustc_middle::ty::{ToPredicate, WithConstness};
+use rustc_middle::ty::ToPredicate;
use rustc_span::DUMMY_SP;
use super::*;
@@ -66,7 +66,8 @@ impl<'a, 'tcx> BlanketImplFinder<'a, 'tcx> {
.into_iter()
.chain(Some(
ty::Binder::dummy(trait_ref)
- .without_const()
+ .to_poly_trait_predicate()
+ .map_bound(ty::PredicateKind::Trait)
.to_predicate(infcx.tcx),
));
for predicate in predicates {
@@ -107,11 +108,11 @@ impl<'a, 'tcx> BlanketImplFinder<'a, 'tcx> {
def_id: ItemId::Blanket { impl_id: impl_def_id, for_: item_def_id },
kind: box ImplItem(Impl {
unsafety: hir::Unsafety::Normal,
- generics: (
+ generics: clean_ty_generics(
+ self.cx,
self.cx.tcx.generics_of(impl_def_id),
self.cx.tcx.explicit_predicates_of(impl_def_id),
- )
- .clean(self.cx),
+ ),
// FIXME(eddyb) compute both `trait_` and `for_` from
// the post-inference `trait_ref`, as it's more accurate.
trait_: Some(trait_ref.clean(self.cx)),
diff --git a/src/librustdoc/clean/inline.rs b/src/librustdoc/clean/inline.rs
index d4bf93bb409..57621f4f18c 100644
--- a/src/librustdoc/clean/inline.rs
+++ b/src/librustdoc/clean/inline.rs
@@ -8,6 +8,7 @@ use rustc_data_structures::fx::FxHashSet;
use rustc_hir as hir;
use rustc_hir::def::{DefKind, Res};
use rustc_hir::def_id::DefId;
+use rustc_hir::definitions::DefPathData;
use rustc_hir::Mutability;
use rustc_metadata::creader::{CStore, LoadedMacro};
use rustc_middle::ty::{self, TyCtxt};
@@ -15,13 +16,12 @@ use rustc_span::hygiene::MacroKind;
use rustc_span::symbol::{kw, sym, Symbol};
use crate::clean::{
- self, utils, Attributes, AttributesExt, ImplKind, ItemId, NestedAttributesExt, Type,
+ self, clean_fn_decl_from_did_and_sig, clean_ty_generics, utils, Attributes, AttributesExt,
+ Clean, ImplKind, ItemId, NestedAttributesExt, Type, Visibility,
};
use crate::core::DocContext;
use crate::formats::item_type::ItemType;
-use super::{Clean, Visibility};
-
type Attrs<'hir> = rustc_middle::ty::Attributes<'hir>;
/// Attempt to inline a definition into this AST.
@@ -166,9 +166,8 @@ crate fn record_extern_fqn(cx: &mut DocContext<'_>, did: DefId, kind: ItemType)
let crate_name = cx.tcx.crate_name(did.krate).to_string();
let relative = cx.tcx.def_path(did).data.into_iter().filter_map(|elem| {
- // extern blocks have an empty name
- let s = elem.data.to_string();
- if !s.is_empty() { Some(s) } else { None }
+ // Filter out extern blocks
+ (elem.data != DefPathData::ForeignMod).then(|| elem.data.to_string())
});
let fqn = if let ItemType::Macro = kind {
// Check to see if it is a macro 2.0 or built-in macro
@@ -208,7 +207,7 @@ crate fn build_external_trait(cx: &mut DocContext<'_>, did: DefId) -> clean::Tra
.collect();
let predicates = cx.tcx.predicates_of(did);
- let generics = (cx.tcx.generics_of(did), predicates).clean(cx);
+ let generics = clean_ty_generics(cx, cx.tcx.generics_of(did), predicates);
let generics = filter_non_trait_generics(did, generics);
let (generics, supertrait_bounds) = separate_supertrait_bounds(generics);
let is_auto = cx.tcx.trait_is_auto(did);
@@ -230,7 +229,9 @@ fn build_external_function(cx: &mut DocContext<'_>, did: DefId) -> clean::Functi
let predicates = cx.tcx.predicates_of(did);
let (generics, decl) = clean::enter_impl_trait(cx, |cx| {
// NOTE: generics need to be cleaned before the decl!
- ((cx.tcx.generics_of(did), predicates).clean(cx), (did, sig).clean(cx))
+ let generics = clean_ty_generics(cx, cx.tcx.generics_of(did), predicates);
+ let decl = clean_fn_decl_from_did_and_sig(cx, did, sig);
+ (generics, decl)
});
clean::Function {
decl,
@@ -243,7 +244,7 @@ fn build_enum(cx: &mut DocContext<'_>, did: DefId) -> clean::Enum {
let predicates = cx.tcx.explicit_predicates_of(did);
clean::Enum {
- generics: (cx.tcx.generics_of(did), predicates).clean(cx),
+ generics: clean_ty_generics(cx, cx.tcx.generics_of(did), predicates),
variants_stripped: false,
variants: cx.tcx.adt_def(did).variants.iter().map(|v| v.clean(cx)).collect(),
}
@@ -255,7 +256,7 @@ fn build_struct(cx: &mut DocContext<'_>, did: DefId) -> clean::Struct {
clean::Struct {
struct_type: variant.ctor_kind,
- generics: (cx.tcx.generics_of(did), predicates).clean(cx),
+ generics: clean_ty_generics(cx, cx.tcx.generics_of(did), predicates),
fields: variant.fields.iter().map(|x| x.clean(cx)).collect(),
fields_stripped: false,
}
@@ -265,7 +266,7 @@ fn build_union(cx: &mut DocContext<'_>, did: DefId) -> clean::Union {
let predicates = cx.tcx.explicit_predicates_of(did);
let variant = cx.tcx.adt_def(did).non_enum_variant();
- let generics = (cx.tcx.generics_of(did), predicates).clean(cx);
+ let generics = clean_ty_generics(cx, cx.tcx.generics_of(did), predicates);
let fields = variant.fields.iter().map(|x| x.clean(cx)).collect();
clean::Union { generics, fields, fields_stripped: false }
}
@@ -276,7 +277,7 @@ fn build_type_alias(cx: &mut DocContext<'_>, did: DefId) -> clean::Typedef {
clean::Typedef {
type_,
- generics: (cx.tcx.generics_of(did), predicates).clean(cx),
+ generics: clean_ty_generics(cx, cx.tcx.generics_of(did), predicates),
item_type: None,
}
}
@@ -359,13 +360,10 @@ crate fn build_impl(
}
let impl_item = match did.as_local() {
- Some(did) => {
- let hir_id = tcx.hir().local_def_id_to_hir_id(did);
- match &tcx.hir().expect_item(hir_id).kind {
- hir::ItemKind::Impl(impl_) => Some(impl_),
- _ => panic!("`DefID` passed to `build_impl` is not an `impl"),
- }
- }
+ Some(did) => match &tcx.hir().expect_item(did).kind {
+ hir::ItemKind::Impl(impl_) => Some(impl_),
+ _ => panic!("`DefID` passed to `build_impl` is not an `impl"),
+ },
None => None,
};
@@ -443,7 +441,9 @@ crate fn build_impl(
}
})
.collect::<Vec<_>>(),
- clean::enter_impl_trait(cx, |cx| (tcx.generics_of(did), predicates).clean(cx)),
+ clean::enter_impl_trait(cx, |cx| {
+ clean_ty_generics(cx, tcx.generics_of(did), predicates)
+ }),
),
};
let polarity = tcx.impl_polarity(did);
diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs
index cd99d5bbe79..2b4466d4041 100644
--- a/src/librustdoc/clean/mod.rs
+++ b/src/librustdoc/clean/mod.rs
@@ -31,6 +31,7 @@ use rustc_typeck::hir_ty_to_ty;
use std::assert_matches::assert_matches;
use std::collections::hash_map::Entry;
+use std::collections::BTreeMap;
use std::default::Default;
use std::hash::Hash;
use std::{mem, vec};
@@ -41,14 +42,8 @@ use crate::visit_ast::Module as DocModule;
use utils::*;
-crate use utils::{get_auto_trait_and_blanket_impls, krate, register_res};
-
-crate use self::types::FnRetTy::*;
-crate use self::types::ItemKind::*;
-crate use self::types::SelfTy::*;
-crate use self::types::Type::*;
-crate use self::types::Visibility::{Inherited, Public};
crate use self::types::*;
+crate use self::utils::{get_auto_trait_and_blanket_impls, krate, register_res};
crate trait Clean<T> {
fn clean(&self, cx: &mut DocContext<'_>) -> T;
@@ -57,9 +52,17 @@ crate trait Clean<T> {
impl Clean<Item> for DocModule<'_> {
fn clean(&self, cx: &mut DocContext<'_>) -> Item {
let mut items: Vec<Item> = vec![];
- items.extend(self.foreigns.iter().map(|x| x.clean(cx)));
+ items.extend(
+ self.foreigns
+ .iter()
+ .map(|(item, renamed)| clean_maybe_renamed_foreign_item(cx, item, *renamed)),
+ );
items.extend(self.mods.iter().map(|x| x.clean(cx)));
- items.extend(self.items.iter().map(|x| x.clean(cx)).flatten());
+ items.extend(
+ self.items
+ .iter()
+ .flat_map(|(item, renamed)| clean_maybe_renamed_item(cx, item, *renamed)),
+ );
// determine if we should display the inner contents or
// the outer `mod` item for the source code.
@@ -108,11 +111,9 @@ impl Clean<GenericBound> for hir::GenericBound<'_> {
_ => bug!("clean: parenthesized `GenericBound::LangItemTrait`"),
};
+ let trait_ = clean_trait_ref_with_bindings(cx, trait_ref, &bindings);
GenericBound::TraitBound(
- PolyTrait {
- trait_: (trait_ref, &bindings[..]).clean(cx),
- generic_params: vec![],
- },
+ PolyTrait { trait_, generic_params: vec![] },
hir::TraitBoundModifier::None,
)
}
@@ -123,64 +124,60 @@ impl Clean<GenericBound> for hir::GenericBound<'_> {
}
}
-impl Clean<Path> for (ty::TraitRef<'_>, &[TypeBinding]) {
- fn clean(&self, cx: &mut DocContext<'_>) -> Path {
- let (trait_ref, bounds) = *self;
- let kind = cx.tcx.def_kind(trait_ref.def_id).into();
- if !matches!(kind, ItemType::Trait | ItemType::TraitAlias) {
- span_bug!(
- cx.tcx.def_span(trait_ref.def_id),
- "`TraitRef` had unexpected kind {:?}",
- kind
- );
- }
- inline::record_extern_fqn(cx, trait_ref.def_id, kind);
- let path = external_path(cx, trait_ref.def_id, true, bounds.to_vec(), trait_ref.substs);
+fn clean_trait_ref_with_bindings(
+ cx: &mut DocContext<'_>,
+ trait_ref: ty::TraitRef<'_>,
+ bindings: &[TypeBinding],
+) -> Path {
+ let kind = cx.tcx.def_kind(trait_ref.def_id).into();
+ if !matches!(kind, ItemType::Trait | ItemType::TraitAlias) {
+ span_bug!(cx.tcx.def_span(trait_ref.def_id), "`TraitRef` had unexpected kind {:?}", kind);
+ }
+ inline::record_extern_fqn(cx, trait_ref.def_id, kind);
+ let path = external_path(cx, trait_ref.def_id, true, bindings.to_vec(), trait_ref.substs);
- debug!("ty::TraitRef\n subst: {:?}\n", trait_ref.substs);
+ debug!("ty::TraitRef\n subst: {:?}\n", trait_ref.substs);
- path
- }
+ path
}
impl Clean<Path> for ty::TraitRef<'tcx> {
fn clean(&self, cx: &mut DocContext<'_>) -> Path {
- (*self, &[][..]).clean(cx)
+ clean_trait_ref_with_bindings(cx, *self, &[])
}
}
-impl Clean<GenericBound> for (ty::PolyTraitRef<'_>, &[TypeBinding]) {
- fn clean(&self, cx: &mut DocContext<'_>) -> GenericBound {
- let (poly_trait_ref, bounds) = *self;
- let poly_trait_ref = poly_trait_ref.lift_to_tcx(cx.tcx).unwrap();
-
- // collect any late bound regions
- let late_bound_regions: Vec<_> = cx
- .tcx
- .collect_referenced_late_bound_regions(&poly_trait_ref)
- .into_iter()
- .filter_map(|br| match br {
- ty::BrNamed(_, name) => Some(GenericParamDef {
- name,
- kind: GenericParamDefKind::Lifetime { outlives: vec![] },
- }),
- _ => None,
- })
- .collect();
+fn clean_poly_trait_ref_with_bindings(
+ cx: &mut DocContext<'_>,
+ poly_trait_ref: ty::PolyTraitRef<'_>,
+ bindings: &[TypeBinding],
+) -> GenericBound {
+ let poly_trait_ref = poly_trait_ref.lift_to_tcx(cx.tcx).unwrap();
+
+ // collect any late bound regions
+ let late_bound_regions: Vec<_> = cx
+ .tcx
+ .collect_referenced_late_bound_regions(&poly_trait_ref)
+ .into_iter()
+ .filter_map(|br| match br {
+ ty::BrNamed(_, name) => Some(GenericParamDef {
+ name,
+ kind: GenericParamDefKind::Lifetime { outlives: vec![] },
+ }),
+ _ => None,
+ })
+ .collect();
- GenericBound::TraitBound(
- PolyTrait {
- trait_: (poly_trait_ref.skip_binder(), bounds).clean(cx),
- generic_params: late_bound_regions,
- },
- hir::TraitBoundModifier::None,
- )
- }
+ let trait_ = clean_trait_ref_with_bindings(cx, poly_trait_ref.skip_binder(), bindings);
+ GenericBound::TraitBound(
+ PolyTrait { trait_, generic_params: late_bound_regions },
+ hir::TraitBoundModifier::None,
+ )
}
impl<'tcx> Clean<GenericBound> for ty::PolyTraitRef<'tcx> {
fn clean(&self, cx: &mut DocContext<'_>) -> GenericBound {
- (*self, &[][..]).clean(cx)
+ clean_poly_trait_ref_with_bindings(cx, *self, &[])
}
}
@@ -534,170 +531,164 @@ impl Clean<Generics> for hir::Generics<'_> {
}
}
-impl<'a, 'tcx> Clean<Generics> for (&'a ty::Generics, ty::GenericPredicates<'tcx>) {
- fn clean(&self, cx: &mut DocContext<'_>) -> Generics {
- use self::WherePredicate as WP;
- use std::collections::BTreeMap;
-
- let (gens, preds) = *self;
-
- // Don't populate `cx.impl_trait_bounds` before `clean`ning `where` clauses,
- // since `Clean for ty::Predicate` would consume them.
- let mut impl_trait = BTreeMap::<ImplTraitParam, Vec<GenericBound>>::default();
-
- // Bounds in the type_params and lifetimes fields are repeated in the
- // predicates field (see rustc_typeck::collect::ty_generics), so remove
- // them.
- let stripped_params = gens
- .params
- .iter()
- .filter_map(|param| match param.kind {
- ty::GenericParamDefKind::Lifetime => Some(param.clean(cx)),
- ty::GenericParamDefKind::Type { synthetic, .. } => {
- if param.name == kw::SelfUpper {
- assert_eq!(param.index, 0);
- return None;
- }
- if synthetic {
- impl_trait.insert(param.index.into(), vec![]);
- return None;
- }
- Some(param.clean(cx))
+fn clean_ty_generics(
+ cx: &mut DocContext<'_>,
+ gens: &ty::Generics,
+ preds: ty::GenericPredicates<'tcx>,
+) -> Generics {
+ // Don't populate `cx.impl_trait_bounds` before `clean`ning `where` clauses,
+ // since `Clean for ty::Predicate` would consume them.
+ let mut impl_trait = BTreeMap::<ImplTraitParam, Vec<GenericBound>>::default();
+
+ // Bounds in the type_params and lifetimes fields are repeated in the
+ // predicates field (see rustc_typeck::collect::ty_generics), so remove
+ // them.
+ let stripped_params = gens
+ .params
+ .iter()
+ .filter_map(|param| match param.kind {
+ ty::GenericParamDefKind::Lifetime => Some(param.clean(cx)),
+ ty::GenericParamDefKind::Type { synthetic, .. } => {
+ if param.name == kw::SelfUpper {
+ assert_eq!(param.index, 0);
+ return None;
}
- ty::GenericParamDefKind::Const { .. } => Some(param.clean(cx)),
- })
- .collect::<Vec<GenericParamDef>>();
-
- // param index -> [(DefId of trait, associated type name, type)]
- let mut impl_trait_proj = FxHashMap::<u32, Vec<(DefId, Symbol, Ty<'tcx>)>>::default();
-
- let where_predicates = preds
- .predicates
- .iter()
- .flat_map(|(p, _)| {
- let mut projection = None;
- let param_idx = (|| {
- let bound_p = p.kind();
- match bound_p.skip_binder() {
- ty::PredicateKind::Trait(pred) => {
- if let ty::Param(param) = pred.self_ty().kind() {
- return Some(param.index);
- }
- }
- ty::PredicateKind::TypeOutlives(ty::OutlivesPredicate(ty, _reg)) => {
- if let ty::Param(param) = ty.kind() {
- return Some(param.index);
- }
+ if synthetic {
+ impl_trait.insert(param.index.into(), vec![]);
+ return None;
+ }
+ Some(param.clean(cx))
+ }
+ ty::GenericParamDefKind::Const { .. } => Some(param.clean(cx)),
+ })
+ .collect::<Vec<GenericParamDef>>();
+
+ // param index -> [(DefId of trait, associated type name, type)]
+ let mut impl_trait_proj = FxHashMap::<u32, Vec<(DefId, Symbol, Ty<'tcx>)>>::default();
+
+ let where_predicates = preds
+ .predicates
+ .iter()
+ .flat_map(|(p, _)| {
+ let mut projection = None;
+ let param_idx = (|| {
+ let bound_p = p.kind();
+ match bound_p.skip_binder() {
+ ty::PredicateKind::Trait(pred) => {
+ if let ty::Param(param) = pred.self_ty().kind() {
+ return Some(param.index);
}
- ty::PredicateKind::Projection(p) => {
- if let ty::Param(param) = p.projection_ty.self_ty().kind() {
- projection = Some(bound_p.rebind(p));
- return Some(param.index);
- }
+ }
+ ty::PredicateKind::TypeOutlives(ty::OutlivesPredicate(ty, _reg)) => {
+ if let ty::Param(param) = ty.kind() {
+ return Some(param.index);
}
- _ => (),
}
-
- None
- })();
-
- if let Some(param_idx) = param_idx {
- if let Some(b) = impl_trait.get_mut(&param_idx.into()) {
- let p = p.clean(cx)?;
-
- b.extend(
- p.get_bounds()
- .into_iter()
- .flatten()
- .cloned()
- .filter(|b| !b.is_sized_bound(cx)),
- );
-
- let proj = projection
- .map(|p| (p.skip_binder().projection_ty.clean(cx), p.skip_binder().ty));
- if let Some(((_, trait_did, name), rhs)) =
- proj.as_ref().and_then(|(lhs, rhs)| Some((lhs.projection()?, rhs)))
- {
- impl_trait_proj
- .entry(param_idx)
- .or_default()
- .push((trait_did, name, rhs));
+ ty::PredicateKind::Projection(p) => {
+ if let ty::Param(param) = p.projection_ty.self_ty().kind() {
+ projection = Some(bound_p.rebind(p));
+ return Some(param.index);
}
-
- return None;
}
+ _ => (),
}
- Some(p)
- })
- .collect::<Vec<_>>();
-
- for (param, mut bounds) in impl_trait {
- // Move trait bounds to the front.
- bounds.sort_by_key(|b| !matches!(b, GenericBound::TraitBound(..)));
-
- if let crate::core::ImplTraitParam::ParamIndex(idx) = param {
- if let Some(proj) = impl_trait_proj.remove(&idx) {
- for (trait_did, name, rhs) in proj {
- let rhs = rhs.clean(cx);
- simplify::merge_bounds(cx, &mut bounds, trait_did, name, &rhs);
+ None
+ })();
+
+ if let Some(param_idx) = param_idx {
+ if let Some(b) = impl_trait.get_mut(&param_idx.into()) {
+ let p = p.clean(cx)?;
+
+ b.extend(
+ p.get_bounds()
+ .into_iter()
+ .flatten()
+ .cloned()
+ .filter(|b| !b.is_sized_bound(cx)),
+ );
+
+ let proj = projection
+ .map(|p| (p.skip_binder().projection_ty.clean(cx), p.skip_binder().ty));
+ if let Some(((_, trait_did, name), rhs)) =
+ proj.as_ref().and_then(|(lhs, rhs)| Some((lhs.projection()?, rhs)))
+ {
+ impl_trait_proj.entry(param_idx).or_default().push((trait_did, name, rhs));
}
+
+ return None;
}
- } else {
- unreachable!();
}
- cx.impl_trait_bounds.insert(param, bounds);
- }
+ Some(p)
+ })
+ .collect::<Vec<_>>();
- // Now that `cx.impl_trait_bounds` is populated, we can process
- // remaining predicates which could contain `impl Trait`.
- let mut where_predicates =
- where_predicates.into_iter().flat_map(|p| p.clean(cx)).collect::<Vec<_>>();
-
- // Type parameters have a Sized bound by default unless removed with
- // ?Sized. Scan through the predicates and mark any type parameter with
- // a Sized bound, removing the bounds as we find them.
- //
- // Note that associated types also have a sized bound by default, but we
- // don't actually know the set of associated types right here so that's
- // handled in cleaning associated types
- let mut sized_params = FxHashSet::default();
- where_predicates.retain(|pred| match *pred {
- WP::BoundPredicate { ty: Generic(ref g), ref bounds, .. } => {
- if bounds.iter().any(|b| b.is_sized_bound(cx)) {
- sized_params.insert(*g);
- false
- } else {
- true
+ for (param, mut bounds) in impl_trait {
+ // Move trait bounds to the front.
+ bounds.sort_by_key(|b| !matches!(b, GenericBound::TraitBound(..)));
+
+ if let crate::core::ImplTraitParam::ParamIndex(idx) = param {
+ if let Some(proj) = impl_trait_proj.remove(&idx) {
+ for (trait_did, name, rhs) in proj {
+ let rhs = rhs.clean(cx);
+ simplify::merge_bounds(cx, &mut bounds, trait_did, name, &rhs);
}
}
- _ => true,
- });
+ } else {
+ unreachable!();
+ }
- // Run through the type parameters again and insert a ?Sized
- // unbound for any we didn't find to be Sized.
- for tp in &stripped_params {
- if matches!(tp.kind, types::GenericParamDefKind::Type { .. })
- && !sized_params.contains(&tp.name)
- {
- where_predicates.push(WP::BoundPredicate {
- ty: Type::Generic(tp.name),
- bounds: vec![GenericBound::maybe_sized(cx)],
- bound_params: Vec::new(),
- })
+ cx.impl_trait_bounds.insert(param, bounds);
+ }
+
+ // Now that `cx.impl_trait_bounds` is populated, we can process
+ // remaining predicates which could contain `impl Trait`.
+ let mut where_predicates =
+ where_predicates.into_iter().flat_map(|p| p.clean(cx)).collect::<Vec<_>>();
+
+ // Type parameters have a Sized bound by default unless removed with
+ // ?Sized. Scan through the predicates and mark any type parameter with
+ // a Sized bound, removing the bounds as we find them.
+ //
+ // Note that associated types also have a sized bound by default, but we
+ // don't actually know the set of associated types right here so that's
+ // handled in cleaning associated types
+ let mut sized_params = FxHashSet::default();
+ where_predicates.retain(|pred| match *pred {
+ WherePredicate::BoundPredicate { ty: Generic(ref g), ref bounds, .. } => {
+ if bounds.iter().any(|b| b.is_sized_bound(cx)) {
+ sized_params.insert(*g);
+ false
+ } else {
+ true
}
}
+ _ => true,
+ });
- // It would be nice to collect all of the bounds on a type and recombine
- // them if possible, to avoid e.g., `where T: Foo, T: Bar, T: Sized, T: 'a`
- // and instead see `where T: Foo + Bar + Sized + 'a`
-
- Generics {
- params: stripped_params,
- where_predicates: simplify::where_clauses(cx, where_predicates),
+ // Run through the type parameters again and insert a ?Sized
+ // unbound for any we didn't find to be Sized.
+ for tp in &stripped_params {
+ if matches!(tp.kind, types::GenericParamDefKind::Type { .. })
+ && !sized_params.contains(&tp.name)
+ {
+ where_predicates.push(WherePredicate::BoundPredicate {
+ ty: Type::Generic(tp.name),
+ bounds: vec![GenericBound::maybe_sized(cx)],
+ bound_params: Vec::new(),
+ })
}
}
+
+ // It would be nice to collect all of the bounds on a type and recombine
+ // them if possible, to avoid e.g., `where T: Foo, T: Bar, T: Sized, T: 'a`
+ // and instead see `where T: Foo + Bar + Sized + 'a`
+
+ Generics {
+ params: stripped_params,
+ where_predicates: simplify::where_clauses(cx, where_predicates),
+ }
}
fn clean_fn_or_proc_macro(
@@ -747,7 +738,7 @@ fn clean_fn_or_proc_macro(
ProcMacroItem(ProcMacro { kind, helpers })
}
None => {
- let mut func = (sig, generics, body_id).clean(cx);
+ let mut func = clean_function(cx, sig, generics, body_id);
let def_id = item.def_id.to_def_id();
func.header.constness =
if cx.tcx.is_const_fn(def_id) && is_unstable_const_fn(cx.tcx, def_id).is_none() {
@@ -755,58 +746,95 @@ fn clean_fn_or_proc_macro(
} else {
hir::Constness::NotConst
};
+ clean_fn_decl_legacy_const_generics(&mut func, attrs);
FunctionItem(func)
}
}
}
-impl<'a> Clean<Function> for (&'a hir::FnSig<'a>, &'a hir::Generics<'a>, hir::BodyId) {
- fn clean(&self, cx: &mut DocContext<'_>) -> Function {
- let (generics, decl) = enter_impl_trait(cx, |cx| {
- // NOTE: generics must be cleaned before args
- let generics = self.1.clean(cx);
- let args = (self.0.decl.inputs, self.2).clean(cx);
- let decl = clean_fn_decl_with_args(cx, self.0.decl, args);
- (generics, decl)
- });
- Function { decl, generics, header: self.0.header }
+/// This is needed to make it more "readable" when documenting functions using
+/// `rustc_legacy_const_generics`. More information in
+/// <https://github.com/rust-lang/rust/issues/83167>.
+fn clean_fn_decl_legacy_const_generics(func: &mut Function, attrs: &[ast::Attribute]) {
+ for meta_item_list in attrs
+ .iter()
+ .filter(|a| a.has_name(sym::rustc_legacy_const_generics))
+ .filter_map(|a| a.meta_item_list())
+ {
+ for (pos, literal) in meta_item_list.iter().filter_map(|meta| meta.literal()).enumerate() {
+ match literal.kind {
+ ast::LitKind::Int(a, _) => {
+ let gen = func.generics.params.remove(0);
+ if let GenericParamDef { name, kind: GenericParamDefKind::Const { ty, .. } } =
+ gen
+ {
+ func.decl
+ .inputs
+ .values
+ .insert(a as _, Argument { name, type_: *ty, is_const: true });
+ } else {
+ panic!("unexpected non const in position {}", pos);
+ }
+ }
+ _ => panic!("invalid arg index"),
+ }
+ }
}
}
-impl<'a> Clean<Arguments> for (&'a [hir::Ty<'a>], &'a [Ident]) {
- fn clean(&self, cx: &mut DocContext<'_>) -> Arguments {
- Arguments {
- values: self
- .0
- .iter()
- .enumerate()
- .map(|(i, ty)| {
- let mut name = self.1.get(i).map_or(kw::Empty, |ident| ident.name);
- if name.is_empty() {
- name = kw::Underscore;
- }
- Argument { name, type_: ty.clean(cx) }
- })
- .collect(),
- }
+fn clean_function(
+ cx: &mut DocContext<'_>,
+ sig: &hir::FnSig<'_>,
+ generics: &hir::Generics<'_>,
+ body_id: hir::BodyId,
+) -> Function {
+ let (generics, decl) = enter_impl_trait(cx, |cx| {
+ // NOTE: generics must be cleaned before args
+ let generics = generics.clean(cx);
+ let args = clean_args_from_types_and_body_id(cx, sig.decl.inputs, body_id);
+ let decl = clean_fn_decl_with_args(cx, sig.decl, args);
+ (generics, decl)
+ });
+ Function { decl, generics, header: sig.header }
+}
+
+fn clean_args_from_types_and_names(
+ cx: &mut DocContext<'_>,
+ types: &[hir::Ty<'_>],
+ names: &[Ident],
+) -> Arguments {
+ Arguments {
+ values: types
+ .iter()
+ .enumerate()
+ .map(|(i, ty)| {
+ let mut name = names.get(i).map_or(kw::Empty, |ident| ident.name);
+ if name.is_empty() {
+ name = kw::Underscore;
+ }
+ Argument { name, type_: ty.clean(cx), is_const: false }
+ })
+ .collect(),
}
}
-impl<'a> Clean<Arguments> for (&'a [hir::Ty<'a>], hir::BodyId) {
- fn clean(&self, cx: &mut DocContext<'_>) -> Arguments {
- let body = cx.tcx.hir().body(self.1);
+fn clean_args_from_types_and_body_id(
+ cx: &mut DocContext<'_>,
+ types: &[hir::Ty<'_>],
+ body_id: hir::BodyId,
+) -> Arguments {
+ let body = cx.tcx.hir().body(body_id);
- Arguments {
- values: self
- .0
- .iter()
- .enumerate()
- .map(|(i, ty)| Argument {
- name: name_from_pat(body.params[i].pat),
- type_: ty.clean(cx),
- })
- .collect(),
- }
+ Arguments {
+ values: types
+ .iter()
+ .enumerate()
+ .map(|(i, ty)| Argument {
+ name: name_from_pat(body.params[i].pat),
+ type_: ty.clean(cx),
+ is_const: false,
+ })
+ .collect(),
}
}
@@ -818,26 +846,28 @@ fn clean_fn_decl_with_args(
FnDecl { inputs: args, output: decl.output.clean(cx), c_variadic: decl.c_variadic }
}
-impl<'tcx> Clean<FnDecl> for (DefId, ty::PolyFnSig<'tcx>) {
- fn clean(&self, cx: &mut DocContext<'_>) -> FnDecl {
- let (did, sig) = *self;
- let mut names = if did.is_local() { &[] } else { cx.tcx.fn_arg_names(did) }.iter();
-
- FnDecl {
- output: Return(sig.skip_binder().output().clean(cx)),
- c_variadic: sig.skip_binder().c_variadic,
- inputs: Arguments {
- values: sig
- .skip_binder()
- .inputs()
- .iter()
- .map(|t| Argument {
- type_: t.clean(cx),
- name: names.next().map_or(kw::Empty, |i| i.name),
- })
- .collect(),
- },
- }
+fn clean_fn_decl_from_did_and_sig(
+ cx: &mut DocContext<'_>,
+ did: DefId,
+ sig: ty::PolyFnSig<'_>,
+) -> FnDecl {
+ let mut names = if did.is_local() { &[] } else { cx.tcx.fn_arg_names(did) }.iter();
+
+ FnDecl {
+ output: Return(sig.skip_binder().output().clean(cx)),
+ c_variadic: sig.skip_binder().c_variadic,
+ inputs: Arguments {
+ values: sig
+ .skip_binder()
+ .inputs()
+ .iter()
+ .map(|t| Argument {
+ type_: t.clean(cx),
+ name: names.next().map_or(kw::Empty, |i| i.name),
+ is_const: false,
+ })
+ .collect(),
+ },
}
}
@@ -882,10 +912,12 @@ impl Clean<Item> for hir::TraitItem<'_> {
cx.with_param_env(local_did, |cx| {
let inner = match self.kind {
hir::TraitItemKind::Const(ref ty, default) => {
- AssocConstItem(ty.clean(cx), default.map(|e| print_const_expr(cx.tcx, e)))
+ let default =
+ default.map(|e| ConstantKind::Local { def_id: local_did, body: e });
+ AssocConstItem(ty.clean(cx), default)
}
hir::TraitItemKind::Fn(ref sig, hir::TraitFn::Provided(body)) => {
- let mut m = (sig, &self.generics, body).clean(cx);
+ let mut m = clean_function(cx, sig, &self.generics, body);
if m.header.constness == hir::Constness::Const
&& is_unstable_const_fn(cx.tcx, local_did).is_some()
{
@@ -897,7 +929,7 @@ impl Clean<Item> for hir::TraitItem<'_> {
let (generics, decl) = enter_impl_trait(cx, |cx| {
// NOTE: generics must be cleaned before args
let generics = self.generics.clean(cx);
- let args = (sig.decl.inputs, names).clean(cx);
+ let args = clean_args_from_types_and_names(cx, sig.decl.inputs, names);
let decl = clean_fn_decl_with_args(cx, sig.decl, args);
(generics, decl)
});
@@ -929,10 +961,11 @@ impl Clean<Item> for hir::ImplItem<'_> {
cx.with_param_env(local_did, |cx| {
let inner = match self.kind {
hir::ImplItemKind::Const(ref ty, expr) => {
- AssocConstItem(ty.clean(cx), Some(print_const_expr(cx.tcx, expr)))
+ let default = Some(ConstantKind::Local { def_id: local_did, body: expr });
+ AssocConstItem(ty.clean(cx), default)
}
hir::ImplItemKind::Fn(ref sig, body) => {
- let mut m = (sig, &self.generics, body).clean(cx);
+ let mut m = clean_function(cx, sig, &self.generics, body);
if m.header.constness == hir::Constness::Const
&& is_unstable_const_fn(cx.tcx, local_did).is_some()
{
@@ -956,7 +989,7 @@ impl Clean<Item> for hir::ImplItem<'_> {
let what_rustc_thinks =
Item::from_def_id_and_parts(local_did, Some(self.ident.name), inner, cx);
- let parent_item = cx.tcx.hir().expect_item(cx.tcx.hir().get_parent_item(self.hir_id()));
+ let parent_item = cx.tcx.hir().expect_item(cx.tcx.hir().get_parent_did(self.hir_id()));
if let hir::ItemKind::Impl(impl_) = &parent_item.kind {
if impl_.of_trait.is_some() {
// Trait impl items always inherit the impl's visibility --
@@ -979,18 +1012,20 @@ impl Clean<Item> for ty::AssocItem {
ty::AssocKind::Const => {
let ty = tcx.type_of(self.def_id);
let default = if self.defaultness.has_value() {
- Some(inline::print_inlined_const(tcx, self.def_id))
+ Some(ConstantKind::Extern { def_id: self.def_id })
} else {
None
};
AssocConstItem(ty.clean(cx), default)
}
ty::AssocKind::Fn => {
- let generics =
- (tcx.generics_of(self.def_id), tcx.explicit_predicates_of(self.def_id))
- .clean(cx);
+ let generics = clean_ty_generics(
+ cx,
+ tcx.generics_of(self.def_id),
+ tcx.explicit_predicates_of(self.def_id),
+ );
let sig = tcx.fn_sig(self.def_id);
- let mut decl = (self.def_id, sig).clean(cx);
+ let mut decl = clean_fn_decl_from_did_and_sig(cx, self.def_id, sig);
if self.fn_has_self_parameter {
let self_ty = match self.container {
@@ -1059,7 +1094,7 @@ impl Clean<Item> for ty::AssocItem {
if let ty::TraitContainer(_) = self.container {
let bounds = tcx.explicit_item_bounds(self.def_id);
let predicates = ty::GenericPredicates { parent: None, predicates: bounds };
- let generics = (tcx.generics_of(self.def_id), predicates).clean(cx);
+ let generics = clean_ty_generics(cx, tcx.generics_of(self.def_id), predicates);
let mut bounds = generics
.where_predicates
.iter()
@@ -1195,9 +1230,8 @@ fn maybe_expand_private_type_alias(cx: &mut DocContext<'_>, path: &hir::Path<'_>
let Res::Def(DefKind::TyAlias, def_id) = path.res else { return None };
// Substitute private type aliases
let Some(def_id) = def_id.as_local() else { return None };
- let hir_id = cx.tcx.hir().local_def_id_to_hir_id(def_id);
let alias = if !cx.cache.access_levels.is_exported(def_id.to_def_id()) {
- &cx.tcx.hir().expect_item(hir_id).kind
+ &cx.tcx.hir().expect_item(def_id).kind
} else {
return None;
};
@@ -1344,25 +1378,15 @@ fn normalize(cx: &mut DocContext<'tcx>, ty: Ty<'_>) -> Option<Ty<'tcx>> {
return None;
}
- use crate::rustc_trait_selection::infer::TyCtxtInferExt;
- use crate::rustc_trait_selection::traits::query::normalize::AtExt;
- use rustc_middle::traits::ObligationCause;
-
// Try to normalize `<X as Y>::T` to a type
let lifted = ty.lift_to_tcx(cx.tcx).unwrap();
- let normalized = cx.tcx.infer_ctxt().enter(|infcx| {
- infcx
- .at(&ObligationCause::dummy(), cx.param_env)
- .normalize(lifted)
- .map(|resolved| infcx.resolve_vars_if_possible(resolved.value))
- });
- match normalized {
+ match cx.tcx.try_normalize_erasing_regions(cx.param_env, lifted) {
Ok(normalized_value) => {
- debug!("normalized {:?} to {:?}", ty, normalized_value);
+ trace!("normalized {:?} to {:?}", ty, normalized_value);
Some(normalized_value)
}
Err(err) => {
- debug!("failed to normalize {:?}: {:?}", ty, err);
+ info!("failed to normalize {:?}: {:?}", ty, err);
None
}
}
@@ -1395,10 +1419,11 @@ impl<'tcx> Clean<Type> for Ty<'tcx> {
let ty = cx.tcx.lift(*self).expect("FnPtr lift failed");
let sig = ty.fn_sig(cx.tcx);
let def_id = DefId::local(CRATE_DEF_INDEX);
+ let decl = clean_fn_decl_from_did_and_sig(cx, def_id, sig);
BareFunction(box BareFunctionDecl {
unsafety: sig.unsafety(),
generic_params: Vec::new(),
- decl: (def_id, sig).clean(cx),
+ decl,
abi: sig.abi(),
})
}
@@ -1411,12 +1436,12 @@ impl<'tcx> Clean<Type> for Ty<'tcx> {
};
inline::record_extern_fqn(cx, did, kind);
let path = external_path(cx, did, false, vec![], substs);
- ResolvedPath { path, did }
+ Type::Path { path }
}
ty::Foreign(did) => {
inline::record_extern_fqn(cx, did, ItemType::ForeignType);
let path = external_path(cx, did, false, vec![], InternalSubsts::empty());
- ResolvedPath { path, did }
+ Type::Path { path }
}
ty::Dynamic(obj, ref reg) => {
// HACK: pick the first `did` as the `did` of the trait object. Someone
@@ -1504,7 +1529,7 @@ impl<'tcx> Clean<Type> for Ty<'tcx> {
}
}
- let bounds: Vec<_> = bounds
+ let bindings: Vec<_> = bounds
.iter()
.filter_map(|bound| {
if let ty::PredicateKind::Projection(proj) =
@@ -1532,7 +1557,7 @@ impl<'tcx> Clean<Type> for Ty<'tcx> {
})
.collect();
- Some((trait_ref, &bounds[..]).clean(cx))
+ Some(clean_poly_trait_ref_with_bindings(cx, trait_ref, &bindings))
})
.collect::<Vec<_>>();
bounds.extend(regions);
@@ -1704,7 +1729,7 @@ impl Clean<BareFunctionDecl> for hir::BareFnTy<'_> {
let (generic_params, decl) = enter_impl_trait(cx, |cx| {
// NOTE: generics must be cleaned before args
let generic_params = self.generic_params.iter().map(|x| x.clean(cx)).collect();
- let args = (self.decl.inputs, self.param_names).clean(cx);
+ let args = clean_args_from_types_and_names(cx, self.decl.inputs, self.param_names);
let decl = clean_fn_decl_with_args(cx, self.decl, args);
(generic_params, decl)
});
@@ -1712,94 +1737,93 @@ impl Clean<BareFunctionDecl> for hir::BareFnTy<'_> {
}
}
-impl Clean<Vec<Item>> for (&hir::Item<'_>, Option<Symbol>) {
- fn clean(&self, cx: &mut DocContext<'_>) -> Vec<Item> {
- use hir::ItemKind;
-
- let (item, renamed) = self;
- let def_id = item.def_id.to_def_id();
- let mut name = renamed.unwrap_or_else(|| cx.tcx.hir().name(item.hir_id()));
- cx.with_param_env(def_id, |cx| {
- let kind = match item.kind {
- ItemKind::Static(ty, mutability, body_id) => {
- StaticItem(Static { type_: ty.clean(cx), mutability, expr: Some(body_id) })
- }
- ItemKind::Const(ty, body_id) => ConstantItem(Constant {
- type_: ty.clean(cx),
- kind: ConstantKind::Local { body: body_id, def_id },
- }),
- ItemKind::OpaqueTy(ref ty) => OpaqueTyItem(OpaqueTy {
- bounds: ty.bounds.iter().map(|x| x.clean(cx)).collect(),
- generics: ty.generics.clean(cx),
- }),
- ItemKind::TyAlias(hir_ty, ref generics) => {
- let rustdoc_ty = hir_ty.clean(cx);
- let ty = hir_ty_to_ty(cx.tcx, hir_ty).clean(cx);
- TypedefItem(
- Typedef {
- type_: rustdoc_ty,
- generics: generics.clean(cx),
- item_type: Some(ty),
- },
- false,
- )
- }
- ItemKind::Enum(ref def, ref generics) => EnumItem(Enum {
- variants: def.variants.iter().map(|v| v.clean(cx)).collect(),
- generics: generics.clean(cx),
- variants_stripped: false,
- }),
- ItemKind::TraitAlias(ref generics, bounds) => TraitAliasItem(TraitAlias {
+fn clean_maybe_renamed_item(
+ cx: &mut DocContext<'_>,
+ item: &hir::Item<'_>,
+ renamed: Option<Symbol>,
+) -> Vec<Item> {
+ use hir::ItemKind;
+
+ let def_id = item.def_id.to_def_id();
+ let mut name = renamed.unwrap_or_else(|| cx.tcx.hir().name(item.hir_id()));
+ cx.with_param_env(def_id, |cx| {
+ let kind = match item.kind {
+ ItemKind::Static(ty, mutability, body_id) => {
+ StaticItem(Static { type_: ty.clean(cx), mutability, expr: Some(body_id) })
+ }
+ ItemKind::Const(ty, body_id) => ConstantItem(Constant {
+ type_: ty.clean(cx),
+ kind: ConstantKind::Local { body: body_id, def_id },
+ }),
+ ItemKind::OpaqueTy(ref ty) => OpaqueTyItem(OpaqueTy {
+ bounds: ty.bounds.iter().map(|x| x.clean(cx)).collect(),
+ generics: ty.generics.clean(cx),
+ }),
+ ItemKind::TyAlias(hir_ty, ref generics) => {
+ let rustdoc_ty = hir_ty.clean(cx);
+ let ty = hir_ty_to_ty(cx.tcx, hir_ty).clean(cx);
+ TypedefItem(
+ Typedef {
+ type_: rustdoc_ty,
+ generics: generics.clean(cx),
+ item_type: Some(ty),
+ },
+ false,
+ )
+ }
+ ItemKind::Enum(ref def, ref generics) => EnumItem(Enum {
+ variants: def.variants.iter().map(|v| v.clean(cx)).collect(),
+ generics: generics.clean(cx),
+ variants_stripped: false,
+ }),
+ ItemKind::TraitAlias(ref generics, bounds) => TraitAliasItem(TraitAlias {
+ generics: generics.clean(cx),
+ bounds: bounds.iter().map(|x| x.clean(cx)).collect(),
+ }),
+ ItemKind::Union(ref variant_data, ref generics) => UnionItem(Union {
+ generics: generics.clean(cx),
+ fields: variant_data.fields().iter().map(|x| x.clean(cx)).collect(),
+ fields_stripped: false,
+ }),
+ ItemKind::Struct(ref variant_data, ref generics) => StructItem(Struct {
+ struct_type: CtorKind::from_hir(variant_data),
+ generics: generics.clean(cx),
+ fields: variant_data.fields().iter().map(|x| x.clean(cx)).collect(),
+ fields_stripped: false,
+ }),
+ ItemKind::Impl(ref impl_) => return clean_impl(impl_, item.hir_id(), cx),
+ // proc macros can have a name set by attributes
+ ItemKind::Fn(ref sig, ref generics, body_id) => {
+ clean_fn_or_proc_macro(item, sig, generics, body_id, &mut name, cx)
+ }
+ ItemKind::Macro(ref macro_def) => {
+ let ty_vis = cx.tcx.visibility(def_id).clean(cx);
+ MacroItem(Macro {
+ source: display_macro_source(cx, name, macro_def, def_id, ty_vis),
+ })
+ }
+ ItemKind::Trait(is_auto, unsafety, ref generics, bounds, item_ids) => {
+ let items =
+ item_ids.iter().map(|ti| cx.tcx.hir().trait_item(ti.id).clean(cx)).collect();
+ TraitItem(Trait {
+ unsafety,
+ items,
generics: generics.clean(cx),
bounds: bounds.iter().map(|x| x.clean(cx)).collect(),
- }),
- ItemKind::Union(ref variant_data, ref generics) => UnionItem(Union {
- generics: generics.clean(cx),
- fields: variant_data.fields().iter().map(|x| x.clean(cx)).collect(),
- fields_stripped: false,
- }),
- ItemKind::Struct(ref variant_data, ref generics) => StructItem(Struct {
- struct_type: CtorKind::from_hir(variant_data),
- generics: generics.clean(cx),
- fields: variant_data.fields().iter().map(|x| x.clean(cx)).collect(),
- fields_stripped: false,
- }),
- ItemKind::Impl(ref impl_) => return clean_impl(impl_, item.hir_id(), cx),
- // proc macros can have a name set by attributes
- ItemKind::Fn(ref sig, ref generics, body_id) => {
- clean_fn_or_proc_macro(item, sig, generics, body_id, &mut name, cx)
- }
- ItemKind::Macro(ref macro_def) => {
- let ty_vis = cx.tcx.visibility(def_id).clean(cx);
- MacroItem(Macro {
- source: display_macro_source(cx, name, macro_def, def_id, ty_vis),
- })
- }
- ItemKind::Trait(is_auto, unsafety, ref generics, bounds, item_ids) => {
- let items = item_ids
- .iter()
- .map(|ti| cx.tcx.hir().trait_item(ti.id).clean(cx))
- .collect();
- TraitItem(Trait {
- unsafety,
- items,
- generics: generics.clean(cx),
- bounds: bounds.iter().map(|x| x.clean(cx)).collect(),
- is_auto: is_auto.clean(cx),
- })
- }
- ItemKind::ExternCrate(orig_name) => {
- return clean_extern_crate(item, name, orig_name, cx);
- }
- ItemKind::Use(path, kind) => {
- return clean_use_statement(item, name, path, kind, cx);
- }
- _ => unreachable!("not yet converted"),
- };
+ is_auto: is_auto.clean(cx),
+ })
+ }
+ ItemKind::ExternCrate(orig_name) => {
+ return clean_extern_crate(item, name, orig_name, cx);
+ }
+ ItemKind::Use(path, kind) => {
+ return clean_use_statement(item, name, path, kind, cx);
+ }
+ _ => unreachable!("not yet converted"),
+ };
- vec![Item::from_def_id_and_parts(def_id, Some(name), kind, cx)]
- })
- }
+ vec![Item::from_def_id_and_parts(def_id, Some(name), kind, cx)]
+ })
}
impl Clean<Item> for hir::Variant<'_> {
@@ -1919,8 +1943,20 @@ fn clean_use_statement(
let inline_attr = attrs.lists(sym::doc).get_word_attr(sym::inline);
let pub_underscore = visibility.is_public() && name == kw::Underscore;
let current_mod = cx.tcx.parent_module_from_def_id(import.def_id);
+
+ // The parent of the module in which this import resides. This
+ // is the same as `current_mod` if that's already the top
+ // level module.
let parent_mod = cx.tcx.parent_module_from_def_id(current_mod);
+ // This checks if the import can be seen from a higher level module.
+ // In other words, it checks if the visibility is the equivalent of
+ // `pub(super)` or higher. If the current module is the top level
+ // module, there isn't really a parent module, which makes the results
+ // meaningless. In this case, we make sure the answer is `false`.
+ let is_visible_from_parent_mod = visibility.is_accessible_from(parent_mod.to_def_id(), cx.tcx)
+ && !current_mod.is_top_level_module();
+
if pub_underscore {
if let Some(ref inline) = inline_attr {
rustc_errors::struct_span_err!(
@@ -1939,8 +1975,7 @@ fn clean_use_statement(
// #[doc(no_inline)] attribute is present.
// Don't inline doc(hidden) imports so they can be stripped at a later stage.
let mut denied = !(visibility.is_public()
- || (cx.render_options.document_private
- && visibility.is_accessible_from(parent_mod.to_def_id(), cx.tcx)))
+ || (cx.render_options.document_private && is_visible_from_parent_mod))
|| pub_underscore
|| attrs.iter().any(|a| {
a.has_name(sym::doc)
@@ -2002,50 +2037,51 @@ fn clean_use_statement(
vec![Item::from_def_id_and_parts(import.def_id.to_def_id(), None, ImportItem(inner), cx)]
}
-impl Clean<Item> for (&hir::ForeignItem<'_>, Option<Symbol>) {
- fn clean(&self, cx: &mut DocContext<'_>) -> Item {
- let (item, renamed) = self;
- let def_id = item.def_id.to_def_id();
- cx.with_param_env(def_id, |cx| {
- let kind = match item.kind {
- hir::ForeignItemKind::Fn(decl, names, ref generics) => {
- let abi = cx.tcx.hir().get_foreign_abi(item.hir_id());
- let (generics, decl) = enter_impl_trait(cx, |cx| {
- // NOTE: generics must be cleaned before args
- let generics = generics.clean(cx);
- let args = (decl.inputs, names).clean(cx);
- let decl = clean_fn_decl_with_args(cx, decl, args);
- (generics, decl)
- });
- ForeignFunctionItem(Function {
- decl,
- generics,
- header: hir::FnHeader {
- unsafety: if abi == Abi::RustIntrinsic {
- intrinsic_operation_unsafety(item.ident.name)
- } else {
- hir::Unsafety::Unsafe
- },
- abi,
- constness: hir::Constness::NotConst,
- asyncness: hir::IsAsync::NotAsync,
+fn clean_maybe_renamed_foreign_item(
+ cx: &mut DocContext<'_>,
+ item: &hir::ForeignItem<'_>,
+ renamed: Option<Symbol>,
+) -> Item {
+ let def_id = item.def_id.to_def_id();
+ cx.with_param_env(def_id, |cx| {
+ let kind = match item.kind {
+ hir::ForeignItemKind::Fn(decl, names, ref generics) => {
+ let abi = cx.tcx.hir().get_foreign_abi(item.hir_id());
+ let (generics, decl) = enter_impl_trait(cx, |cx| {
+ // NOTE: generics must be cleaned before args
+ let generics = generics.clean(cx);
+ let args = clean_args_from_types_and_names(cx, decl.inputs, names);
+ let decl = clean_fn_decl_with_args(cx, decl, args);
+ (generics, decl)
+ });
+ ForeignFunctionItem(Function {
+ decl,
+ generics,
+ header: hir::FnHeader {
+ unsafety: if abi == Abi::RustIntrinsic {
+ intrinsic_operation_unsafety(item.ident.name)
+ } else {
+ hir::Unsafety::Unsafe
},
- })
- }
- hir::ForeignItemKind::Static(ref ty, mutability) => {
- ForeignStaticItem(Static { type_: ty.clean(cx), mutability, expr: None })
- }
- hir::ForeignItemKind::Type => ForeignTypeItem,
- };
+ abi,
+ constness: hir::Constness::NotConst,
+ asyncness: hir::IsAsync::NotAsync,
+ },
+ })
+ }
+ hir::ForeignItemKind::Static(ref ty, mutability) => {
+ ForeignStaticItem(Static { type_: ty.clean(cx), mutability, expr: None })
+ }
+ hir::ForeignItemKind::Type => ForeignTypeItem,
+ };
- Item::from_hir_id_and_parts(
- item.hir_id(),
- Some(renamed.unwrap_or(item.ident.name)),
- kind,
- cx,
- )
- })
- }
+ Item::from_hir_id_and_parts(
+ item.hir_id(),
+ Some(renamed.unwrap_or(item.ident.name)),
+ kind,
+ cx,
+ )
+ })
}
impl Clean<TypeBinding> for hir::TypeBinding<'_> {
diff --git a/src/librustdoc/clean/types.rs b/src/librustdoc/clean/types.rs
index d28f3ce8778..2bd90f67cf4 100644
--- a/src/librustdoc/clean/types.rs
+++ b/src/librustdoc/clean/types.rs
@@ -1,7 +1,6 @@
use std::cell::RefCell;
use std::default::Default;
use std::hash::{Hash, Hasher};
-use std::iter::FromIterator;
use std::lazy::SyncOnceCell as OnceCell;
use std::path::PathBuf;
use std::rc::Rc;
@@ -34,7 +33,6 @@ use rustc_target::spec::abi::Abi;
use crate::clean::cfg::Cfg;
use crate::clean::external_path;
use crate::clean::inline::{self, print_inlined_const};
-use crate::clean::types::Type::{QPath, ResolvedPath};
use crate::clean::utils::{is_literal_expr, print_const_expr, print_evaluated_const};
use crate::clean::Clean;
use crate::core::DocContext;
@@ -43,10 +41,14 @@ use crate::formats::item_type::ItemType;
use crate::html::render::cache::ExternalLocation;
use crate::html::render::Context;
-use self::FnRetTy::*;
-use self::ItemKind::*;
-use self::SelfTy::*;
-use self::Type::*;
+crate use self::FnRetTy::*;
+crate use self::ItemKind::*;
+crate use self::SelfTy::*;
+crate use self::Type::{
+ Array, BareFunction, BorrowedRef, DynTrait, Generic, ImplTrait, Infer, Primitive, QPath,
+ RawPointer, Slice, Tuple,
+};
+crate use self::Visibility::{Inherited, Public};
crate type ItemIdSet = FxHashSet<ItemId>;
@@ -373,8 +375,8 @@ impl Item {
self.def_id.as_def_id().and_then(|did| tcx.lookup_stability(did))
}
- crate fn const_stability<'tcx>(&self, tcx: TyCtxt<'tcx>) -> Option<&'tcx ConstStability> {
- self.def_id.as_def_id().and_then(|did| tcx.lookup_const_stability(did))
+ crate fn const_stability<'tcx>(&self, tcx: TyCtxt<'tcx>) -> Option<ConstStability> {
+ self.def_id.as_def_id().and_then(|did| tcx.lookup_const_stability(did)).map(|cs| *cs)
}
crate fn deprecation(&self, tcx: TyCtxt<'_>) -> Option<Deprecation> {
@@ -599,16 +601,16 @@ impl Item {
})
}
- crate fn stable_since(&self, tcx: TyCtxt<'_>) -> Option<SymbolStr> {
+ crate fn stable_since(&self, tcx: TyCtxt<'_>) -> Option<Symbol> {
match self.stability(tcx)?.level {
- StabilityLevel::Stable { since, .. } => Some(since.as_str()),
+ StabilityLevel::Stable { since, .. } => Some(since),
StabilityLevel::Unstable { .. } => None,
}
}
- crate fn const_stable_since(&self, tcx: TyCtxt<'_>) -> Option<SymbolStr> {
+ crate fn const_stable_since(&self, tcx: TyCtxt<'_>) -> Option<Symbol> {
match self.const_stability(tcx)?.level {
- StabilityLevel::Stable { since, .. } => Some(since.as_str()),
+ StabilityLevel::Stable { since, .. } => Some(since),
StabilityLevel::Unstable { .. } => None,
}
}
@@ -667,7 +669,7 @@ crate enum ItemKind {
MacroItem(Macro),
ProcMacroItem(ProcMacro),
PrimitiveItem(PrimitiveType),
- AssocConstItem(Type, Option<String>),
+ AssocConstItem(Type, Option<ConstantKind>),
/// An associated item in a trait or trait impl.
///
/// The bounds may be non-empty if there is a `where` clause.
@@ -955,16 +957,14 @@ fn add_doc_fragment(out: &mut String, frag: &DocFragment) {
}
}
-impl<'a> FromIterator<&'a DocFragment> for String {
- fn from_iter<T>(iter: T) -> Self
- where
- T: IntoIterator<Item = &'a DocFragment>,
- {
- iter.into_iter().fold(String::new(), |mut acc, frag| {
- add_doc_fragment(&mut acc, frag);
- acc
- })
+/// Collapse a collection of [`DocFragment`]s into one string,
+/// handling indentation and newlines as needed.
+crate fn collapse_doc_fragments(doc_strings: &[DocFragment]) -> String {
+ let mut acc = String::new();
+ for frag in doc_strings {
+ add_doc_fragment(&mut acc, frag);
}
+ acc
}
/// A link that has not yet been rendered.
@@ -1110,7 +1110,11 @@ impl Attributes {
/// Finds all `doc` attributes as NameValues and returns their corresponding values, joined
/// with newlines.
crate fn collapsed_doc_value(&self) -> Option<String> {
- if self.doc_strings.is_empty() { None } else { Some(self.doc_strings.iter().collect()) }
+ if self.doc_strings.is_empty() {
+ None
+ } else {
+ Some(collapse_doc_fragments(&self.doc_strings))
+ }
}
crate fn get_doc_aliases(&self) -> Box<[Symbol]> {
@@ -1204,10 +1208,6 @@ impl GenericBound {
crate struct Lifetime(pub Symbol);
impl Lifetime {
- crate fn get_ref(&self) -> SymbolStr {
- self.0.as_str()
- }
-
crate fn statik() -> Lifetime {
Lifetime(kw::StaticLifetime)
}
@@ -1245,17 +1245,6 @@ impl GenericParamDefKind {
crate fn is_type(&self) -> bool {
matches!(self, GenericParamDefKind::Type { .. })
}
-
- // FIXME(eddyb) this either returns the default of a type parameter, or the
- // type of a `const` parameter. It seems that the intention is to *visit*
- // any embedded types, but `get_type` seems to be the wrong name for that.
- crate fn get_type(&self) -> Option<Type> {
- match self {
- GenericParamDefKind::Type { default, .. } => default.as_deref().cloned(),
- GenericParamDefKind::Const { ty, .. } => Some((&**ty).clone()),
- GenericParamDefKind::Lifetime { .. } => None,
- }
- }
}
#[derive(Clone, PartialEq, Eq, Debug, Hash)]
@@ -1280,10 +1269,6 @@ impl GenericParamDef {
self.kind.is_type()
}
- crate fn get_type(&self) -> Option<Type> {
- self.kind.get_type()
- }
-
crate fn get_bounds(&self) -> Option<&[GenericBound]> {
match self.kind {
GenericParamDefKind::Type { ref bounds, .. } => Some(bounds),
@@ -1350,6 +1335,9 @@ crate struct Arguments {
crate struct Argument {
crate type_: Type,
crate name: Symbol,
+ /// This field is used to represent "const" arguments from the `rustc_legacy_const_generics`
+ /// feature. More information in <https://github.com/rust-lang/rust/issues/83167>.
+ crate is_const: bool,
}
#[derive(Clone, PartialEq, Debug)]
@@ -1418,8 +1406,9 @@ crate struct PolyTrait {
crate enum Type {
/// A named type, which could be a trait.
///
- /// This is mostly Rustdoc's version of [`hir::Path`]. It has to be different because Rustdoc's [`PathSegment`] can contain cleaned generics.
- ResolvedPath { path: Path, did: DefId },
+ /// This is mostly Rustdoc's version of [`hir::Path`].
+ /// It has to be different because Rustdoc's [`PathSegment`] can contain cleaned generics.
+ Path { path: Path },
/// A `dyn Trait` object: `dyn for<'a> Trait<'a> + Send + 'static`
DynTrait(Vec<PolyTrait>, Option<Lifetime>),
/// A type parameter.
@@ -1464,6 +1453,45 @@ crate enum Type {
rustc_data_structures::static_assert_size!(Type, 72);
impl Type {
+ /// When comparing types for equality, it can help to ignore `&` wrapping.
+ crate fn without_borrowed_ref(&self) -> &Type {
+ let mut result = self;
+ while let Type::BorrowedRef { type_, .. } = result {
+ result = &*type_;
+ }
+ result
+ }
+
+ /// Check if two types are "potentially the same".
+ /// This is different from `Eq`, because it knows that things like
+ /// `Placeholder` are possible matches for everything.
+ crate fn is_same(&self, other: &Self, cache: &Cache) -> bool {
+ match (self, other) {
+ // Recursive cases.
+ (Type::Tuple(a), Type::Tuple(b)) => {
+ a.len() == b.len() && a.iter().zip(b).all(|(a, b)| a.is_same(&b, cache))
+ }
+ (Type::Slice(a), Type::Slice(b)) => a.is_same(&b, cache),
+ (Type::Array(a, al), Type::Array(b, bl)) => al == bl && a.is_same(&b, cache),
+ (Type::RawPointer(mutability, type_), Type::RawPointer(b_mutability, b_type_)) => {
+ mutability == b_mutability && type_.is_same(&b_type_, cache)
+ }
+ (
+ Type::BorrowedRef { mutability, type_, .. },
+ Type::BorrowedRef { mutability: b_mutability, type_: b_type_, .. },
+ ) => mutability == b_mutability && type_.is_same(&b_type_, cache),
+ // Placeholders and generics are equal to all other types.
+ (Type::Infer, _) | (_, Type::Infer) => true,
+ (Type::Generic(_), _) | (_, Type::Generic(_)) => true,
+ // Other cases, such as primitives, just use recursion.
+ (a, b) => a
+ .def_id(cache)
+ .and_then(|a| Some((a, b.def_id(cache)?)))
+ .map(|(a, b)| a == b)
+ .unwrap_or(false),
+ }
+ }
+
crate fn primitive_type(&self) -> Option<PrimitiveType> {
match *self {
Primitive(p) | BorrowedRef { type_: box Primitive(p), .. } => Some(p),
@@ -1485,7 +1513,7 @@ impl Type {
/// Checks if this is a `T::Name` path for an associated type.
crate fn is_assoc_ty(&self) -> bool {
match self {
- ResolvedPath { path, .. } => path.is_assoc_ty(),
+ Type::Path { path, .. } => path.is_assoc_ty(),
_ => false,
}
}
@@ -1499,7 +1527,7 @@ impl Type {
crate fn generics(&self) -> Option<Vec<&Type>> {
match self {
- ResolvedPath { path, .. } => path.generics(),
+ Type::Path { path, .. } => path.generics(),
_ => None,
}
}
@@ -1522,7 +1550,7 @@ impl Type {
fn inner_def_id(&self, cache: Option<&Cache>) -> Option<DefId> {
let t: PrimitiveType = match *self {
- ResolvedPath { did, .. } => return Some(did),
+ Type::Path { ref path } => return Some(path.def_id()),
DynTrait(ref bounds, _) => return Some(bounds[0].trait_.def_id()),
Primitive(p) => return cache.and_then(|c| c.primitive_locations.get(&p).cloned()),
BorrowedRef { type_: box Generic(..), .. } => PrimitiveType::Reference,
@@ -2126,7 +2154,21 @@ crate enum ConstantKind {
impl Constant {
crate fn expr(&self, tcx: TyCtxt<'_>) -> String {
- match self.kind {
+ self.kind.expr(tcx)
+ }
+
+ crate fn value(&self, tcx: TyCtxt<'_>) -> Option<String> {
+ self.kind.value(tcx)
+ }
+
+ crate fn is_literal(&self, tcx: TyCtxt<'_>) -> bool {
+ self.kind.is_literal(tcx)
+ }
+}
+
+impl ConstantKind {
+ crate fn expr(&self, tcx: TyCtxt<'_>) -> String {
+ match *self {
ConstantKind::TyConst { ref expr } => expr.clone(),
ConstantKind::Extern { def_id } => print_inlined_const(tcx, def_id),
ConstantKind::Local { body, .. } | ConstantKind::Anonymous { body } => {
@@ -2136,7 +2178,7 @@ impl Constant {
}
crate fn value(&self, tcx: TyCtxt<'_>) -> Option<String> {
- match self.kind {
+ match *self {
ConstantKind::TyConst { .. } | ConstantKind::Anonymous { .. } => None,
ConstantKind::Extern { def_id } | ConstantKind::Local { def_id, .. } => {
print_evaluated_const(tcx, def_id)
@@ -2145,7 +2187,7 @@ impl Constant {
}
crate fn is_literal(&self, tcx: TyCtxt<'_>) -> bool {
- match self.kind {
+ match *self {
ConstantKind::TyConst { .. } => false,
ConstantKind::Extern { def_id } => def_id.as_local().map_or(false, |def_id| {
is_literal_expr(tcx, tcx.hir().local_def_id_to_hir_id(def_id))
diff --git a/src/librustdoc/clean/utils.rs b/src/librustdoc/clean/utils.rs
index 11032211236..7f7be246367 100644
--- a/src/librustdoc/clean/utils.rs
+++ b/src/librustdoc/clean/utils.rs
@@ -2,8 +2,7 @@ use crate::clean::auto_trait::AutoTraitFinder;
use crate::clean::blanket_impl::BlanketImplFinder;
use crate::clean::{
inline, Clean, Crate, ExternalCrate, Generic, GenericArg, GenericArgs, ImportSource, Item,
- ItemKind, Lifetime, Path, PathSegment, Primitive, PrimitiveType, ResolvedPath, Type,
- TypeBinding, Visibility,
+ ItemKind, Lifetime, Path, PathSegment, Primitive, PrimitiveType, Type, TypeBinding, Visibility,
};
use crate::core::DocContext;
use crate::formats::item_type::ItemType;
@@ -142,17 +141,12 @@ pub(super) fn external_path(
}
/// Remove the generic arguments from a path.
-crate fn strip_path_generics(path: Path) -> Path {
- let segments = path
- .segments
- .iter()
- .map(|s| PathSegment {
- name: s.name,
- args: GenericArgs::AngleBracketed { args: vec![], bindings: vec![] },
- })
- .collect();
+crate fn strip_path_generics(mut path: Path) -> Path {
+ for ps in path.segments.iter_mut() {
+ ps.args = GenericArgs::AngleBracketed { args: vec![], bindings: vec![] }
+ }
- Path { res: path.res, segments }
+ path
}
crate fn qpath_to_string(p: &hir::QPath<'_>) -> String {
@@ -187,7 +181,8 @@ crate fn build_deref_target_impls(cx: &mut DocContext<'_>, items: &[Item], ret:
for &did in prim.impls(tcx).iter().filter(|did| !did.is_local()) {
inline::build_impl(cx, None, did, None, ret);
}
- } else if let ResolvedPath { did, .. } = *target {
+ } else if let Type::Path { path } = target {
+ let did = path.def_id();
if !did.is_local() {
inline::build_impls(cx, None, did, None, ret);
}
@@ -360,8 +355,8 @@ crate fn resolve_type(cx: &mut DocContext<'_>, path: Path) -> Type {
Res::SelfTy(..) if path.segments.len() == 1 => Generic(kw::SelfUpper),
Res::Def(DefKind::TyParam, _) if path.segments.len() == 1 => Generic(path.segments[0].name),
_ => {
- let did = register_res(cx, path.res);
- ResolvedPath { path, did }
+ let _ = register_res(cx, path.res);
+ Type::Path { path }
}
}
}
@@ -393,20 +388,10 @@ crate fn register_res(cx: &mut DocContext<'_>, res: Res) -> DefId {
debug!("register_res({:?})", res);
let (did, kind) = match res {
- Res::Def(DefKind::AssocTy | DefKind::AssocFn | DefKind::AssocConst, i) => {
- // associated items are documented, but on the page of their parent
- (cx.tcx.parent(i).unwrap(), ItemType::Trait)
- }
- Res::Def(DefKind::Variant, i) => {
- // variant items are documented, but on the page of their parent
- (cx.tcx.parent(i).expect("cannot get parent def id"), ItemType::Enum)
- }
- // Each of these have their own page.
+ // These should be added to the cache using `record_extern_fqn`.
Res::Def(
- kind
- @
- (Fn | TyAlias | Enum | Trait | Struct | Union | Mod | ForeignTy | Const | Static
- | Macro(..) | TraitAlias),
+ kind @ (AssocTy | AssocFn | AssocConst | Variant | Fn | TyAlias | Enum | Trait | Struct
+ | Union | Mod | ForeignTy | Const | Static | Macro(..) | TraitAlias),
i,
) => (i, kind.into()),
// This is part of a trait definition; document the trait.
diff --git a/src/librustdoc/config.rs b/src/librustdoc/config.rs
index 493aa56fce6..35df5fa1b74 100644
--- a/src/librustdoc/config.rs
+++ b/src/librustdoc/config.rs
@@ -136,9 +136,6 @@ crate struct Options {
///
/// Be aware: This option can come both from the CLI and from crate attributes!
crate manual_passes: Vec<String>,
- /// Whether to display warnings during doc generation or while gathering doctests. By default,
- /// all non-rustdoc-specific lints are allowed when generating docs.
- crate display_doctest_warnings: bool,
/// Whether to run the `calculate-doc-coverage` pass, which counts the number of public items
/// with and without documentation.
crate show_coverage: bool,
@@ -197,7 +194,6 @@ impl fmt::Debug for Options {
.field("persist_doctests", &self.persist_doctests)
.field("default_passes", &self.default_passes)
.field("manual_passes", &self.manual_passes)
- .field("display_doctest_warnings", &self.display_doctest_warnings)
.field("show_coverage", &self.show_coverage)
.field("crate_version", &self.crate_version)
.field("render_options", &self.render_options)
@@ -331,6 +327,19 @@ impl Options {
return Err(0);
}
+ let color = config::parse_color(matches);
+ let config::JsonConfig { json_rendered, json_unused_externs, .. } =
+ config::parse_json(matches);
+ let error_format = config::parse_error_format(matches, color, json_rendered);
+
+ let codegen_options = CodegenOptions::build(matches, error_format);
+ let debugging_opts = DebuggingOptions::build(matches, error_format);
+
+ let diag = new_handler(error_format, None, &debugging_opts);
+
+ // check for deprecated options
+ check_deprecated_options(matches, &diag);
+
if matches.opt_strs("passes") == ["list"] {
println!("Available passes for running rustdoc:");
for pass in passes::PASSES {
@@ -363,19 +372,6 @@ impl Options {
return Err(0);
}
- let color = config::parse_color(matches);
- let config::JsonConfig { json_rendered, json_unused_externs, .. } =
- config::parse_json(matches);
- let error_format = config::parse_error_format(matches, color, json_rendered);
-
- let codegen_options = CodegenOptions::build(matches, error_format);
- let debugging_opts = DebuggingOptions::build(matches, error_format);
-
- let diag = new_handler(error_format, None, &debugging_opts);
-
- // check for deprecated options
- check_deprecated_options(matches, &diag);
-
let mut emit = Vec::new();
for list in matches.opt_strs("emit") {
for kind in list.split(',') {
@@ -508,8 +504,18 @@ impl Options {
return Err(1);
}
- let output =
- matches.opt_str("o").map(|s| PathBuf::from(&s)).unwrap_or_else(|| PathBuf::from("doc"));
+ let out_dir = matches.opt_str("out-dir").map(|s| PathBuf::from(&s));
+ let output = matches.opt_str("output").map(|s| PathBuf::from(&s));
+ let output = match (out_dir, output) {
+ (Some(_), Some(_)) => {
+ diag.struct_err("cannot use both 'out-dir' and 'output' at once").emit();
+ return Err(1);
+ }
+ (Some(out_dir), None) => out_dir,
+ (None, Some(output)) => output,
+ (None, None) => PathBuf::from("doc"),
+ };
+
let cfgs = matches.opt_strs("cfg");
let extension_css = matches.opt_str("e").map(|s| PathBuf::from(&s));
@@ -556,7 +562,7 @@ impl Options {
))
.emit();
}
- themes.push(StylePath { path: theme_file, disabled: true });
+ themes.push(StylePath { path: theme_file });
}
}
@@ -639,7 +645,6 @@ impl Options {
let proc_macro_crate = crate_types.contains(&CrateType::ProcMacro);
let playground_url = matches.opt_str("playground-url");
let maybe_sysroot = matches.opt_str("sysroot").map(PathBuf::from);
- let display_doctest_warnings = matches.opt_present("display-doctest-warnings");
let sort_modules_alphabetically = !matches.opt_present("sort-modules-by-appearance");
let resource_suffix = matches.opt_str("resource-suffix").unwrap_or_default();
let enable_minification = !matches.opt_present("disable-minification");
@@ -707,7 +712,6 @@ impl Options {
test_args,
default_passes,
manual_passes,
- display_doctest_warnings,
show_coverage,
crate_version,
test_run_directory,
diff --git a/src/librustdoc/doctest.rs b/src/librustdoc/doctest.rs
index 37db20aaefa..ac24543929b 100644
--- a/src/librustdoc/doctest.rs
+++ b/src/librustdoc/doctest.rs
@@ -1,4 +1,4 @@
-use rustc_ast::{self as ast, token};
+use rustc_ast as ast;
use rustc_data_structures::fx::{FxHashMap, FxHashSet};
use rustc_data_structures::sync::Lrc;
use rustc_errors::{ColorConfig, ErrorReported, FatalError};
@@ -29,23 +29,21 @@ use std::sync::atomic::{AtomicUsize, Ordering};
use std::sync::{Arc, Mutex};
use crate::clean::{types::AttributesExt, Attributes};
-use crate::config::Options;
+use crate::config::Options as RustdocOptions;
use crate::html::markdown::{self, ErrorCodes, Ignore, LangString};
use crate::lint::init_lints;
use crate::passes::span_of_attrs;
+/// Options that apply to all doctests in a crate or Markdown file (for `rustdoc foo.md`).
#[derive(Clone, Default)]
-crate struct TestOptions {
+crate struct GlobalTestOptions {
/// Whether to disable the default `extern crate my_crate;` when creating doctests.
crate no_crate_inject: bool,
- /// Whether to emit compilation warnings when compiling doctests. Setting this will suppress
- /// the default `#![allow(unused)]`.
- crate display_doctest_warnings: bool,
/// Additional crate-level attributes to add to doctests.
crate attrs: Vec<String>,
}
-crate fn run(options: Options) -> Result<(), ErrorReported> {
+crate fn run(options: RustdocOptions) -> Result<(), ErrorReported> {
let input = config::Input::File(options.input.clone());
let invalid_codeblock_attributes_name = crate::lint::INVALID_CODEBLOCK_ATTRIBUTES.name;
@@ -65,6 +63,8 @@ crate fn run(options: Options) -> Result<(), ErrorReported> {
}
});
+ debug!(?lint_opts);
+
let crate_types =
if options.proc_macro_crate { vec![CrateType::ProcMacro] } else { vec![CrateType::Rlib] };
@@ -72,7 +72,7 @@ crate fn run(options: Options) -> Result<(), ErrorReported> {
maybe_sysroot: options.maybe_sysroot.clone(),
search_paths: options.libs.clone(),
crate_types,
- lint_opts: if !options.display_doctest_warnings { lint_opts } else { vec![] },
+ lint_opts,
lint_cap: Some(options.lint_cap.unwrap_or(lint::Forbid)),
cg: options.codegen_options.clone(),
externs: options.externs.clone(),
@@ -106,7 +106,6 @@ crate fn run(options: Options) -> Result<(), ErrorReported> {
};
let test_args = options.test_args.clone();
- let display_doctest_warnings = options.display_doctest_warnings;
let nocapture = options.nocapture;
let externs = options.externs.clone();
let json_unused_externs = options.json_unused_externs;
@@ -118,8 +117,7 @@ crate fn run(options: Options) -> Result<(), ErrorReported> {
let collector = global_ctxt.enter(|tcx| {
let crate_attrs = tcx.hir().attrs(CRATE_HIR_ID);
- let mut opts = scrape_test_config(crate_attrs);
- opts.display_doctest_warnings |= options.display_doctest_warnings;
+ let opts = scrape_test_config(crate_attrs);
let enable_per_target_ignores = options.enable_per_target_ignores;
let mut collector = Collector::new(
tcx.crate_name(LOCAL_CRATE),
@@ -165,7 +163,7 @@ crate fn run(options: Options) -> Result<(), ErrorReported> {
Err(ErrorReported) => return Err(ErrorReported),
};
- run_tests(test_args, nocapture, display_doctest_warnings, tests);
+ run_tests(test_args, nocapture, tests);
// Collect and warn about unused externs, but only if we've gotten
// reports for each doctest
@@ -208,29 +206,19 @@ crate fn run(options: Options) -> Result<(), ErrorReported> {
Ok(())
}
-crate fn run_tests(
- mut test_args: Vec<String>,
- nocapture: bool,
- display_doctest_warnings: bool,
- tests: Vec<test::TestDescAndFn>,
-) {
+crate fn run_tests(mut test_args: Vec<String>, nocapture: bool, tests: Vec<test::TestDescAndFn>) {
test_args.insert(0, "rustdoctest".to_string());
if nocapture {
test_args.push("--nocapture".to_string());
}
- test::test_main(
- &test_args,
- tests,
- Some(test::Options::new().display_output(display_doctest_warnings)),
- );
+ test::test_main(&test_args, tests, None);
}
// Look for `#![doc(test(no_crate_inject))]`, used by crates in the std facade.
-fn scrape_test_config(attrs: &[ast::Attribute]) -> TestOptions {
+fn scrape_test_config(attrs: &[ast::Attribute]) -> GlobalTestOptions {
use rustc_ast_pretty::pprust;
- let mut opts =
- TestOptions { no_crate_inject: false, display_doctest_warnings: false, attrs: Vec::new() };
+ let mut opts = GlobalTestOptions { no_crate_inject: false, attrs: Vec::new() };
let test_attrs: Vec<_> = attrs
.iter()
@@ -305,16 +293,13 @@ fn run_test(
test: &str,
crate_name: &str,
line: usize,
- options: Options,
- should_panic: bool,
+ rustdoc_options: RustdocOptions,
+ mut lang_string: LangString,
no_run: bool,
- as_test_harness: bool,
runtool: Option<String>,
runtool_args: Vec<String>,
target: TargetTriple,
- compile_fail: bool,
- mut error_codes: Vec<String>,
- opts: &TestOptions,
+ opts: &GlobalTestOptions,
edition: Edition,
outdir: DirState,
path: PathBuf,
@@ -322,49 +307,49 @@ fn run_test(
report_unused_externs: impl Fn(UnusedExterns),
) -> Result<(), TestFailure> {
let (test, line_offset, supports_color) =
- make_test(test, Some(crate_name), as_test_harness, opts, edition, Some(test_id));
+ make_test(test, Some(crate_name), lang_string.test_harness, opts, edition, Some(test_id));
let output_file = outdir.path().join("rust_out");
- let rustc_binary = options
+ let rustc_binary = rustdoc_options
.test_builder
.as_deref()
.unwrap_or_else(|| rustc_interface::util::rustc_path().expect("found rustc"));
let mut compiler = Command::new(&rustc_binary);
compiler.arg("--crate-type").arg("bin");
- for cfg in &options.cfgs {
+ for cfg in &rustdoc_options.cfgs {
compiler.arg("--cfg").arg(&cfg);
}
- if let Some(sysroot) = options.maybe_sysroot {
+ if let Some(sysroot) = rustdoc_options.maybe_sysroot {
compiler.arg("--sysroot").arg(sysroot);
}
compiler.arg("--edition").arg(&edition.to_string());
compiler.env("UNSTABLE_RUSTDOC_TEST_PATH", path);
compiler.env("UNSTABLE_RUSTDOC_TEST_LINE", format!("{}", line as isize - line_offset as isize));
compiler.arg("-o").arg(&output_file);
- if as_test_harness {
+ if lang_string.test_harness {
compiler.arg("--test");
}
- if options.json_unused_externs && !compile_fail {
+ if rustdoc_options.json_unused_externs && !lang_string.compile_fail {
compiler.arg("--error-format=json");
compiler.arg("--json").arg("unused-externs");
compiler.arg("-Z").arg("unstable-options");
compiler.arg("-W").arg("unused_crate_dependencies");
}
- for lib_str in &options.lib_strs {
+ for lib_str in &rustdoc_options.lib_strs {
compiler.arg("-L").arg(&lib_str);
}
- for extern_str in &options.extern_strs {
+ for extern_str in &rustdoc_options.extern_strs {
compiler.arg("--extern").arg(&extern_str);
}
compiler.arg("-Ccodegen-units=1");
- for codegen_options_str in &options.codegen_options_strs {
+ for codegen_options_str in &rustdoc_options.codegen_options_strs {
compiler.arg("-C").arg(&codegen_options_str);
}
- for debugging_option_str in &options.debugging_opts_strs {
+ for debugging_option_str in &rustdoc_options.debugging_opts_strs {
compiler.arg("-Z").arg(&debugging_option_str);
}
- if no_run && !compile_fail && options.persist_doctests.is_none() {
+ if no_run && !lang_string.compile_fail && rustdoc_options.persist_doctests.is_none() {
compiler.arg("--emit=metadata");
}
compiler.arg("--target").arg(match target {
@@ -373,7 +358,7 @@ fn run_test(
path.to_str().expect("target path must be valid unicode").to_string()
}
});
- if let ErrorOutputType::HumanReadable(kind) = options.error_format {
+ if let ErrorOutputType::HumanReadable(kind) = rustdoc_options.error_format {
let (short, color_config) = kind.unzip();
if short {
@@ -431,20 +416,20 @@ fn run_test(
let out = out_lines.join("\n");
let _bomb = Bomb(&out);
- match (output.status.success(), compile_fail) {
+ match (output.status.success(), lang_string.compile_fail) {
(true, true) => {
return Err(TestFailure::UnexpectedCompilePass);
}
(true, false) => {}
(false, true) => {
- if !error_codes.is_empty() {
+ if !lang_string.error_codes.is_empty() {
// We used to check if the output contained "error[{}]: " but since we added the
// colored output, we can't anymore because of the color escape characters before
// the ":".
- error_codes.retain(|err| !out.contains(&format!("error[{}]", err)));
+ lang_string.error_codes.retain(|err| !out.contains(&format!("error[{}]", err)));
- if !error_codes.is_empty() {
- return Err(TestFailure::MissingErrorCodes(error_codes));
+ if !lang_string.error_codes.is_empty() {
+ return Err(TestFailure::MissingErrorCodes(lang_string.error_codes));
}
}
}
@@ -467,11 +452,11 @@ fn run_test(
} else {
cmd = Command::new(output_file);
}
- if let Some(run_directory) = options.test_run_directory {
+ if let Some(run_directory) = rustdoc_options.test_run_directory {
cmd.current_dir(run_directory);
}
- let result = if options.nocapture {
+ let result = if rustdoc_options.nocapture {
cmd.status().map(|status| process::Output {
status,
stdout: Vec::new(),
@@ -483,9 +468,9 @@ fn run_test(
match result {
Err(e) => return Err(TestFailure::ExecutionError(e)),
Ok(out) => {
- if should_panic && out.status.success() {
+ if lang_string.should_panic && out.status.success() {
return Err(TestFailure::UnexpectedRunPass);
- } else if !should_panic && !out.status.success() {
+ } else if !lang_string.should_panic && !out.status.success() {
return Err(TestFailure::ExecutionFailure(out));
}
}
@@ -500,7 +485,7 @@ crate fn make_test(
s: &str,
crate_name: Option<&str>,
dont_insert_main: bool,
- opts: &TestOptions,
+ opts: &GlobalTestOptions,
edition: Edition,
test_id: Option<&str>,
) -> (String, usize, bool) {
@@ -510,7 +495,7 @@ crate fn make_test(
let mut prog = String::new();
let mut supports_color = false;
- if opts.attrs.is_empty() && !opts.display_doctest_warnings {
+ if opts.attrs.is_empty() {
// If there aren't any attributes supplied by #![doc(test(attr(...)))], then allow some
// lints that are commonly triggered in doctests. The crate-level test attributes are
// commonly used to make tests fail in case they trigger warnings, so having this there in
@@ -537,6 +522,7 @@ crate fn make_test(
use rustc_errors::emitter::{Emitter, EmitterWriter};
use rustc_errors::Handler;
use rustc_parse::maybe_new_parser_from_source_str;
+ use rustc_parse::parser::ForceCollect;
use rustc_session::parse::ParseSess;
use rustc_span::source_map::FilePathMapping;
@@ -572,9 +558,9 @@ crate fn make_test(
}
};
- match parser.parse_mod(&token::Eof) {
- Ok((_attrs, items, _span)) => {
- for item in items {
+ loop {
+ match parser.parse_item(ForceCollect::No) {
+ Ok(Some(item)) => {
if !found_main {
if let ast::ItemKind::Fn(..) = item.kind {
if item.ident.name == sym::main {
@@ -606,10 +592,16 @@ crate fn make_test(
break;
}
}
+ Ok(None) => break,
+ Err(mut e) => {
+ e.cancel();
+ break;
+ }
}
- Err(mut e) => {
- e.cancel();
- }
+
+ // The supplied slice is only used for diagnostics,
+ // which are swallowed here anyway.
+ parser.maybe_consume_incorrect_semicolon(&[]);
}
// Reset errors so that they won't be reported as compiler bugs when dropping the
@@ -810,11 +802,11 @@ crate struct Collector {
// the `names` vector of that test will be `["Title", "Subtitle"]`.
names: Vec<String>,
- options: Options,
+ rustdoc_options: RustdocOptions,
use_headers: bool,
enable_per_target_ignores: bool,
crate_name: Symbol,
- opts: TestOptions,
+ opts: GlobalTestOptions,
position: Span,
source_map: Option<Lrc<SourceMap>>,
filename: Option<PathBuf>,
@@ -826,9 +818,9 @@ crate struct Collector {
impl Collector {
crate fn new(
crate_name: Symbol,
- options: Options,
+ rustdoc_options: RustdocOptions,
use_headers: bool,
- opts: TestOptions,
+ opts: GlobalTestOptions,
source_map: Option<Lrc<SourceMap>>,
filename: Option<PathBuf>,
enable_per_target_ignores: bool,
@@ -836,7 +828,7 @@ impl Collector {
Collector {
tests: Vec::new(),
names: Vec::new(),
- options,
+ rustdoc_options,
use_headers,
enable_per_target_ignores,
crate_name,
@@ -890,14 +882,14 @@ impl Tester for Collector {
let name = self.generate_name(line, &filename);
let crate_name = self.crate_name.to_string();
let opts = self.opts.clone();
- let edition = config.edition.unwrap_or(self.options.edition);
- let options = self.options.clone();
- let runtool = self.options.runtool.clone();
- let runtool_args = self.options.runtool_args.clone();
- let target = self.options.target.clone();
+ let edition = config.edition.unwrap_or(self.rustdoc_options.edition);
+ let rustdoc_options = self.rustdoc_options.clone();
+ let runtool = self.rustdoc_options.runtool.clone();
+ let runtool_args = self.rustdoc_options.runtool_args.clone();
+ let target = self.rustdoc_options.target.clone();
let target_str = target.to_string();
let unused_externs = self.unused_extern_reports.clone();
- let no_run = config.no_run || options.no_run;
+ let no_run = config.no_run || rustdoc_options.no_run;
if !config.compile_fail {
self.compiling_test_count.fetch_add(1, Ordering::SeqCst);
}
@@ -931,7 +923,7 @@ impl Tester for Collector {
self.visited_tests.entry((file.clone(), line)).and_modify(|v| *v += 1).or_insert(0)
},
);
- let outdir = if let Some(mut path) = options.persist_doctests.clone() {
+ let outdir = if let Some(mut path) = rustdoc_options.persist_doctests.clone() {
path.push(&test_id);
std::fs::create_dir_all(&path)
@@ -971,15 +963,12 @@ impl Tester for Collector {
&test,
&crate_name,
line,
- options,
- config.should_panic,
+ rustdoc_options,
+ config,
no_run,
- config.test_harness,
runtool,
runtool_args,
target,
- config.compile_fail,
- config.error_codes,
&opts,
edition,
outdir,
diff --git a/src/librustdoc/doctest/tests.rs b/src/librustdoc/doctest/tests.rs
index 18517080965..360d2259ea3 100644
--- a/src/librustdoc/doctest/tests.rs
+++ b/src/librustdoc/doctest/tests.rs
@@ -1,10 +1,10 @@
-use super::{make_test, TestOptions};
+use super::{make_test, GlobalTestOptions};
use rustc_span::edition::DEFAULT_EDITION;
#[test]
fn make_test_basic() {
//basic use: wraps with `fn main`, adds `#![allow(unused)]`
- let opts = TestOptions::default();
+ let opts = GlobalTestOptions::default();
let input = "assert_eq!(2+2, 4);";
let expected = "#![allow(unused)]
fn main() {
@@ -19,7 +19,7 @@ assert_eq!(2+2, 4);
fn make_test_crate_name_no_use() {
// If you give a crate name but *don't* use it within the test, it won't bother inserting
// the `extern crate` statement.
- let opts = TestOptions::default();
+ let opts = GlobalTestOptions::default();
let input = "assert_eq!(2+2, 4);";
let expected = "#![allow(unused)]
fn main() {
@@ -34,7 +34,7 @@ assert_eq!(2+2, 4);
fn make_test_crate_name() {
// If you give a crate name and use it within the test, it will insert an `extern crate`
// statement before `fn main`.
- let opts = TestOptions::default();
+ let opts = GlobalTestOptions::default();
let input = "use asdf::qwop;
assert_eq!(2+2, 4);";
let expected = "#![allow(unused)]
@@ -52,8 +52,7 @@ assert_eq!(2+2, 4);
fn make_test_no_crate_inject() {
// Even if you do use the crate within the test, setting `opts.no_crate_inject` will skip
// adding it anyway.
- let opts =
- TestOptions { no_crate_inject: true, display_doctest_warnings: false, attrs: vec![] };
+ let opts = GlobalTestOptions { no_crate_inject: true, attrs: vec![] };
let input = "use asdf::qwop;
assert_eq!(2+2, 4);";
let expected = "#![allow(unused)]
@@ -71,7 +70,7 @@ fn make_test_ignore_std() {
// Even if you include a crate name, and use it in the doctest, we still won't include an
// `extern crate` statement if the crate is "std" -- that's included already by the
// compiler!
- let opts = TestOptions::default();
+ let opts = GlobalTestOptions::default();
let input = "use std::*;
assert_eq!(2+2, 4);";
let expected = "#![allow(unused)]
@@ -88,7 +87,7 @@ assert_eq!(2+2, 4);
fn make_test_manual_extern_crate() {
// When you manually include an `extern crate` statement in your doctest, `make_test`
// assumes you've included one for your own crate too.
- let opts = TestOptions::default();
+ let opts = GlobalTestOptions::default();
let input = "extern crate asdf;
use asdf::qwop;
assert_eq!(2+2, 4);";
@@ -105,7 +104,7 @@ assert_eq!(2+2, 4);
#[test]
fn make_test_manual_extern_crate_with_macro_use() {
- let opts = TestOptions::default();
+ let opts = GlobalTestOptions::default();
let input = "#[macro_use] extern crate asdf;
use asdf::qwop;
assert_eq!(2+2, 4);";
@@ -124,7 +123,7 @@ assert_eq!(2+2, 4);
fn make_test_opts_attrs() {
// If you supplied some doctest attributes with `#![doc(test(attr(...)))]`, it will use
// those instead of the stock `#![allow(unused)]`.
- let mut opts = TestOptions::default();
+ let mut opts = GlobalTestOptions::default();
opts.attrs.push("feature(sick_rad)".to_string());
let input = "use asdf::qwop;
assert_eq!(2+2, 4);";
@@ -156,7 +155,7 @@ assert_eq!(2+2, 4);
fn make_test_crate_attrs() {
// Including inner attributes in your doctest will apply them to the whole "crate", pasting
// them outside the generated main function.
- let opts = TestOptions::default();
+ let opts = GlobalTestOptions::default();
let input = "#![feature(sick_rad)]
assert_eq!(2+2, 4);";
let expected = "#![allow(unused)]
@@ -172,7 +171,7 @@ assert_eq!(2+2, 4);
#[test]
fn make_test_with_main() {
// Including your own `fn main` wrapper lets the test use it verbatim.
- let opts = TestOptions::default();
+ let opts = GlobalTestOptions::default();
let input = "fn main() {
assert_eq!(2+2, 4);
}";
@@ -188,7 +187,7 @@ fn main() {
#[test]
fn make_test_fake_main() {
// ... but putting it in a comment will still provide a wrapper.
- let opts = TestOptions::default();
+ let opts = GlobalTestOptions::default();
let input = "//Ceci n'est pas une `fn main`
assert_eq!(2+2, 4);";
let expected = "#![allow(unused)]
@@ -204,7 +203,7 @@ assert_eq!(2+2, 4);
#[test]
fn make_test_dont_insert_main() {
// Even with that, if you set `dont_insert_main`, it won't create the `fn main` wrapper.
- let opts = TestOptions::default();
+ let opts = GlobalTestOptions::default();
let input = "//Ceci n'est pas une `fn main`
assert_eq!(2+2, 4);";
let expected = "#![allow(unused)]
@@ -216,22 +215,8 @@ assert_eq!(2+2, 4);"
}
#[test]
-fn make_test_display_doctest_warnings() {
- // If the user is asking to display doctest warnings, suppress the default `allow(unused)`.
- let mut opts = TestOptions::default();
- opts.display_doctest_warnings = true;
- let input = "assert_eq!(2+2, 4);";
- let expected = "fn main() {
-assert_eq!(2+2, 4);
-}"
- .to_string();
- let (output, len, _) = make_test(input, None, false, &opts, DEFAULT_EDITION, None);
- assert_eq!((output, len), (expected, 1));
-}
-
-#[test]
fn make_test_issues_21299_33731() {
- let opts = TestOptions::default();
+ let opts = GlobalTestOptions::default();
let input = "// fn main
assert_eq!(2+2, 4);";
@@ -263,7 +248,7 @@ assert_eq!(asdf::foo, 4);
#[test]
fn make_test_main_in_macro() {
- let opts = TestOptions::default();
+ let opts = GlobalTestOptions::default();
let input = "#[macro_use] extern crate my_crate;
test_wrapper! {
fn main() {}
@@ -282,7 +267,7 @@ test_wrapper! {
#[test]
fn make_test_returns_result() {
// creates an inner function and unwraps it
- let opts = TestOptions::default();
+ let opts = GlobalTestOptions::default();
let input = "use std::io;
let mut input = String::new();
io::stdin().read_line(&mut input)?;
@@ -302,7 +287,7 @@ Ok::<(), io:Error>(())
#[test]
fn make_test_named_wrapper() {
// creates an inner function with a specific name
- let opts = TestOptions::default();
+ let opts = GlobalTestOptions::default();
let input = "assert_eq!(2+2, 4);";
let expected = "#![allow(unused)]
fn main() { #[allow(non_snake_case)] fn _doctest_main__some_unique_name() {
diff --git a/src/librustdoc/error.rs b/src/librustdoc/error.rs
index 82d0002b98b..8eadbf63f33 100644
--- a/src/librustdoc/error.rs
+++ b/src/librustdoc/error.rs
@@ -39,7 +39,10 @@ macro_rules! try_none {
match $e {
Some(e) => e,
None => {
- return Err(Error::new(io::Error::new(io::ErrorKind::Other, "not found"), $file));
+ return Err(<crate::error::Error as crate::docfs::PathError>::new(
+ io::Error::new(io::ErrorKind::Other, "not found"),
+ $file,
+ ));
}
}
}};
diff --git a/src/librustdoc/formats/cache.rs b/src/librustdoc/formats/cache.rs
index db2b836de86..d3831450e1d 100644
--- a/src/librustdoc/formats/cache.rs
+++ b/src/librustdoc/formats/cache.rs
@@ -27,7 +27,7 @@ use crate::html::render::IndexItem;
#[derive(Default)]
crate struct Cache {
/// Maps a type ID to all known implementations for that type. This is only
- /// recognized for intra-crate `ResolvedPath` types, and is used to print
+ /// recognized for intra-crate [`clean::Type::Path`]s, and is used to print
/// out extra documentation on the page of an enum/struct.
///
/// The values of the map are a list of implementations and documentation
@@ -401,8 +401,8 @@ impl<'a, 'tcx> DocFolder for CacheBuilder<'a, 'tcx> {
clean::ImplItem(ref i) => {
self.cache.parent_is_trait_impl = i.trait_.is_some();
match i.for_ {
- clean::ResolvedPath { did, .. } => {
- self.cache.parent_stack.push(did);
+ clean::Type::Path { ref path } => {
+ self.cache.parent_stack.push(path.def_id());
true
}
clean::DynTrait(ref bounds, _)
@@ -436,9 +436,9 @@ impl<'a, 'tcx> DocFolder for CacheBuilder<'a, 'tcx> {
// Note: matching twice to restrict the lifetime of the `i` borrow.
let mut dids = FxHashSet::default();
match i.for_ {
- clean::ResolvedPath { did, .. }
- | clean::BorrowedRef { type_: box clean::ResolvedPath { did, .. }, .. } => {
- dids.insert(did);
+ clean::Type::Path { ref path }
+ | clean::BorrowedRef { type_: box clean::Type::Path { ref path }, .. } => {
+ dids.insert(path.def_id());
}
clean::DynTrait(ref bounds, _)
| clean::BorrowedRef { type_: box clean::DynTrait(ref bounds, _), .. } => {
diff --git a/src/librustdoc/html/format.rs b/src/librustdoc/html/format.rs
index 4f204913204..f6788e94431 100644
--- a/src/librustdoc/html/format.rs
+++ b/src/librustdoc/html/format.rs
@@ -13,8 +13,10 @@ use rustc_attr::{ConstStability, StabilityLevel};
use rustc_data_structures::captures::Captures;
use rustc_data_structures::fx::FxHashSet;
use rustc_hir as hir;
+use rustc_hir::def::DefKind;
use rustc_hir::def_id::DefId;
use rustc_middle::ty;
+use rustc_middle::ty::DefIdTree;
use rustc_middle::ty::TyCtxt;
use rustc_span::def_id::CRATE_DEF_INDEX;
use rustc_target::spec::abi::Abi;
@@ -25,6 +27,8 @@ use crate::html::escape::Escape;
use crate::html::render::cache::ExternalLocation;
use crate::html::render::Context;
+use super::url_parts_builder::UrlPartsBuilder;
+
crate trait Print {
fn print(self, buffer: &mut Buffer);
}
@@ -344,7 +348,7 @@ crate fn print_where_clause<'a, 'tcx: 'a>(
impl clean::Lifetime {
crate fn print(&self) -> impl fmt::Display + '_ {
- self.get_ref()
+ self.0.as_str()
}
}
@@ -502,7 +506,16 @@ crate fn href_with_root_path(
cx: &Context<'_>,
root_path: Option<&str>,
) -> Result<(String, ItemType, Vec<String>), HrefError> {
- let cache = &cx.cache();
+ let tcx = cx.tcx();
+ let def_kind = tcx.def_kind(did);
+ let did = match def_kind {
+ DefKind::AssocTy | DefKind::AssocFn | DefKind::AssocConst | DefKind::Variant => {
+ // documented on their parent's page
+ tcx.parent(did).unwrap()
+ }
+ _ => did,
+ };
+ let cache = cx.cache();
let relative_to = &cx.current;
fn to_module_fqp(shortty: ItemType, fqp: &[String]) -> &[String] {
if shortty == ItemType::Module { fqp } else { &fqp[..fqp.len() - 1] }
@@ -533,9 +546,9 @@ crate fn href_with_root_path(
ExternalLocation::Remote(ref s) => {
is_remote = true;
let s = s.trim_end_matches('/');
- let mut s = vec![s];
- s.extend(module_fqp[..].iter().map(String::as_str));
- s
+ let mut builder = UrlPartsBuilder::singleton(s);
+ builder.extend(module_fqp.iter().map(String::as_str));
+ builder
}
ExternalLocation::Local => href_relative_parts(module_fqp, relative_to),
ExternalLocation::Unknown => return Err(HrefError::DocumentationNotBuilt),
@@ -549,22 +562,21 @@ crate fn href_with_root_path(
if !is_remote {
if let Some(root_path) = root_path {
let root = root_path.trim_end_matches('/');
- url_parts.insert(0, root);
+ url_parts.push_front(root);
}
}
debug!(?url_parts);
let last = &fqp.last().unwrap()[..];
- let filename;
match shortty {
ItemType::Module => {
url_parts.push("index.html");
}
_ => {
- filename = format!("{}.{}.html", shortty.as_str(), last);
+ let filename = format!("{}.{}.html", shortty.as_str(), last);
url_parts.push(&filename);
}
}
- Ok((url_parts.join("/"), shortty, fqp.to_vec()))
+ Ok((url_parts.finish(), shortty, fqp.to_vec()))
}
crate fn href(did: DefId, cx: &Context<'_>) -> Result<(String, ItemType, Vec<String>), HrefError> {
@@ -574,7 +586,7 @@ crate fn href(did: DefId, cx: &Context<'_>) -> Result<(String, ItemType, Vec<Str
/// Both paths should only be modules.
/// This is because modules get their own directories; that is, `std::vec` and `std::vec::Vec` will
/// both need `../iter/trait.Iterator.html` to get at the iterator trait.
-crate fn href_relative_parts<'a>(fqp: &'a [String], relative_to_fqp: &'a [String]) -> Vec<&'a str> {
+crate fn href_relative_parts(fqp: &[String], relative_to_fqp: &[String]) -> UrlPartsBuilder {
for (i, (f, r)) in fqp.iter().zip(relative_to_fqp.iter()).enumerate() {
// e.g. linking to std::iter from std::vec (`dissimilar_part_count` will be 1)
if f != r {
@@ -592,12 +604,11 @@ crate fn href_relative_parts<'a>(fqp: &'a [String], relative_to_fqp: &'a [String
iter::repeat("..").take(dissimilar_part_count).collect()
// linking to the same module
} else {
- Vec::new()
+ UrlPartsBuilder::new()
}
}
-/// Used when rendering a `ResolvedPath` structure. This invokes the `path`
-/// rendering function with the necessary arguments for linking to a local path.
+/// Used to render a [`clean::Path`].
fn resolved_path<'cx>(
w: &mut fmt::Formatter<'_>,
did: DefId,
@@ -751,8 +762,9 @@ fn fmt_type<'cx>(
match *t {
clean::Generic(name) => write!(f, "{}", name),
- clean::ResolvedPath { did, ref path } => {
+ clean::Type::Path { ref path } => {
// Paths like `T::Output` and `Self::Output` should be rendered with all segments.
+ let did = path.def_id();
resolved_path(f, did, path, path.is_assoc_ty(), use_absolute, cx)
}
clean::DynTrait(ref bounds, ref lt) => {
@@ -1166,6 +1178,10 @@ impl clean::FnDecl {
args.push_str(" <br>");
args_plain.push(' ');
}
+ if input.is_const {
+ args.push_str("const ");
+ args_plain.push_str("const ");
+ }
if !input.name.is_empty() {
args.push_str(&format!("{}: ", input.name));
args_plain.push_str(&format!("{}: ", input.name));
@@ -1338,10 +1354,7 @@ impl PrintWithSpace for hir::Mutability {
}
}
-crate fn print_constness_with_space(
- c: &hir::Constness,
- s: Option<&ConstStability>,
-) -> &'static str {
+crate fn print_constness_with_space(c: &hir::Constness, s: Option<ConstStability>) -> &'static str {
match (c, s) {
// const stable or when feature(staged_api) is not set
(
diff --git a/src/librustdoc/html/highlight.rs b/src/librustdoc/html/highlight.rs
index e177a113036..688860f94e1 100644
--- a/src/librustdoc/html/highlight.rs
+++ b/src/librustdoc/html/highlight.rs
@@ -632,7 +632,7 @@ impl<'a> Classifier<'a> {
},
Some(c) => c,
},
- TokenKind::RawIdent | TokenKind::UnknownPrefix => {
+ TokenKind::RawIdent | TokenKind::UnknownPrefix | TokenKind::InvalidIdent => {
Class::Ident(self.new_span(before, text))
}
TokenKind::Lifetime { .. } => Class::Lifetime,
diff --git a/src/librustdoc/html/layout.rs b/src/librustdoc/html/layout.rs
index 71d7cc1a09d..3d3fa3aaeaa 100644
--- a/src/librustdoc/html/layout.rs
+++ b/src/librustdoc/html/layout.rs
@@ -2,8 +2,8 @@ use std::path::PathBuf;
use rustc_data_structures::fx::FxHashMap;
+use crate::error::Error;
use crate::externalfiles::ExternalHtml;
-use crate::html::escape::Escape;
use crate::html::format::{Buffer, Print};
use crate::html::render::{ensure_trailing_slash, StylePath};
@@ -50,10 +50,11 @@ struct PageLayout<'a> {
static_root_path: &'a str,
page: &'a Page<'a>,
layout: &'a Layout,
- style_files: String,
+ themes: Vec<String>,
sidebar: String,
content: String,
krate_with_trailing_slash: String,
+ crate rustdoc_version: &'a str,
}
crate fn render<T: Print, S: Print>(
@@ -66,29 +67,24 @@ crate fn render<T: Print, S: Print>(
) -> String {
let static_root_path = page.get_static_root_path();
let krate_with_trailing_slash = ensure_trailing_slash(&layout.krate).to_string();
- let style_files = style_files
+ let mut themes: Vec<String> = style_files
.iter()
- .filter_map(|t| t.path.file_stem().map(|stem| (stem, t.disabled)))
- .filter_map(|t| t.0.to_str().map(|path| (path, t.1)))
- .map(|t| {
- format!(
- r#"<link rel="stylesheet" type="text/css" href="{}.css" {} {}>"#,
- Escape(&format!("{}{}{}", static_root_path, t.0, page.resource_suffix)),
- if t.1 { "disabled" } else { "" },
- if t.0 == "light" { "id=\"themeStyle\"" } else { "" }
- )
- })
- .collect::<String>();
+ .map(StylePath::basename)
+ .collect::<Result<_, Error>>()
+ .unwrap_or_default();
+ themes.sort();
+ let rustdoc_version = rustc_interface::util::version_str().unwrap_or("unknown version");
let content = Buffer::html().to_display(t); // Note: This must happen before making the sidebar.
let sidebar = Buffer::html().to_display(sidebar);
let teractx = tera::Context::from_serialize(PageLayout {
static_root_path,
page,
layout,
- style_files,
+ themes,
sidebar,
content,
krate_with_trailing_slash,
+ rustdoc_version,
})
.unwrap();
templates.render("page.html", &teractx).unwrap()
diff --git a/src/librustdoc/html/markdown.rs b/src/librustdoc/html/markdown.rs
index d811c85ea58..545b409175e 100644
--- a/src/librustdoc/html/markdown.rs
+++ b/src/librustdoc/html/markdown.rs
@@ -1447,7 +1447,7 @@ fn init_id_map() -> FxHashMap<String, usize> {
map.insert("theme-choices".to_owned(), 1);
map.insert("settings-menu".to_owned(), 1);
map.insert("help-button".to_owned(), 1);
- map.insert("main".to_owned(), 1);
+ map.insert("main-content".to_owned(), 1);
map.insert("search".to_owned(), 1);
map.insert("crate-search".to_owned(), 1);
map.insert("render-detail".to_owned(), 1);
diff --git a/src/librustdoc/html/markdown/tests.rs b/src/librustdoc/html/markdown/tests.rs
index 68ab002f138..d4af3663b62 100644
--- a/src/librustdoc/html/markdown/tests.rs
+++ b/src/librustdoc/html/markdown/tests.rs
@@ -12,7 +12,7 @@ fn test_unique_id() {
"examples",
"method.into_iter",
"foo",
- "main",
+ "main-content",
"search",
"methods",
"examples",
@@ -28,7 +28,7 @@ fn test_unique_id() {
"examples-2",
"method.into_iter-1",
"foo-1",
- "main-1",
+ "main-content-1",
"search-1",
"methods",
"examples-3",
@@ -219,8 +219,8 @@ fn test_header_ids_multiple_blocks() {
);
t(
&mut map,
- "# Main",
- "<h2 id=\"main-1\" class=\"section-header\"><a href=\"#main-1\">Main</a></h2>",
+ "# Search",
+ "<h2 id=\"search-1\" class=\"section-header\"><a href=\"#search-1\">Search</a></h2>",
);
t(
&mut map,
diff --git a/src/librustdoc/html/mod.rs b/src/librustdoc/html/mod.rs
index 109b0a356db..e1bbc784fd1 100644
--- a/src/librustdoc/html/mod.rs
+++ b/src/librustdoc/html/mod.rs
@@ -9,6 +9,7 @@ crate mod render;
crate mod sources;
crate mod static_files;
crate mod toc;
+mod url_parts_builder;
#[cfg(test)]
mod tests;
diff --git a/src/librustdoc/html/render/cache.rs b/src/librustdoc/html/render/cache.rs
index 9aa69d94215..631eacc9618 100644
--- a/src/librustdoc/html/render/cache.rs
+++ b/src/librustdoc/html/render/cache.rs
@@ -184,8 +184,8 @@ crate fn build_index<'tcx>(krate: &clean::Crate, cache: &mut Cache, tcx: TyCtxt<
})
.expect("failed serde conversion")
// All these `replace` calls are because we have to go through JS string for JSON content.
- .replace(r"\", r"\\")
- .replace("'", r"\'")
+ .replace(r#"\"#, r"\\")
+ .replace(r#"'"#, r"\'")
// We need to escape double quotes for the JSON.
.replace("\\\"", "\\\\\"")
)
@@ -218,7 +218,7 @@ fn get_index_type(clean_type: &clean::Type, generics: Vec<TypeWithKind>) -> Rend
fn get_index_type_name(clean_type: &clean::Type, accept_generic: bool) -> Option<Symbol> {
match *clean_type {
- clean::ResolvedPath { ref path, .. } => {
+ clean::Type::Path { ref path, .. } => {
let path_segment = path.segments.last().unwrap();
Some(path_segment.name)
}
@@ -347,19 +347,19 @@ crate fn get_real_types<'tcx>(
let bounds = where_pred.get_bounds().unwrap_or_else(|| &[]);
for bound in bounds.iter() {
if let GenericBound::TraitBound(poly_trait, _) = bound {
- for x in poly_trait.generic_params.iter() {
- if !x.is_type() {
- continue;
- }
- if let Some(ty) = x.get_type() {
- get_real_types(
- generics,
- &ty,
- tcx,
- recurse + 1,
- &mut ty_generics,
- cache,
- );
+ for param_def in poly_trait.generic_params.iter() {
+ match &param_def.kind {
+ clean::GenericParamDefKind::Type { default: Some(ty), .. } => {
+ get_real_types(
+ generics,
+ ty,
+ tcx,
+ recurse + 1,
+ &mut ty_generics,
+ cache,
+ )
+ }
+ _ => {}
}
}
}
@@ -371,7 +371,7 @@ crate fn get_real_types<'tcx>(
let mut ty_generics = Vec::new();
for bound in bound.get_bounds().unwrap_or(&[]) {
if let Some(path) = bound.get_trait_path() {
- let ty = Type::ResolvedPath { did: path.def_id(), path };
+ let ty = Type::Path { path };
get_real_types(generics, &ty, tcx, recurse + 1, &mut ty_generics, cache);
}
}
diff --git a/src/librustdoc/html/render/context.rs b/src/librustdoc/html/render/context.rs
index 069862efde6..365d959ad9f 100644
--- a/src/librustdoc/html/render/context.rs
+++ b/src/librustdoc/html/render/context.rs
@@ -504,9 +504,9 @@ impl<'tcx> FormatRenderer<'tcx> for Context<'tcx> {
// by the browser as the theme stylesheet. The theme system (hackily) works by
// changing the href to this stylesheet. All other themes are disabled to
// prevent rule conflicts
- scx.style_files.push(StylePath { path: PathBuf::from("light.css"), disabled: false });
- scx.style_files.push(StylePath { path: PathBuf::from("dark.css"), disabled: true });
- scx.style_files.push(StylePath { path: PathBuf::from("ayu.css"), disabled: true });
+ scx.style_files.push(StylePath { path: PathBuf::from("light.css") });
+ scx.style_files.push(StylePath { path: PathBuf::from("dark.css") });
+ scx.style_files.push(StylePath { path: PathBuf::from("ayu.css") });
let dst = output;
scx.ensure_dir(&dst)?;
@@ -596,9 +596,13 @@ impl<'tcx> FormatRenderer<'tcx> for Context<'tcx> {
page.description = "Settings of Rustdoc";
page.root_path = "./";
- let mut style_files = self.shared.style_files.clone();
let sidebar = "<h2 class=\"location\">Settings</h2><div class=\"sidebar-elems\"></div>";
- style_files.push(StylePath { path: PathBuf::from("settings.css"), disabled: false });
+ let theme_names: Vec<String> = self
+ .shared
+ .style_files
+ .iter()
+ .map(StylePath::basename)
+ .collect::<Result<_, Error>>()?;
let v = layout::render(
&self.shared.templates,
&self.shared.layout,
@@ -607,9 +611,9 @@ impl<'tcx> FormatRenderer<'tcx> for Context<'tcx> {
settings(
self.shared.static_root_path.as_deref().unwrap_or("./"),
&self.shared.resource_suffix,
- &self.shared.style_files,
+ theme_names,
)?,
- &style_files,
+ &self.shared.style_files,
);
self.shared.fs.write(settings_file, v)?;
if let Some(ref redirections) = self.shared.redirections {
diff --git a/src/librustdoc/html/render/mod.rs b/src/librustdoc/html/render/mod.rs
index ffd09663f82..2432f5cc085 100644
--- a/src/librustdoc/html/render/mod.rs
+++ b/src/librustdoc/html/render/mod.rs
@@ -64,7 +64,6 @@ use serde::ser::SerializeSeq;
use serde::{Serialize, Serializer};
use crate::clean::{self, ItemId, RenderedLink, SelfTy};
-use crate::docfs::PathError;
use crate::error::Error;
use crate::formats::cache::Cache;
use crate::formats::item_type::ItemType;
@@ -173,8 +172,12 @@ impl Serialize for TypeWithKind {
crate struct StylePath {
/// The path to the theme
crate path: PathBuf,
- /// What the `disabled` attribute should be set to in the HTML tag
- crate disabled: bool,
+}
+
+impl StylePath {
+ pub fn basename(&self) -> Result<String, Error> {
+ Ok(try_none!(try_none!(self.path.file_stem(), &self.path).to_str(), &self.path).to_string())
+ }
}
fn write_srclink(cx: &Context<'_>, item: &clean::Item, buf: &mut Buffer) {
@@ -353,7 +356,7 @@ enum Setting {
js_data_name: &'static str,
description: &'static str,
default_value: &'static str,
- options: Vec<(String, String)>,
+ options: Vec<String>,
},
}
@@ -393,10 +396,9 @@ impl Setting {
options
.iter()
.map(|opt| format!(
- "<option value=\"{}\" {}>{}</option>",
- opt.0,
- if opt.0 == default_value { "selected" } else { "" },
- opt.1,
+ "<option value=\"{name}\" {}>{name}</option>",
+ if opt == default_value { "selected" } else { "" },
+ name = opt,
))
.collect::<String>(),
root_path,
@@ -421,18 +423,7 @@ impl<T: Into<Setting>> From<(&'static str, Vec<T>)> for Setting {
}
}
-fn settings(root_path: &str, suffix: &str, themes: &[StylePath]) -> Result<String, Error> {
- let theme_names: Vec<(String, String)> = themes
- .iter()
- .map(|entry| {
- let theme =
- try_none!(try_none!(entry.path.file_stem(), &entry.path).to_str(), &entry.path)
- .to_string();
-
- Ok((theme.clone(), theme))
- })
- .collect::<Result<_, Error>>()?;
-
+fn settings(root_path: &str, suffix: &str, theme_names: Vec<String>) -> Result<String, Error> {
// (id, explanation, default value)
let settings: &[Setting] = &[
(
@@ -469,10 +460,11 @@ fn settings(root_path: &str, suffix: &str, themes: &[StylePath]) -> Result<Strin
<span class=\"in-band\">Rustdoc settings</span>\
</h1>\
<div class=\"settings\">{}</div>\
- <script src=\"{}settings{}.js\"></script>",
+ <link rel=\"stylesheet\" href=\"{root_path}settings{suffix}.css\">\
+ <script src=\"{root_path}settings{suffix}.js\"></script>",
settings.iter().map(|s| s.display(root_path, suffix)).collect::<String>(),
- root_path,
- suffix
+ root_path = root_path,
+ suffix = suffix
))
}
@@ -682,7 +674,7 @@ fn short_item_info(
// Render unstable items. But don't render "rustc_private" crates (internal compiler crates).
// Those crates are permanently unstable so it makes no sense to render "unstable" everywhere.
- if let Some((StabilityLevel::Unstable { reason, issue, .. }, feature)) = item
+ if let Some((StabilityLevel::Unstable { reason: _, issue, .. }, feature)) = item
.stability(cx.tcx())
.as_ref()
.filter(|stab| stab.feature != sym::rustc_private)
@@ -702,22 +694,6 @@ fn short_item_info(
message.push_str(&format!(" ({})", feature));
- if let Some(unstable_reason) = reason {
- let mut ids = cx.id_map.borrow_mut();
- message = format!(
- "<details><summary>{}</summary>{}</details>",
- message,
- MarkdownHtml(
- &unstable_reason.as_str(),
- &mut ids,
- error_codes,
- cx.shared.edition(),
- &cx.shared.playground,
- )
- .into_string()
- );
- }
-
extra_info.push(format!("<div class=\"stab unstable\">{}</div>", message));
}
@@ -786,7 +762,6 @@ fn assoc_const(
w: &mut Buffer,
it: &clean::Item,
ty: &clean::Type,
- _default: Option<&String>,
link: AssocItemLink<'_>,
extra: &str,
cx: &Context<'_>,
@@ -828,17 +803,17 @@ fn assoc_type(
fn render_stability_since_raw(
w: &mut Buffer,
- ver: Option<&str>,
- const_stability: Option<&ConstStability>,
- containing_ver: Option<&str>,
- containing_const_ver: Option<&str>,
+ ver: Option<Symbol>,
+ const_stability: Option<ConstStability>,
+ containing_ver: Option<Symbol>,
+ containing_const_ver: Option<Symbol>,
) {
let ver = ver.filter(|inner| !inner.is_empty());
match (ver, const_stability) {
// stable and const stable
(Some(v), Some(ConstStability { level: StabilityLevel::Stable { since }, .. }))
- if Some(since.as_str()).as_deref() != containing_const_ver =>
+ if Some(since) != containing_const_ver =>
{
write!(
w,
@@ -885,6 +860,7 @@ fn render_assoc_item(
link: AssocItemLink<'_>,
parent: ItemType,
cx: &Context<'_>,
+ render_mode: RenderMode,
) {
fn method(
w: &mut Buffer,
@@ -895,6 +871,7 @@ fn render_assoc_item(
link: AssocItemLink<'_>,
parent: ItemType,
cx: &Context<'_>,
+ render_mode: RenderMode,
) {
let name = meth.name.as_ref().unwrap();
let href = match link {
@@ -917,8 +894,14 @@ fn render_assoc_item(
}
};
let vis = meth.visibility.print_with_space(meth.def_id, cx).to_string();
- let constness =
- print_constness_with_space(&header.constness, meth.const_stability(cx.tcx()));
+ // FIXME: Once https://github.com/rust-lang/rust/issues/67792 is implemented, we can remove
+ // this condition.
+ let constness = match render_mode {
+ RenderMode::Normal => {
+ print_constness_with_space(&header.constness, meth.const_stability(cx.tcx()))
+ }
+ RenderMode::ForDeref { .. } => "",
+ };
let asyncness = header.asyncness.print_with_space();
let unsafety = header.unsafety.print_with_space();
let defaultness = print_default_space(meth.is_default());
@@ -969,20 +952,14 @@ fn render_assoc_item(
match *item.kind {
clean::StrippedItem(..) => {}
clean::TyMethodItem(ref m) => {
- method(w, item, m.header, &m.generics, &m.decl, link, parent, cx)
+ method(w, item, m.header, &m.generics, &m.decl, link, parent, cx, render_mode)
}
clean::MethodItem(ref m, _) => {
- method(w, item, m.header, &m.generics, &m.decl, link, parent, cx)
+ method(w, item, m.header, &m.generics, &m.decl, link, parent, cx, render_mode)
+ }
+ clean::AssocConstItem(ref ty, _) => {
+ assoc_const(w, item, ty, link, if parent == ItemType::Trait { " " } else { "" }, cx)
}
- clean::AssocConstItem(ref ty, ref default) => assoc_const(
- w,
- item,
- ty,
- default.as_ref(),
- link,
- if parent == ItemType::Trait { " " } else { "" },
- cx,
- ),
clean::AssocTypeItem(ref bounds, ref default) => assoc_type(
w,
item,
@@ -1005,7 +982,7 @@ fn attributes(it: &clean::Item) -> Vec<String> {
.iter()
.filter_map(|attr| {
if ALLOWED_ATTRIBUTES.contains(&attr.name_or_empty()) {
- Some(pprust::attribute_to_string(attr).replace("\n", "").replace(" ", " "))
+ Some(pprust::attribute_to_string(attr).replace('\n', "").replace(" ", " "))
} else {
None
}
@@ -1243,8 +1220,8 @@ fn should_render_item(item: &clean::Item, deref_mut_: bool, tcx: TyCtxt<'_>) ->
| SelfTy::SelfExplicit(clean::BorrowedRef { mutability, .. }) => {
(mutability == Mutability::Mut, false, false)
}
- SelfTy::SelfExplicit(clean::ResolvedPath { did, .. }) => {
- (false, Some(did) == tcx.lang_items().owned_box(), false)
+ SelfTy::SelfExplicit(clean::Type::Path { path }) => {
+ (false, Some(path.def_id()) == tcx.lang_items().owned_box(), false)
}
SelfTy::SelfValue => (false, false, true),
_ => (false, false, false),
@@ -1259,10 +1236,17 @@ fn should_render_item(item: &clean::Item, deref_mut_: bool, tcx: TyCtxt<'_>) ->
fn notable_traits_decl(decl: &clean::FnDecl, cx: &Context<'_>) -> String {
let mut out = Buffer::html();
- if let Some(did) = decl.output.as_return().and_then(|t| t.def_id(cx.cache())) {
+ if let Some((did, ty)) = decl.output.as_return().and_then(|t| Some((t.def_id(cx.cache())?, t)))
+ {
if let Some(impls) = cx.cache().impls.get(&did) {
for i in impls {
let impl_ = i.inner_impl();
+ if !impl_.for_.without_borrowed_ref().is_same(ty.without_borrowed_ref(), cx.cache())
+ {
+ // Two different types might have the same did,
+ // without actually being the same.
+ continue;
+ }
if let Some(trait_) = &impl_.trait_ {
let trait_did = trait_.def_id();
@@ -1439,7 +1423,7 @@ fn render_impl(
"<div id=\"{}\" class=\"{}{} has-srclink\">",
id, item_type, in_trait_class,
);
- render_rightside(w, cx, item, containing_item);
+ render_rightside(w, cx, item, containing_item, render_mode);
write!(w, "<a href=\"#{}\" class=\"anchor\"></a>", id);
w.write_str("<h4 class=\"code-header\">");
render_assoc_item(
@@ -1448,6 +1432,7 @@ fn render_impl(
link.anchor(source_id.as_ref().unwrap_or(&id)),
ItemType::Impl,
cx,
+ render_mode,
);
w.write_str("</h4>");
w.write_str("</div>");
@@ -1475,7 +1460,7 @@ fn render_impl(
w.write_str("</h4>");
w.write_str("</div>");
}
- clean::AssocConstItem(ref ty, ref default) => {
+ clean::AssocConstItem(ref ty, _) => {
let source_id = format!("{}.{}", item_type, name);
let id = cx.derive_id(source_id.clone());
write!(
@@ -1483,14 +1468,13 @@ fn render_impl(
"<div id=\"{}\" class=\"{}{} has-srclink\">",
id, item_type, in_trait_class
);
- render_rightside(w, cx, item, containing_item);
+ render_rightside(w, cx, item, containing_item, render_mode);
write!(w, "<a href=\"#{}\" class=\"anchor\"></a>", id);
w.write_str("<h4 class=\"code-header\">");
assoc_const(
w,
item,
ty,
- default.as_ref(),
link.anchor(if trait_.is_some() { &source_id } else { &id }),
"",
cx,
@@ -1662,16 +1646,24 @@ fn render_rightside(
cx: &Context<'_>,
item: &clean::Item,
containing_item: &clean::Item,
+ render_mode: RenderMode,
) {
let tcx = cx.tcx();
+ // FIXME: Once https://github.com/rust-lang/rust/issues/67792 is implemented, we can remove
+ // this condition.
+ let (const_stability, const_stable_since) = match render_mode {
+ RenderMode::Normal => (item.const_stability(tcx), containing_item.const_stable_since(tcx)),
+ RenderMode::ForDeref { .. } => (None, None),
+ };
+
write!(w, "<div class=\"rightside\">");
render_stability_since_raw(
w,
- item.stable_since(tcx).as_deref(),
- item.const_stability(tcx),
- containing_item.stable_since(tcx).as_deref(),
- containing_item.const_stable_since(tcx).as_deref(),
+ item.stable_since(tcx),
+ const_stability,
+ containing_item.stable_since(tcx),
+ const_stable_since,
);
write_srclink(cx, item, w);
@@ -1707,7 +1699,7 @@ pub(crate) fn render_impl_summary(
format!(" data-aliases=\"{}\"", aliases.join(","))
};
write!(w, "<div id=\"{}\" class=\"impl has-srclink\"{}>", id, aliases);
- render_rightside(w, cx, &i.impl_item, containing_item);
+ render_rightside(w, cx, &i.impl_item, containing_item, RenderMode::Normal);
write!(w, "<a href=\"#{}\" class=\"anchor\"></a>", id);
write!(w, "<h3 class=\"code-header in-band\">");
@@ -2536,7 +2528,7 @@ fn collect_paths_for_type(first_ty: clean::Type, cache: &Cache) -> Vec<String> {
}
match ty {
- clean::Type::ResolvedPath { did, .. } => process_path(did),
+ clean::Type::Path { path } => process_path(path.def_id()),
clean::Type::Tuple(tys) => {
work.extend(tys.into_iter());
}
diff --git a/src/librustdoc/html/render/print_item.rs b/src/librustdoc/html/render/print_item.rs
index 049d17a4b47..9943e23b928 100644
--- a/src/librustdoc/html/render/print_item.rs
+++ b/src/librustdoc/html/render/print_item.rs
@@ -101,7 +101,7 @@ pub(super) fn print_item(
let mut stability_since_raw = Buffer::new();
render_stability_since_raw(
&mut stability_since_raw,
- item.stable_since(cx.tcx()).as_deref(),
+ item.stable_since(cx.tcx()),
item.const_stability(cx.tcx()),
None,
None,
@@ -296,7 +296,7 @@ fn item_module(w: &mut Buffer, cx: &Context<'_>, item: &clean::Item, items: &[cl
let (short, name) = item_ty_to_strs(myty.unwrap());
write!(
w,
- "<h2 id=\"{id}\" class=\"section-header\">\
+ "<h2 id=\"{id}\" class=\"small-section-header\">\
<a href=\"#{id}\">{name}</a>\
</h2>\n{}",
ITEM_TABLE_OPEN,
@@ -556,7 +556,14 @@ fn item_trait(w: &mut Buffer, cx: &Context<'_>, it: &clean::Item, t: &clean::Tra
);
}
for t in &types {
- render_assoc_item(w, t, AssocItemLink::Anchor(None), ItemType::Trait, cx);
+ render_assoc_item(
+ w,
+ t,
+ AssocItemLink::Anchor(None),
+ ItemType::Trait,
+ cx,
+ RenderMode::Normal,
+ );
w.write_str(";\n");
}
// If there are too many associated constants, hide everything after them
@@ -580,7 +587,14 @@ fn item_trait(w: &mut Buffer, cx: &Context<'_>, it: &clean::Item, t: &clean::Tra
w.write_str("\n");
}
for t in &consts {
- render_assoc_item(w, t, AssocItemLink::Anchor(None), ItemType::Trait, cx);
+ render_assoc_item(
+ w,
+ t,
+ AssocItemLink::Anchor(None),
+ ItemType::Trait,
+ cx,
+ RenderMode::Normal,
+ );
w.write_str(";\n");
}
if !toggle && should_hide_fields(count_methods) {
@@ -591,7 +605,14 @@ fn item_trait(w: &mut Buffer, cx: &Context<'_>, it: &clean::Item, t: &clean::Tra
w.write_str("\n");
}
for (pos, m) in required.iter().enumerate() {
- render_assoc_item(w, m, AssocItemLink::Anchor(None), ItemType::Trait, cx);
+ render_assoc_item(
+ w,
+ m,
+ AssocItemLink::Anchor(None),
+ ItemType::Trait,
+ cx,
+ RenderMode::Normal,
+ );
w.write_str(";\n");
if pos < required.len() - 1 {
@@ -602,7 +623,14 @@ fn item_trait(w: &mut Buffer, cx: &Context<'_>, it: &clean::Item, t: &clean::Tra
w.write_str("\n");
}
for (pos, m) in provided.iter().enumerate() {
- render_assoc_item(w, m, AssocItemLink::Anchor(None), ItemType::Trait, cx);
+ render_assoc_item(
+ w,
+ m,
+ AssocItemLink::Anchor(None),
+ ItemType::Trait,
+ cx,
+ RenderMode::Normal,
+ );
match *m.kind {
clean::MethodItem(ref inner, _)
if !inner.generics.where_predicates.is_empty() =>
@@ -655,7 +683,14 @@ fn item_trait(w: &mut Buffer, cx: &Context<'_>, it: &clean::Item, t: &clean::Tra
write_srclink(cx, m, w);
write!(w, "</div>");
write!(w, "<h4 class=\"code-header\">");
- render_assoc_item(w, m, AssocItemLink::Anchor(Some(&id)), ItemType::Impl, cx);
+ render_assoc_item(
+ w,
+ m,
+ AssocItemLink::Anchor(Some(&id)),
+ ItemType::Impl,
+ cx,
+ RenderMode::Normal,
+ );
w.write_str("</h4>");
w.write_str("</div>");
if toggled {
@@ -727,10 +762,11 @@ fn item_trait(w: &mut Buffer, cx: &Context<'_>, it: &clean::Item, t: &clean::Tra
let mut implementor_dups: FxHashMap<Symbol, (DefId, bool)> = FxHashMap::default();
for implementor in implementors {
match implementor.inner_impl().for_ {
- clean::ResolvedPath { ref path, did, .. }
- | clean::BorrowedRef {
- type_: box clean::ResolvedPath { ref path, did, .. }, ..
- } if !path.is_assoc_ty() => {
+ clean::Type::Path { ref path }
+ | clean::BorrowedRef { type_: box clean::Type::Path { ref path }, .. }
+ if !path.is_assoc_ty() =>
+ {
+ let did = path.def_id();
let &mut (prev_did, ref mut has_duplicates) =
implementor_dups.entry(path.last()).or_insert((did, false));
if prev_did != did {
@@ -940,6 +976,7 @@ fn item_typedef(
// associated items from the aliased type (see discussion in #32077), but
// we need #14072 to make sense of the generics.
render_assoc_items(w, cx, it, def_id, AssocItemRender::All);
+ document_type_layout(w, cx, def_id);
}
fn item_union(w: &mut Buffer, cx: &Context<'_>, it: &clean::Item, s: &clean::Union) {
@@ -1426,10 +1463,10 @@ fn render_stability_since(
) {
render_stability_since_raw(
w,
- item.stable_since(tcx).as_deref(),
+ item.stable_since(tcx),
item.const_stability(tcx),
- containing_item.stable_since(tcx).as_deref(),
- containing_item.const_stable_since(tcx).as_deref(),
+ containing_item.stable_since(tcx),
+ containing_item.const_stable_since(tcx),
)
}
@@ -1452,8 +1489,8 @@ fn render_implementor(
// If there's already another implementor that has the same abridged name, use the
// full path, for example in `std::iter::ExactSizeIterator`
let use_absolute = match implementor.inner_impl().for_ {
- clean::ResolvedPath { ref path, .. }
- | clean::BorrowedRef { type_: box clean::ResolvedPath { ref path, .. }, .. }
+ clean::Type::Path { ref path, .. }
+ | clean::BorrowedRef { type_: box clean::Type::Path { ref path, .. }, .. }
if !path.is_assoc_ty() =>
{
implementor_dups[&path.last()].1
@@ -1768,6 +1805,13 @@ fn document_type_layout(w: &mut Buffer, cx: &Context<'_>, ty_def_id: DefId) {
the type was too big.</p>"
);
}
+ Err(LayoutError::NormalizationFailure(_, _)) => {
+ writeln!(
+ w,
+ "<p><strong>Note:</strong> Encountered an error during type layout; \
+ the type failed to be normalized.</p>"
+ )
+ }
}
writeln!(w, "</div>");
diff --git a/src/librustdoc/html/render/write_shared.rs b/src/librustdoc/html/render/write_shared.rs
index 2d3b2490677..0d5ba8e80d2 100644
--- a/src/librustdoc/html/render/write_shared.rs
+++ b/src/librustdoc/html/render/write_shared.rs
@@ -181,42 +181,34 @@ pub(super) fn write_shared(
cx.write_shared(SharedResource::InvocationSpecific { basename: p }, content, &options.emit)
};
- fn add_background_image_to_css(
- cx: &Context<'_>,
- css: &mut String,
- rule: &str,
- file: &'static str,
- ) {
- css.push_str(&format!(
- "{} {{ background-image: url({}); }}",
- rule,
- SharedResource::ToolchainSpecific { basename: file }
+ // Given "foo.svg", return e.g. "url(\"foo1.58.0.svg\")"
+ fn ver_url(cx: &Context<'_>, basename: &'static str) -> String {
+ format!(
+ "url(\"{}\")",
+ SharedResource::ToolchainSpecific { basename }
.path(cx)
.file_name()
.unwrap()
.to_str()
.unwrap()
- ))
+ )
}
- // Add all the static files. These may already exist, but we just
- // overwrite them anyway to make sure that they're fresh and up-to-date.
- let mut rustdoc_css = static_files::RUSTDOC_CSS.to_owned();
- add_background_image_to_css(
- cx,
- &mut rustdoc_css,
- "details.undocumented[open] > summary::before, \
- details.rustdoc-toggle[open] > summary::before, \
- details.rustdoc-toggle[open] > summary.hideme::before",
- "toggle-minus.svg",
- );
- add_background_image_to_css(
+ // We use the AUTOREPLACE mechanism to inject into our static JS and CSS certain
+ // values that are only known at doc build time. Since this mechanism is somewhat
+ // surprising when reading the code, please limit it to rustdoc.css.
+ write_minify(
+ "rustdoc.css",
+ static_files::RUSTDOC_CSS
+ .replace(
+ "/* AUTOREPLACE: */url(\"toggle-minus.svg\")",
+ &ver_url(cx, "toggle-minus.svg"),
+ )
+ .replace("/* AUTOREPLACE: */url(\"toggle-plus.svg\")", &ver_url(cx, "toggle-plus.svg"))
+ .replace("/* AUTOREPLACE: */url(\"down-arrow.svg\")", &ver_url(cx, "down-arrow.svg")),
cx,
- &mut rustdoc_css,
- "details.undocumented > summary::before, details.rustdoc-toggle > summary::before",
- "toggle-plus.svg",
- );
- write_minify("rustdoc.css", rustdoc_css, cx, options)?;
+ options,
+ )?;
// Add all the static files. These may already exist, but we just
// overwrite them anyway to make sure that they're fresh and up-to-date.
@@ -228,12 +220,12 @@ pub(super) fn write_shared(
let mut themes: FxHashSet<String> = FxHashSet::default();
for entry in &cx.shared.style_files {
- let theme = try_none!(try_none!(entry.path.file_stem(), &entry.path).to_str(), &entry.path);
+ let theme = entry.basename()?;
let extension =
try_none!(try_none!(entry.path.extension(), &entry.path).to_str(), &entry.path);
// Handle the official themes
- match theme {
+ match theme.as_str() {
"light" => write_minify("light.css", static_files::themes::LIGHT, cx, options)?,
"dark" => write_minify("dark.css", static_files::themes::DARK, cx, options)?,
"ayu" => write_minify("ayu.css", static_files::themes::AYU, cx, options)?,
@@ -265,26 +257,7 @@ pub(super) fn write_shared(
let mut themes: Vec<&String> = themes.iter().collect();
themes.sort();
- // FIXME: this should probably not be a toolchain file since it depends on `--theme`.
- // But it seems a shame to copy it over and over when it's almost always the same.
- // Maybe we can change the representation to move this out of main.js?
- write_minify(
- "main.js",
- static_files::MAIN_JS
- .replace(
- "/* INSERT THEMES HERE */",
- &format!(" = {}", serde_json::to_string(&themes).unwrap()),
- )
- .replace(
- "/* INSERT RUSTDOC_VERSION HERE */",
- &format!(
- "rustdoc {}",
- rustc_interface::util::version_str().unwrap_or("unknown version")
- ),
- ),
- cx,
- options,
- )?;
+ write_minify("main.js", static_files::MAIN_JS, cx, options)?;
write_minify("search.js", static_files::SEARCH_JS, cx, options)?;
write_minify("settings.js", static_files::SETTINGS_JS, cx, options)?;
@@ -292,18 +265,7 @@ pub(super) fn write_shared(
write_minify("source-script.js", static_files::sidebar::SOURCE_SCRIPT, cx, options)?;
}
- {
- write_minify(
- "storage.js",
- format!(
- "var resourcesSuffix = \"{}\";{}",
- cx.shared.resource_suffix,
- static_files::STORAGE_JS
- ),
- cx,
- options,
- )?;
- }
+ write_minify("storage.js", static_files::STORAGE_JS, cx, options)?;
if cx.shared.layout.scrape_examples_extension {
cx.write_minify(
diff --git a/src/librustdoc/html/static/css/noscript.css b/src/librustdoc/html/static/css/noscript.css
index 37ea7b00033..e35358c5649 100644
--- a/src/librustdoc/html/static/css/noscript.css
+++ b/src/librustdoc/html/static/css/noscript.css
@@ -4,7 +4,7 @@ of content is hidden by default (depending on the settings too), we have to over
rules.
*/
-#main .attributes {
+#main-content .attributes {
/* Since there is no toggle (the "[-]") when JS is disabled, no need for this margin either. */
margin-left: 0 !important;
}
diff --git a/src/librustdoc/html/static/css/rustdoc.css b/src/librustdoc/html/static/css/rustdoc.css
index 400ed0a48ce..cbb078f2ab3 100644
--- a/src/librustdoc/html/static/css/rustdoc.css
+++ b/src/librustdoc/html/static/css/rustdoc.css
@@ -111,7 +111,6 @@ body {
font: 16px/1.4 "Source Serif 4", NanumBarunGothic, serif;
margin: 0;
position: relative;
- padding: 10px 15px 20px 15px;
-webkit-font-feature-settings: "kern", "liga";
-moz-font-feature-settings: "kern", "liga";
@@ -202,7 +201,7 @@ details.rustdoc-toggle > summary::before,
div.impl-items > div:not(.docblock):not(.item-info),
.content ul.crate a.crate, a.srclink,
/* This selector is for the items listed in the "all items" page. */
-#main > ul.docblock > li > a {
+#main-content > ul.docblock > li > a {
font-family: "Fira Sans", Arial, NanumBarunGothic, sans-serif;
}
@@ -248,6 +247,32 @@ textarea {
/* end tweaks for normalize.css 8 */
+.rustdoc {
+ display: flex;
+ flex-direction: row;
+ flex-wrap: nowrap;
+}
+
+main {
+ position: relative;
+ flex-grow: 1;
+ padding: 10px 15px 40px 45px;
+ min-width: 0;
+}
+
+.source main {
+ padding: 15px;
+}
+
+.width-limiter {
+ max-width: 960px;
+ margin-right: auto;
+}
+
+.source .width-limiter {
+ max-width: unset;
+}
+
details:not(.rustdoc-toggle) summary {
margin-bottom: .6em;
}
@@ -285,24 +310,74 @@ li {
}
.source .content {
- margin-top: 50px;
max-width: none;
overflow: visible;
margin-left: 0px;
}
nav.sub {
+ position: relative;
font-size: 16px;
text-transform: uppercase;
}
+.sub-container {
+ display: flex;
+ flex-direction: row;
+ flex-wrap: nowrap;
+}
+
+.sub-logo-container {
+ display: none;
+ margin-right: 20px;
+}
+
+.source .sub-logo-container {
+ display: block;
+}
+
+.source .sub-logo-container > img {
+ height: 60px;
+ width: 60px;
+ object-fit: contain;
+}
+
.sidebar {
width: 200px;
- position: fixed;
- left: 0;
- top: 0;
- bottom: 0;
overflow-y: scroll;
+ position: sticky;
+ min-width: 200px;
+ height: 100vh;
+ top: 0;
+ left: 0;
+}
+
+.rustdoc.source .sidebar {
+ width: 50px;
+ min-width: 0px;
+ max-width: 300px;
+ flex-grow: 0;
+ flex-shrink: 0;
+ flex-basis: auto;
+ border-right: 1px solid;
+ overflow-x: hidden;
+ /* The sidebar is by default hidden */
+ overflow-y: hidden;
+}
+
+.source .sidebar > *:not(:first-child) {
+ transition: opacity 0.5s, visibility 0.2s;
+ opacity: 0;
+ visibility: hidden;
+}
+
+.source .sidebar.expanded {
+ overflow-y: auto;
+}
+
+.source .sidebar.expanded > * {
+ opacity: 1;
+ visibility: visible;
}
/* Improve the scrollbar display on firefox */
@@ -328,10 +403,6 @@ nav.sub {
margin-right: -10px;
}
-.content, nav {
- max-width: 960px;
-}
-
/* Everything else */
.hidden {
@@ -339,23 +410,15 @@ nav.sub {
}
.logo-container {
- height: 100px;
- width: 100px;
- position: relative;
- margin: 20px auto;
- display: block;
+ display: flex;
margin-top: 10px;
+ margin-bottom: 10px;
+ justify-content: center;
}
.logo-container > img {
- max-width: 100px;
- max-height: 100px;
- height: 100%;
- position: absolute;
- left: 50%;
- top: 50%;
- transform: translate(-50%, -50%);
- display: block;
+ height: 100px;
+ width: 100px;
}
.sidebar .location {
@@ -435,10 +498,6 @@ nav.sub {
display: none;
}
-.content {
- padding: 15px 0;
-}
-
.source .content pre.rust {
white-space: pre;
overflow: auto;
@@ -483,7 +542,6 @@ nav.sub {
}
#search {
- margin-left: 230px;
position: relative;
}
@@ -574,10 +632,10 @@ nav.sub {
display: inline-block;
}
-#main {
+#main-content {
position: relative;
}
-#main > .since {
+#main-content > .since {
top: inherit;
font-family: "Fira Sans", Arial, sans-serif;
}
@@ -696,14 +754,18 @@ nav.sub {
flex-basis: 100%;
}
-#main > .item-info {
+#main-content > .item-info {
margin-top: 0;
}
nav:not(.sidebar) {
+ flex-grow: 1;
border-bottom: 1px solid;
padding-bottom: 10px;
- margin-bottom: 10px;
+ margin-bottom: 25px;
+}
+.source nav:not(.sidebar).sub {
+ margin-left: 32px;
}
nav.main {
padding: 20px 0;
@@ -722,10 +784,6 @@ nav.main .separator {
nav.sum { text-align: right; }
nav.sub form { display: inline; }
-nav.sub, .content {
- margin-left: 230px;
-}
-
a {
text-decoration: none;
background: transparent;
@@ -798,6 +856,7 @@ h2.small-section-header > .anchor {
.search-container {
position: relative;
+ max-width: 960px;
}
.search-container > div {
display: inline-flex;
@@ -824,6 +883,7 @@ h2.small-section-header > .anchor {
background-color: transparent;
background-size: 20px;
background-position: calc(100% - 1px) 56%;
+ background-image: /* AUTOREPLACE: */url("down-arrow.svg");
}
.search-container > .top-button {
position: absolute;
@@ -831,6 +891,10 @@ h2.small-section-header > .anchor {
top: 10px;
}
.search-input {
+ /* Override Normalize.css: it has a rule that sets
+ -webkit-appearance: textfield for search inputs. That
+ causes rounded corners and no border on iOS Safari. */
+ -webkit-appearance: none;
/* Override Normalize.css: we have margins and do
not want to overflow - the `moz` attribute is necessary
until Firefox 29, too early to drop at this point */
@@ -964,8 +1028,6 @@ body.blur > :not(#help) {
display: table;
}
.stab {
- border-width: 1px;
- border-style: solid;
padding: 3px;
margin-bottom: 5px;
font-size: 90%;
@@ -976,7 +1038,7 @@ body.blur > :not(#help) {
}
.stab .emoji {
- font-size: 1.5em;
+ font-size: 1.2em;
}
/* Black one-pixel outline around emoji shapes */
@@ -1078,10 +1140,6 @@ a.test-arrow:hover{
text-decoration: none;
}
-.section-header a {
- color: inherit;
-}
-
.code-attribute {
font-weight: 300;
}
@@ -1131,15 +1189,17 @@ h3.variant {
margin-top: 3px;
}
-.docblock > .section-header:first-child {
+.top-doc .docblock > .section-header:first-child {
margin-left: 15px;
- margin-top: 0;
}
-
-.docblock > .section-header:first-child:hover > a:before {
+.top-doc .docblock > .section-header:first-child:hover > a:before {
left: -10px;
}
+.docblock > .section-header:first-child {
+ margin-top: 0;
+}
+
:target > code, :target > .code-header {
opacity: 1;
}
@@ -1319,30 +1379,23 @@ pre.rust {
}
#sidebar-toggle {
- position: fixed;
- top: 30px;
- left: 300px;
- z-index: 10;
- padding: 3px;
- border-top-right-radius: 3px;
- border-bottom-right-radius: 3px;
+ position: sticky;
+ top: 0;
+ left: 0;
cursor: pointer;
font-weight: bold;
- transition: left .5s;
font-size: 1.2em;
- border: 1px solid;
- border-left: 0;
+ border-bottom: 1px solid;
+ display: flex;
+ height: 40px;
+ justify-content: center;
+ align-items: center;
+ z-index: 10;
}
#source-sidebar {
- position: fixed;
- top: 0;
- bottom: 0;
- left: 0;
- width: 300px;
+ width: 100%;
z-index: 1;
overflow: auto;
- transition: left .5s;
- border-right: 1px solid;
}
#source-sidebar > .title {
font-size: 1.5em;
@@ -1353,8 +1406,8 @@ pre.rust {
.theme-picker {
position: absolute;
- left: 211px;
- top: 19px;
+ left: -34px;
+ top: 9px;
}
.theme-picker button {
@@ -1471,10 +1524,10 @@ kbd {
left: -5px;
}
-#main > ul {
+#main-content > ul {
padding-left: 10px;
}
-#main > ul > li {
+#main-content > ul > li {
list-style: none;
}
@@ -1610,6 +1663,16 @@ details.rustdoc-toggle[open] > summary.hideme > span {
display: none;
}
+details.undocumented[open] > summary::before,
+details.rustdoc-toggle[open] > summary::before,
+details.rustdoc-toggle[open] > summary.hideme::before {
+ background-image: /* AUTOREPLACE: */url("toggle-minus.svg");
+}
+
+details.undocumented > summary::before, details.rustdoc-toggle > summary::before {
+ background-image: /* AUTOREPLACE: */url("toggle-plus.svg");
+}
+
details.rustdoc-toggle[open] > summary::before,
details.rustdoc-toggle[open] > summary.hideme::before {
width: 17px;
@@ -1635,6 +1698,22 @@ details.rustdoc-toggle[open] > summary.hideme::after {
.docblock > .information:first-child > .tooltip {
margin-top: 16px;
}
+
+ /* When we expand the sidebar on the source code page, we hide the logo on the left of the
+ search bar to have more space. */
+ .sidebar.expanded + main .width-limiter .sub-logo-container.rust-logo {
+ display: none;
+ }
+
+ /* It doesn't render well on mobile because of the layout, so better only have the transition
+ on desktop. */
+ .rustdoc.source .sidebar {
+ transition: width .5s;
+ }
+
+ .source .sidebar.expanded {
+ width: 300px;
+ }
}
@media (max-width: 700px) {
@@ -1642,14 +1721,43 @@ details.rustdoc-toggle[open] > summary.hideme::after {
padding-top: 0px;
}
- .rustdoc > .sidebar {
+ main {
+ padding-left: 15px;
+ padding-top: 0px;
+ }
+
+ .rustdoc {
+ flex-direction: column;
+ }
+
+ .rustdoc:not(.source) > .sidebar {
+ width: 100%;
height: 45px;
min-height: 40px;
+ max-height: 45px;
margin: 0;
- margin-left: -15px;
padding: 0 15px;
position: static;
z-index: 11;
+ overflow-y: hidden;
+ }
+
+ .rustdoc.source > .sidebar {
+ position: fixed;
+ top: 0;
+ left: 0;
+ margin: 0;
+ z-index: 11;
+ width: 0;
+ }
+
+ .sidebar.mobile {
+ position: sticky !important;
+ top: 0;
+ left: 0;
+ width: 100%;
+ margin-left: 0;
+ background-color: rgba(0,0,0,0);
}
.sidebar > .location {
@@ -1667,7 +1775,7 @@ details.rustdoc-toggle[open] > summary.hideme::after {
padding: 0;
}
- .sidebar .logo-container {
+ .rustdoc:not(.source) .sidebar .logo-container {
width: 35px;
height: 35px;
margin-top: 5px;
@@ -1688,6 +1796,7 @@ details.rustdoc-toggle[open] > summary.hideme::after {
cursor: pointer;
width: 45px;
left: 0;
+ top: 0;
text-align: center;
display: block;
border-bottom: 1px solid;
@@ -1737,20 +1846,25 @@ details.rustdoc-toggle[open] > summary.hideme::after {
nav.sub {
width: calc(100% - 32px);
- float: right;
+ margin-left: 32px;
+ margin-bottom: 10px;
+ }
+
+ .source nav:not(.sidebar).sub {
+ margin-left: 32px;
}
.content {
margin-left: 0px;
}
- #main, #search {
- margin-top: 45px;
- padding: 0;
+ .source .content {
+ margin-top: 10px;
}
#search {
margin-left: 0;
+ padding: 0;
}
.anchor {
@@ -1758,8 +1872,6 @@ details.rustdoc-toggle[open] > summary.hideme::after {
}
.theme-picker {
- left: 10px;
- top: 54px;
z-index: 1;
}
@@ -1778,25 +1890,6 @@ details.rustdoc-toggle[open] > summary.hideme::after {
height: 50px;
}
- .sidebar.mobile {
- position: fixed;
- width: 100%;
- margin-left: 0;
- background-color: rgba(0,0,0,0);
- height: 100%;
- }
- /*
- This allows to prevent the version text to overflow the sidebar title on mobile mode when the
- sidebar is displayed (after clicking on the "hamburger" button).
- */
- .sidebar.mobile > div.version {
- overflow: hidden;
- max-height: 33px;
- }
- .sidebar {
- width: calc(100% + 30px);
- }
-
.show-it, .sidebar-elems:focus-within {
z-index: 2;
left: 0;
@@ -1834,8 +1927,8 @@ details.rustdoc-toggle[open] > summary.hideme::after {
border-bottom: 1px solid;
}
- #main > details.rustdoc-toggle > summary::before,
- #main > div > details.rustdoc-toggle > summary::before {
+ #main-content > details.rustdoc-toggle > summary::before,
+ #main-content > div > details.rustdoc-toggle > summary::before {
left: -11px;
}
@@ -1843,19 +1936,32 @@ details.rustdoc-toggle[open] > summary.hideme::after {
margin: 10px;
}
- #sidebar-toggle {
+ .sidebar.expanded #sidebar-toggle {
+ font-size: 1.5rem;
+ }
+
+ .sidebar:not(.expanded) #sidebar-toggle {
+ position: fixed;
+ left: 1px;
top: 100px;
width: 30px;
font-size: 1.5rem;
text-align: center;
padding: 0;
+ z-index: 10;
+ border-top-right-radius: 3px;
+ border-bottom-right-radius: 3px;
+ cursor: pointer;
+ font-weight: bold;
+ border: 1px solid;
+ border-left: 0;
}
#source-sidebar {
z-index: 11;
}
- #main > .line-numbers {
+ #main-content > .line-numbers {
margin-top: 0;
}
@@ -1896,6 +2002,11 @@ details.rustdoc-toggle[open] > summary.hideme::after {
.search-results div.desc, .search-results .result-description, .item-right {
padding-left: 2em;
}
+
+ .source .sidebar.expanded {
+ max-width: 100vw;
+ width: 100vw;
+ }
}
@media print {
@@ -1909,14 +2020,7 @@ details.rustdoc-toggle[open] > summary.hideme::after {
height: 73px;
}
- /* This is to prevent the search bar from being underneath the <section>
- * element following it.
- */
- #main, #search {
- margin-top: 100px;
- }
-
- #main > table:not(.table-display) td {
+ #main-content > table:not(.table-display) td {
word-break: break-word;
width: 50%;
}
@@ -1958,6 +2062,23 @@ details.rustdoc-toggle[open] > summary.hideme::after {
.docblock code {
overflow-wrap: anywhere;
}
+
+ .sub-container {
+ flex-direction: column;
+ }
+
+ .sub-logo-container {
+ align-self: center;
+ }
+
+ .source .sub-logo-container > img {
+ height: 35px;
+ width: 35px;
+ }
+
+ .sidebar:not(.expanded) #sidebar-toggle {
+ top: 10px;
+ }
}
diff --git a/src/librustdoc/html/static/css/themes/ayu.css b/src/librustdoc/html/static/css/themes/ayu.css
index 91ede47c156..dea6d08396f 100644
--- a/src/librustdoc/html/static/css/themes/ayu.css
+++ b/src/librustdoc/html/static/css/themes/ayu.css
@@ -61,7 +61,7 @@ pre, .rustdoc.source .example-wrap {
background-color: #14191f;
}
-.logo-container.rust-logo > img {
+.rust-logo > img {
filter: drop-shadow(1px 0 0px #fff)
drop-shadow(0 1px 0 #fff)
drop-shadow(-1px 0 0 #fff)
@@ -97,7 +97,7 @@ pre, .rustdoc.source .example-wrap {
}
.source .sidebar {
- background-color: #0f1419;
+ background-color: #14191f;
}
.sidebar .location {
@@ -214,18 +214,25 @@ nav.main .separator {
border: 1px solid #5c6773;
}
a {
+ color: #39AFD7;
+}
+a.srclink,
+a#toggle-all-docs,
+a.anchor,
+.small-section-header a,
+#source-sidebar a,
+pre.rust a,
+.sidebar a,
+.in-band a {
color: #c5c5c5;
}
+.search-results a {
+ color: #0096cf;
+}
body.source .example-wrap pre.rust a {
background: #333;
}
-.docblock:not(.item-decl) a:not(.srclink):not(.test-arrow),
-.docblock-short a:not(.srclink):not(.test-arrow), .item-info a,
-#help a {
- color: #39AFD7;
-}
-
details.rustdoc-toggle > summary.hideme > span,
details.rustdoc-toggle > summary::before,
details.undocumented > summary::before {
diff --git a/src/librustdoc/html/static/css/themes/dark.css b/src/librustdoc/html/static/css/themes/dark.css
index 74a4fe45a3d..6e2cbbecbf7 100644
--- a/src/librustdoc/html/static/css/themes/dark.css
+++ b/src/librustdoc/html/static/css/themes/dark.css
@@ -32,7 +32,7 @@ pre, .rustdoc.source .example-wrap {
background-color: #505050;
}
-.logo-container.rust-logo > img {
+.rust-logo > img {
filter: drop-shadow(1px 0 0px #fff)
drop-shadow(0 1px 0 #fff)
drop-shadow(-1px 0 0 #fff)
@@ -66,7 +66,7 @@ pre, .rustdoc.source .example-wrap {
}
.source .sidebar {
- background-color: #353535;
+ background-color: #565656;
}
.sidebar .location {
@@ -174,22 +174,29 @@ nav.main .current {
nav.main .separator {
border-color: #eee;
}
+
a {
- color: #ddd;
+ color: #D2991D;
}
-body.source .example-wrap pre.rust a {
- background: #333;
+a.srclink,
+a#toggle-all-docs,
+a.anchor,
+.small-section-header a,
+#source-sidebar a,
+pre.rust a,
+.sidebar a,
+.in-band a {
+ color: #ddd;
}
-
-.docblock:not(.item-decl) a:not(.srclink):not(.test-arrow),
-.docblock-short a:not(.srclink):not(.test-arrow), .item-info a,
-#help a {
- color: #D2991D;
+.search-results a {
+ color: #ddd;
}
-
a.test-arrow {
color: #dedede;
}
+body.source .example-wrap pre.rust a {
+ background: #333;
+}
details.rustdoc-toggle > summary.hideme > span,
details.rustdoc-toggle > summary::before,
diff --git a/src/librustdoc/html/static/css/themes/light.css b/src/librustdoc/html/static/css/themes/light.css
index 6df137e3914..4bf411d459a 100644
--- a/src/librustdoc/html/static/css/themes/light.css
+++ b/src/librustdoc/html/static/css/themes/light.css
@@ -43,7 +43,7 @@ pre, .rustdoc.source .example-wrap {
scrollbar-color: rgba(36, 37, 39, 0.6) #d9d9d9;
}
-.logo-container.rust-logo > img {
+.rust-logo > img {
/* No need for a border in here! */
}
@@ -66,7 +66,7 @@ pre, .rustdoc.source .example-wrap {
}
.source .sidebar {
- background-color: #fff;
+ background-color: #f1f1f1;
}
.sidebar .location {
@@ -169,22 +169,29 @@ nav.main .current {
nav.main .separator {
border: 1px solid #000;
}
+
a {
+ color: #3873AD;
+}
+a.srclink,
+a#toggle-all-docs,
+a.anchor,
+.small-section-header a,
+#source-sidebar a,
+pre.rust a,
+.sidebar a,
+.in-band a {
color: #000;
}
-body.source .example-wrap pre.rust a {
- background: #eee;
+.search-results a {
+ color: initial;
}
-
-.docblock:not(.item-decl) a:not(.srclink):not(.test-arrow),
-.docblock-short a:not(.srclink):not(.test-arrow), .item-info a,
-#help a {
- color: #3873AD;
-}
-
a.test-arrow {
color: #f5f5f5;
}
+body.source .example-wrap pre.rust a {
+ background: #eee;
+}
details.rustdoc-toggle > summary.hideme > span,
details.rustdoc-toggle > summary::before,
diff --git a/src/librustdoc/html/static/js/main.js b/src/librustdoc/html/static/js/main.js
index 4b55a0a69b6..411a94ef2d1 100644
--- a/src/librustdoc/html/static/js/main.js
+++ b/src/librustdoc/html/static/js/main.js
@@ -37,14 +37,29 @@ if (!DOMTokenList.prototype.remove) {
};
}
-(function () {
- var rustdocVars = document.getElementById("rustdoc-vars");
- if (rustdocVars) {
- window.rootPath = rustdocVars.attributes["data-root-path"].value;
- window.currentCrate = rustdocVars.attributes["data-current-crate"].value;
- window.searchJS = rustdocVars.attributes["data-search-js"].value;
- window.searchIndexJS = rustdocVars.attributes["data-search-index-js"].value;
+// Get a value from the rustdoc-vars div, which is used to convey data from
+// Rust to the JS. If there is no such element, return null.
+function getVar(name) {
+ var el = document.getElementById("rustdoc-vars");
+ if (el) {
+ return el.attributes["data-" + name].value;
+ } else {
+ return null;
}
+}
+
+// Given a basename (e.g. "storage") and an extension (e.g. ".js"), return a URL
+// for a resource under the root-path, with the resource-suffix.
+function resourcePath(basename, extension) {
+ return getVar("root-path") + basename + getVar("resource-suffix") + extension;
+}
+
+
+(function () {
+ window.rootPath = getVar("root-path");
+ window.currentCrate = getVar("current-crate");
+ window.searchJS = resourcePath("search", ".js");
+ window.searchIndexJS = resourcePath("search-index", ".js");
var sidebarVars = document.getElementById("sidebar-vars");
if (sidebarVars) {
window.sidebarCurrent = {
@@ -79,6 +94,7 @@ function getVirtualKey(ev) {
var THEME_PICKER_ELEMENT_ID = "theme-picker";
var THEMES_ELEMENT_ID = "theme-choices";
+var MAIN_ID = "main-content";
function getThemesElement() {
return document.getElementById(THEMES_ELEMENT_ID);
@@ -115,7 +131,7 @@ function hideThemeButtonState() {
(function () {
var themeChoices = getThemesElement();
var themePicker = getThemePickerElement();
- var availableThemes/* INSERT THEMES HERE */;
+ var availableThemes = getVar("themes").split(",");
function switchThemeButtonState() {
if (themeChoices.style.display === "block") {
@@ -347,7 +363,7 @@ function hideThemeButtonState() {
}
var toggleAllDocsId = "toggle-all-docs";
- var main = document.getElementById("main");
+ var main = document.getElementById(MAIN_ID);
var savedHash = "";
function handleHashes(ev) {
@@ -772,7 +788,7 @@ function hideThemeButtonState() {
} else {
addClass(innerToggle, "will-expand");
onEachLazy(document.getElementsByClassName("rustdoc-toggle"), function(e) {
- if (e.parentNode.id !== "main" ||
+ if (e.parentNode.id !== MAIN_ID ||
(!hasClass(e, "implementors-toggle") &&
!hasClass(e, "type-contents-toggle")))
{
@@ -886,6 +902,14 @@ function hideThemeButtonState() {
}
});
+ onEachLazy(document.querySelectorAll(".rustdoc-toggle > summary:not(.hideme)"), function(el) {
+ el.addEventListener("click", function(e) {
+ if (e.target.tagName != "SUMMARY" && e.target.tagName != "A") {
+ e.preventDefault();
+ }
+ });
+ });
+
onEachLazy(document.getElementsByClassName("notable-traits"), function(e) {
e.onclick = function() {
this.getElementsByClassName('notable-traits-tooltiptext')[0]
@@ -972,13 +996,13 @@ function hideThemeButtonState() {
var rustdoc_version = document.createElement("span");
rustdoc_version.className = "bottom";
var rustdoc_version_code = document.createElement("code");
- rustdoc_version_code.innerText = "/* INSERT RUSTDOC_VERSION HERE */";
+ rustdoc_version_code.innerText = "rustdoc " + getVar("rustdoc-version");
rustdoc_version.appendChild(rustdoc_version_code);
container.appendChild(rustdoc_version);
popup.appendChild(container);
- insertAfter(popup, searchState.outputElement());
+ insertAfter(popup, document.querySelector("main"));
// So that it's only built once and then it'll do nothing when called!
buildHelperPopup = function() {};
};
diff --git a/src/librustdoc/html/static/js/search.js b/src/librustdoc/html/static/js/search.js
index c2ea54abd2e..d419e384a59 100644
--- a/src/librustdoc/html/static/js/search.js
+++ b/src/librustdoc/html/static/js/search.js
@@ -4,32 +4,34 @@
(function() {
// This mapping table should match the discriminants of
// `rustdoc::html::item_type::ItemType` type in Rust.
-var itemTypes = ["mod",
- "externcrate",
- "import",
- "struct",
- "enum",
- "fn",
- "type",
- "static",
- "trait",
- "impl",
- "tymethod",
- "method",
- "structfield",
- "variant",
- "macro",
- "primitive",
- "associatedtype",
- "constant",
- "associatedconstant",
- "union",
- "foreigntype",
- "keyword",
- "existential",
- "attr",
- "derive",
- "traitalias"];
+var itemTypes = [
+ "mod",
+ "externcrate",
+ "import",
+ "struct",
+ "enum",
+ "fn",
+ "type",
+ "static",
+ "trait",
+ "impl",
+ "tymethod",
+ "method",
+ "structfield",
+ "variant",
+ "macro",
+ "primitive",
+ "associatedtype",
+ "constant",
+ "associatedconstant",
+ "union",
+ "foreigntype",
+ "keyword",
+ "existential",
+ "attr",
+ "derive",
+ "traitalias",
+];
// used for special search precedence
var TY_PRIMITIVE = itemTypes.indexOf("primitive");
@@ -174,16 +176,13 @@ window.initSearch = function(rawSearchIndex) {
var ar = [];
for (var entry in results) {
if (hasOwnPropertyRustdoc(results, entry)) {
- ar.push(results[entry]);
+ var result = results[entry];
+ result.word = searchWords[result.id];
+ result.item = searchIndex[result.id] || {};
+ ar.push(result);
}
}
results = ar;
- var i, len, result;
- for (i = 0, len = results.length; i < len; ++i) {
- result = results[i];
- result.word = searchWords[result.id];
- result.item = searchIndex[result.id] || {};
- }
// if there are no results then return to default and fail
if (results.length === 0) {
return [];
@@ -256,7 +255,7 @@ window.initSearch = function(rawSearchIndex) {
return 0;
});
- for (i = 0, len = results.length; i < len; ++i) {
+ for (var i = 0, len = results.length; i < len; ++i) {
result = results[i];
// this validation does not make sense when searching by types
@@ -342,7 +341,17 @@ window.initSearch = function(rawSearchIndex) {
return MAX_LEV_DISTANCE + 1;
}
- // Check for type name and type generics (if any).
+ /**
+ * This function checks if the object (`obj`) matches the given type (`val`) and its
+ * generics (if any).
+ *
+ * @param {Object} obj
+ * @param {string} val
+ * @param {boolean} literalSearch
+ *
+ * @return {integer} - Returns a Levenshtein distance to the best match. If there is
+ * no match, returns `MAX_LEV_DISTANCE + 1`.
+ */
function checkType(obj, val, literalSearch) {
var lev_distance = MAX_LEV_DISTANCE + 1;
var tmp_lev = MAX_LEV_DISTANCE + 1;
@@ -361,24 +370,23 @@ window.initSearch = function(rawSearchIndex) {
elems[obj[GENERICS_DATA][x][NAME]] += 1;
}
- var allFound = true;
len = val.generics.length;
for (x = 0; x < len; ++x) {
firstGeneric = val.generics[x];
if (elems[firstGeneric]) {
elems[firstGeneric] -= 1;
} else {
- allFound = false;
- break;
+ // Something wasn't found and this is a literal search so
+ // abort and return a "failing" distance.
+ return MAX_LEV_DISTANCE + 1;
}
}
- if (allFound) {
- return true;
- }
+ // Everything was found, success!
+ return 0;
}
- return false;
+ return MAX_LEV_DISTANCE + 1;
}
- return true;
+ return 0;
} else {
// If the type has generics but don't match, then it won't return at this point.
// Otherwise, `checkGenerics` will return 0 and it'll return.
@@ -390,14 +398,15 @@ window.initSearch = function(rawSearchIndex) {
}
}
} else if (literalSearch) {
+ var found = false;
if ((!val.generics || val.generics.length === 0) &&
obj.length > GENERICS_DATA && obj[GENERICS_DATA].length > 0) {
- return obj[GENERICS_DATA].some(
+ found = obj[GENERICS_DATA].some(
function(gen) {
return gen[NAME] === val.name;
});
}
- return false;
+ return found ? 0 : MAX_LEV_DISTANCE + 1;
}
lev_distance = Math.min(levenshtein(obj[NAME], val.name), lev_distance);
if (lev_distance <= MAX_LEV_DISTANCE) {
@@ -428,6 +437,17 @@ window.initSearch = function(rawSearchIndex) {
return Math.min(lev_distance, tmp_lev) + 1;
}
+ /**
+ * This function checks if the object (`obj`) has an argument with the given type (`val`).
+ *
+ * @param {Object} obj
+ * @param {string} val
+ * @param {boolean} literalSearch
+ * @param {integer} typeFilter
+ *
+ * @return {integer} - Returns a Levenshtein distance to the best match. If there is no
+ * match, returns `MAX_LEV_DISTANCE + 1`.
+ */
function findArg(obj, val, literalSearch, typeFilter) {
var lev_distance = MAX_LEV_DISTANCE + 1;
@@ -439,19 +459,15 @@ window.initSearch = function(rawSearchIndex) {
continue;
}
tmp = checkType(tmp, val, literalSearch);
- if (literalSearch) {
- if (tmp) {
- return true;
- }
+ if (tmp === 0) {
+ return 0;
+ } else if (literalSearch) {
continue;
}
lev_distance = Math.min(tmp, lev_distance);
- if (lev_distance === 0) {
- return 0;
- }
}
}
- return literalSearch ? false : lev_distance;
+ return literalSearch ? MAX_LEV_DISTANCE + 1 : lev_distance;
}
function checkReturned(obj, val, literalSearch, typeFilter) {
@@ -468,19 +484,15 @@ window.initSearch = function(rawSearchIndex) {
continue;
}
tmp = checkType(tmp, val, literalSearch);
- if (literalSearch) {
- if (tmp) {
- return true;
- }
+ if (tmp === 0) {
+ return 0;
+ } else if (literalSearch) {
continue;
}
lev_distance = Math.min(tmp, lev_distance);
- if (lev_distance === 0) {
- return 0;
- }
}
}
- return literalSearch ? false : lev_distance;
+ return literalSearch ? MAX_LEV_DISTANCE + 1 : lev_distance;
}
function checkPath(contains, lastElem, ty) {
@@ -610,6 +622,44 @@ window.initSearch = function(rawSearchIndex) {
onEach(crateAliases, pushFunc);
}
+ /**
+ * This function adds the given result into the provided `res` map if it matches the
+ * following condition:
+ *
+ * * If it is a "literal search" (`isExact`), then `lev` must be 0.
+ * * If it is not a "literal search", `lev` must be <= `MAX_LEV_DISTANCE`.
+ *
+ * The `res` map contains information which will be used to sort the search results:
+ *
+ * * `fullId` is a `string`` used as the key of the object we use for the `res` map.
+ * * `id` is the index in both `searchWords` and `searchIndex` arrays for this element.
+ * * `index` is an `integer`` used to sort by the position of the word in the item's name.
+ * * `lev` is the main metric used to sort the search results.
+ *
+ * @param {boolean} isExact
+ * @param {Object} res
+ * @param {string} fullId
+ * @param {integer} id
+ * @param {integer} index
+ * @param {integer} lev
+ */
+ function addIntoResults(isExact, res, fullId, id, index, lev) {
+ if (lev === 0 || (!isExact && lev <= MAX_LEV_DISTANCE)) {
+ if (res[fullId] !== undefined) {
+ var result = res[fullId];
+ if (result.dontValidate || result.lev <= lev) {
+ return;
+ }
+ }
+ res[fullId] = {
+ id: id,
+ index: index,
+ dontValidate: isExact,
+ lev: lev,
+ };
+ }
+ }
+
// quoted values mean literal search
var nSearchWords = searchWords.length;
var i, it;
@@ -632,28 +682,11 @@ window.initSearch = function(rawSearchIndex) {
fullId = ty.id;
if (searchWords[i] === val.name
- && typePassesFilter(typeFilter, searchIndex[i].ty)
- && results[fullId] === undefined) {
- results[fullId] = {
- id: i,
- index: -1,
- dontValidate: true,
- };
- }
- if (in_args && results_in_args[fullId] === undefined) {
- results_in_args[fullId] = {
- id: i,
- index: -1,
- dontValidate: true,
- };
- }
- if (returned && results_returned[fullId] === undefined) {
- results_returned[fullId] = {
- id: i,
- index: -1,
- dontValidate: true,
- };
+ && typePassesFilter(typeFilter, searchIndex[i].ty)) {
+ addIntoResults(true, results, fullId, i, -1, 0);
}
+ addIntoResults(true, results_in_args, fullId, i, -1, in_args);
+ addIntoResults(true, results_returned, fullId, i, -1, returned);
}
query.inputs = [val];
query.output = val;
@@ -682,39 +715,27 @@ window.initSearch = function(rawSearchIndex) {
fullId = ty.id;
returned = checkReturned(ty, output, true, NO_TYPE_FILTER);
- if (output.name === "*" || returned) {
+ if (output.name === "*" || returned === 0) {
in_args = false;
var is_module = false;
if (input === "*") {
is_module = true;
} else {
- var allFound = true;
- for (it = 0, len = inputs.length; allFound && it < len; it++) {
- allFound = checkType(type, inputs[it], true);
+ var firstNonZeroDistance = 0;
+ for (it = 0, len = inputs.length; it < len; it++) {
+ var distance = checkType(type, inputs[it], true);
+ if (distance > 0) {
+ firstNonZeroDistance = distance;
+ break;
+ }
}
- in_args = allFound;
- }
- if (in_args) {
- results_in_args[fullId] = {
- id: i,
- index: -1,
- dontValidate: true,
- };
- }
- if (returned) {
- results_returned[fullId] = {
- id: i,
- index: -1,
- dontValidate: true,
- };
+ in_args = firstNonZeroDistance;
}
+ addIntoResults(true, results_in_args, fullId, i, -1, in_args);
+ addIntoResults(true, results_returned, fullId, i, -1, returned);
if (is_module) {
- results[fullId] = {
- id: i,
- index: -1,
- dontValidate: true,
- };
+ addIntoResults(true, results, fullId, i, -1, 0);
}
}
}
@@ -786,41 +807,14 @@ window.initSearch = function(rawSearchIndex) {
lev = 0;
}
}
- if (in_args <= MAX_LEV_DISTANCE) {
- if (results_in_args[fullId] === undefined) {
- results_in_args[fullId] = {
- id: j,
- index: index,
- lev: in_args,
- };
- }
- results_in_args[fullId].lev =
- Math.min(results_in_args[fullId].lev, in_args);
- }
- if (returned <= MAX_LEV_DISTANCE) {
- if (results_returned[fullId] === undefined) {
- results_returned[fullId] = {
- id: j,
- index: index,
- lev: returned,
- };
- }
- results_returned[fullId].lev =
- Math.min(results_returned[fullId].lev, returned);
- }
+ addIntoResults(false, results_in_args, fullId, j, index, in_args);
+ addIntoResults(false, results_returned, fullId, j, index, returned);
if (typePassesFilter(typeFilter, ty.ty) &&
(index !== -1 || lev <= MAX_LEV_DISTANCE)) {
if (index !== -1 && paths.length < 2) {
lev = 0;
}
- if (results[fullId] === undefined) {
- results[fullId] = {
- id: j,
- index: index,
- lev: lev,
- };
- }
- results[fullId].lev = Math.min(results[fullId].lev, lev);
+ addIntoResults(false, results, fullId, j, index, lev);
}
}
}
diff --git a/src/librustdoc/html/static/js/source-script.js b/src/librustdoc/html/static/js/source-script.js
index 4d9a59f836b..81dc0b2fb1e 100644
--- a/src/librustdoc/html/static/js/source-script.js
+++ b/src/librustdoc/html/static/js/source-script.js
@@ -77,16 +77,14 @@ function createDirEntry(elem, parent, fullPath, currentFile, hasFoundFile) {
}
function toggleSidebar() {
- var sidebar = document.getElementById("source-sidebar");
- var child = this.children[0].children[0];
+ var sidebar = document.querySelector("nav.sidebar");
+ var child = this.children[0];
if (child.innerText === ">") {
- sidebar.style.left = "";
- this.style.left = "";
+ sidebar.classList.add("expanded");
child.innerText = "<";
updateLocalStorage("rustdoc-source-sidebar-show", "true");
} else {
- sidebar.style.left = "-300px";
- this.style.left = "0";
+ sidebar.classList.remove("expanded");
child.innerText = ">";
updateLocalStorage("rustdoc-source-sidebar-show", "false");
}
@@ -97,20 +95,15 @@ function createSidebarToggle() {
sidebarToggle.id = "sidebar-toggle";
sidebarToggle.onclick = toggleSidebar;
- var inner1 = document.createElement("div");
- inner1.style.position = "relative";
+ var inner = document.createElement("div");
- var inner2 = document.createElement("div");
- inner2.style.paddingTop = "3px";
if (getCurrentValue("rustdoc-source-sidebar-show") === "true") {
- inner2.innerText = "<";
+ inner.innerText = "<";
} else {
- inner2.innerText = ">";
- sidebarToggle.style.left = "0";
+ inner.innerText = ">";
}
- inner1.appendChild(inner2);
- sidebarToggle.appendChild(inner1);
+ sidebarToggle.appendChild(inner);
return sidebarToggle;
}
@@ -120,15 +113,17 @@ function createSourceSidebar() {
if (!window.rootPath.endsWith("/")) {
window.rootPath += "/";
}
- var main = document.getElementById("main");
+ var container = document.querySelector("nav.sidebar");
var sidebarToggle = createSidebarToggle();
- main.insertBefore(sidebarToggle, main.firstChild);
+ container.insertBefore(sidebarToggle, container.firstChild);
var sidebar = document.createElement("div");
sidebar.id = "source-sidebar";
if (getCurrentValue("rustdoc-source-sidebar-show") !== "true") {
- sidebar.style.left = "-300px";
+ container.classList.remove("expanded");
+ } else {
+ container.classList.add("expanded");
}
var currentFile = getCurrentFilePath();
@@ -144,7 +139,7 @@ function createSourceSidebar() {
currentFile, hasFoundFile);
});
- main.insertBefore(sidebar, main.firstChild);
+ container.insertBefore(sidebar, document.querySelector(".sidebar-logo").nextSibling);
// Focus on the current file in the source files sidebar.
var selected_elem = sidebar.getElementsByClassName("selected")[0];
if (typeof selected_elem !== "undefined") {
diff --git a/src/librustdoc/html/static/js/storage.js b/src/librustdoc/html/static/js/storage.js
index 78ed17e6899..606c237aea7 100644
--- a/src/librustdoc/html/static/js/storage.js
+++ b/src/librustdoc/html/static/js/storage.js
@@ -1,5 +1,3 @@
-// From rust:
-/* global resourcesSuffix */
var darkThemes = ["dark", "ayu"];
window.currentTheme = document.getElementById("themeStyle");
window.mainTheme = document.getElementById("mainThemeStyle");
@@ -107,9 +105,8 @@ function getCurrentValue(name) {
}
function switchTheme(styleElem, mainStyleElem, newTheme, saveTheme) {
- var fullBasicCss = "rustdoc" + resourcesSuffix + ".css";
- var fullNewTheme = newTheme + resourcesSuffix + ".css";
- var newHref = mainStyleElem.href.replace(fullBasicCss, fullNewTheme);
+ var newHref = mainStyleElem.href.replace(
+ /\/rustdoc([^/]*)\.css/, "/" + newTheme + "$1" + ".css");
// If this new value comes from a system setting or from the previously
// saved theme, no need to save it.
diff --git a/src/librustdoc/html/templates/page.html b/src/librustdoc/html/templates/page.html
index cf57d4cf3aa..00b46b1ba91 100644
--- a/src/librustdoc/html/templates/page.html
+++ b/src/librustdoc/html/templates/page.html
@@ -7,12 +7,27 @@
<meta name="description" content="{{page.description}}"> {#- -#}
<meta name="keywords" content="{{page.keywords}}"> {#- -#}
<title>{{page.title}}</title> {#- -#}
+ <link rel="preload" as="font" type="font/woff2" crossorigin href="{{static_root_path | safe}}SourceSerif4-Regular.ttf.woff2"> {#- -#}
+ <link rel="preload" as="font" type="font/woff2" crossorigin href="{{static_root_path | safe}}FiraSans-Regular.woff2"> {#- -#}
+ <link rel="preload" as="font" type="font/woff2" crossorigin href="{{static_root_path | safe}}FiraSans-Medium.woff2"> {#- -#}
+ <link rel="preload" as="font" type="font/woff2" crossorigin href="{{static_root_path | safe}}SourceCodePro-Regular.ttf.woff2"> {#- -#}
+ <link rel="preload" as="font" type="font/woff2" crossorigin href="{{static_root_path | safe}}SourceSerif4-Bold.ttf.woff2"> {#- -#}
+ <link rel="preload" as="font" type="font/woff2" crossorigin href="{{static_root_path | safe}}SourceCodePro-Semibold.ttf.woff2"> {#- -#}
<link rel="stylesheet" type="text/css" {# -#}
href="{{static_root_path | safe}}normalize{{page.resource_suffix}}.css"> {#- -#}
<link rel="stylesheet" type="text/css" {# -#}
href="{{static_root_path | safe}}rustdoc{{page.resource_suffix}}.css" {# -#}
id="mainThemeStyle"> {#- -#}
- {{- style_files | safe -}}
+ {%- for theme in themes -%}
+ <link rel="stylesheet" type="text/css" {# -#}
+ href="{{static_root_path | safe}}{{theme}}{{page.resource_suffix}}.css" {# -#}
+ {%- if theme == "light" -%}
+ id="themeStyle"
+ {%- else -%}
+ disabled
+ {%- endif -%}
+ >
+ {%- endfor -%}
<script id="default-settings" {# -#}
{% for k, v in layout.default_settings %}
data-{{k}}="{{v}}"
@@ -49,11 +64,6 @@
href="{{static_root_path | safe}}favicon{{page.resource_suffix}}.svg"> {#- -#}
{%- endif -%}
{{- layout.external_html.in_header | safe -}}
- <style type="text/css"> {#- -#}
- #crate-search{ {#- -#}
- background-image:url("{{static_root_path | safe}}down-arrow{{page.resource_suffix}}.svg"); {#- -#}
- } {#- -#}
- </style> {#- -#}
</head> {#- -#}
<body class="rustdoc {{page.css_class}}"> {#- -#}
<!--[if lte IE 11]> {#- -#}
@@ -64,58 +74,71 @@
{{- layout.external_html.before_content | safe -}}
<nav class="sidebar"> {#- -#}
<div class="sidebar-menu" role="button">&#9776;</div> {#- -#}
- <a href='{{page.root_path | safe}}{{krate_with_trailing_slash | safe}}index.html'> {#- -#}
- <div class='logo-container rust-logo'> {#- -#}
- <img src='
- {%- if layout.logo -%}
- {{layout.logo}}
- {%- else -%}
- {{static_root_path | safe}}rust-logo{{page.resource_suffix}}.png
- {%- endif -%}
- ' alt='logo'> {#- -#}
- </div> {#- -#}
+ <a class="sidebar-logo" href="{{page.root_path | safe}}{{krate_with_trailing_slash | safe}}index.html"> {#- -#}
+ <div class="logo-container"> {#- -#}
+ {%- if layout.logo -%}
+ <img src="{{layout.logo}}" alt="logo"> {#- -#}
+ {%- else -%}
+ <img class="rust-logo" src="{{static_root_path | safe}}rust-logo{{page.resource_suffix}}.png" alt="logo"> {#- -#}
+ {%- endif -%}
+ </div>
</a> {#- -#}
{{- sidebar | safe -}}
</nav> {#- -#}
- <div class="theme-picker"> {#- -#}
- <button id="theme-picker" aria-label="Pick another theme!" aria-haspopup="menu" title="themes"> {#- -#}
- <img width="18" height="18" alt="Pick another theme!" {# -#}
- src="{{static_root_path | safe}}brush{{page.resource_suffix}}.svg"> {#- -#}
- </button> {#- -#}
- <div id="theme-choices" role="menu"></div> {#- -#}
- </div> {#- -#}
- <nav class="sub"> {#- -#}
- <form class="search-form"> {#- -#}
- <div class="search-container"> {#- -#}
- <div>{%- if layout.generate_search_filter -%}
- <select id="crate-search"> {#- -#}
- <option value="All crates">All crates</option> {#- -#}
- </select> {#- -#}
+ <main> {#- -#}
+ <div class="width-limiter"> {#- -#}
+ <div class="sub-container"> {#- -#}
+ <a class="sub-logo-container" href="{{page.root_path | safe}}{{krate_with_trailing_slash | safe}}index.html"> {#- -#}
+ {%- if layout.logo -%}
+ <img src="{{layout.logo}}" alt="logo">
+ {%- else -%}
+ <img class="rust-logo" src="{{static_root_path | safe}}rust-logo{{page.resource_suffix}}.png" alt="logo">
{%- endif -%}
- <input {# -#}
- class="search-input" {# -#}
- name="search" {# -#}
- autocomplete="off" {# -#}
- spellcheck="false" {# -#}
- placeholder="Click or press ‘S’ to search, ‘?’ for more options…" {# -#}
- type="search"> {#- -#}
- </div> {#- -#}
- <button type="button" id="help-button" title="help">?</button> {#- -#}
- <a id="settings-menu" href="{{page.root_path | safe}}settings.html" title="settings"> {#- -#}
- <img width="18" height="18" alt="Change settings" {# -#}
- src="{{static_root_path | safe}}wheel{{page.resource_suffix}}.svg"> {#- -#}
</a> {#- -#}
+ <nav class="sub"> {#- -#}
+ <div class="theme-picker"> {#- -#}
+ <button id="theme-picker" aria-label="Pick another theme!" aria-haspopup="menu" title="themes"> {#- -#}
+ <img width="18" height="18" alt="Pick another theme!" {# -#}
+ src="{{static_root_path | safe}}brush{{page.resource_suffix}}.svg"> {#- -#}
+ </button> {#- -#}
+ <div id="theme-choices" role="menu"></div> {#- -#}
+ </div> {#- -#}
+ <form class="search-form"> {#- -#}
+ <div class="search-container"> {#- -#}
+ <div>{%- if layout.generate_search_filter -%}
+ <select id="crate-search"> {#- -#}
+ <option value="All crates">All crates</option> {#- -#}
+ </select> {#- -#}
+ {%- endif -%}
+ <input {# -#}
+ class="search-input" {# -#}
+ name="search" {# -#}
+ autocomplete="off" {# -#}
+ spellcheck="false" {# -#}
+ placeholder="Click or press ‘S’ to search, ‘?’ for more options…" {# -#}
+ type="search"> {#- -#}
+ </div> {#- -#}
+ <button type="button" id="help-button" title="help">?</button> {#- -#}
+ <a id="settings-menu" href="{{page.root_path | safe}}settings.html" title="settings"> {#- -#}
+ <img width="18" height="18" alt="Change settings" {# -#}
+ src="{{static_root_path | safe}}wheel{{page.resource_suffix}}.svg"> {#- -#}
+ </a> {#- -#}
+ </div> {#- -#}
+ </form> {#- -#}
+ </nav> {#- -#}
</div> {#- -#}
- </form> {#- -#}
- </nav> {#- -#}
- <section id="main" class="content">{{- content | safe -}}</section> {#- -#}
- <section id="search" class="content hidden"></section> {#- -#}
+ <section id="main-content" class="content">{{- content | safe -}}</section> {#- -#}
+ <section id="search" class="content hidden"></section> {#- -#}
+ </div> {#- -#}
+ </main> {#- -#}
{{- layout.external_html.after_content | safe -}}
<div id="rustdoc-vars" {# -#}
data-root-path="{{page.root_path | safe}}" {# -#}
data-current-crate="{{layout.krate}}" {# -#}
- data-search-index-js="{{page.root_path | safe}}search-index{{page.resource_suffix}}.js" {# -#}
- data-search-js="{{static_root_path | safe}}search{{page.resource_suffix}}.js"> {#- -#}
+ data-themes="{{themes | join(sep=",") }}" {# -#}
+ data-resource-suffix="{{page.resource_suffix}}" {# -#}
+ data-rustdoc-version="{{rustdoc_version}}" {# -#}
+ > {#- -#}
</div>
</body> {#- -#}
</html> {#- -#}
diff --git a/src/librustdoc/html/tests.rs b/src/librustdoc/html/tests.rs
index 5d537dabd0c..dee9f5e5038 100644
--- a/src/librustdoc/html/tests.rs
+++ b/src/librustdoc/html/tests.rs
@@ -1,44 +1,44 @@
use crate::html::format::href_relative_parts;
-fn assert_relative_path(expected: &[&str], relative_to_fqp: &[&str], fqp: &[&str]) {
+fn assert_relative_path(expected: &str, relative_to_fqp: &[&str], fqp: &[&str]) {
let relative_to_fqp: Vec<String> = relative_to_fqp.iter().copied().map(String::from).collect();
let fqp: Vec<String> = fqp.iter().copied().map(String::from).collect();
- assert_eq!(expected, href_relative_parts(&fqp, &relative_to_fqp));
+ assert_eq!(expected, href_relative_parts(&fqp, &relative_to_fqp).finish());
}
#[test]
fn href_relative_parts_basic() {
let relative_to_fqp = &["std", "vec"];
let fqp = &["std", "iter"];
- assert_relative_path(&["..", "iter"], relative_to_fqp, fqp);
+ assert_relative_path("../iter", relative_to_fqp, fqp);
}
#[test]
fn href_relative_parts_parent_module() {
let relative_to_fqp = &["std", "vec"];
let fqp = &["std"];
- assert_relative_path(&[".."], relative_to_fqp, fqp);
+ assert_relative_path("..", relative_to_fqp, fqp);
}
#[test]
fn href_relative_parts_different_crate() {
let relative_to_fqp = &["std", "vec"];
let fqp = &["core", "iter"];
- assert_relative_path(&["..", "..", "core", "iter"], relative_to_fqp, fqp);
+ assert_relative_path("../../core/iter", relative_to_fqp, fqp);
}
#[test]
fn href_relative_parts_same_module() {
let relative_to_fqp = &["std", "vec"];
let fqp = &["std", "vec"];
- assert_relative_path(&[], relative_to_fqp, fqp);
+ assert_relative_path("", relative_to_fqp, fqp);
}
#[test]
fn href_relative_parts_child_module() {
let relative_to_fqp = &["std"];
let fqp = &["std", "vec"];
- assert_relative_path(&["vec"], relative_to_fqp, fqp);
+ assert_relative_path("vec", relative_to_fqp, fqp);
}
#[test]
fn href_relative_parts_root() {
let relative_to_fqp = &[];
let fqp = &["std"];
- assert_relative_path(&["std"], relative_to_fqp, fqp);
+ assert_relative_path("std", relative_to_fqp, fqp);
}
diff --git a/src/librustdoc/html/url_parts_builder.rs b/src/librustdoc/html/url_parts_builder.rs
new file mode 100644
index 00000000000..918d5e6bd1b
--- /dev/null
+++ b/src/librustdoc/html/url_parts_builder.rs
@@ -0,0 +1,119 @@
+/// A builder that allows efficiently and easily constructing the part of a URL
+/// after the domain: `nightly/core/str/struct.Bytes.html`.
+///
+/// This type is a wrapper around the final `String` buffer,
+/// but its API is like that of a `Vec` of URL components.
+#[derive(Debug)]
+crate struct UrlPartsBuilder {
+ buf: String,
+}
+
+impl UrlPartsBuilder {
+ /// Create an empty buffer.
+ crate fn new() -> Self {
+ Self { buf: String::new() }
+ }
+
+ /// Create an empty buffer with capacity for the specified number of bytes.
+ fn with_capacity_bytes(count: usize) -> Self {
+ Self { buf: String::with_capacity(count) }
+ }
+
+ /// Create a buffer with one URL component.
+ ///
+ /// # Examples
+ ///
+ /// Basic usage:
+ ///
+ /// ```ignore (private-type)
+ /// let builder = UrlPartsBuilder::singleton("core");
+ /// assert_eq!(builder.finish(), "core");
+ /// ```
+ ///
+ /// Adding more components afterward.
+ ///
+ /// ```ignore (private-type)
+ /// let mut builder = UrlPartsBuilder::singleton("core");
+ /// builder.push("str");
+ /// builder.push_front("nightly");
+ /// assert_eq!(builder.finish(), "nightly/core/str");
+ /// ```
+ crate fn singleton(part: &str) -> Self {
+ Self { buf: part.to_owned() }
+ }
+
+ /// Push a component onto the buffer.
+ ///
+ /// # Examples
+ ///
+ /// Basic usage:
+ ///
+ /// ```ignore (private-type)
+ /// let mut builder = UrlPartsBuilder::new();
+ /// builder.push("core");
+ /// builder.push("str");
+ /// builder.push("struct.Bytes.html");
+ /// assert_eq!(builder.finish(), "core/str/struct.Bytes.html");
+ /// ```
+ crate fn push(&mut self, part: &str) {
+ if !self.buf.is_empty() {
+ self.buf.push('/');
+ }
+ self.buf.push_str(part);
+ }
+
+ /// Push a component onto the front of the buffer.
+ ///
+ /// # Examples
+ ///
+ /// Basic usage:
+ ///
+ /// ```ignore (private-type)
+ /// let mut builder = UrlPartsBuilder::new();
+ /// builder.push("core");
+ /// builder.push("str");
+ /// builder.push_front("nightly");
+ /// builder.push("struct.Bytes.html");
+ /// assert_eq!(builder.finish(), "nightly/core/str/struct.Bytes.html");
+ /// ```
+ crate fn push_front(&mut self, part: &str) {
+ let is_empty = self.buf.is_empty();
+ self.buf.reserve(part.len() + if !is_empty { 1 } else { 0 });
+ self.buf.insert_str(0, part);
+ if !is_empty {
+ self.buf.insert(part.len(), '/');
+ }
+ }
+
+ /// Get the final `String` buffer.
+ crate fn finish(self) -> String {
+ self.buf
+ }
+}
+
+/// This is just a guess at the average length of a URL part,
+/// used for [`String::with_capacity`] calls in the [`FromIterator`]
+/// and [`Extend`] impls.
+///
+/// This is intentionally on the lower end to avoid overallocating.
+const AVG_PART_LENGTH: usize = 5;
+
+impl<'a> FromIterator<&'a str> for UrlPartsBuilder {
+ fn from_iter<T: IntoIterator<Item = &'a str>>(iter: T) -> Self {
+ let iter = iter.into_iter();
+ let mut builder = Self::with_capacity_bytes(AVG_PART_LENGTH * iter.size_hint().0);
+ iter.for_each(|part| builder.push(part));
+ builder
+ }
+}
+
+impl<'a> Extend<&'a str> for UrlPartsBuilder {
+ fn extend<T: IntoIterator<Item = &'a str>>(&mut self, iter: T) {
+ let iter = iter.into_iter();
+ self.buf.reserve(AVG_PART_LENGTH * iter.size_hint().0);
+ iter.for_each(|part| self.push(part));
+ }
+}
+
+#[cfg(test)]
+mod tests;
diff --git a/src/librustdoc/html/url_parts_builder/tests.rs b/src/librustdoc/html/url_parts_builder/tests.rs
new file mode 100644
index 00000000000..43338c95010
--- /dev/null
+++ b/src/librustdoc/html/url_parts_builder/tests.rs
@@ -0,0 +1,54 @@
+use super::*;
+
+fn t(builder: UrlPartsBuilder, expect: &str) {
+ assert_eq!(builder.finish(), expect);
+}
+
+#[test]
+fn empty() {
+ t(UrlPartsBuilder::new(), "");
+}
+
+#[test]
+fn singleton() {
+ t(UrlPartsBuilder::singleton("index.html"), "index.html");
+}
+
+#[test]
+fn push_several() {
+ let mut builder = UrlPartsBuilder::new();
+ builder.push("core");
+ builder.push("str");
+ builder.push("struct.Bytes.html");
+ t(builder, "core/str/struct.Bytes.html");
+}
+
+#[test]
+fn push_front_empty() {
+ let mut builder = UrlPartsBuilder::new();
+ builder.push_front("page.html");
+ t(builder, "page.html");
+}
+
+#[test]
+fn push_front_non_empty() {
+ let mut builder = UrlPartsBuilder::new();
+ builder.push("core");
+ builder.push("str");
+ builder.push("struct.Bytes.html");
+ builder.push_front("nightly");
+ t(builder, "nightly/core/str/struct.Bytes.html");
+}
+
+#[test]
+fn collect() {
+ t(["core", "str"].into_iter().collect(), "core/str");
+ t(["core", "str", "struct.Bytes.html"].into_iter().collect(), "core/str/struct.Bytes.html");
+}
+
+#[test]
+fn extend() {
+ let mut builder = UrlPartsBuilder::singleton("core");
+ builder.extend(["str", "struct.Bytes.html"]);
+ t(builder, "core/str/struct.Bytes.html");
+}
diff --git a/src/librustdoc/json/conversions.rs b/src/librustdoc/json/conversions.rs
index a46518ef489..ee29bfcc7a4 100644
--- a/src/librustdoc/json/conversions.rs
+++ b/src/librustdoc/json/conversions.rs
@@ -219,7 +219,9 @@ fn from_clean_item(item: clean::Item, tcx: TyCtxt<'_>) -> ItemEnum {
MacroItem(m) => ItemEnum::Macro(m.source),
ProcMacroItem(m) => ItemEnum::ProcMacro(m.into_tcx(tcx)),
PrimitiveItem(p) => ItemEnum::PrimitiveType(p.as_sym().to_string()),
- AssocConstItem(t, s) => ItemEnum::AssocConst { type_: t.into_tcx(tcx), default: s },
+ AssocConstItem(ty, default) => {
+ ItemEnum::AssocConst { type_: ty.into_tcx(tcx), default: default.map(|c| c.expr(tcx)) }
+ }
AssocTypeItem(g, t) => ItemEnum::AssocType {
bounds: g.into_iter().map(|x| x.into_tcx(tcx)).collect(),
default: t.map(|x| x.into_tcx(tcx)),
@@ -365,8 +367,7 @@ impl FromWithTcx<clean::GenericBound> for GenericBound {
match bound {
TraitBound(clean::PolyTrait { trait_, generic_params }, modifier) => {
// FIXME: should `trait_` be a clean::Path equivalent in JSON?
- let trait_ =
- clean::ResolvedPath { did: trait_.def_id(), path: trait_ }.into_tcx(tcx);
+ let trait_ = clean::Type::Path { path: trait_ }.into_tcx(tcx);
GenericBound::TraitBound {
trait_,
generic_params: generic_params.into_iter().map(|x| x.into_tcx(tcx)).collect(),
@@ -389,11 +390,15 @@ crate fn from_trait_bound_modifier(modifier: rustc_hir::TraitBoundModifier) -> T
impl FromWithTcx<clean::Type> for Type {
fn from_tcx(ty: clean::Type, tcx: TyCtxt<'_>) -> Self {
- use clean::Type::*;
+ use clean::Type::{
+ Array, BareFunction, BorrowedRef, DynTrait, Generic, ImplTrait, Infer, Primitive,
+ QPath, RawPointer, Slice, Tuple,
+ };
+
match ty {
- ResolvedPath { path, did } => Type::ResolvedPath {
+ clean::Type::Path { path } => Type::ResolvedPath {
name: path.whole_name(),
- id: from_item_id(did.into()),
+ id: from_item_id(path.def_id().into()),
args: path.segments.last().map(|args| Box::new(args.clone().args.into_tcx(tcx))),
param_names: Vec::new(),
},
@@ -436,7 +441,7 @@ impl FromWithTcx<clean::Type> for Type {
},
QPath { name, self_type, trait_, .. } => {
// FIXME: should `trait_` be a clean::Path equivalent in JSON?
- let trait_ = ResolvedPath { did: trait_.def_id(), path: trait_ }.into_tcx(tcx);
+ let trait_ = clean::Type::Path { path: trait_ }.into_tcx(tcx);
Type::QualifiedPath {
name: name.to_string(),
self_type: Box::new((*self_type).into_tcx(tcx)),
@@ -502,10 +507,7 @@ impl FromWithTcx<clean::Impl> for Impl {
let provided_trait_methods = impl_.provided_trait_methods(tcx);
let clean::Impl { unsafety, generics, trait_, for_, items, polarity, kind } = impl_;
// FIXME: should `trait_` be a clean::Path equivalent in JSON?
- let trait_ = trait_.map(|path| {
- let did = path.def_id();
- clean::ResolvedPath { path, did }.into_tcx(tcx)
- });
+ let trait_ = trait_.map(|path| clean::Type::Path { path }.into_tcx(tcx));
// FIXME: use something like ImplKind in JSON?
let (synthetic, blanket_impl) = match kind {
clean::ImplKind::Normal => (false, None),
diff --git a/src/librustdoc/lib.rs b/src/librustdoc/lib.rs
index b6311abb5c3..8699ab20b19 100644
--- a/src/librustdoc/lib.rs
+++ b/src/librustdoc/lib.rs
@@ -278,7 +278,16 @@ fn opts() -> Vec<RustcOptGroup> {
o.optopt("r", "input-format", "the input type of the specified file", "[rust]")
}),
stable("w", |o| o.optopt("w", "output-format", "the output type to write", "[html]")),
- stable("o", |o| o.optopt("o", "output", "where to place the output", "PATH")),
+ stable("output", |o| {
+ o.optopt(
+ "",
+ "output",
+ "Which directory to place the output. \
+ This option is deprecated, use --out-dir instead.",
+ "PATH",
+ )
+ }),
+ stable("o", |o| o.optopt("o", "out-dir", "which directory to place the output", "PATH")),
stable("crate-name", |o| {
o.optopt("", "crate-name", "specify the name of this crate", "NAME")
}),
diff --git a/src/librustdoc/markdown.rs b/src/librustdoc/markdown.rs
index 47b24d40edc..906b8f8a245 100644
--- a/src/librustdoc/markdown.rs
+++ b/src/librustdoc/markdown.rs
@@ -7,7 +7,7 @@ use rustc_span::source_map::DUMMY_SP;
use rustc_span::Symbol;
use crate::config::{Options, RenderOptions};
-use crate::doctest::{Collector, TestOptions};
+use crate::doctest::{Collector, GlobalTestOptions};
use crate::html::escape::Escape;
use crate::html::markdown;
use crate::html::markdown::{
@@ -129,9 +129,8 @@ crate fn render<P: AsRef<Path>>(
crate fn test(options: Options) -> Result<(), String> {
let input_str = read_to_string(&options.input)
.map_err(|err| format!("{}: {}", options.input.display(), err))?;
- let mut opts = TestOptions::default();
+ let mut opts = GlobalTestOptions::default();
opts.no_crate_inject = true;
- opts.display_doctest_warnings = options.display_doctest_warnings;
let mut collector = Collector::new(
Symbol::intern(&options.input.display().to_string()),
options.clone(),
@@ -146,11 +145,6 @@ crate fn test(options: Options) -> Result<(), String> {
find_testable_code(&input_str, &mut collector, codes, options.enable_per_target_ignores, None);
- crate::doctest::run_tests(
- options.test_args,
- options.nocapture,
- options.display_doctest_warnings,
- collector.tests,
- );
+ crate::doctest::run_tests(options.test_args, options.nocapture, collector.tests);
Ok(())
}
diff --git a/src/librustdoc/passes/bare_urls.rs b/src/librustdoc/passes/bare_urls.rs
index 4e146a07d15..3410f46e2a8 100644
--- a/src/librustdoc/passes/bare_urls.rs
+++ b/src/librustdoc/passes/bare_urls.rs
@@ -1,3 +1,5 @@
+//! Detects links that are not linkified, e.g., in Markdown such as `Go to https://example.com/.`
+//! Suggests wrapping the link with angle brackets: `Go to <https://example.com/>.` to linkify it.
use super::Pass;
use crate::clean::*;
use crate::core::DocContext;
diff --git a/src/librustdoc/passes/calculate_doc_coverage.rs b/src/librustdoc/passes/calculate_doc_coverage.rs
index 85542ebd9ac..6111c982de9 100644
--- a/src/librustdoc/passes/calculate_doc_coverage.rs
+++ b/src/librustdoc/passes/calculate_doc_coverage.rs
@@ -1,3 +1,4 @@
+//! Calculates information used for the --show-coverage flag.
use crate::clean;
use crate::core::DocContext;
use crate::html::markdown::{find_testable_code, ErrorCodes};
diff --git a/src/librustdoc/passes/check_code_block_syntax.rs b/src/librustdoc/passes/check_code_block_syntax.rs
index fd2ab0dc97c..a50bf558bf3 100644
--- a/src/librustdoc/passes/check_code_block_syntax.rs
+++ b/src/librustdoc/passes/check_code_block_syntax.rs
@@ -1,3 +1,4 @@
+//! Validates syntax inside Rust code blocks (\`\`\`rust).
use rustc_data_structures::sync::{Lock, Lrc};
use rustc_errors::{emitter::Emitter, Applicability, Diagnostic, Handler};
use rustc_middle::lint::LintDiagnosticBuilder;
diff --git a/src/librustdoc/passes/check_doc_test_visibility.rs b/src/librustdoc/passes/check_doc_test_visibility.rs
index 7d3010cf332..b86ec8abefa 100644
--- a/src/librustdoc/passes/check_doc_test_visibility.rs
+++ b/src/librustdoc/passes/check_doc_test_visibility.rs
@@ -1,3 +1,5 @@
+//! Looks for items missing (or incorrectly having) doctests.
+//!
//! This pass is overloaded and runs two different lints.
//!
//! - MISSING_DOC_CODE_EXAMPLES: this lint is **UNSTABLE** and looks for public items missing doctests.
diff --git a/src/librustdoc/passes/collect_intra_doc_links.rs b/src/librustdoc/passes/collect_intra_doc_links.rs
index 4e5812d7f84..2faf7781807 100644
--- a/src/librustdoc/passes/collect_intra_doc_links.rs
+++ b/src/librustdoc/passes/collect_intra_doc_links.rs
@@ -963,7 +963,7 @@ fn preprocess_link<'a>(
return None;
}
- let stripped = ori_link.link.replace("`", "");
+ let stripped = ori_link.link.replace('`', "");
let mut parts = stripped.split('#');
let link = parts.next().unwrap();
diff --git a/src/librustdoc/passes/collect_trait_impls.rs b/src/librustdoc/passes/collect_trait_impls.rs
index 8524f872ca3..baa0c7595eb 100644
--- a/src/librustdoc/passes/collect_trait_impls.rs
+++ b/src/librustdoc/passes/collect_trait_impls.rs
@@ -1,3 +1,6 @@
+//! Collects trait impls for each item in the crate. For example, if a crate
+//! defines a struct that implements a trait, this pass will note that the
+//! struct implements that trait.
use super::Pass;
use crate::clean::*;
use crate::core::DocContext;
diff --git a/src/librustdoc/passes/html_tags.rs b/src/librustdoc/passes/html_tags.rs
index 56b222d8932..f7a9a0899e3 100644
--- a/src/librustdoc/passes/html_tags.rs
+++ b/src/librustdoc/passes/html_tags.rs
@@ -1,3 +1,4 @@
+//! Detects invalid HTML (like an unclosed `<span>`) in doc comments.
use super::Pass;
use crate::clean::*;
use crate::core::DocContext;
diff --git a/src/librustdoc/passes/propagate_doc_cfg.rs b/src/librustdoc/passes/propagate_doc_cfg.rs
index f5a362bfbe8..d3df2d2794b 100644
--- a/src/librustdoc/passes/propagate_doc_cfg.rs
+++ b/src/librustdoc/passes/propagate_doc_cfg.rs
@@ -1,3 +1,4 @@
+//! Propagates [`#[doc(cfg(...))]`](https://github.com/rust-lang/rust/issues/43781) to child items.
use std::sync::Arc;
use crate::clean::cfg::Cfg;
diff --git a/src/librustdoc/passes/strip_hidden.rs b/src/librustdoc/passes/strip_hidden.rs
index 0aedbda35e9..e63534659ad 100644
--- a/src/librustdoc/passes/strip_hidden.rs
+++ b/src/librustdoc/passes/strip_hidden.rs
@@ -1,3 +1,4 @@
+//! Strip all doc(hidden) items from the output.
use rustc_span::symbol::sym;
use std::mem;
diff --git a/src/librustdoc/passes/strip_priv_imports.rs b/src/librustdoc/passes/strip_priv_imports.rs
index 63869324cb8..21ce9ae7a28 100644
--- a/src/librustdoc/passes/strip_priv_imports.rs
+++ b/src/librustdoc/passes/strip_priv_imports.rs
@@ -1,3 +1,5 @@
+//! Strips all private import statements (use, extern crate) from a
+//! crate.
use crate::clean;
use crate::core::DocContext;
use crate::fold::DocFolder;
diff --git a/src/librustdoc/passes/strip_private.rs b/src/librustdoc/passes/strip_private.rs
index dfdba2a4b36..c6b5bec4692 100644
--- a/src/librustdoc/passes/strip_private.rs
+++ b/src/librustdoc/passes/strip_private.rs
@@ -1,3 +1,5 @@
+//! Strip all private items from the output. Additionally implies strip_priv_imports.
+//! Basically, the goal is to remove items that are not relevant for public documentation.
use crate::clean::{self, ItemIdSet};
use crate::core::DocContext;
use crate::fold::DocFolder;
diff --git a/src/librustdoc/passes/stripper.rs b/src/librustdoc/passes/stripper.rs
index 74a9a2da06d..675443b48a2 100644
--- a/src/librustdoc/passes/stripper.rs
+++ b/src/librustdoc/passes/stripper.rs
@@ -1,3 +1,4 @@
+//! A collection of utility functions for the `strip_*` passes.
use rustc_hir::def_id::DefId;
use rustc_middle::middle::privacy::AccessLevels;
use std::mem;
diff --git a/src/librustdoc/passes/unindent_comments.rs b/src/librustdoc/passes/unindent_comments.rs
index 97f4f941e06..6cac31d2f90 100644
--- a/src/librustdoc/passes/unindent_comments.rs
+++ b/src/librustdoc/passes/unindent_comments.rs
@@ -1,3 +1,16 @@
+//! Removes excess indentation on comments in order for the Markdown
+//! to be parsed correctly. This is necessary because the convention for
+//! writing documentation is to provide a space between the /// or //! marker
+//! and the doc text, but Markdown is whitespace-sensitive. For example,
+//! a block of text with four-space indentation is parsed as a code block,
+//! so if we didn't unindent comments, these list items
+//!
+//! /// A list:
+//! ///
+//! /// - Foo
+//! /// - Bar
+//!
+//! would be parsed as if they were in a code block, which is likely not what the user intended.
use std::cmp;
use rustc_span::symbol::kw;
diff --git a/src/librustdoc/passes/unindent_comments/tests.rs b/src/librustdoc/passes/unindent_comments/tests.rs
index daec04e11cd..3d3d2e50321 100644
--- a/src/librustdoc/passes/unindent_comments/tests.rs
+++ b/src/librustdoc/passes/unindent_comments/tests.rs
@@ -1,4 +1,7 @@
use super::*;
+
+use crate::clean::collapse_doc_fragments;
+
use rustc_span::create_default_session_globals_then;
use rustc_span::source_map::DUMMY_SP;
use rustc_span::symbol::Symbol;
@@ -19,7 +22,7 @@ fn run_test(input: &str, expected: &str) {
create_default_session_globals_then(|| {
let mut s = create_doc_fragment(input);
unindent_fragments(&mut s);
- assert_eq!(&s.iter().collect::<String>(), expected);
+ assert_eq!(collapse_doc_fragments(&s), expected);
});
}
diff --git a/src/librustdoc/scrape_examples.rs b/src/librustdoc/scrape_examples.rs
index 3b39e3576e6..10b6fdf87f4 100644
--- a/src/librustdoc/scrape_examples.rs
+++ b/src/librustdoc/scrape_examples.rs
@@ -142,16 +142,21 @@ where
hir::ExprKind::Call(f, _) => {
let types = tcx.typeck(ex.hir_id.owner);
- match types.node_type_opt(f.hir_id) {
- Some(ty) => (ty, ex.span),
- None => {
- return;
- }
+ if let Some(ty) = types.node_type_opt(f.hir_id) {
+ (ty, ex.span)
+ } else {
+ trace!("node_type_opt({}) = None", f.hir_id);
+ return;
}
}
hir::ExprKind::MethodCall(_, _, _, span) => {
let types = tcx.typeck(ex.hir_id.owner);
- let def_id = types.type_dependent_def_id(ex.hir_id).unwrap();
+ let def_id = if let Some(def_id) = types.type_dependent_def_id(ex.hir_id) {
+ def_id
+ } else {
+ trace!("type_dependent_def_id({}) = None", ex.hir_id);
+ return;
+ };
(tcx.type_of(def_id), span)
}
_ => {
diff --git a/src/librustdoc/theme.rs b/src/librustdoc/theme.rs
index b8b3f9634e5..1e9a65e1d2f 100644
--- a/src/librustdoc/theme.rs
+++ b/src/librustdoc/theme.rs
@@ -173,11 +173,11 @@ fn build_rule(v: &[u8], positions: &[usize]) -> String {
.map(|x| ::std::str::from_utf8(&v[x[0]..x[1]]).unwrap_or(""))
.collect::<String>()
.trim()
- .replace("\n", " ")
- .replace("/", "")
- .replace("\t", " ")
- .replace("{", "")
- .replace("}", "")
+ .replace('\n', " ")
+ .replace('/', "")
+ .replace('\t', " ")
+ .replace('{', "")
+ .replace('}', "")
.split(' ')
.filter(|s| !s.is_empty())
.collect::<Vec<&str>>()
diff --git a/src/librustdoc/visit_ast.rs b/src/librustdoc/visit_ast.rs
index 379de080ffd..ea7372761ba 100644
--- a/src/librustdoc/visit_ast.rs
+++ b/src/librustdoc/visit_ast.rs
@@ -5,6 +5,7 @@ use rustc_data_structures::fx::{FxHashMap, FxHashSet};
use rustc_hir as hir;
use rustc_hir::def::{DefKind, Res};
use rustc_hir::def_id::DefId;
+use rustc_hir::definitions::DefPathData;
use rustc_hir::Node;
use rustc_hir::CRATE_HIR_ID;
use rustc_middle::middle::privacy::AccessLevel;
@@ -45,9 +46,8 @@ impl Module<'hir> {
fn def_id_to_path(tcx: TyCtxt<'_>, did: DefId) -> Vec<String> {
let crate_name = tcx.crate_name(did.krate).to_string();
let relative = tcx.def_path(did).data.into_iter().filter_map(|elem| {
- // extern blocks have an empty name
- let s = elem.data.to_string();
- if !s.is_empty() { Some(s) } else { None }
+ // Filter out extern blocks
+ (elem.data != DefPathData::ForeignMod).then(|| elem.data.to_string())
});
std::iter::once(crate_name).chain(relative).collect()
}
@@ -117,8 +117,7 @@ impl<'a, 'tcx> RustdocVisitor<'a, 'tcx> {
if let Some(local_def_id) = def_id.as_local() {
if self.cx.tcx.has_attr(def_id, sym::macro_export) {
if inserted.insert(def_id) {
- let hir_id = self.cx.tcx.hir().local_def_id_to_hir_id(local_def_id);
- let item = self.cx.tcx.hir().expect_item(hir_id);
+ let item = self.cx.tcx.hir().expect_item(local_def_id);
top_level_module.items.push((item, None));
}
}
diff --git a/src/llvm-project b/src/llvm-project
-Subproject f9b03d0e2d7378f8dd5697ceb72b310060f7598
+Subproject 8404254254e2b4c9a80e7403659f6391b08203d
diff --git a/src/stage0.json b/src/stage0.json
index b5a4a3a03fd..6c1b95b4145 100644
--- a/src/stage0.json
+++ b/src/stage0.json
@@ -2,347 +2,347 @@
"__comment": "Generated by `./x.py run src/tools/bump-stage0`. Run that command again to update the bootstrap compiler.",
"dist_server": "https://static.rust-lang.org",
"compiler": {
- "date": "2021-10-22",
+ "date": "2021-11-30",
"version": "beta"
},
"rustfmt": {
- "date": "2021-10-23",
+ "date": "2021-11-30",
"version": "nightly"
},
"checksums_sha256": {
- "dist/2021-10-22/cargo-beta-aarch64-apple-darwin.tar.gz": "b81ef641492ff2f03a93c8fbfbcfa78db2f6574d1998569d68dd2ba0e08ee186",
- "dist/2021-10-22/cargo-beta-aarch64-apple-darwin.tar.xz": "925090782ad982202ca554a84e9d4a7b190f94b0b220c23e73235383d6ca367d",
- "dist/2021-10-22/cargo-beta-aarch64-pc-windows-msvc.tar.gz": "eba42edfebc85c744f4c6874337847748df65e430915f47238a93b1b7e96840a",
- "dist/2021-10-22/cargo-beta-aarch64-pc-windows-msvc.tar.xz": "fd04a8c4058ff287ea0256fd9f33a4b04b4f098d6911e8d827525cdeda6f169e",
- "dist/2021-10-22/cargo-beta-aarch64-unknown-linux-gnu.tar.gz": "c7abbf1f265435cc9f6f0773d30321fc99353e0ddbf0004d00f47433eb3aaab1",
- "dist/2021-10-22/cargo-beta-aarch64-unknown-linux-gnu.tar.xz": "3363dfdcd7106841edbd9029676ac339ff54c142921d71d92e308bee2ee33066",
- "dist/2021-10-22/cargo-beta-aarch64-unknown-linux-musl.tar.gz": "fbc5d5f70a36fc73f4d34d101aef4be78e38b5009ebf690fe46ba32eff6c1fce",
- "dist/2021-10-22/cargo-beta-aarch64-unknown-linux-musl.tar.xz": "220f23f50645532df4e5a4b1d6d894ce66a6ee2e5576fdf552081644a74a1c8f",
- "dist/2021-10-22/cargo-beta-arm-unknown-linux-gnueabi.tar.gz": "94b42b8639ce541c1a355991f20d9934c72e766b6200d742d2d5b3b2f499f782",
- "dist/2021-10-22/cargo-beta-arm-unknown-linux-gnueabi.tar.xz": "e32e9df3ab261fe20c363406d655fdaeeefc9dbb3d69da4551cdf9c22c418eb2",
- "dist/2021-10-22/cargo-beta-arm-unknown-linux-gnueabihf.tar.gz": "301c303ec0db0e342ecce4e259e79810e082766bac8f9907c353bdf490177863",
- "dist/2021-10-22/cargo-beta-arm-unknown-linux-gnueabihf.tar.xz": "d6f9409076ab4e2dac5ac5c07bac6be30e83e281df9efe2fa68386928e2e6faf",
- "dist/2021-10-22/cargo-beta-armv7-unknown-linux-gnueabihf.tar.gz": "a4a82d48b2b1e6a49c0a765f9ee4d01e7ce4b0543128745d13cf4684c56eca8c",
- "dist/2021-10-22/cargo-beta-armv7-unknown-linux-gnueabihf.tar.xz": "c9ca524ba0e76d9fe38f0e4af337d14b97fd97dcd83d80ebf4725b5b03bea3ac",
- "dist/2021-10-22/cargo-beta-i686-pc-windows-gnu.tar.gz": "973eabda91963d58a9cdd1491bcea15834874fbca018287fb7f5c8bdcdf323d1",
- "dist/2021-10-22/cargo-beta-i686-pc-windows-gnu.tar.xz": "cbbc14d1ef0e4579167fce4a5fac43b22c87882049a3d0edfbace9fc5c103ad3",
- "dist/2021-10-22/cargo-beta-i686-pc-windows-msvc.tar.gz": "ef090943f6c90bb3327225e0256e73762ca2f73ae5d0d07b2c828709077e1132",
- "dist/2021-10-22/cargo-beta-i686-pc-windows-msvc.tar.xz": "42708683ba5ad855880ec69d92192bd9f99ebf102beaf6c53680cb8733fba9e7",
- "dist/2021-10-22/cargo-beta-i686-unknown-linux-gnu.tar.gz": "b6c260ba19734482439bf6d12b8e87e82f269f1bec447ec85e59372ef6489eec",
- "dist/2021-10-22/cargo-beta-i686-unknown-linux-gnu.tar.xz": "fb6036ff910d075fb5e483000af641328e6d7d01c33255c099ed1b0302239918",
- "dist/2021-10-22/cargo-beta-mips-unknown-linux-gnu.tar.gz": "71e4e5fcf055251089ac0d37b5ad873eaee6aa0380438cd68f140a16d3a37cd1",
- "dist/2021-10-22/cargo-beta-mips-unknown-linux-gnu.tar.xz": "b89acabf106b10c5c3421574bea83d8baf1f29d040c40d5522f85e2e6afa6373",
- "dist/2021-10-22/cargo-beta-mips64-unknown-linux-gnuabi64.tar.gz": "f544ea08d2f6086dc49c4d635116f3b4b804e5b68251e5fad433d538ae5e8226",
- "dist/2021-10-22/cargo-beta-mips64-unknown-linux-gnuabi64.tar.xz": "54b0cbb4292cc4733a704017775e5cd4a9be34d53a4c666d6fc556472b508e1c",
- "dist/2021-10-22/cargo-beta-mips64el-unknown-linux-gnuabi64.tar.gz": "5e81253ec483f096e23ed98f939220b029814c041b4b72b93e994cead3dc4f4c",
- "dist/2021-10-22/cargo-beta-mips64el-unknown-linux-gnuabi64.tar.xz": "1a66beee5ccfd8b0fb4de52bccd11a0057248ac7fe8daf4f4d6fe0c0088044ea",
- "dist/2021-10-22/cargo-beta-mipsel-unknown-linux-gnu.tar.gz": "2a6cc2e98ed575df64661595b6e1ec2814ed79fb63fe697c0201193eb52d70e0",
- "dist/2021-10-22/cargo-beta-mipsel-unknown-linux-gnu.tar.xz": "ab3f70ea6977306c26c9cc368d64a116716f9ac6ad1a55eed23ddac894e7717b",
- "dist/2021-10-22/cargo-beta-powerpc-unknown-linux-gnu.tar.gz": "ddd840c0c19077b4b45dc85920a2b2a37f176795b3d9390f1faccd44aa3d55e5",
- "dist/2021-10-22/cargo-beta-powerpc-unknown-linux-gnu.tar.xz": "f5c9f1df082a7c48a63e786e5104d31e616c31d47514e9233b4a86d24700159c",
- "dist/2021-10-22/cargo-beta-powerpc64-unknown-linux-gnu.tar.gz": "4d39fac4d45dd73221b93b1d1351988ab4bf07ab04187a815467ab9b992f9490",
- "dist/2021-10-22/cargo-beta-powerpc64-unknown-linux-gnu.tar.xz": "3b6b0d38a3644028ca76347d5b82da6bac6e761a235516bf5b321d12ba909519",
- "dist/2021-10-22/cargo-beta-powerpc64le-unknown-linux-gnu.tar.gz": "0d5992a6e66207e4ead98d5bd627c181a052775f03ebdd2a0313574092a12abc",
- "dist/2021-10-22/cargo-beta-powerpc64le-unknown-linux-gnu.tar.xz": "217940928d5c22553f910f3abf7b56bc832ddcd36282cb85c4b8142f9411147f",
- "dist/2021-10-22/cargo-beta-riscv64gc-unknown-linux-gnu.tar.gz": "67ce7cb12cbd06e114a2f5dedd1d94c844f091ab05a764579dccf30e6158ea46",
- "dist/2021-10-22/cargo-beta-riscv64gc-unknown-linux-gnu.tar.xz": "2cb17c66bdfcfeb567bb021c25c33a8c2b8df1366601d09fd9332278517a2f4c",
- "dist/2021-10-22/cargo-beta-s390x-unknown-linux-gnu.tar.gz": "e25a7fa310019a3457b317c9e3fe052602c82a25939c2ea8c012ff6016c622d9",
- "dist/2021-10-22/cargo-beta-s390x-unknown-linux-gnu.tar.xz": "1722ef69ea949c365f6b64735ee31dc92082db1177b94f0086b8aca790378398",
- "dist/2021-10-22/cargo-beta-x86_64-apple-darwin.tar.gz": "f171fb45017640db15d437198b25758c49649b64338118501905f48ce957b93f",
- "dist/2021-10-22/cargo-beta-x86_64-apple-darwin.tar.xz": "59c5f8ce9fa9dbf3e96dd8a38a52b8bff0ff0d97c081b1d343a654257df1e500",
- "dist/2021-10-22/cargo-beta-x86_64-pc-windows-gnu.tar.gz": "4f219f3661a03330b33d33cebadd5eac759968e1c4c3449f0f27433e715ab55e",
- "dist/2021-10-22/cargo-beta-x86_64-pc-windows-gnu.tar.xz": "5aed2d9631a2aa3fe016ae5e2ee312aa5357ce470c26c01171d14a159af7750c",
- "dist/2021-10-22/cargo-beta-x86_64-pc-windows-msvc.tar.gz": "c9dfb9c486cedac794cab6ac524805c10d2853c15416f3037ff4a5098514427a",
- "dist/2021-10-22/cargo-beta-x86_64-pc-windows-msvc.tar.xz": "a1e0aca8a32700e62fbc73b17dbb0be711db4e9caf535440b08bb1465d6a9c9c",
- "dist/2021-10-22/cargo-beta-x86_64-unknown-freebsd.tar.gz": "61c041ba51632c029d916f274ed8ff92f1f7b23b5e9641591828e6251e205f6b",
- "dist/2021-10-22/cargo-beta-x86_64-unknown-freebsd.tar.xz": "b61464e9e1c2e820a237f1f3d91cae8b0e62cda16dea51b32a8cf695b7a5707c",
- "dist/2021-10-22/cargo-beta-x86_64-unknown-illumos.tar.gz": "1f9b7e500b22c34fa3080e4a15397a3a3827797c237d21459841055b5cb6cbaa",
- "dist/2021-10-22/cargo-beta-x86_64-unknown-illumos.tar.xz": "97aba07cede4a9228ff1b937b8e884b23e9e246afe39b9d68896e6b4a346d972",
- "dist/2021-10-22/cargo-beta-x86_64-unknown-linux-gnu.tar.gz": "c82bf6a11f468ba1d865a3cdc036b03f01e63a23272512583afa9dd9bbf95824",
- "dist/2021-10-22/cargo-beta-x86_64-unknown-linux-gnu.tar.xz": "2efde3ef57e877f7a0aaba264ec14bc94d0cf3e4451b072c004c37e3f86288a9",
- "dist/2021-10-22/cargo-beta-x86_64-unknown-linux-musl.tar.gz": "17df9a194a8cd80871981fbde5fc333794e36a4ab219aafa7849ffeaf07d95c1",
- "dist/2021-10-22/cargo-beta-x86_64-unknown-linux-musl.tar.xz": "54fd84ff5bdf3221b151945ceacd71f51e71898927fe4b57887a0eba5d3e3676",
- "dist/2021-10-22/cargo-beta-x86_64-unknown-netbsd.tar.gz": "0bd987dd970f98b297afbb7cf4906b1d2045ad09df929e8ebd291125e3c36126",
- "dist/2021-10-22/cargo-beta-x86_64-unknown-netbsd.tar.xz": "054af5ef3148902a8fe07c2c445ea98a526f63203c13b849ba464d17145afe07",
- "dist/2021-10-22/rust-std-beta-aarch64-apple-darwin.tar.gz": "2228315b5b7280a7ea9b3acfdfa1a8f0921391f67d792f32f53c1b303565a20b",
- "dist/2021-10-22/rust-std-beta-aarch64-apple-darwin.tar.xz": "777d4c1c6bd3430771280dad79aaa16a6903901875529391e4779f0c2fadb0d8",
- "dist/2021-10-22/rust-std-beta-aarch64-apple-ios-sim.tar.gz": "1d2a74d8ff44feae6551613c182a87d078c0d4cc8f5117c6a3763f28d0af306e",
- "dist/2021-10-22/rust-std-beta-aarch64-apple-ios-sim.tar.xz": "67ab7519c7182a582fbd3e477b8bbbcba143a76e442cef94a47f0a03fa36ed05",
- "dist/2021-10-22/rust-std-beta-aarch64-apple-ios.tar.gz": "2c2a8ca955cc99e86823bf7ede5492b04ea28c182a94d0f59b0d542f10128e88",
- "dist/2021-10-22/rust-std-beta-aarch64-apple-ios.tar.xz": "bfd421654ad72aaff2610a104d0ea2afec579803ed16ac70ab594067cac292aa",
- "dist/2021-10-22/rust-std-beta-aarch64-fuchsia.tar.gz": "b06020ac4aa9b5236d1888a59e2dc3519ac63c760ed0ef47b706466df437d5ba",
- "dist/2021-10-22/rust-std-beta-aarch64-fuchsia.tar.xz": "92ffbe22d8fe9474aef42cd3bbe4808c4afa212a3f65f07828b39848dc03a1f9",
- "dist/2021-10-22/rust-std-beta-aarch64-linux-android.tar.gz": "55aa7b2b3b79aba674bfc496efba37400086e192e6c7fa8483f5501ba31e68a8",
- "dist/2021-10-22/rust-std-beta-aarch64-linux-android.tar.xz": "6219a156e46b7056a9046ab5a58af1a5386024b2961528a54fe6b1c3ec09a91f",
- "dist/2021-10-22/rust-std-beta-aarch64-pc-windows-msvc.tar.gz": "f43fecdf75ac81f8b18ba5ec59625ce93b0debd27c0016edd76d5058e8182118",
- "dist/2021-10-22/rust-std-beta-aarch64-pc-windows-msvc.tar.xz": "a032b56685b2b8431068565d652e5a174dbc9febe6de96945c037b96359d5cfe",
- "dist/2021-10-22/rust-std-beta-aarch64-unknown-linux-gnu.tar.gz": "bdb7d197cc36c774fe4d59a1c86b46325e93d82462c1cbe87e8ab415aba78e4c",
- "dist/2021-10-22/rust-std-beta-aarch64-unknown-linux-gnu.tar.xz": "061cb27b6d5b8e416457137334969733cd0727afe75d63d7954ccf547b7edc51",
- "dist/2021-10-22/rust-std-beta-aarch64-unknown-linux-musl.tar.gz": "895d936a579c9642efcfdca400662264b8ba84ab9130f88e4dcd11c968a81e4d",
- "dist/2021-10-22/rust-std-beta-aarch64-unknown-linux-musl.tar.xz": "29f3aa4005c64fa28f99af20221956ad21aff4a37c5cab9723959ddebb3c2b9d",
- "dist/2021-10-22/rust-std-beta-aarch64-unknown-none-softfloat.tar.gz": "b1e326b0ab30a2f9172a55272926cfa62dca9fbc2c590579f6c7685b8b4ad789",
- "dist/2021-10-22/rust-std-beta-aarch64-unknown-none-softfloat.tar.xz": "616fa68272334400c9110cf5a2cbd7d5c6e462cef8d2c5bc443c3ef6e9843e3b",
- "dist/2021-10-22/rust-std-beta-aarch64-unknown-none.tar.gz": "ec7d513787434a3cf2d523dcff7e37c28cff4b09b13be93c024729cbbbb5aa83",
- "dist/2021-10-22/rust-std-beta-aarch64-unknown-none.tar.xz": "5a396cc0499690193879d10da333f5a3acc6586f1c216f751a1e62bf1a8b6618",
- "dist/2021-10-22/rust-std-beta-arm-linux-androideabi.tar.gz": "f9baf9d74b094cabdab59c1eaaf5238caa175e7865c3497c34eba68be5b2d756",
- "dist/2021-10-22/rust-std-beta-arm-linux-androideabi.tar.xz": "0c5f14f311e29233057ea466123ef9c33e3fffdc798358f0f339ce3869ffe9e4",
- "dist/2021-10-22/rust-std-beta-arm-unknown-linux-gnueabi.tar.gz": "e3c2ffd3d69ba9035048fad22103989ec97b892de955a94015e16578e42481e9",
- "dist/2021-10-22/rust-std-beta-arm-unknown-linux-gnueabi.tar.xz": "3e716d6aab270f764233f50a25a33d37a6d34c2dea23b3cd1aa5733c72c13958",
- "dist/2021-10-22/rust-std-beta-arm-unknown-linux-gnueabihf.tar.gz": "65b74540b47fcf7fc8a88cbc5cfe54ad67c1060722c37af7e31bebe2b3c204ed",
- "dist/2021-10-22/rust-std-beta-arm-unknown-linux-gnueabihf.tar.xz": "4bf4f75f7c4ed171ef7705764f71eb899763205a9a4727343b96cb209691a97c",
- "dist/2021-10-22/rust-std-beta-arm-unknown-linux-musleabi.tar.gz": "be073a69a1e9de0f87511a5a8b3454b3a2d24319571c25f347f7213c872a54bf",
- "dist/2021-10-22/rust-std-beta-arm-unknown-linux-musleabi.tar.xz": "57be5edb2c00745235dc486b4e6e6f0e6b40edf16481405abe3ac360190040e1",
- "dist/2021-10-22/rust-std-beta-arm-unknown-linux-musleabihf.tar.gz": "53c39c89d7b19e45e1a4f32b07eac8214a7d5d277a83e4a88d7ab8820bf2de86",
- "dist/2021-10-22/rust-std-beta-arm-unknown-linux-musleabihf.tar.xz": "b9f058907117e3f1921fb5ee73e04c6114154870067dc8791382f3099aeb5c0a",
- "dist/2021-10-22/rust-std-beta-armebv7r-none-eabi.tar.gz": "bc3d93dd7381749a7d24eb904c7fa74aa6e2a575ad1af5ef7e34ffa07e91105e",
- "dist/2021-10-22/rust-std-beta-armebv7r-none-eabi.tar.xz": "b605ced5cb597a2973417f4de55fb39cfe12b1209c4249ced9232091395d8e91",
- "dist/2021-10-22/rust-std-beta-armebv7r-none-eabihf.tar.gz": "315432af4541ceabb14891da9ab6af6717bba88f1caaf216053f75405ff8997f",
- "dist/2021-10-22/rust-std-beta-armebv7r-none-eabihf.tar.xz": "aa643ea7978ea7911e50ab65ba0af7bf018a4bf9ded1da8e161ee7ab13decbfa",
- "dist/2021-10-22/rust-std-beta-armv5te-unknown-linux-gnueabi.tar.gz": "3f780d36c780b1379fde18fbcd6a1f75efa766b56a4aa6933c9bb88dcd4f4ba8",
- "dist/2021-10-22/rust-std-beta-armv5te-unknown-linux-gnueabi.tar.xz": "d0c87b4127f10c85368254377013053747c10d2d7dafae2f5643a3526f938f48",
- "dist/2021-10-22/rust-std-beta-armv5te-unknown-linux-musleabi.tar.gz": "fb4a610676f9102dd206a1762be6bf7838b3eb0fa08629df8199573246bfc38e",
- "dist/2021-10-22/rust-std-beta-armv5te-unknown-linux-musleabi.tar.xz": "192d9bf1354737dc576bfdcc310c936e065039f39303370008dd0fe3d3e8ec65",
- "dist/2021-10-22/rust-std-beta-armv7-linux-androideabi.tar.gz": "5dd746bb8db14ca9f968a651f3ae7e3c3c5a505800c0c3da8f6469809a81230a",
- "dist/2021-10-22/rust-std-beta-armv7-linux-androideabi.tar.xz": "2cd651fad1f2820a2bb9b828faf292d3029ce633d24283d9a5363a726a024044",
- "dist/2021-10-22/rust-std-beta-armv7-unknown-linux-gnueabi.tar.gz": "06f337db74903b607d09151f8a5178ce48e8b5905af407ae9b37445fe78aeed0",
- "dist/2021-10-22/rust-std-beta-armv7-unknown-linux-gnueabi.tar.xz": "8851247487823bbee990937a1f83578d910985ed4055fe3bf339871a7aa28bce",
- "dist/2021-10-22/rust-std-beta-armv7-unknown-linux-gnueabihf.tar.gz": "5696a2c0fc2c3141d43f2d97d8e4959310032756cbdf0140dde28a5843b431e8",
- "dist/2021-10-22/rust-std-beta-armv7-unknown-linux-gnueabihf.tar.xz": "d8f9a3669d550f1c6f338d99ea74f4e48771620d4125bbd408cc750a70ee4686",
- "dist/2021-10-22/rust-std-beta-armv7-unknown-linux-musleabi.tar.gz": "326e4ac48ef1e1a60c434699b5fb09b9d0581e020bb745196011f2f61af41a13",
- "dist/2021-10-22/rust-std-beta-armv7-unknown-linux-musleabi.tar.xz": "cbd10db975412fe275d12b81cdfd5e97c0b464194639dcc439cd72a65790d601",
- "dist/2021-10-22/rust-std-beta-armv7-unknown-linux-musleabihf.tar.gz": "977c9e94e25fa9a1db5f93ec800d529d80d874ceb2ed3a10bff63639fd24da59",
- "dist/2021-10-22/rust-std-beta-armv7-unknown-linux-musleabihf.tar.xz": "0729470e2138e90d9140e30779d7397e58ebfc1ec243e55caf90ab12ef904da4",
- "dist/2021-10-22/rust-std-beta-armv7a-none-eabi.tar.gz": "3115e3b7f0981dba799902b212f350608042a2beff3bc3b32e930e9c9c3cca17",
- "dist/2021-10-22/rust-std-beta-armv7a-none-eabi.tar.xz": "75b3d8eba51877916129d8dec07bc86ec6e88076af79cc221e8543695e64da63",
- "dist/2021-10-22/rust-std-beta-armv7r-none-eabi.tar.gz": "9787d23a7078c94b4ac33d34cdfb68da586d777f020a6284bb1540b54069f476",
- "dist/2021-10-22/rust-std-beta-armv7r-none-eabi.tar.xz": "c8f9b933b2e9c955e6bbcb141082f6b5833f89f34de16e14f54e8d4aac02c473",
- "dist/2021-10-22/rust-std-beta-armv7r-none-eabihf.tar.gz": "ce9ea3ade0886bf7ea40a1066981d172d915aff4c54ca325d72ed823c7e17787",
- "dist/2021-10-22/rust-std-beta-armv7r-none-eabihf.tar.xz": "2d2442ed2ac017777d3fab1a3f69a578a9db1139fa1aa63dc87113071f08a6f8",
- "dist/2021-10-22/rust-std-beta-asmjs-unknown-emscripten.tar.gz": "98258ea791d398c6a29e1ebe28557aceb59ac228a0bb1332bdbd9f702c61a4bd",
- "dist/2021-10-22/rust-std-beta-asmjs-unknown-emscripten.tar.xz": "a4172c8c2b719d0391654968377fdba932343e444bc78482f19f731ca45806ca",
- "dist/2021-10-22/rust-std-beta-i586-pc-windows-msvc.tar.gz": "2221360e32bdbbdbf073a4bc1fbbb98b86bd0a1df526cb8dd05dd521ea402c7a",
- "dist/2021-10-22/rust-std-beta-i586-pc-windows-msvc.tar.xz": "03c53e31762e5ccc58d1296a8fcee123592dc6d3b88d0c81ed1f8305545faca1",
- "dist/2021-10-22/rust-std-beta-i586-unknown-linux-gnu.tar.gz": "612eb9bc2a06779ec05f6033f44b18f283d6cc8dccac0d5c81a6d09f515fc077",
- "dist/2021-10-22/rust-std-beta-i586-unknown-linux-gnu.tar.xz": "70ad4e52227ae069a9e99cf53e07470267abf1f2ae0398192ac854cfd31d50d9",
- "dist/2021-10-22/rust-std-beta-i586-unknown-linux-musl.tar.gz": "8a5dd3dd62cb31c77aec2e00847812ba53e951fb284c74671cf3875b18a015eb",
- "dist/2021-10-22/rust-std-beta-i586-unknown-linux-musl.tar.xz": "10650efcfda713c2a3053a9c505847dd021bed19b1e3af12d58742deb76cb421",
- "dist/2021-10-22/rust-std-beta-i686-linux-android.tar.gz": "6fb4f4ac2b448bebade72ba2080bdcf579b6a40041b311301452ee41ea267ea1",
- "dist/2021-10-22/rust-std-beta-i686-linux-android.tar.xz": "6e0e8feb477ad35bab1ef599f51f64b4720dc37194dd6354a7a4bfdbacbf2c82",
- "dist/2021-10-22/rust-std-beta-i686-pc-windows-gnu.tar.gz": "0b0c0e86be0fb63dd56b419f0b8d05eb59841649120e16a8216bbe490a76db1c",
- "dist/2021-10-22/rust-std-beta-i686-pc-windows-gnu.tar.xz": "c54a116404d31591d6a6a1a332e4bb8ee177ea7a0367b11eef6a8cae6c1c0325",
- "dist/2021-10-22/rust-std-beta-i686-pc-windows-msvc.tar.gz": "14313eb7b20a3a3739a28406b1544cfe421c593a3198b081956a1a54387cd0b8",
- "dist/2021-10-22/rust-std-beta-i686-pc-windows-msvc.tar.xz": "54fb4abc77fb6c97929641095ef86e559a4cb116cdac7dc4bf34a81aafa03681",
- "dist/2021-10-22/rust-std-beta-i686-unknown-freebsd.tar.gz": "9a2a5b2d3d5cd98cb3f9a43fc34d3dd0dcdf9bd104798380f70373440edaefa4",
- "dist/2021-10-22/rust-std-beta-i686-unknown-freebsd.tar.xz": "d0165b16890da11196a1e4cd6b48d545f44ddb996ba9515a919ecad85cddaceb",
- "dist/2021-10-22/rust-std-beta-i686-unknown-linux-gnu.tar.gz": "a42e125c252eed17664a50713d5e2f0c43f0f9ffe54e471500db75352d1e2147",
- "dist/2021-10-22/rust-std-beta-i686-unknown-linux-gnu.tar.xz": "705185a2b4b98f6ac16a9106af60f30618c24d6d93ffb0283a41cd31f992750e",
- "dist/2021-10-22/rust-std-beta-i686-unknown-linux-musl.tar.gz": "1a01712d4b8b470548c22a24e7e9524c0ddacfcf15459b490531e68e62b8a400",
- "dist/2021-10-22/rust-std-beta-i686-unknown-linux-musl.tar.xz": "a86f8080ea25267f7e127f23bb75538cc3032091061b1fc3ce95c917d2a1cc92",
- "dist/2021-10-22/rust-std-beta-mips-unknown-linux-gnu.tar.gz": "d6d06becfaa6a4b0cb7131fbadd6cc6ff58edfa11fc6d98e69d2cf5388e8bdef",
- "dist/2021-10-22/rust-std-beta-mips-unknown-linux-gnu.tar.xz": "65bafaa34e506e8bab15d2442742fc075dab2ea8687c69f6090acf0204b6fb06",
- "dist/2021-10-22/rust-std-beta-mips-unknown-linux-musl.tar.gz": "53a48c17c4ed3740049d0c88b14d2a1189e7ef5fa08a926c8ca26ec5b2b298b8",
- "dist/2021-10-22/rust-std-beta-mips-unknown-linux-musl.tar.xz": "14525b83b69fc54d4c808ffb69e06f015850ea9186837c670dcc23b5bc66d4bd",
- "dist/2021-10-22/rust-std-beta-mips64-unknown-linux-gnuabi64.tar.gz": "1b8f11cb2ab076f00cd601c1465ff3a2e3857cdec255c8ecc1697efa713f5626",
- "dist/2021-10-22/rust-std-beta-mips64-unknown-linux-gnuabi64.tar.xz": "31e824a6243a6e15ea96a2984c69711e312eefa5214ba349ef6d6a4c42fffffa",
- "dist/2021-10-22/rust-std-beta-mips64-unknown-linux-muslabi64.tar.gz": "89178cf43cfbffea696390c317230d39108e529803e28ca60d37b6167e589dbd",
- "dist/2021-10-22/rust-std-beta-mips64-unknown-linux-muslabi64.tar.xz": "8b9fc0f9a2297d15abc86db95ac8768e872ec1acd21461e599a1aacb80f4b182",
- "dist/2021-10-22/rust-std-beta-mips64el-unknown-linux-gnuabi64.tar.gz": "13ec0039303d3df358ccfa4fc19924df0ce17b31e8f57b13e7367db68bb9dfe8",
- "dist/2021-10-22/rust-std-beta-mips64el-unknown-linux-gnuabi64.tar.xz": "1266340a228c8cd657d0ee7ef257d80a33b193c4ecb742cdb82d469772311499",
- "dist/2021-10-22/rust-std-beta-mips64el-unknown-linux-muslabi64.tar.gz": "b100adc79e776116a267bc918ded30c4c8d27d83ed21f65f9428ed8831d101b6",
- "dist/2021-10-22/rust-std-beta-mips64el-unknown-linux-muslabi64.tar.xz": "6966af76ccf83f37657efc4aff88887de81642dddc3f2ef59dcaa91219d4f674",
- "dist/2021-10-22/rust-std-beta-mipsel-unknown-linux-gnu.tar.gz": "0b7a859f952741a740458609cd207d5f7291c054fc6d9a0191d3acf0f216bd17",
- "dist/2021-10-22/rust-std-beta-mipsel-unknown-linux-gnu.tar.xz": "2e6e61f68fc3772a6c3b3f0b3be6d99bca1a57b5f568e87397765cf6fe867dd1",
- "dist/2021-10-22/rust-std-beta-mipsel-unknown-linux-musl.tar.gz": "881946b261399e50992beb3cc613ca2141736a7480103fa1fb117c1e7df2b1db",
- "dist/2021-10-22/rust-std-beta-mipsel-unknown-linux-musl.tar.xz": "223a78a4c5055ca00a7d5b40491aef9498a204759cb388e734408e305999713b",
- "dist/2021-10-22/rust-std-beta-nvptx64-nvidia-cuda.tar.gz": "76d81922eb6f61d33c10f2754ccc9b1394ae09feee5818b23b62f768f0e6a370",
- "dist/2021-10-22/rust-std-beta-nvptx64-nvidia-cuda.tar.xz": "be57410669ba5a516dc935fd1eaa73b2d0d3d237a2eb184a8dadce919bf1975f",
- "dist/2021-10-22/rust-std-beta-powerpc-unknown-linux-gnu.tar.gz": "cebf48de57e57285c91092abc01ab1fd9bc7eb660eaad3db2ce71877bd6b9352",
- "dist/2021-10-22/rust-std-beta-powerpc-unknown-linux-gnu.tar.xz": "30a8fc47441c4f7b34f540f5132b3d7ff9756e8906ac6e2b9df5ea8fb622ad65",
- "dist/2021-10-22/rust-std-beta-powerpc64-unknown-linux-gnu.tar.gz": "7deb058683792cd3fcab92b950f653a4ba0d2a2997bef508c6d1d04be319f057",
- "dist/2021-10-22/rust-std-beta-powerpc64-unknown-linux-gnu.tar.xz": "c5d26bbe5b6c64ce9cae78465d22faa98ef956dc4d8bacc91a127a7f439f7b11",
- "dist/2021-10-22/rust-std-beta-powerpc64le-unknown-linux-gnu.tar.gz": "bf06959a991270e9e15d538e70d078a5241b6e87d62a55a655e4c2f9e8ea2964",
- "dist/2021-10-22/rust-std-beta-powerpc64le-unknown-linux-gnu.tar.xz": "d85b330532cb6743071ffa117fbe8bc26b9c6167a0ff76c0ba32fb17c0247c70",
- "dist/2021-10-22/rust-std-beta-riscv32i-unknown-none-elf.tar.gz": "7dda5e010ddb4afd6e6efeb9f43ef17cb30af7ed9f172b59e6c737b2f9d66ef8",
- "dist/2021-10-22/rust-std-beta-riscv32i-unknown-none-elf.tar.xz": "35d8feb28897bead99c17d952b711888f2f6f613fef767f28e3593fb4aa2dc36",
- "dist/2021-10-22/rust-std-beta-riscv32imac-unknown-none-elf.tar.gz": "2e7067692c10447d50df8e9871f95b4ea925a88c5792f973b3c51325afaa8457",
- "dist/2021-10-22/rust-std-beta-riscv32imac-unknown-none-elf.tar.xz": "4b2d3bc61727c87f7c2ba129e9147621c3e3efd542feba3acb6596ea91d10d71",
- "dist/2021-10-22/rust-std-beta-riscv32imc-unknown-none-elf.tar.gz": "093aa10e425beef7d66e9986b045543b3dc04c296fa3b3fdd9071fd6d61b269b",
- "dist/2021-10-22/rust-std-beta-riscv32imc-unknown-none-elf.tar.xz": "8f3512c368b7c44c7d8ec9e1dbdbaed344859ebe2d0dcee22118397d41b841b3",
- "dist/2021-10-22/rust-std-beta-riscv64gc-unknown-linux-gnu.tar.gz": "adab0b58b93d37949eb35d4a6f3ba9e6b43630e4a82f1d9047116f1462cd1809",
- "dist/2021-10-22/rust-std-beta-riscv64gc-unknown-linux-gnu.tar.xz": "6a0410d1194ec0c471e384c5d02aba555efbd47b36a3544c56674fc2080c51e7",
- "dist/2021-10-22/rust-std-beta-riscv64gc-unknown-none-elf.tar.gz": "19c8be8430ab59b92006e0bccf186687569ca172b54f934ff4763da20cebdb58",
- "dist/2021-10-22/rust-std-beta-riscv64gc-unknown-none-elf.tar.xz": "6cb9647a504683fa5c67e5ab2e737bf1d6004dd4a7ffbaf593dea0f9844ced6f",
- "dist/2021-10-22/rust-std-beta-riscv64imac-unknown-none-elf.tar.gz": "cc2d94e753035ff0b49490173b042d21f1ea58711f7c6ce5cfdfd79a76e539b1",
- "dist/2021-10-22/rust-std-beta-riscv64imac-unknown-none-elf.tar.xz": "de398391e577f2fa09f369fbea4114c6cc0f1412884c6f52c97d71c74920462b",
- "dist/2021-10-22/rust-std-beta-s390x-unknown-linux-gnu.tar.gz": "feefd67b9c9dceee7ef7947753ebd990a914d7a54562b718e6704d35a1f5c75f",
- "dist/2021-10-22/rust-std-beta-s390x-unknown-linux-gnu.tar.xz": "1b550a911a51514f8d69b9b763cc3379cd674615090652a253eeb7b585d2d97d",
- "dist/2021-10-22/rust-std-beta-sparc64-unknown-linux-gnu.tar.gz": "4d7d78589d6d72e5ce60d6997394c4d7ff03fd2bae471ef3334f1d5bff9f18d7",
- "dist/2021-10-22/rust-std-beta-sparc64-unknown-linux-gnu.tar.xz": "ec499330b2f63047eb43bf98b1e66d301d7ea7015447c83307ab528421387502",
- "dist/2021-10-22/rust-std-beta-sparcv9-sun-solaris.tar.gz": "7e48f11954d44dade640c86cc87d5841ebd708643cd5220ae7d07127f71ff333",
- "dist/2021-10-22/rust-std-beta-sparcv9-sun-solaris.tar.xz": "5038770dbb2dda71d32c4270653fd3ece96062b24ad55dc8def6475e464210df",
- "dist/2021-10-22/rust-std-beta-thumbv6m-none-eabi.tar.gz": "b8b9a59bf1a9127b26aff54dde3a1da9992a99fd3d601be7cc1daa6ce3c7b6e4",
- "dist/2021-10-22/rust-std-beta-thumbv6m-none-eabi.tar.xz": "e0a96a8b105466a3279da3d9bf589724def7326448bc6f51ae6f8e8aee2ac880",
- "dist/2021-10-22/rust-std-beta-thumbv7em-none-eabi.tar.gz": "cc3a8d935ae2101cff8af86fb066c09672f9fd0297cd9d6b960c9f4877618e98",
- "dist/2021-10-22/rust-std-beta-thumbv7em-none-eabi.tar.xz": "9bafbfbcb01e23f58b1adc7fab26e8ebd135c5c20589887278065f75cb5b5350",
- "dist/2021-10-22/rust-std-beta-thumbv7em-none-eabihf.tar.gz": "8dd7c2cbc2c24e5220ff6a7f5caffcca6605f3d76ff66f766af00ba4bb316067",
- "dist/2021-10-22/rust-std-beta-thumbv7em-none-eabihf.tar.xz": "963a698d49c8742ec5c7520fdefa1668db573eb01bd7774f80133496122b0517",
- "dist/2021-10-22/rust-std-beta-thumbv7m-none-eabi.tar.gz": "3a01a35a10f0efe48cef64d45e80fccab31df8287f500bf280b5d9bd5784ea3a",
- "dist/2021-10-22/rust-std-beta-thumbv7m-none-eabi.tar.xz": "84a5b9d9cc21a13cf1e2e1c29e7af63c75690cbb2293c63fe95e075ebf59815d",
- "dist/2021-10-22/rust-std-beta-thumbv7neon-linux-androideabi.tar.gz": "946e96f404b8a9f4c8139e90172ea26f3a6c509effc6e1ff16a49dc9ff6cc1e4",
- "dist/2021-10-22/rust-std-beta-thumbv7neon-linux-androideabi.tar.xz": "787cd874aeb33e4a4fed2726a571d39f6687da20625aa9a485a95d7167b321b5",
- "dist/2021-10-22/rust-std-beta-thumbv7neon-unknown-linux-gnueabihf.tar.gz": "70fd17c069fe4b6a318d887794c54a142275cc65f088a7bcbda5bbbd7c9d6aa7",
- "dist/2021-10-22/rust-std-beta-thumbv7neon-unknown-linux-gnueabihf.tar.xz": "15ce829bd9ea0a1ee918e7887392ce1e74e00b23509b802f5f45550176d78768",
- "dist/2021-10-22/rust-std-beta-thumbv8m.base-none-eabi.tar.gz": "2edc66ee89c319ef7c9520c5203185a5b5203ca4ea9996e0142075273ccf84b6",
- "dist/2021-10-22/rust-std-beta-thumbv8m.base-none-eabi.tar.xz": "3c129a2557639fad501c7f1474f45535a55c33813a889f08521f4a7d527010ab",
- "dist/2021-10-22/rust-std-beta-thumbv8m.main-none-eabi.tar.gz": "354e644c51ad5863bb0eea09e0c5d1aa32858e7025c039d693e2e433e1c18c04",
- "dist/2021-10-22/rust-std-beta-thumbv8m.main-none-eabi.tar.xz": "6996a329a81624537d45b2401b8dba81911e5c61d2fff6bcd63c5fb15b2fbec3",
- "dist/2021-10-22/rust-std-beta-thumbv8m.main-none-eabihf.tar.gz": "97d6aa47e209650860e97d442f7ec5c5da385399aa5f06bca4c7f9a08767026d",
- "dist/2021-10-22/rust-std-beta-thumbv8m.main-none-eabihf.tar.xz": "dac5cadd67e5d162e00861ec5d2c96166fe1a80954237068aed6072afe0f728e",
- "dist/2021-10-22/rust-std-beta-wasm32-unknown-emscripten.tar.gz": "e0161120cb6cefb23514c839eb2be13a54139d4f408563bd9dc1d6b9d665496a",
- "dist/2021-10-22/rust-std-beta-wasm32-unknown-emscripten.tar.xz": "94bcd63f3712cb3b09948ed62c8db889e2bc78b97d868c89386f912d0daa1b4d",
- "dist/2021-10-22/rust-std-beta-wasm32-unknown-unknown.tar.gz": "00a37ebbf36bd66ab6e0b957e93c7a2e5c2d8567583c65873abc1c79b37bbabf",
- "dist/2021-10-22/rust-std-beta-wasm32-unknown-unknown.tar.xz": "75589caa1835ee12362a2ad581828c9faf0d527f48d5a07c1d7f0b810e035def",
- "dist/2021-10-22/rust-std-beta-wasm32-wasi.tar.gz": "2276b9ef2ff2faa665f15d3572abe0d13a5bb9ec0ad08a6a0c00d9e143464993",
- "dist/2021-10-22/rust-std-beta-wasm32-wasi.tar.xz": "fa132a08849d7c583dbf37db97f3702c263b17de595823d87fa14e56ff21ef3c",
- "dist/2021-10-22/rust-std-beta-x86_64-apple-darwin.tar.gz": "47454a419e6a87b057047c002932cd2f0f52a77ed4c3b4e4d9b65cc4f4ddaaf4",
- "dist/2021-10-22/rust-std-beta-x86_64-apple-darwin.tar.xz": "f9040fa310d122651461d026f43873aa18d5f2c63a9f3bdd47f9a034e4153348",
- "dist/2021-10-22/rust-std-beta-x86_64-apple-ios.tar.gz": "e143c4c8d394810c7734824476dbbfb2a73b3b62cb8a708f796e0c0332deede9",
- "dist/2021-10-22/rust-std-beta-x86_64-apple-ios.tar.xz": "53c660ef68e1898574f62725c2f50fc2f26539143c0be0675327a33511142f8f",
- "dist/2021-10-22/rust-std-beta-x86_64-fortanix-unknown-sgx.tar.gz": "e419db2f8f12467335c8571902f1ed163a5407394914f55416fe948525140ec5",
- "dist/2021-10-22/rust-std-beta-x86_64-fortanix-unknown-sgx.tar.xz": "efd2b6df7dd439b0ae0312831afd4517cf19adf619916eeda1f571daf1dae723",
- "dist/2021-10-22/rust-std-beta-x86_64-fuchsia.tar.gz": "e669378ed5da5948dbe232323ef3926f37ad430feb8c398259229fd18675de20",
- "dist/2021-10-22/rust-std-beta-x86_64-fuchsia.tar.xz": "5a26a35164ae44467d256e6fab0e8f45731e8840204635ac9b1dd1d7d8f96810",
- "dist/2021-10-22/rust-std-beta-x86_64-linux-android.tar.gz": "0d922ff7d7658c296246c22f4440a8975c8036f7159508e2fa964d1f2ad3aebb",
- "dist/2021-10-22/rust-std-beta-x86_64-linux-android.tar.xz": "d775ecb6054216f0f48dbd0acb7710fc097ef6d61df9c1f59139721ada7bef8a",
- "dist/2021-10-22/rust-std-beta-x86_64-pc-solaris.tar.gz": "1e830dc490e9b00b86c9d55c974feefdd87efc06c1bb90088b41737151987dce",
- "dist/2021-10-22/rust-std-beta-x86_64-pc-solaris.tar.xz": "cb37a89a871d61849f9aa262bee7248813a8c7a422872aa3926f20c1adf4ec63",
- "dist/2021-10-22/rust-std-beta-x86_64-pc-windows-gnu.tar.gz": "d83a17c374e937b9a06a364d0be980f4dc953df01efccdb3a0bf853ffd889718",
- "dist/2021-10-22/rust-std-beta-x86_64-pc-windows-gnu.tar.xz": "94fb51d1db6482adf683b9953fcc942923fa5c85cbb63f7b05ad19c24272a21e",
- "dist/2021-10-22/rust-std-beta-x86_64-pc-windows-msvc.tar.gz": "4b7cc0a0a6b07054bb1da0b75d5f687fb38653a7b31f7610f5a90a402839e481",
- "dist/2021-10-22/rust-std-beta-x86_64-pc-windows-msvc.tar.xz": "267f634ec4e08d0a76a75ec0f4ae037aaba44db3ac2969ed3f34d74db43bea1a",
- "dist/2021-10-22/rust-std-beta-x86_64-sun-solaris.tar.gz": "3648f1129895e89467a569219570061a6c50937d87bbb407e6b3b6b1f488bac3",
- "dist/2021-10-22/rust-std-beta-x86_64-sun-solaris.tar.xz": "3a7d686102d9f2469e180a80679db52b6c8dc8ca35adf3e50a25b7bd35f4c6a5",
- "dist/2021-10-22/rust-std-beta-x86_64-unknown-freebsd.tar.gz": "6cb296c0d9e07e00b8561c2f39a7dad9c9d74e224658fa9a7039e34d4b5f3aa7",
- "dist/2021-10-22/rust-std-beta-x86_64-unknown-freebsd.tar.xz": "9e951fec5ee4a4a655693d1c9e205413aeb3120a7b2c0bb6673f4392cdf9fa6d",
- "dist/2021-10-22/rust-std-beta-x86_64-unknown-illumos.tar.gz": "35b6775e13b79b946398a65d6cd4f15d26e160dbf44718cf177679964b2f3cec",
- "dist/2021-10-22/rust-std-beta-x86_64-unknown-illumos.tar.xz": "84d127ce90d62f1698a948ffb247cba400bd162b9864d2ca7c0240a46b23c88b",
- "dist/2021-10-22/rust-std-beta-x86_64-unknown-linux-gnu.tar.gz": "53a627ff89fbfd2abe9b4354e25e02d2ae8d05fcf6f6cefe99b84aec9775acd0",
- "dist/2021-10-22/rust-std-beta-x86_64-unknown-linux-gnu.tar.xz": "7692b0b44eea139874fb8c6cbaca46b8f156ce392454ee4891daad532a5c6baa",
- "dist/2021-10-22/rust-std-beta-x86_64-unknown-linux-gnux32.tar.gz": "853db076a2c469e37003fc8e52af2d0a2e31cd7f74c51147f00b04532df5721e",
- "dist/2021-10-22/rust-std-beta-x86_64-unknown-linux-gnux32.tar.xz": "6925429b5f25d0454abbd68ee333623ccec9d706fe0ec528fb619b2688528770",
- "dist/2021-10-22/rust-std-beta-x86_64-unknown-linux-musl.tar.gz": "13e920a779485d04952e4c402b42fac9b7570098e5e32394996cd985889682fc",
- "dist/2021-10-22/rust-std-beta-x86_64-unknown-linux-musl.tar.xz": "158062a56de043afc4acefc8eafaa536c3018cbdc7696b6d909c757050062b42",
- "dist/2021-10-22/rust-std-beta-x86_64-unknown-netbsd.tar.gz": "1701a13827b3ab22fe78569704d39a2f699f463b2f6f159407a39eaf4c7fd6d8",
- "dist/2021-10-22/rust-std-beta-x86_64-unknown-netbsd.tar.xz": "f10ff1def90cb101179f11b4b07ceeec0ae26ee15c7a85f80e4e31c61baf846c",
- "dist/2021-10-22/rust-std-beta-x86_64-unknown-redox.tar.gz": "20c6c718322cc341f0e1f69a9dc42f3146d10f32075d32376a241a90a2e40f48",
- "dist/2021-10-22/rust-std-beta-x86_64-unknown-redox.tar.xz": "d0429de3b0391f063836c765ad17e2fd1940f737b69961f501eb9d2573cba6e5",
- "dist/2021-10-22/rustc-beta-aarch64-apple-darwin.tar.gz": "31d16857f6fec033e6f79121040eb025c28a1d049014c6047fbf1057450f86d6",
- "dist/2021-10-22/rustc-beta-aarch64-apple-darwin.tar.xz": "997a9aa6db5e23f476aefd3f4799f986a51fda3e31e2b293309fb65fa92b0370",
- "dist/2021-10-22/rustc-beta-aarch64-pc-windows-msvc.tar.gz": "73fb943292d50a372f2df490e47235f395ff7eceac353be74fde3adcf45d363f",
- "dist/2021-10-22/rustc-beta-aarch64-pc-windows-msvc.tar.xz": "30a4a4cbe3fb683b8e846052a83a3185d1b8d714251bd6ad0bfc251b49a72121",
- "dist/2021-10-22/rustc-beta-aarch64-unknown-linux-gnu.tar.gz": "b238cffde0b9ae2305e501970cb9cff1782331f1cccbf8dff84979d1ffdf0625",
- "dist/2021-10-22/rustc-beta-aarch64-unknown-linux-gnu.tar.xz": "5d01b8e471419036703886fc7dcceb89ffc88fa62994727109865339fbe0c92c",
- "dist/2021-10-22/rustc-beta-aarch64-unknown-linux-musl.tar.gz": "8b8b48fc67a2093502baf21c372870bad42840377548e250023c9f83884322b5",
- "dist/2021-10-22/rustc-beta-aarch64-unknown-linux-musl.tar.xz": "a9e73e67a7120968474040dbde7b12668bd6e3a6b4f9d91b8c9a66474f68e40b",
- "dist/2021-10-22/rustc-beta-arm-unknown-linux-gnueabi.tar.gz": "4e83419922b4f02b1c1c62ca14db65863f4226cbaa61674ac792e860c026a948",
- "dist/2021-10-22/rustc-beta-arm-unknown-linux-gnueabi.tar.xz": "20d7369422ebb89f8e1064616a9842cbc98d9056910a2d0ba46f8bcf144cb794",
- "dist/2021-10-22/rustc-beta-arm-unknown-linux-gnueabihf.tar.gz": "05ab3071cdb3ea4e39f53e179c754d2cf64800ca1c38ff887e45f60294d6e222",
- "dist/2021-10-22/rustc-beta-arm-unknown-linux-gnueabihf.tar.xz": "e8509c60955ecf4938575a7a40091ba5d7aff77c9c3e24208623882d1bb45e6f",
- "dist/2021-10-22/rustc-beta-armv7-unknown-linux-gnueabihf.tar.gz": "185a3e399dcc67d8fb43a0174ef8e15c36a068b82aa33db8b42c948c2ee15689",
- "dist/2021-10-22/rustc-beta-armv7-unknown-linux-gnueabihf.tar.xz": "69be7881ba1b2d4348ea06fc2d31a62fe484843e660f399349c49a17852cfaa7",
- "dist/2021-10-22/rustc-beta-i686-pc-windows-gnu.tar.gz": "74c3a25a67b10abbefadf63bc09f6069242267a9ca8a9177e2f46e2b29869b75",
- "dist/2021-10-22/rustc-beta-i686-pc-windows-gnu.tar.xz": "9f0d3ce0a00b33bb591d6b615f9cc80a714f3ea0d787f410da7d643ac5e1144a",
- "dist/2021-10-22/rustc-beta-i686-pc-windows-msvc.tar.gz": "feac518beb813b2d553d6ee1ce03daf890c956918f0de69d5f59d4067f2f60d3",
- "dist/2021-10-22/rustc-beta-i686-pc-windows-msvc.tar.xz": "aad640ae5e48f489148e1edf5e815a78b19288d916615e2af8805f0023e15686",
- "dist/2021-10-22/rustc-beta-i686-unknown-linux-gnu.tar.gz": "c5996c458e6e1a3f3dbcb70debe562bb5d0f4a6eadd97932d8935209fbbe6809",
- "dist/2021-10-22/rustc-beta-i686-unknown-linux-gnu.tar.xz": "d5ed640d08bcf3770b80386282c442d79af38e4c7e73be9617d0ac72d553c507",
- "dist/2021-10-22/rustc-beta-mips-unknown-linux-gnu.tar.gz": "aa0dd3e77f92c1cc21f550c59761a437d3a8ddf31b23040e8849dd116e209835",
- "dist/2021-10-22/rustc-beta-mips-unknown-linux-gnu.tar.xz": "3c7bfcd663507730ad3d07024e1d884dee6adb49343bef0cfb8fd07b8a56c6e4",
- "dist/2021-10-22/rustc-beta-mips64-unknown-linux-gnuabi64.tar.gz": "0370337cce565e6e363e6de59aaa8c2e17db49d79496086c20f00d80198635c8",
- "dist/2021-10-22/rustc-beta-mips64-unknown-linux-gnuabi64.tar.xz": "30413f65a4fcafbbb6a5302cc65bc35edc549cded8ce6a32277ae9a499adfe59",
- "dist/2021-10-22/rustc-beta-mips64el-unknown-linux-gnuabi64.tar.gz": "0e6ee26e237a185a26068c2c69ef095ff37f24af7984bad91196ad253dae196b",
- "dist/2021-10-22/rustc-beta-mips64el-unknown-linux-gnuabi64.tar.xz": "f0185e074bb0c6811d244502ce93384cd7256840fbf64025e074d97e4ccb03a9",
- "dist/2021-10-22/rustc-beta-mipsel-unknown-linux-gnu.tar.gz": "a2c1f733c16d62300adef3ed41f9c5926f704e6b3d47e98cc615665496aa4f17",
- "dist/2021-10-22/rustc-beta-mipsel-unknown-linux-gnu.tar.xz": "3945ad08c0b296a700bfca778994fd93bd3cbe643517ba20a60aa1f9a88eb2cf",
- "dist/2021-10-22/rustc-beta-powerpc-unknown-linux-gnu.tar.gz": "e3871e21ac938b4bf3a1ed44fed2f05fa3a27d3eb000d98876f9f220a5fe9175",
- "dist/2021-10-22/rustc-beta-powerpc-unknown-linux-gnu.tar.xz": "bdc7cddaf0031af1b737fd0c2510ef018d68ebed914200ae8acbfd31ad38ad06",
- "dist/2021-10-22/rustc-beta-powerpc64-unknown-linux-gnu.tar.gz": "9ea42f7e50864bb514293461d3622096fd7a73e8f487578ba1425a3e8d26a970",
- "dist/2021-10-22/rustc-beta-powerpc64-unknown-linux-gnu.tar.xz": "c39cf38c563b16d303bc2cde8c67527e7d2a74e8c5375af73744d9a9e3dc5e1e",
- "dist/2021-10-22/rustc-beta-powerpc64le-unknown-linux-gnu.tar.gz": "dee289bd99b3b573493160446f923fb2f2b66926a5a69c0a7704eb2aaaac3ea8",
- "dist/2021-10-22/rustc-beta-powerpc64le-unknown-linux-gnu.tar.xz": "e3c89f1baa358b6a28ae567981d5efd457d2df61f2eeee19bceeac715793510b",
- "dist/2021-10-22/rustc-beta-riscv64gc-unknown-linux-gnu.tar.gz": "748df03717e997a01a6d222bdb6d6c0b1e206d9be55b74c14c3374a333ad8d55",
- "dist/2021-10-22/rustc-beta-riscv64gc-unknown-linux-gnu.tar.xz": "5cbef13c038d0fe822920eabf91c152a7130e50824fd203e3fffff4a44b10bcc",
- "dist/2021-10-22/rustc-beta-s390x-unknown-linux-gnu.tar.gz": "dd0ec4dba66712a10c3ee5e5ef1835210d8632766c17a4afa1ba0594b6fdd35c",
- "dist/2021-10-22/rustc-beta-s390x-unknown-linux-gnu.tar.xz": "30d736ad6f32019435613fec04b4474795c8915e878a528c46de453a25df1bd9",
- "dist/2021-10-22/rustc-beta-x86_64-apple-darwin.tar.gz": "14c1ba057a56a0c34f129ebae29c6a9453faa03125f1fe88b564355c186d42bb",
- "dist/2021-10-22/rustc-beta-x86_64-apple-darwin.tar.xz": "67d1c23c910e038c6238d286af0141f0a954799dc12a6b935d47239f4d2e8bd9",
- "dist/2021-10-22/rustc-beta-x86_64-pc-windows-gnu.tar.gz": "7685e5b408bf70aa4c8af5ce7b5e5d5a6ac7125c75e7b10a9b3dc0e2dbd4cca1",
- "dist/2021-10-22/rustc-beta-x86_64-pc-windows-gnu.tar.xz": "a52b846d34cfaeddb57d00d0209b1829fb129049ef61212937c0f19fff5efc91",
- "dist/2021-10-22/rustc-beta-x86_64-pc-windows-msvc.tar.gz": "a5c2dce3211ec671959abb8b2f7fc34b572e3bd44362c61b98e0850c0530d1bb",
- "dist/2021-10-22/rustc-beta-x86_64-pc-windows-msvc.tar.xz": "ba948c4a665c349732de9f8faddc2f7e0f7be5995ad88af44f8f4f5ffd4b9387",
- "dist/2021-10-22/rustc-beta-x86_64-unknown-freebsd.tar.gz": "edf7d1c9c9288cca973a0bc3a90bf005d25df324c592b0b8d051f0de98b85f78",
- "dist/2021-10-22/rustc-beta-x86_64-unknown-freebsd.tar.xz": "0c01b34ed39016866e945e0f01de830a68c54f7eef2ac83c3ab85318b01debb0",
- "dist/2021-10-22/rustc-beta-x86_64-unknown-illumos.tar.gz": "6ddf6e92653ab0c00ec524e1274be3e644868cfa867933bc383e8e3e7674945f",
- "dist/2021-10-22/rustc-beta-x86_64-unknown-illumos.tar.xz": "14353a439a306d0803d89a3ce3da5e5c91b9236ed84759fecf8b38ebe1d8a8b1",
- "dist/2021-10-22/rustc-beta-x86_64-unknown-linux-gnu.tar.gz": "4d7feace1b414919ba2e682c748e24b31d811d7b54d710a7cf70e0b3c9c1a591",
- "dist/2021-10-22/rustc-beta-x86_64-unknown-linux-gnu.tar.xz": "35593657a752a66f3052752c67c380e7ebace191a0be78c5def2cc3c1fb3a18a",
- "dist/2021-10-22/rustc-beta-x86_64-unknown-linux-musl.tar.gz": "04e752df5371b5d3879c8514b7dab27bcb35a7b8c7eaec0ec6e3ec5f51ff84a2",
- "dist/2021-10-22/rustc-beta-x86_64-unknown-linux-musl.tar.xz": "b0ef02ff310386b80a9b6113a6e44a437ab78b42480b4d0a86e828d97d92a3dc",
- "dist/2021-10-22/rustc-beta-x86_64-unknown-netbsd.tar.gz": "387040cfbb92e6b2acc52067ab2184313de2588a6af65c0af003432bc9e69c75",
- "dist/2021-10-22/rustc-beta-x86_64-unknown-netbsd.tar.xz": "a617e0ee647908038bd1b3f233b99db1a82b0f32875c9093cb66387f3b2bf430",
- "dist/2021-10-23/rustfmt-nightly-aarch64-apple-darwin.tar.gz": "5ef7d34a33925b7af081f2e135a0fd20ebb18f711372d432a570f8983243c93b",
- "dist/2021-10-23/rustfmt-nightly-aarch64-apple-darwin.tar.xz": "6003e9f8fb4b2a581e359e2e4f1bad83b9055d5a0c60fa0b752ef1aa15957f28",
- "dist/2021-10-23/rustfmt-nightly-aarch64-pc-windows-msvc.tar.gz": "838f7773a9aaec82c4323d8412a441eb3db94da8384bc1a4a50969c5beea9aa8",
- "dist/2021-10-23/rustfmt-nightly-aarch64-pc-windows-msvc.tar.xz": "403a2141367854a281302f9cdcc2d1b37a2415e8aca4cd5e5308af5fa254601d",
- "dist/2021-10-23/rustfmt-nightly-aarch64-unknown-linux-gnu.tar.gz": "6a3b69c8352c8262a37ba0104043a66bc579fb033166434a1b9eeaf115d8d1c2",
- "dist/2021-10-23/rustfmt-nightly-aarch64-unknown-linux-gnu.tar.xz": "f272195798b40df211b1d2e817e91bba68a1083026159cab4414ecc88ddb06f3",
- "dist/2021-10-23/rustfmt-nightly-aarch64-unknown-linux-musl.tar.gz": "5ec04606fc7196f9a5cd130dc4c98e8df58994278ab50f7ea6baf2cdca957b07",
- "dist/2021-10-23/rustfmt-nightly-aarch64-unknown-linux-musl.tar.xz": "a24513ffce8f76fa3334932268aed073958f904b1988d337df7bd4277d3a139b",
- "dist/2021-10-23/rustfmt-nightly-arm-unknown-linux-gnueabi.tar.gz": "8f078b404db9fabd8b0a45deb5110fab32e2ffe5f604f74ef787d9baf3f857ad",
- "dist/2021-10-23/rustfmt-nightly-arm-unknown-linux-gnueabi.tar.xz": "3569e3ed42cd9b4dd6f8b2838329c7864c6d3f7a5242cbdbcd9a756e6f2ca5ea",
- "dist/2021-10-23/rustfmt-nightly-arm-unknown-linux-gnueabihf.tar.gz": "afa42b42631320a68d6a99902fd48b1e72d2daeb07a5be34b833f22ba6dcb67a",
- "dist/2021-10-23/rustfmt-nightly-arm-unknown-linux-gnueabihf.tar.xz": "839a8576012332bb2ad01d5b4ab24d46af8644e38b3019b36c0ba5a9417bfd07",
- "dist/2021-10-23/rustfmt-nightly-armv7-unknown-linux-gnueabihf.tar.gz": "aa59c2ebf3bbff46b6c09aa1e7784ebf83dccd6df60e1295935ff3cc954fa755",
- "dist/2021-10-23/rustfmt-nightly-armv7-unknown-linux-gnueabihf.tar.xz": "e7f479891368cebb99f41b59508a3904321d600e20cc2507954f78386a448601",
- "dist/2021-10-23/rustfmt-nightly-i686-pc-windows-gnu.tar.gz": "a971a861cc76d0a2a4c5fecfc4537c8e1c14f4d43013bceeed395722e8620cbd",
- "dist/2021-10-23/rustfmt-nightly-i686-pc-windows-gnu.tar.xz": "5879a7a9af9c6ef6397f75e4b062527fee5006d655fac5b7538915b176d9faa8",
- "dist/2021-10-23/rustfmt-nightly-i686-pc-windows-msvc.tar.gz": "dc66ac568c709f4b580b46d567bf2d79481566688e0ae55df1edd2a5f07fe0a9",
- "dist/2021-10-23/rustfmt-nightly-i686-pc-windows-msvc.tar.xz": "a2ea4554d52b1181c589eefdf67c60bc0831f2e26430bd6e5e7bb4094db5dfc5",
- "dist/2021-10-23/rustfmt-nightly-i686-unknown-linux-gnu.tar.gz": "8d9ef4755d32e8dc480db1b130943f47b45cc2ba69b1e9fa3dfa128d63780b70",
- "dist/2021-10-23/rustfmt-nightly-i686-unknown-linux-gnu.tar.xz": "3cac0853da192779f4edc5bc3c913e4b93a02ae98b883cfe2717cc58329d7469",
- "dist/2021-10-23/rustfmt-nightly-mips-unknown-linux-gnu.tar.gz": "14c5197f4884f418a392bccce9ac3c9a09dcd0a710a337bba5959f5570c41e98",
- "dist/2021-10-23/rustfmt-nightly-mips-unknown-linux-gnu.tar.xz": "f9b14921e3a6bd006479a01579e6601787082ecc0ec8e631b8cea6a4f1c0b967",
- "dist/2021-10-23/rustfmt-nightly-mips64-unknown-linux-gnuabi64.tar.gz": "9f4efc8229a5a8561bea614a3df0da49349dc4118d72905ecd6feb6b6e1eba9f",
- "dist/2021-10-23/rustfmt-nightly-mips64-unknown-linux-gnuabi64.tar.xz": "02d829ac6d9013f7268e505aa2b0aa99db7e25ddc3d6555ca8f9a4c5ed3f01e7",
- "dist/2021-10-23/rustfmt-nightly-mips64el-unknown-linux-gnuabi64.tar.gz": "8192413e5e376bf957a2caffe8ab15b3c235c714f8214a0f3a46711a79fe33c5",
- "dist/2021-10-23/rustfmt-nightly-mips64el-unknown-linux-gnuabi64.tar.xz": "be155309daae3cb39dbbc874b2ddaebd1ad303b09f40e130ea8429cc7c9c366f",
- "dist/2021-10-23/rustfmt-nightly-mipsel-unknown-linux-gnu.tar.gz": "318c3e8235913f64c9e90b0e7c1fb50229caf59c02f0ddc702cf0728d54dc41c",
- "dist/2021-10-23/rustfmt-nightly-mipsel-unknown-linux-gnu.tar.xz": "50bf71e32ae2228142ad88d67e794ab00b632147fb554ebbfcda7ec79304ae2f",
- "dist/2021-10-23/rustfmt-nightly-powerpc-unknown-linux-gnu.tar.gz": "80f5b76c38d7300c5aa6a71a8b3325b28290b1bb936dd59287fa87d6dee044da",
- "dist/2021-10-23/rustfmt-nightly-powerpc-unknown-linux-gnu.tar.xz": "30a71791c6ed0cf3e0fb955fa697549dcd13d2c0f3e357d9723fa729c3a03698",
- "dist/2021-10-23/rustfmt-nightly-powerpc64-unknown-linux-gnu.tar.gz": "7e5dc3dc89cb21638b452eb9b5c9f008803ee5845c973f2547f59db01b7a0100",
- "dist/2021-10-23/rustfmt-nightly-powerpc64-unknown-linux-gnu.tar.xz": "e1a949b29d249361b306af38bba7118aa1931c14061b6fa7621027e9994b519f",
- "dist/2021-10-23/rustfmt-nightly-powerpc64le-unknown-linux-gnu.tar.gz": "ae4186e4faebc9ad8a13f06a97f96c48cbb35353ad649e25f2e80e519a9d272a",
- "dist/2021-10-23/rustfmt-nightly-powerpc64le-unknown-linux-gnu.tar.xz": "ca4466d872bb050cabce20ae04eb915ac3e39e4788899db7bec5b51ed7d5b579",
- "dist/2021-10-23/rustfmt-nightly-riscv64gc-unknown-linux-gnu.tar.gz": "0f39f27e2ee437df69975578c6e32b6e293bf3129f7e63bde83091330aaa496c",
- "dist/2021-10-23/rustfmt-nightly-riscv64gc-unknown-linux-gnu.tar.xz": "55700dff4b4f3f7d9dfee3317d984afe2b44681deb7b074441b41cfd59e497ed",
- "dist/2021-10-23/rustfmt-nightly-s390x-unknown-linux-gnu.tar.gz": "6273db29aa2715ffe38593802c520adafcbb2300ed2595121bff628686eae675",
- "dist/2021-10-23/rustfmt-nightly-s390x-unknown-linux-gnu.tar.xz": "7a4ce848a1083c16bc17bd22345427ba4c920cb887e90d612a8c3d1ddcf802ed",
- "dist/2021-10-23/rustfmt-nightly-x86_64-apple-darwin.tar.gz": "12a715fca796c192514157b43b0296d688cc46e9d81416a67a0019184c1703d4",
- "dist/2021-10-23/rustfmt-nightly-x86_64-apple-darwin.tar.xz": "9a651e94a0cdddef7c7a56e356e25d0f35d0c592b6a54f2cbeeb3364fc5d457c",
- "dist/2021-10-23/rustfmt-nightly-x86_64-pc-windows-gnu.tar.gz": "2ea52a8413a43a10165322135064692faee0d03a453c4b28ddea480b153de5c8",
- "dist/2021-10-23/rustfmt-nightly-x86_64-pc-windows-gnu.tar.xz": "843b06b9b21c56fe1749e8a5bda908dcc2b6d8206faabd04d050ce83f8c32b73",
- "dist/2021-10-23/rustfmt-nightly-x86_64-pc-windows-msvc.tar.gz": "69210991cca5a07c0421254a2e18a29de28ab5019b490a576f7bb94496ca10b8",
- "dist/2021-10-23/rustfmt-nightly-x86_64-pc-windows-msvc.tar.xz": "3f5a59ba68e004c06cb07ce83d4a567b77179e11071a8b5b8ab6fe3a70bdb872",
- "dist/2021-10-23/rustfmt-nightly-x86_64-unknown-freebsd.tar.gz": "7225fde4655ed5b4479ff9f4e61237a16280541f44aa751c5a06d5916e8fde3f",
- "dist/2021-10-23/rustfmt-nightly-x86_64-unknown-freebsd.tar.xz": "e844e80d99418bea9e7cf96cd389056d17f3be60e9412983d91c64e107a28b92",
- "dist/2021-10-23/rustfmt-nightly-x86_64-unknown-illumos.tar.gz": "6c1b031bc408349c5d15bf494881dd75aa68df8e7417e6c72c061c7d3270cdf8",
- "dist/2021-10-23/rustfmt-nightly-x86_64-unknown-illumos.tar.xz": "d24b970a15dfd41cb1b0027a4a5822e8c2b0217dd1984503d60a85fc6acf7414",
- "dist/2021-10-23/rustfmt-nightly-x86_64-unknown-linux-gnu.tar.gz": "5b5aec4bfde07863d2d5bb71f38d3459db0659df75f53567be6fbaacec33c7b3",
- "dist/2021-10-23/rustfmt-nightly-x86_64-unknown-linux-gnu.tar.xz": "851b9582bd2518a3e050127c46e59f7bb6b24d354c6e89a9b0fe4d3e09cfbbb9",
- "dist/2021-10-23/rustfmt-nightly-x86_64-unknown-linux-musl.tar.gz": "758a05277e99d00e21ff9d8abf96a6da71350664a1eb85adbb1ad4cfa1934255",
- "dist/2021-10-23/rustfmt-nightly-x86_64-unknown-linux-musl.tar.xz": "6431dabc8ef72ca252b257683fd2f5ce3c1347b18ff1d4b7ee7758c6906ba2af",
- "dist/2021-10-23/rustfmt-nightly-x86_64-unknown-netbsd.tar.gz": "51bdea94714c0892ca7020ddcc7c55bb20ac69eaf5152a38f83925d793b90eb1",
- "dist/2021-10-23/rustfmt-nightly-x86_64-unknown-netbsd.tar.xz": "660a23d1430164b01b3e1e8b50233be07fa0988d90e9880bb9044fe661537cde"
+ "dist/2021-11-30/cargo-beta-aarch64-apple-darwin.tar.gz": "f7dadcadc22aab3ed9ddd737a9c2af05f42ffe48b431bbad5d43128130480279",
+ "dist/2021-11-30/cargo-beta-aarch64-apple-darwin.tar.xz": "0ee7c052bb1fd3f3655d9ff74b3f38ebb256d3f523750dbde1be9bceb207cda9",
+ "dist/2021-11-30/cargo-beta-aarch64-pc-windows-msvc.tar.gz": "68d914f773b122bd1ceae13a55d3c8365753d09d4371e3962401b9a48945cf20",
+ "dist/2021-11-30/cargo-beta-aarch64-pc-windows-msvc.tar.xz": "b0204e516f0c22b956f227555be5665df96c4e0f60281592b00678b4ea8ad4e9",
+ "dist/2021-11-30/cargo-beta-aarch64-unknown-linux-gnu.tar.gz": "77b771198aaf78c039df9c08493a9af5d1eb02e6b88bd4fc3b42269cdbf582d0",
+ "dist/2021-11-30/cargo-beta-aarch64-unknown-linux-gnu.tar.xz": "6f6465db2c726cc3d2db73150377ed17cbe164297f8cbffc51c8194494cb0384",
+ "dist/2021-11-30/cargo-beta-aarch64-unknown-linux-musl.tar.gz": "76a8001adffd5d7a607459f1726f3d68c95e6eb4925eac9ccb77b213c37d2385",
+ "dist/2021-11-30/cargo-beta-aarch64-unknown-linux-musl.tar.xz": "07dac7cfe68cb6b0a1872728c1dfb3fde0f9fa27a08933494faaf58a5e35865a",
+ "dist/2021-11-30/cargo-beta-arm-unknown-linux-gnueabi.tar.gz": "d2d6d2b56cbcc8bb5b2139818770fc155146d6b4469678de8a1e8249f15137d7",
+ "dist/2021-11-30/cargo-beta-arm-unknown-linux-gnueabi.tar.xz": "5f97d1449b9c4461be47615ab49ec408d8f1981b7a1bc0d7b7cce606c14cd5ed",
+ "dist/2021-11-30/cargo-beta-arm-unknown-linux-gnueabihf.tar.gz": "097d346e828a37ae5be077f0896796ab6238194846f8ae279cd9e2f510645625",
+ "dist/2021-11-30/cargo-beta-arm-unknown-linux-gnueabihf.tar.xz": "71a7906aea42e1048fc43828ece3da720eea4f9d4ff59e970e273f0fe9191e12",
+ "dist/2021-11-30/cargo-beta-armv7-unknown-linux-gnueabihf.tar.gz": "20e49a6995503dd8215dc9f56ffb87dc9f07fe85a1b0d2f409313836dc0dda3f",
+ "dist/2021-11-30/cargo-beta-armv7-unknown-linux-gnueabihf.tar.xz": "b9388524cec65e789bb5eaf22cfd63ce837b9a98d1b769901597c6f061f1b93d",
+ "dist/2021-11-30/cargo-beta-i686-pc-windows-gnu.tar.gz": "7b0bf29bc67904a64560402891d60506a29b7cd64007d7c1f4e168a574009a9c",
+ "dist/2021-11-30/cargo-beta-i686-pc-windows-gnu.tar.xz": "c580c17566e36cbb91945e0fb9e592ac7578d32da948c70aabb90de80000f5c8",
+ "dist/2021-11-30/cargo-beta-i686-pc-windows-msvc.tar.gz": "e34436449fb69b8ca696b4bcba8e18a612fee189ad8069d765813d39c708ad58",
+ "dist/2021-11-30/cargo-beta-i686-pc-windows-msvc.tar.xz": "322836c74da2b221426782e4b5e174571d1da1935d478b4b8b948608a28a20e8",
+ "dist/2021-11-30/cargo-beta-i686-unknown-linux-gnu.tar.gz": "ab2361cb4cbe44331e34a50728dd56a3db220e08f1b29452f781ee075b236c33",
+ "dist/2021-11-30/cargo-beta-i686-unknown-linux-gnu.tar.xz": "6375ef38e8e6270d6d932d176a7e62014daf153e873667f6d4a5335fa15f8bf3",
+ "dist/2021-11-30/cargo-beta-mips-unknown-linux-gnu.tar.gz": "3e80c94aef4511090e6a83f64b304b835ae2a8e769d3beec96e3f08c0faca01c",
+ "dist/2021-11-30/cargo-beta-mips-unknown-linux-gnu.tar.xz": "af954c96c823d711b372c94a2f2bab32536a4e39bcdd0351674252837096f8b4",
+ "dist/2021-11-30/cargo-beta-mips64-unknown-linux-gnuabi64.tar.gz": "92464fb6d0691a591637cf342842b42b940f8a84525f1e1f51493734f2ad7b1b",
+ "dist/2021-11-30/cargo-beta-mips64-unknown-linux-gnuabi64.tar.xz": "5ddeb87b53749bc532322ee8435fd442adbfaa5e80f3b614b7153c40f46d63d1",
+ "dist/2021-11-30/cargo-beta-mips64el-unknown-linux-gnuabi64.tar.gz": "1c60eccc658664853232131fb48dc5d2c66340bb95d242084c211c59407fa667",
+ "dist/2021-11-30/cargo-beta-mips64el-unknown-linux-gnuabi64.tar.xz": "257aab89cd0d5d9af408fc346aeccb8d51e1eba5dc0db074db1f4b57a8d4aab2",
+ "dist/2021-11-30/cargo-beta-mipsel-unknown-linux-gnu.tar.gz": "20b1fa2138a547f5f6644acfbca9e73f8d228578a600c7710cb2fc34a20eb058",
+ "dist/2021-11-30/cargo-beta-mipsel-unknown-linux-gnu.tar.xz": "134dde13eb7dedb8fc608acae62d715937c168a9fe5a449262e9ac9b3f042396",
+ "dist/2021-11-30/cargo-beta-powerpc-unknown-linux-gnu.tar.gz": "4ffca03462b91b9cbb02a022546aa0e16118eb1950a8f040929e5bfceee2b9f7",
+ "dist/2021-11-30/cargo-beta-powerpc-unknown-linux-gnu.tar.xz": "14bfd567241f969de712240f78d83d21dab0bd11ac42da38a2b02da7a59a9dc9",
+ "dist/2021-11-30/cargo-beta-powerpc64-unknown-linux-gnu.tar.gz": "f44113175429958961148bef66d0ec1b52850c19c035ac83b0d20139e1116d97",
+ "dist/2021-11-30/cargo-beta-powerpc64-unknown-linux-gnu.tar.xz": "3e5f05f0f5aa2fb8b2e63eed7b29ce67831158648f64c2892b477b318a86e300",
+ "dist/2021-11-30/cargo-beta-powerpc64le-unknown-linux-gnu.tar.gz": "76258605464ea434a2c28c2fd05f1947b2165fa10a2810958397d8352e20215d",
+ "dist/2021-11-30/cargo-beta-powerpc64le-unknown-linux-gnu.tar.xz": "c4f2e0756f8571ed7b1bd82702d91b32cc40af58e0697c2f307feeb5755f93ae",
+ "dist/2021-11-30/cargo-beta-riscv64gc-unknown-linux-gnu.tar.gz": "c466a280084c164ca4a120b184eab6403c80db962c0d2d1f2cb5b662746ec4da",
+ "dist/2021-11-30/cargo-beta-riscv64gc-unknown-linux-gnu.tar.xz": "b6f97111eeab0403c67965d57f9bee2ecdf5f39eb44941070d3cd06745f235a3",
+ "dist/2021-11-30/cargo-beta-s390x-unknown-linux-gnu.tar.gz": "2ab5f013205446852a06f27b326f6454a5b3fb958413a7e00e1d8402413155b5",
+ "dist/2021-11-30/cargo-beta-s390x-unknown-linux-gnu.tar.xz": "49dd5e7e3b8091546ef932f359fc4260e3f0b7ec851f43dd10f471c6fe50a5cd",
+ "dist/2021-11-30/cargo-beta-x86_64-apple-darwin.tar.gz": "ac20e50e745914c8431a5c6993b9dbb6bf7b745e4b45283b230207e7be1bb167",
+ "dist/2021-11-30/cargo-beta-x86_64-apple-darwin.tar.xz": "dec91c3f6eda827d3976b96da8def71ad3cc0b71fbe1b4e5387a464a8bbd85c3",
+ "dist/2021-11-30/cargo-beta-x86_64-pc-windows-gnu.tar.gz": "e11e26ad4fde6109808f4cd752c2a810c8ca81b890b0c09902be981a72c43723",
+ "dist/2021-11-30/cargo-beta-x86_64-pc-windows-gnu.tar.xz": "fb49db7bce2376335f4fda11cc454b3d762bd7f95c5dba85596100bd0c1e148a",
+ "dist/2021-11-30/cargo-beta-x86_64-pc-windows-msvc.tar.gz": "7703eb725703aeffb57d6a2c0c95c44b6e4eed09b4a99b37346ea895a1d51088",
+ "dist/2021-11-30/cargo-beta-x86_64-pc-windows-msvc.tar.xz": "65e0f34d9b4af3b270d8d4752c94b58e54895d180fddc3f4b535406e16b8a356",
+ "dist/2021-11-30/cargo-beta-x86_64-unknown-freebsd.tar.gz": "4624bd8e93bc1c36bccd15b44f484059f485df1c0cd1b8bcf21c4855c85b7ea4",
+ "dist/2021-11-30/cargo-beta-x86_64-unknown-freebsd.tar.xz": "a277a3fccfba30db2942c8303db16e5112d72c7721fe7a777cf24a301b68ad2c",
+ "dist/2021-11-30/cargo-beta-x86_64-unknown-illumos.tar.gz": "37e034e5c83bab47ac5cd502d4f6385af270040fb7eb59221bc02cdbcf949d0b",
+ "dist/2021-11-30/cargo-beta-x86_64-unknown-illumos.tar.xz": "d26eda6fd5533defbf3983f2bb9c07c0cba00abf4c346443080059c4810ef1b6",
+ "dist/2021-11-30/cargo-beta-x86_64-unknown-linux-gnu.tar.gz": "909f8bc8dce0276695f1e88994bd21ba2ad4a3ff66b8172e566b7907d9f2531c",
+ "dist/2021-11-30/cargo-beta-x86_64-unknown-linux-gnu.tar.xz": "52807fac650c03c9d398ce6e5987ecfd5e8e30b5c4e94c320ebc2a6fd665740c",
+ "dist/2021-11-30/cargo-beta-x86_64-unknown-linux-musl.tar.gz": "3158dcde7e05e9871572dd7044b3c8466687d8afadbbffa4021a443f4973a4ac",
+ "dist/2021-11-30/cargo-beta-x86_64-unknown-linux-musl.tar.xz": "551ef92e71c001fe48804587e8532b5032d419bd139b2f59cbd8c2e308e3c2ae",
+ "dist/2021-11-30/cargo-beta-x86_64-unknown-netbsd.tar.gz": "9dd630b19f6c9ce26d2ed6a1f46c383d6bc3eecf1efb80f15a651ef4408197c0",
+ "dist/2021-11-30/cargo-beta-x86_64-unknown-netbsd.tar.xz": "1f128e4e8f9e98839caf64e68fbd163de1d5323abf40f718643a815081f898ac",
+ "dist/2021-11-30/rust-std-beta-aarch64-apple-darwin.tar.gz": "3aecc61fe4e056326182db5942cd472039f95788d165940df8b53742f70fb051",
+ "dist/2021-11-30/rust-std-beta-aarch64-apple-darwin.tar.xz": "db3cdaf50925184df6a79914cd1c0df0c9782f96829d23428b1a0ebc814fb468",
+ "dist/2021-11-30/rust-std-beta-aarch64-apple-ios-sim.tar.gz": "61df5ab32d3e11243bc2b8506c65af9d8a84a2bc93fc1315d046e20eb048c62e",
+ "dist/2021-11-30/rust-std-beta-aarch64-apple-ios-sim.tar.xz": "42603c786c02ce754b4c756ac0fe4d88574231f5a8d31b6f9a1192680f8eb180",
+ "dist/2021-11-30/rust-std-beta-aarch64-apple-ios.tar.gz": "49e5d2df9b1019e21c14a1b7f8e69515c16d810dc354ddbe2429857214b3c33e",
+ "dist/2021-11-30/rust-std-beta-aarch64-apple-ios.tar.xz": "5323762166729cc7c3c5045b484ea2f50ec0dbdca15d8c7e82f0c29e1247f8e2",
+ "dist/2021-11-30/rust-std-beta-aarch64-fuchsia.tar.gz": "7510b5b538c735362ec6b12beaa9d3c8720c4ea1f686c643fcc40c5dabca5435",
+ "dist/2021-11-30/rust-std-beta-aarch64-fuchsia.tar.xz": "19b4d188923a820bc8424fed062bab64a56d33f8f00d9ba6792331f06eb0cbc0",
+ "dist/2021-11-30/rust-std-beta-aarch64-linux-android.tar.gz": "77a5e84c97f83ea8263fd147e5f5781a61bb5bdbf1cc40a3a8a72becc8dd486d",
+ "dist/2021-11-30/rust-std-beta-aarch64-linux-android.tar.xz": "c17f843d951d9fa72760e3a071557635da83c0dc279887648979277bcef66aff",
+ "dist/2021-11-30/rust-std-beta-aarch64-pc-windows-msvc.tar.gz": "6e86b78826f5e3d18b2f2aa4f274a5d7bacadbde8d7cfc72cc89dbcb0455fec3",
+ "dist/2021-11-30/rust-std-beta-aarch64-pc-windows-msvc.tar.xz": "e1b1e9eb09e851c8125319432b9fb52a6aa815b7f5bc82efbba7e375aab44764",
+ "dist/2021-11-30/rust-std-beta-aarch64-unknown-linux-gnu.tar.gz": "a6589e628f03fc7c39345cfa23827be6cf26391848bc576a66c7701f18a01669",
+ "dist/2021-11-30/rust-std-beta-aarch64-unknown-linux-gnu.tar.xz": "a0cb9706216575748a953b6e36b59875c6bf9b9410d4a8085974e324c0cbb7e0",
+ "dist/2021-11-30/rust-std-beta-aarch64-unknown-linux-musl.tar.gz": "c803cfd7c803de2b210d5e9800d44f3365a0b4ae581d987b415fdfb990de1a30",
+ "dist/2021-11-30/rust-std-beta-aarch64-unknown-linux-musl.tar.xz": "a93310d2102699602c348901186992c1305a1a20fd0a2e5d8985a4f32e61eb28",
+ "dist/2021-11-30/rust-std-beta-aarch64-unknown-none-softfloat.tar.gz": "2ce3460b436c8c44e074ce1cb8c81bb2cd37ec8ea8fde1b766f113b39412d71c",
+ "dist/2021-11-30/rust-std-beta-aarch64-unknown-none-softfloat.tar.xz": "5e65f8409d2a8eb366f29fe994469f257b18e70ad0707be2ca9c144a0b6f9a78",
+ "dist/2021-11-30/rust-std-beta-aarch64-unknown-none.tar.gz": "a4b73dfbf9df497883b2f5ea3053c256838e1e706f312ee02e1b018b9a7f6099",
+ "dist/2021-11-30/rust-std-beta-aarch64-unknown-none.tar.xz": "a70bd19ae1fa41a3413f0a0b6b2beff569c1b16829cd675967a6d1cd92d8dd54",
+ "dist/2021-11-30/rust-std-beta-arm-linux-androideabi.tar.gz": "46eabf68836f62fe8dfb39c54ee63e9fe211ab84443ff17c46b5240e0d08e723",
+ "dist/2021-11-30/rust-std-beta-arm-linux-androideabi.tar.xz": "9a4e53e3e867e9e18959cba32078c4f7d588247b74e156cc68345808d7b7ecc4",
+ "dist/2021-11-30/rust-std-beta-arm-unknown-linux-gnueabi.tar.gz": "66d9e4de284d7a221f66a2c615d6ec0805dc8f1a91a184cc96701cf98116be60",
+ "dist/2021-11-30/rust-std-beta-arm-unknown-linux-gnueabi.tar.xz": "1af2fd7a16d51e2f4bd6e1840b935e2cdc7a8f3b3b1144d22b42cea52b9bd185",
+ "dist/2021-11-30/rust-std-beta-arm-unknown-linux-gnueabihf.tar.gz": "cb479e676240ef682d3ad27390bc2498f80a421d321e9423cb923b972ea86675",
+ "dist/2021-11-30/rust-std-beta-arm-unknown-linux-gnueabihf.tar.xz": "0011ba4db5a8310199011d37818818867703bf6fbbcd7e1a7bead621eda1e5f2",
+ "dist/2021-11-30/rust-std-beta-arm-unknown-linux-musleabi.tar.gz": "8b192e6f0263d925aac1436887f67b24fa02f31c0fc708c30827f0363f032ceb",
+ "dist/2021-11-30/rust-std-beta-arm-unknown-linux-musleabi.tar.xz": "688755d433c1227db1125ee52e7aa643f27f922b21fbe3a5fcaf70467d159a79",
+ "dist/2021-11-30/rust-std-beta-arm-unknown-linux-musleabihf.tar.gz": "b336cef0e11136ccf5c41669869426a376d570042d3c99eed6c448cfe165818e",
+ "dist/2021-11-30/rust-std-beta-arm-unknown-linux-musleabihf.tar.xz": "1be7d7f0de2ae63b9dd282efc24531f1146fbc7831b84d9c0cd2c8cbdff32fe3",
+ "dist/2021-11-30/rust-std-beta-armebv7r-none-eabi.tar.gz": "33d49bd069b9fdbae8a6868e2cce6fcea26cfd0248372d3d3c977828b3fc51cd",
+ "dist/2021-11-30/rust-std-beta-armebv7r-none-eabi.tar.xz": "e204295b8b17388d8b4cfc04de5690b4b6a377da12df7c24f930c064da787200",
+ "dist/2021-11-30/rust-std-beta-armebv7r-none-eabihf.tar.gz": "07584d1a4f4979ff86aa8b8be820810366c4fdbda4e5dec93c0a5883804a2103",
+ "dist/2021-11-30/rust-std-beta-armebv7r-none-eabihf.tar.xz": "4f73d8af677409960ac480c254f25547752ffe08b80785dceb6b6f1fdc0b6646",
+ "dist/2021-11-30/rust-std-beta-armv5te-unknown-linux-gnueabi.tar.gz": "fb998ae84f383f1ee93fb946f396545a60d4a58f1f0107653f3dcf97e2cfb4f7",
+ "dist/2021-11-30/rust-std-beta-armv5te-unknown-linux-gnueabi.tar.xz": "8d8fdc9404422d0519328d6a622262833c5465b1cba62a59951a05f59d6cb15a",
+ "dist/2021-11-30/rust-std-beta-armv5te-unknown-linux-musleabi.tar.gz": "c8abc1c472326419065caed5567bffc4bcfac2af45fafb7f1327b468f26a0112",
+ "dist/2021-11-30/rust-std-beta-armv5te-unknown-linux-musleabi.tar.xz": "d905b6339363b2538bc39607c0fc58dae2b8023b1c3c1f745654a839ec178988",
+ "dist/2021-11-30/rust-std-beta-armv7-linux-androideabi.tar.gz": "69dbb3e17dcdfa9e6acc465fae4427a2596e8bfc024cc18d30201f41bcdd1be2",
+ "dist/2021-11-30/rust-std-beta-armv7-linux-androideabi.tar.xz": "f012832da820d59a791bf39c25e282c2b92bee75377e4fca7e9520162be62b83",
+ "dist/2021-11-30/rust-std-beta-armv7-unknown-linux-gnueabi.tar.gz": "bb742536d0d7b664ac7277bc5e45f40d64001da0ff1f9e088edc5240e1b35dcf",
+ "dist/2021-11-30/rust-std-beta-armv7-unknown-linux-gnueabi.tar.xz": "6d4c050229400ef1f2e384a4a360569309d1a0828ff07f97c73ca294ef114ca1",
+ "dist/2021-11-30/rust-std-beta-armv7-unknown-linux-gnueabihf.tar.gz": "c7c354d1bd4071ef69e8d91ee5c020c9aac613ddb2565c9a3a01fa41903e3715",
+ "dist/2021-11-30/rust-std-beta-armv7-unknown-linux-gnueabihf.tar.xz": "1bfe9acf4bc7f1e58f1e5a721172df69be65e049894046561bc94ed6ed67c24c",
+ "dist/2021-11-30/rust-std-beta-armv7-unknown-linux-musleabi.tar.gz": "96fe9952332d7aee42e61445226793af32995d0f21fde7ebfe751ef2f9acfd90",
+ "dist/2021-11-30/rust-std-beta-armv7-unknown-linux-musleabi.tar.xz": "2f85ea745f03f779306f78ddff9389f4417d826258a90740a76b37bd14b8fca6",
+ "dist/2021-11-30/rust-std-beta-armv7-unknown-linux-musleabihf.tar.gz": "434b6eaffa2a4c798b4a6f00997d65c55d9fad24d176bbc54dc045339e654432",
+ "dist/2021-11-30/rust-std-beta-armv7-unknown-linux-musleabihf.tar.xz": "955fd83cc57de91fea9aea3f563c4cb5a2611e6dd24406845f7e8be5b7f25f3c",
+ "dist/2021-11-30/rust-std-beta-armv7a-none-eabi.tar.gz": "45a4818cc22f80252264309263994270b2e15ec8db7ced500cef838f09260fa5",
+ "dist/2021-11-30/rust-std-beta-armv7a-none-eabi.tar.xz": "8748379556a312b31788b5458b74d5d7fb2fa61f29e5528e449d216c21f4e9ed",
+ "dist/2021-11-30/rust-std-beta-armv7r-none-eabi.tar.gz": "928a6b77d3e6e8030c6ee454d648c5f6eb0b79a8beda3d11fc3578cc4556ac45",
+ "dist/2021-11-30/rust-std-beta-armv7r-none-eabi.tar.xz": "428526e30a28a9dba01943800a179b7ba144866f36dd69171a4fd1804345b75f",
+ "dist/2021-11-30/rust-std-beta-armv7r-none-eabihf.tar.gz": "e1e43b61b7826fe4f8063d89896e7b86a13e41ed3a17ef2684d1bded5252b7b6",
+ "dist/2021-11-30/rust-std-beta-armv7r-none-eabihf.tar.xz": "5f6478a196f1eabd6d4b58ebacf89c3635a9488f4b2f145283e9352cff5da7b8",
+ "dist/2021-11-30/rust-std-beta-asmjs-unknown-emscripten.tar.gz": "65b23ab952ed313cc9de94eae473a28eb9b7d9ca8aa432f4d3a08c30484e30c7",
+ "dist/2021-11-30/rust-std-beta-asmjs-unknown-emscripten.tar.xz": "949e3b832f70c3effa2b78363b42caf0720ede57722c360b710773bd7f3e1502",
+ "dist/2021-11-30/rust-std-beta-i586-pc-windows-msvc.tar.gz": "06667714b168e2e0d6e0f3e81cc3fb68940f77aa3cd3495d91ce9ff15502ab9f",
+ "dist/2021-11-30/rust-std-beta-i586-pc-windows-msvc.tar.xz": "9794592856633299de53e697579c75bcf6009c6f05c7bfcadf8c63dfa383b3f9",
+ "dist/2021-11-30/rust-std-beta-i586-unknown-linux-gnu.tar.gz": "ffb8b8ec98f9732602edcf3e4e628327f8ef80712c59ebaab5392503ed04460c",
+ "dist/2021-11-30/rust-std-beta-i586-unknown-linux-gnu.tar.xz": "7f60c2798023bdf3993b443783d3d6dd350abfa3bbdce58ada3e9b3d3c4391f0",
+ "dist/2021-11-30/rust-std-beta-i586-unknown-linux-musl.tar.gz": "f086f349faf5f44b0fbd060f3c40b553aa5a6309a02c08e8a45d27cb3a820926",
+ "dist/2021-11-30/rust-std-beta-i586-unknown-linux-musl.tar.xz": "05ebd51df4b17c22569d69a65d9542b5010beea023e545859a23bb244162b537",
+ "dist/2021-11-30/rust-std-beta-i686-linux-android.tar.gz": "0f2a192b970209d10f2ffb4f88dcb6637e1ed822e47fef8e0d3daf4ca8b250d9",
+ "dist/2021-11-30/rust-std-beta-i686-linux-android.tar.xz": "3aee7e88fbcc0290219a8d980efb1c6d8a1642a1576393fe3b5d400a68b17f8b",
+ "dist/2021-11-30/rust-std-beta-i686-pc-windows-gnu.tar.gz": "251780731ee8c996dc1adb59148d7a0307642e11f3bf767c0caaf5f37b70b395",
+ "dist/2021-11-30/rust-std-beta-i686-pc-windows-gnu.tar.xz": "76c8cd535a4ab4f9c0ccca19986f483de63e7c6c0708e37de653acb80621bce0",
+ "dist/2021-11-30/rust-std-beta-i686-pc-windows-msvc.tar.gz": "ce1b7c98f381f207a26ca3fa5937f5e276eb8f91ef6ae2e0e082370e9ca1c21e",
+ "dist/2021-11-30/rust-std-beta-i686-pc-windows-msvc.tar.xz": "106f655c10d182b6581e87cff881bf081efe9404b52885b6efed4eb0f09a3a04",
+ "dist/2021-11-30/rust-std-beta-i686-unknown-freebsd.tar.gz": "2cac777f7178954e5c19e266d57927ddf68b74aa5a0161e35e096569d0a6946c",
+ "dist/2021-11-30/rust-std-beta-i686-unknown-freebsd.tar.xz": "abd915c242fdd2e8f7d53291b2d84d269f9c6f4c4059c725770c3e47e50c4758",
+ "dist/2021-11-30/rust-std-beta-i686-unknown-linux-gnu.tar.gz": "f680956e937e421c7868a22ec3ac2a6de7bc8203fae17937793914f4a9fd1657",
+ "dist/2021-11-30/rust-std-beta-i686-unknown-linux-gnu.tar.xz": "15c71b8a2e8604a49240f5d6d0da65c40c8c207f1ebec943cb8c50cd7a51d879",
+ "dist/2021-11-30/rust-std-beta-i686-unknown-linux-musl.tar.gz": "71c15bbabb5bcadb603513c73e40a96026fc8f6d5c82e9ea9b6569fcc22d5af2",
+ "dist/2021-11-30/rust-std-beta-i686-unknown-linux-musl.tar.xz": "4a9af011d4a2b63a0357c6367210fbf4b6e116b5388ed3a62b758a4bad1fa77f",
+ "dist/2021-11-30/rust-std-beta-mips-unknown-linux-gnu.tar.gz": "c44531c5467c1e01739f3796db1f59c4b6d6483f4bb8c398c751dbc30ed550ed",
+ "dist/2021-11-30/rust-std-beta-mips-unknown-linux-gnu.tar.xz": "0ec54d445e3c24bf7aa8ecdca45f49abfc2e4013c7af682d7134a5e52e752d23",
+ "dist/2021-11-30/rust-std-beta-mips-unknown-linux-musl.tar.gz": "3ea1a25b04112d83771e7b713ff8d33418bd18a7adcaaf6cce68f537cb27fefb",
+ "dist/2021-11-30/rust-std-beta-mips-unknown-linux-musl.tar.xz": "c904834d0fa015d24ba0e929e900ad06bfe773bc4a439f9bbcd8862a5065171c",
+ "dist/2021-11-30/rust-std-beta-mips64-unknown-linux-gnuabi64.tar.gz": "498cda7a23e81ed7563650deb320361c8cffdc10de13ce143175e77f720600ed",
+ "dist/2021-11-30/rust-std-beta-mips64-unknown-linux-gnuabi64.tar.xz": "bb0e95d7fad089cc84e826adffc416757df4480ffdfd09547625950b13b9e934",
+ "dist/2021-11-30/rust-std-beta-mips64-unknown-linux-muslabi64.tar.gz": "87ae1f563963370eeaa3f46d568339d5589e4fd509d21087db43ca2f1d6a1daf",
+ "dist/2021-11-30/rust-std-beta-mips64-unknown-linux-muslabi64.tar.xz": "da6268585d69c9c71c92dadb658bc7c055b5ce4c87abc52b5451d1111c1675dd",
+ "dist/2021-11-30/rust-std-beta-mips64el-unknown-linux-gnuabi64.tar.gz": "93c67427050266f49dc367a1f8e694989424664f740ae3911f78f1cc53faf35c",
+ "dist/2021-11-30/rust-std-beta-mips64el-unknown-linux-gnuabi64.tar.xz": "03f9a6e921555954b33fd7f446e9093ad4b631c86d001303e4c47078d0e1d385",
+ "dist/2021-11-30/rust-std-beta-mips64el-unknown-linux-muslabi64.tar.gz": "6c96a53e86f71965f1922585469501504b79c3347d09409033f871b1c9cdc856",
+ "dist/2021-11-30/rust-std-beta-mips64el-unknown-linux-muslabi64.tar.xz": "000e43f7e40abecd402242455f8a3d60692043ddb80bd15dd6f52acd1c5af096",
+ "dist/2021-11-30/rust-std-beta-mipsel-unknown-linux-gnu.tar.gz": "7ee55e1f5a63b52d7b87882fa4131fe848d18dba819d46e16ea2435889d84722",
+ "dist/2021-11-30/rust-std-beta-mipsel-unknown-linux-gnu.tar.xz": "b8fc28ffd7d97e76913755bedc2f9e7cec7150e036d13fcf7e50dc5a2422d1dd",
+ "dist/2021-11-30/rust-std-beta-mipsel-unknown-linux-musl.tar.gz": "af81aaa9bd624f57168762dfbae39853ada92043809bff953e108e97169e5732",
+ "dist/2021-11-30/rust-std-beta-mipsel-unknown-linux-musl.tar.xz": "37357e40af421ca5b4d2b95f19eca41ce016404ffcce8abea45e08721664f0e3",
+ "dist/2021-11-30/rust-std-beta-nvptx64-nvidia-cuda.tar.gz": "cbbd98fd3ee6bdd3c01e590c2f10367ec38d799e02ddbc1b0e31027684a356f6",
+ "dist/2021-11-30/rust-std-beta-nvptx64-nvidia-cuda.tar.xz": "defda4e2ef2f3baf8c7d2a9159d17ca439004687f0b6714826408b94d4f0aed0",
+ "dist/2021-11-30/rust-std-beta-powerpc-unknown-linux-gnu.tar.gz": "201c5bdc1dba11e039bea9257e17ddd2f50b29448b070fc0edb4a7a9f4e45f45",
+ "dist/2021-11-30/rust-std-beta-powerpc-unknown-linux-gnu.tar.xz": "0319b07244f443e254e10a04e75633b293faffc5896ade44c05dde0739356f38",
+ "dist/2021-11-30/rust-std-beta-powerpc64-unknown-linux-gnu.tar.gz": "54e7cb5a1534ecdbd484ef304f608eb48464ae2c2330958b65b8101f81291319",
+ "dist/2021-11-30/rust-std-beta-powerpc64-unknown-linux-gnu.tar.xz": "aecedf5ca4d91e98ba3c4faba64699d79b3fd4877f880840d492b4872ccb924a",
+ "dist/2021-11-30/rust-std-beta-powerpc64le-unknown-linux-gnu.tar.gz": "a4cf3bde61d46484e36fd41386840250e0c031414ee422bbb3d37f7ac7489ca3",
+ "dist/2021-11-30/rust-std-beta-powerpc64le-unknown-linux-gnu.tar.xz": "d93e2a290aea3075cd61b950ded4c3756611acc6a59ba7efb9ce2e4dbac76c59",
+ "dist/2021-11-30/rust-std-beta-riscv32i-unknown-none-elf.tar.gz": "69c9f09416b788d93f54734a953ed8dead2a31e1dacd6e67a6550529385b338f",
+ "dist/2021-11-30/rust-std-beta-riscv32i-unknown-none-elf.tar.xz": "808a02952a31ae3a171849dc217763f5cd142622e92ae2b383014bbe37e9b551",
+ "dist/2021-11-30/rust-std-beta-riscv32imac-unknown-none-elf.tar.gz": "67e6b61d822cfc9f95a2808917601cf3d2560d636b12a19ee29a790cc06e8235",
+ "dist/2021-11-30/rust-std-beta-riscv32imac-unknown-none-elf.tar.xz": "7310493bc6f184b401650fb399015be29a8df009e55fa1cbfbcf9d9608fe61e2",
+ "dist/2021-11-30/rust-std-beta-riscv32imc-unknown-none-elf.tar.gz": "fd4db925d7eb598f210ab2d96f692cbdb627acbd6a8976259411a4d2356b8728",
+ "dist/2021-11-30/rust-std-beta-riscv32imc-unknown-none-elf.tar.xz": "b5b0394ef612188fd094e355892aafe4530758fe38dc8859ba917cb2febe028e",
+ "dist/2021-11-30/rust-std-beta-riscv64gc-unknown-linux-gnu.tar.gz": "3b7c3ad97393bc702dbd71bc819c0e5f6164cf471171c7c48cfffdf5477b35b6",
+ "dist/2021-11-30/rust-std-beta-riscv64gc-unknown-linux-gnu.tar.xz": "21e6f247a6663918c6e38782e43211224d50d4de22a9162be0c5f6d6d0a9afea",
+ "dist/2021-11-30/rust-std-beta-riscv64gc-unknown-none-elf.tar.gz": "d0c9bd56dcac12d7174e11f2acdb16fba41ffb3aba71b6b1b4b49ce7fa115f6e",
+ "dist/2021-11-30/rust-std-beta-riscv64gc-unknown-none-elf.tar.xz": "c89adc1cbdb7bfa27f5bfdac38b5ff084eafe081b27548dc243bbff378ec7118",
+ "dist/2021-11-30/rust-std-beta-riscv64imac-unknown-none-elf.tar.gz": "3e6f8a86901c1350c54bd89e156af029978f4a25f578ea26f49a1f3332da2187",
+ "dist/2021-11-30/rust-std-beta-riscv64imac-unknown-none-elf.tar.xz": "43e74dbeb89547be1b3ad1b532bef97b577530a8b19b825342efb72d91d4b0bd",
+ "dist/2021-11-30/rust-std-beta-s390x-unknown-linux-gnu.tar.gz": "c8c7a22e63353e7c7766e254c3fc0b0277bc8265f1123a38705bf319a7d99a19",
+ "dist/2021-11-30/rust-std-beta-s390x-unknown-linux-gnu.tar.xz": "1759ca2de0ff890918a0f634782557ae2b3181e543790878093f303ede45e215",
+ "dist/2021-11-30/rust-std-beta-sparc64-unknown-linux-gnu.tar.gz": "a9ac36f2b4e88ce2f2789e9df46ae679879c111594cfe82b538e4067adad2b5e",
+ "dist/2021-11-30/rust-std-beta-sparc64-unknown-linux-gnu.tar.xz": "6260f0616828d79898165bf42875881dc5253143d940ac951b7f295553afb8c9",
+ "dist/2021-11-30/rust-std-beta-sparcv9-sun-solaris.tar.gz": "42d3e5acf2475d732ce5afe3c2ebea6d332c137d061aa256df75b7ce54c16b16",
+ "dist/2021-11-30/rust-std-beta-sparcv9-sun-solaris.tar.xz": "7f84ff29dc36a224961e87d40cd6e531c9309bdafaec5de2b043aa89af511552",
+ "dist/2021-11-30/rust-std-beta-thumbv6m-none-eabi.tar.gz": "6bfdf4e59ac3f9dbde2fa46797bd9bb9cbda232c0d507f04bafd937e88945cb7",
+ "dist/2021-11-30/rust-std-beta-thumbv6m-none-eabi.tar.xz": "d12901a4efc8395df3c1ac137f86c3da07477277fad138edb49d5c4382a3a114",
+ "dist/2021-11-30/rust-std-beta-thumbv7em-none-eabi.tar.gz": "38718b50fa2acacc0fac98931a5714df38feb8370fccf8d7a955de3b2c117dd0",
+ "dist/2021-11-30/rust-std-beta-thumbv7em-none-eabi.tar.xz": "9753c00de1117a5fb9bff4ce2a4434ac6d3d06a1b4b3d0cc44ddb590739b9a0b",
+ "dist/2021-11-30/rust-std-beta-thumbv7em-none-eabihf.tar.gz": "c1eb35c914ad1a762cf550d54b7ec80cb3a8ab6ab39f5c89709f88e04eeba46f",
+ "dist/2021-11-30/rust-std-beta-thumbv7em-none-eabihf.tar.xz": "3c092ac130633f327a0afc8bdf8ba252f05d9b0050383122d7ba31cc3f5ddfc5",
+ "dist/2021-11-30/rust-std-beta-thumbv7m-none-eabi.tar.gz": "fb391d1199eab0854228323d08dd8b27709175697532e4b47e9dab6f26f24a8f",
+ "dist/2021-11-30/rust-std-beta-thumbv7m-none-eabi.tar.xz": "82347d3a0a123c430a526486dbd8c424732181eede038e2f91f1504d510a755b",
+ "dist/2021-11-30/rust-std-beta-thumbv7neon-linux-androideabi.tar.gz": "0cb559fff7f8dc35e5279217ef6fe7c2b5fa3d68f5ca82f258b6885f42e8d144",
+ "dist/2021-11-30/rust-std-beta-thumbv7neon-linux-androideabi.tar.xz": "ee1fe1dc9fe620743022939cdeac3ab34135e61897f0707c3b1a0a1b7d730360",
+ "dist/2021-11-30/rust-std-beta-thumbv7neon-unknown-linux-gnueabihf.tar.gz": "bb8de6fe10aa624fdd63484403e228a5c592b94d4aac95e2b2401cd8b9472f0a",
+ "dist/2021-11-30/rust-std-beta-thumbv7neon-unknown-linux-gnueabihf.tar.xz": "1bb7f7ac88e250534d89f0b0dc74f13ca563bad53956be74418d2aef28d250a5",
+ "dist/2021-11-30/rust-std-beta-thumbv8m.base-none-eabi.tar.gz": "0aea9f5cddb136591d105ebd3607a2e1f402f1c707cf33f21fb5cf1d30101ee0",
+ "dist/2021-11-30/rust-std-beta-thumbv8m.base-none-eabi.tar.xz": "f547622b8f052c6290c530d506d8ee314f90c81ace562a0a533b6ad2ba00b987",
+ "dist/2021-11-30/rust-std-beta-thumbv8m.main-none-eabi.tar.gz": "80f8f7c613c7ff2097f5c346b3ac4a5cf750167277f28655e0263b05a231668d",
+ "dist/2021-11-30/rust-std-beta-thumbv8m.main-none-eabi.tar.xz": "a57b4489a1d46ad3fc303a3b2dd478df66407a3e2dfeb9c12860a543ae5210eb",
+ "dist/2021-11-30/rust-std-beta-thumbv8m.main-none-eabihf.tar.gz": "6c4264b2bcecc951c39626fc1cf8de36f1eadbda31a552e14274f728978e16a5",
+ "dist/2021-11-30/rust-std-beta-thumbv8m.main-none-eabihf.tar.xz": "ec72f8e861eed6b5e2518b46cd8008d3bd2b6f2a7a42784a2dc8a6184d3ecc62",
+ "dist/2021-11-30/rust-std-beta-wasm32-unknown-emscripten.tar.gz": "0fc209babd43546d04b3fdd27ce77c96d75aa5eb6595f00586a19a17e4530b59",
+ "dist/2021-11-30/rust-std-beta-wasm32-unknown-emscripten.tar.xz": "ecdb8152992b4a9779aeda2b4cc638163ac24faf45c484f27316a6b3ff0eb297",
+ "dist/2021-11-30/rust-std-beta-wasm32-unknown-unknown.tar.gz": "52bbea99f2405f35f58d5448c353c605c2a87e7546e95b86d8baa39b4fc7a9a2",
+ "dist/2021-11-30/rust-std-beta-wasm32-unknown-unknown.tar.xz": "47ea301d79eada8898907af226b39b4c73ac1fe974963139aee78c3567ee53e4",
+ "dist/2021-11-30/rust-std-beta-wasm32-wasi.tar.gz": "dc9ccfa3e46e4f3b0e11de8a83885695ab154a2211fa89a20670db116d63a4c2",
+ "dist/2021-11-30/rust-std-beta-wasm32-wasi.tar.xz": "52d890b402c7e7bb7c0f9b34f2e216f0937453ab42e7c4ce205739bd64ba7dc7",
+ "dist/2021-11-30/rust-std-beta-x86_64-apple-darwin.tar.gz": "0ccbff8a582047cd6d2a6b30387ea73cfce7e0c61eddf516126836b9f9ca86ff",
+ "dist/2021-11-30/rust-std-beta-x86_64-apple-darwin.tar.xz": "cab55f71575d58aa7213a7dc4cfb0704ca7faec7203c545aeaff178eebe40436",
+ "dist/2021-11-30/rust-std-beta-x86_64-apple-ios.tar.gz": "6863523669b65464bd52e1a47f6decf868cc93d2111ffc222bb4a032a0095e3f",
+ "dist/2021-11-30/rust-std-beta-x86_64-apple-ios.tar.xz": "d5c6e65a656621891f387861c8259116dd9a8ab14e13ea10e93b78834e1d334a",
+ "dist/2021-11-30/rust-std-beta-x86_64-fortanix-unknown-sgx.tar.gz": "ec7130bfff74b7226fb5d0f311dd399f7628cb59ce06b4bc9a9f394067855eda",
+ "dist/2021-11-30/rust-std-beta-x86_64-fortanix-unknown-sgx.tar.xz": "0f52f00f03126aed0260cbfdd9790a62f9f4ceb24e2a3a6d80e8a15a1b4a09c2",
+ "dist/2021-11-30/rust-std-beta-x86_64-fuchsia.tar.gz": "1a3f4c6c1528050820b85e07aa96af6588c7d61935108cb5110d1e0c964142e8",
+ "dist/2021-11-30/rust-std-beta-x86_64-fuchsia.tar.xz": "fe9488c3476e931440ad487a4cf265fdd3c01e18c9e43b33f51b9eb078821282",
+ "dist/2021-11-30/rust-std-beta-x86_64-linux-android.tar.gz": "c7205b1cdcdff00d91a3991b1f40674b075c34dc0877de4786da5ab85e3b6cfa",
+ "dist/2021-11-30/rust-std-beta-x86_64-linux-android.tar.xz": "87a3cfe8992ad615d5522d97ace91dcc86057d060d82b581df206f2802225a0e",
+ "dist/2021-11-30/rust-std-beta-x86_64-pc-solaris.tar.gz": "cd9eeb26fe909e38d8d8129829d19b4d04d96014496cc7f2f4ae077b94f2aae3",
+ "dist/2021-11-30/rust-std-beta-x86_64-pc-solaris.tar.xz": "b6e59180ff89f7e460fcbc246802e6441c71600774ae5cb2d9af464365a642cb",
+ "dist/2021-11-30/rust-std-beta-x86_64-pc-windows-gnu.tar.gz": "45e07be14211ec7c9f3c1ad0eb9f7a9b422b10c842d5d0e8b0b498751ab7ae0f",
+ "dist/2021-11-30/rust-std-beta-x86_64-pc-windows-gnu.tar.xz": "593f70209f3b5b4e126d57ece0b1adefb4bc1055cfd168779d854369985b2b2e",
+ "dist/2021-11-30/rust-std-beta-x86_64-pc-windows-msvc.tar.gz": "6e14f3431da08f63d82e5b1e2c56fdf13f93ea7b6660dc64b1c855d00c008257",
+ "dist/2021-11-30/rust-std-beta-x86_64-pc-windows-msvc.tar.xz": "6e6355686d22213d27f5dbec0b7ded38532e79ac904bae978a8eb5fc880916cf",
+ "dist/2021-11-30/rust-std-beta-x86_64-sun-solaris.tar.gz": "39bdaa250d8f17914602a2185c51014f7fbfb1e30991816a432c3897338b52a1",
+ "dist/2021-11-30/rust-std-beta-x86_64-sun-solaris.tar.xz": "ebab0e4b13e0b3bdbe0ac858d5a4ca28bb813854aea1d8ec86d8e220c68b3442",
+ "dist/2021-11-30/rust-std-beta-x86_64-unknown-freebsd.tar.gz": "a700f1736b96c4e7237305dc98a79163b07127f0aac1f436415c233b8495a5af",
+ "dist/2021-11-30/rust-std-beta-x86_64-unknown-freebsd.tar.xz": "e94ecf7d1c9a5144577fdb14b7232b11dff0ebbfa8aae8cb4884d4ed9c5bae77",
+ "dist/2021-11-30/rust-std-beta-x86_64-unknown-illumos.tar.gz": "209dc9917790c2be8777c597e19a9f43301aaaaac3c9731e9d0512e6918334b9",
+ "dist/2021-11-30/rust-std-beta-x86_64-unknown-illumos.tar.xz": "6e4810c7484c231f0edb15ae5acea822ed5d868eaf041438afea4b6ba38be35e",
+ "dist/2021-11-30/rust-std-beta-x86_64-unknown-linux-gnu.tar.gz": "df952ee1385da9457c4e95dc08ab59ca915f5f211738982f8db3684cf80967fc",
+ "dist/2021-11-30/rust-std-beta-x86_64-unknown-linux-gnu.tar.xz": "62d7383ee21b0a7d072b15a9877a922f8dbcea42d910c2cb3c4129152b26ea9a",
+ "dist/2021-11-30/rust-std-beta-x86_64-unknown-linux-gnux32.tar.gz": "be28225516fa38edd34e1af5f051d7c8ab5f433cc5814df199bc451285d95e0c",
+ "dist/2021-11-30/rust-std-beta-x86_64-unknown-linux-gnux32.tar.xz": "1a6fdfac24feb34744daced6c6545c844ff13d5e5f14620520d5ed4b85be8742",
+ "dist/2021-11-30/rust-std-beta-x86_64-unknown-linux-musl.tar.gz": "c0f098faa0c9de6a8e82b80dfe44bfa9d4482e118259c33452ef025885ceab6e",
+ "dist/2021-11-30/rust-std-beta-x86_64-unknown-linux-musl.tar.xz": "1d1ed7cf8fc16efab3faab9ef5abadac9ab98d3b60522fde0612ac0b256de528",
+ "dist/2021-11-30/rust-std-beta-x86_64-unknown-netbsd.tar.gz": "1ed41e8019480cd151a9ddd0f080afc56ed0afe47cfb7c6b5a6a2473ff6e7e81",
+ "dist/2021-11-30/rust-std-beta-x86_64-unknown-netbsd.tar.xz": "849c04115660abdf1d4460aef2d87021c6ad52423c83dfed3c2cec8e380ae6fe",
+ "dist/2021-11-30/rust-std-beta-x86_64-unknown-redox.tar.gz": "e3a35d33b3282fd156482c85e19817f78dcd964de8b712a6e46b965dc60d5204",
+ "dist/2021-11-30/rust-std-beta-x86_64-unknown-redox.tar.xz": "d5bfbb1415a62547b9e2a24b770a3c6e4d531101cfb2360b7a7de34d0bf18974",
+ "dist/2021-11-30/rustc-beta-aarch64-apple-darwin.tar.gz": "28beba0ff958b93f85618e49f13f4062cefacc82f6b5911d42f00515f99c5abe",
+ "dist/2021-11-30/rustc-beta-aarch64-apple-darwin.tar.xz": "07c6a43130112c93745e729c91669243cd28b73fafc7d9b32b4f22650db7bcad",
+ "dist/2021-11-30/rustc-beta-aarch64-pc-windows-msvc.tar.gz": "9e70dc74c4428438716d14861797380ce7f6617bc93b83c74fc1a6f8aca99392",
+ "dist/2021-11-30/rustc-beta-aarch64-pc-windows-msvc.tar.xz": "8f61ec8129b7b0bcc6b329337e5e0323054a438e999615687a18fdc42a8d0692",
+ "dist/2021-11-30/rustc-beta-aarch64-unknown-linux-gnu.tar.gz": "bba3cbfdd2842cdf8f2698b709401db6a641227d1742595e3959f1f0ace37c5f",
+ "dist/2021-11-30/rustc-beta-aarch64-unknown-linux-gnu.tar.xz": "fe74ad76a2cffdff0a2fb953f31b73d80a0bce75402bf65f01d250fcae6ff779",
+ "dist/2021-11-30/rustc-beta-aarch64-unknown-linux-musl.tar.gz": "cde952fb3c38a969c0743d2f9d90e256db8613c463a4b23d6119656570978eb5",
+ "dist/2021-11-30/rustc-beta-aarch64-unknown-linux-musl.tar.xz": "f2dd88f1b4ec97aaaebb601d20751d50536e85b2cac36740abbc03fa8a4d0d06",
+ "dist/2021-11-30/rustc-beta-arm-unknown-linux-gnueabi.tar.gz": "1a4414987e4da2c8086590fe4ad531f78862443eede3bc9069efb424900746d2",
+ "dist/2021-11-30/rustc-beta-arm-unknown-linux-gnueabi.tar.xz": "1682f8bde2562d4b9183fa512bc1e54d2a821fd9f63208a51489f21deeb7fcfd",
+ "dist/2021-11-30/rustc-beta-arm-unknown-linux-gnueabihf.tar.gz": "ca40f3c5e8fd8bd6d89d3c0a3ad4d767353c1b4138e2720371a275c9c52c9117",
+ "dist/2021-11-30/rustc-beta-arm-unknown-linux-gnueabihf.tar.xz": "c7afe4eba5cdb02a2e8ae224a0970c8aa36ef429ac298b0f98ff41a0d911aad1",
+ "dist/2021-11-30/rustc-beta-armv7-unknown-linux-gnueabihf.tar.gz": "6acd677fda38aea2b960f2af6438b30c3b6bd759bb3e56228a1096445ddd100f",
+ "dist/2021-11-30/rustc-beta-armv7-unknown-linux-gnueabihf.tar.xz": "451a2e139771f39ec09a7cefd48885ec30f732668d50c750d42e6c58c250f8fe",
+ "dist/2021-11-30/rustc-beta-i686-pc-windows-gnu.tar.gz": "a1df7d105231d4941a55a9f850d39acc201a99dd408d523935799b70fec30c6a",
+ "dist/2021-11-30/rustc-beta-i686-pc-windows-gnu.tar.xz": "3005718736a2a0fa3a4f1be10239cfb467e9cabe6ce366f9909826bd3c06a990",
+ "dist/2021-11-30/rustc-beta-i686-pc-windows-msvc.tar.gz": "695039c6737fb3bfd325fbebdab61aeef80ec427ae3d40d8b82e8b317e147fc8",
+ "dist/2021-11-30/rustc-beta-i686-pc-windows-msvc.tar.xz": "7a5038b7299de71d3677042647fca501984d1f2a52c1d84052956ff7854622b3",
+ "dist/2021-11-30/rustc-beta-i686-unknown-linux-gnu.tar.gz": "d21dd4c98d38186544aee9b22b439d67d77c0a740357dfad7fea3c4a9b8d1332",
+ "dist/2021-11-30/rustc-beta-i686-unknown-linux-gnu.tar.xz": "e62a7c9809de668343323eb9fa1a1f6cc302a6e161e64826e9d31bd202f2f472",
+ "dist/2021-11-30/rustc-beta-mips-unknown-linux-gnu.tar.gz": "b85eb1bff16384b4f6ad268a01bdcec539b9ea412abb6d64618521cb0e63985d",
+ "dist/2021-11-30/rustc-beta-mips-unknown-linux-gnu.tar.xz": "ce79b36723a65419e03ec77ea14680791d683e5e04332eebdf59550bdaaa164d",
+ "dist/2021-11-30/rustc-beta-mips64-unknown-linux-gnuabi64.tar.gz": "e778edd911e09c5c3b46aeccbabcd8ead78dd38086206d03406fc8dce52806e7",
+ "dist/2021-11-30/rustc-beta-mips64-unknown-linux-gnuabi64.tar.xz": "10afe035ca7d3a967b467875b1345dde8bdcd3f8c4af1e917bfa2c676e0fec70",
+ "dist/2021-11-30/rustc-beta-mips64el-unknown-linux-gnuabi64.tar.gz": "6b6c3386ebec138ff07a21d3f5631263219c226ca146bf97fe0a7bb9fee9d0c5",
+ "dist/2021-11-30/rustc-beta-mips64el-unknown-linux-gnuabi64.tar.xz": "5ff6430623d0f3aa14748f371e34072aba126a16429928f8f99172190f369fee",
+ "dist/2021-11-30/rustc-beta-mipsel-unknown-linux-gnu.tar.gz": "369ad16e85e4f2956e400105e6d8374ff64c473c3c3b61ae4d916214d5f922da",
+ "dist/2021-11-30/rustc-beta-mipsel-unknown-linux-gnu.tar.xz": "1c8adfb22f724fa98f30f23378a28729e144f6ab9bba54adf13111ca4648ed78",
+ "dist/2021-11-30/rustc-beta-powerpc-unknown-linux-gnu.tar.gz": "b3e270c6272420c31ee7bed8ed36c113c879a384fa5b85af0deb7d43a355ca2c",
+ "dist/2021-11-30/rustc-beta-powerpc-unknown-linux-gnu.tar.xz": "a21cdd8d182cc64ceaa83e522299860c2710dee780e8f49ff107a73fbd73c3ca",
+ "dist/2021-11-30/rustc-beta-powerpc64-unknown-linux-gnu.tar.gz": "1a81076b8e49647b61761a38ed283a9a71b326dc321920f7be453e0e15ae2465",
+ "dist/2021-11-30/rustc-beta-powerpc64-unknown-linux-gnu.tar.xz": "3f8ce23f81623a00de63ce7e82e448eec0901a92f908e6aff362807bae14ff84",
+ "dist/2021-11-30/rustc-beta-powerpc64le-unknown-linux-gnu.tar.gz": "eaa3b365bd91a5770db85e8541ee28c99988635521c0f2dfea05218172f11a55",
+ "dist/2021-11-30/rustc-beta-powerpc64le-unknown-linux-gnu.tar.xz": "3f856ae24c4737bf1928025a10712b6d856788d988fb5018631c525d13b68e29",
+ "dist/2021-11-30/rustc-beta-riscv64gc-unknown-linux-gnu.tar.gz": "c672cbf2caef81f7ab923ff7c6a05f1865057278180a686f810ddc71dacc49d0",
+ "dist/2021-11-30/rustc-beta-riscv64gc-unknown-linux-gnu.tar.xz": "bda5d2234aebdc175c87da3b77d050c56bced21a794c416bb9090c0ae3374be2",
+ "dist/2021-11-30/rustc-beta-s390x-unknown-linux-gnu.tar.gz": "59e01371664f8d39c7a06c205af0f5ab9aabdb3942be4f493d05ab71047619e8",
+ "dist/2021-11-30/rustc-beta-s390x-unknown-linux-gnu.tar.xz": "de956b5275e38e0b4223819973e85f5f65c409addd786f7ac2d525a79c3f0c92",
+ "dist/2021-11-30/rustc-beta-x86_64-apple-darwin.tar.gz": "4f78d90362488a866ea7b1cccbc61f925d94034b46dfa775dea75223e67d755a",
+ "dist/2021-11-30/rustc-beta-x86_64-apple-darwin.tar.xz": "3520d028e9370087cfa57eb7225dd76c008cb08ffb01c8101aaa86104f427f12",
+ "dist/2021-11-30/rustc-beta-x86_64-pc-windows-gnu.tar.gz": "f954349daa7dfd819ec0a7335a47b1d3b2ed0138eae31c56288d9c523cdf56b2",
+ "dist/2021-11-30/rustc-beta-x86_64-pc-windows-gnu.tar.xz": "ca046d8fca5fa48117c61c70a21176d9220a3c62af9fdc9b899c157bb196a5b5",
+ "dist/2021-11-30/rustc-beta-x86_64-pc-windows-msvc.tar.gz": "61ae4421bdf798a5ca1a8bc8c8521dfb29a707e40d382dbd2e155f134956ac33",
+ "dist/2021-11-30/rustc-beta-x86_64-pc-windows-msvc.tar.xz": "495076dfc2fa0b8d96613e34f867de9d43483984a8bd6839bf273c2be38039b6",
+ "dist/2021-11-30/rustc-beta-x86_64-unknown-freebsd.tar.gz": "828526bc23ad8802071bf4f2984faf3549139eb4ce8ebb9ba8711c196d2bf437",
+ "dist/2021-11-30/rustc-beta-x86_64-unknown-freebsd.tar.xz": "fa2464350b2ac29bec6751c551cc45b7af92c25d2cf1109397e724802d4859cf",
+ "dist/2021-11-30/rustc-beta-x86_64-unknown-illumos.tar.gz": "a1d9719668ea1887d6202c25b9dd2b7d40bdd240f3f753af77ac93f126c84c38",
+ "dist/2021-11-30/rustc-beta-x86_64-unknown-illumos.tar.xz": "4b36f5d448bf022f90e284c22a44e0b87ef8518ec93a297ceb703eb612ef80d8",
+ "dist/2021-11-30/rustc-beta-x86_64-unknown-linux-gnu.tar.gz": "63e654f5e8707a0536381025bdbb43d498c70a29a5ada0ecdb12e23844cc9a9f",
+ "dist/2021-11-30/rustc-beta-x86_64-unknown-linux-gnu.tar.xz": "6b5b74abdcb1cae42620cabc142a119b58823e9f2ac0c3151e087a76323c5cae",
+ "dist/2021-11-30/rustc-beta-x86_64-unknown-linux-musl.tar.gz": "f3aa2d52ce5da066c59de609ebd5df60ac908c7e0db23ac4afe69b927ef2a974",
+ "dist/2021-11-30/rustc-beta-x86_64-unknown-linux-musl.tar.xz": "6e8858dbaf50a8211516e5afa83e4133d878e0d4b19ba4a3e4c3e51cb80210b7",
+ "dist/2021-11-30/rustc-beta-x86_64-unknown-netbsd.tar.gz": "9028dd44728092ccaec86f415abdb3733f3ea58ab7c3d736e96e27540cc66a2d",
+ "dist/2021-11-30/rustc-beta-x86_64-unknown-netbsd.tar.xz": "c6720fd231b54a04e1ba3ed3fe333b1d8ef5b771ce341b4c112169a293bf713a",
+ "dist/2021-11-30/rustfmt-nightly-aarch64-apple-darwin.tar.gz": "d987783ba5117529b325bcf6f5e7abd9eee42b5ea86ce5109a4fd3f450af8062",
+ "dist/2021-11-30/rustfmt-nightly-aarch64-apple-darwin.tar.xz": "5d5838733dc64e302991465c1f371fde855ee410d42d1713ddc1c471b469e1a8",
+ "dist/2021-11-30/rustfmt-nightly-aarch64-pc-windows-msvc.tar.gz": "8593ab35bb800312d6fe4c4a4d151feb26187c6db0d0d5ca5e3e98a007f8a4ff",
+ "dist/2021-11-30/rustfmt-nightly-aarch64-pc-windows-msvc.tar.xz": "a2ded0420cc1d98df255c7ef93247b9a6d3d9ec22e42c477305dc15ef35fd329",
+ "dist/2021-11-30/rustfmt-nightly-aarch64-unknown-linux-gnu.tar.gz": "652275e77d73f122c12eb952338661562a48fc76164d6549158abc14fb4e4a4a",
+ "dist/2021-11-30/rustfmt-nightly-aarch64-unknown-linux-gnu.tar.xz": "fbb49b56bb11348e07124d8216b8f8b6e26d8697abb05afec0ddb07a456b29e5",
+ "dist/2021-11-30/rustfmt-nightly-aarch64-unknown-linux-musl.tar.gz": "817c7ed90ab8cdec1dcfc8571391a714002b49fd20da0ae32135f57d233ffbfb",
+ "dist/2021-11-30/rustfmt-nightly-aarch64-unknown-linux-musl.tar.xz": "cbd8674c65babce944bab6a6f013d44a2c7d6829434a6b97edb1f1e1df1c076f",
+ "dist/2021-11-30/rustfmt-nightly-arm-unknown-linux-gnueabi.tar.gz": "66b13ffad073bc624ebdef219e61f8972fc6be354aaf1f8ede58a3acc01314c3",
+ "dist/2021-11-30/rustfmt-nightly-arm-unknown-linux-gnueabi.tar.xz": "11ecfef218376fd2232ad552526b39173c5269130f02e408a7492762cde87a6a",
+ "dist/2021-11-30/rustfmt-nightly-arm-unknown-linux-gnueabihf.tar.gz": "07ad99e019141843f5d6f8c302b9d20c7453ebead79e9711af33c9c8081b9e22",
+ "dist/2021-11-30/rustfmt-nightly-arm-unknown-linux-gnueabihf.tar.xz": "6656be84a9b5a63083d63e3a87bc928b424109efff48e3a6770e026c6ea7c2e8",
+ "dist/2021-11-30/rustfmt-nightly-armv7-unknown-linux-gnueabihf.tar.gz": "155422628d41ce9730f4503bffa12e396b58692c906828acf15f0dd39b3d491e",
+ "dist/2021-11-30/rustfmt-nightly-armv7-unknown-linux-gnueabihf.tar.xz": "fc75c3836489bda30d340132d0d5ab8ee7f7c67617e4dc66a9eae559bbdb0421",
+ "dist/2021-11-30/rustfmt-nightly-i686-pc-windows-gnu.tar.gz": "181d557c8f73c8f22ed63a8f98e53f6d88871fd694173aea70c53d42c0c55ae2",
+ "dist/2021-11-30/rustfmt-nightly-i686-pc-windows-gnu.tar.xz": "5defc562a2f0ced4539006692cc969cf89756637f5f5c62be0276dfedd6f3db6",
+ "dist/2021-11-30/rustfmt-nightly-i686-pc-windows-msvc.tar.gz": "f28b3fdf5425e7b782d0f78ca95613efd87b2b0d14d44c4490f17d4eb452f183",
+ "dist/2021-11-30/rustfmt-nightly-i686-pc-windows-msvc.tar.xz": "b6cebd5a23bcc504d05c8dd79654baf2ab45b162c59b7b843e24efb7e2344011",
+ "dist/2021-11-30/rustfmt-nightly-i686-unknown-linux-gnu.tar.gz": "c59850b28fcfb1608c7e91890b8628ac201b87b4d9af7e9fd019e3e4a137c033",
+ "dist/2021-11-30/rustfmt-nightly-i686-unknown-linux-gnu.tar.xz": "ad808569083691ba31b0e10222f9dd01822ade91689bcb060544f28b99f2a299",
+ "dist/2021-11-30/rustfmt-nightly-mips-unknown-linux-gnu.tar.gz": "8fca357226b91cc712b888c0a62f9e52b121ab6d9815ea5f53bbfd243b895b69",
+ "dist/2021-11-30/rustfmt-nightly-mips-unknown-linux-gnu.tar.xz": "7f5451fe6946c16a7ba404c8bab33816d58d478b1dc0ea1ce6b85befe26ddf77",
+ "dist/2021-11-30/rustfmt-nightly-mips64-unknown-linux-gnuabi64.tar.gz": "7cc76ce31cf59f1cbeca87a46c996e905f048acfc70d438eae2a32bb67fc60c1",
+ "dist/2021-11-30/rustfmt-nightly-mips64-unknown-linux-gnuabi64.tar.xz": "429bacebe2a9f1478a00b1573fe4e1b071c6348d800182993c8b5d8ba54d9615",
+ "dist/2021-11-30/rustfmt-nightly-mips64el-unknown-linux-gnuabi64.tar.gz": "701a12b5a4a689e6b2ef260e35ed2d22c00452cde5e18ce0d886ace37e81964f",
+ "dist/2021-11-30/rustfmt-nightly-mips64el-unknown-linux-gnuabi64.tar.xz": "0ef78c91a3220226619f20b28bf67947a56ff31f369d5ea7bfc2aef356060e42",
+ "dist/2021-11-30/rustfmt-nightly-mipsel-unknown-linux-gnu.tar.gz": "0765a3b65315bbb1381927eaf6f65f16fd09dddab41d7398e483bf001ee7bc3e",
+ "dist/2021-11-30/rustfmt-nightly-mipsel-unknown-linux-gnu.tar.xz": "c74b0833f995ffad5c812ba130f423485bd8297eca0c4eae227852a88ece8521",
+ "dist/2021-11-30/rustfmt-nightly-powerpc-unknown-linux-gnu.tar.gz": "3c9d5a35ef1e459ded4dcdcad40bc5e3bcd5b2821cf4f46dbaf2c2c3259fa3ff",
+ "dist/2021-11-30/rustfmt-nightly-powerpc-unknown-linux-gnu.tar.xz": "0aa8975a6dbd103a4764ad643de6094bd6911bd3a90d46e24ad1eafcea2870e7",
+ "dist/2021-11-30/rustfmt-nightly-powerpc64-unknown-linux-gnu.tar.gz": "a0ee2ec59ed07ba9c9e48076c954f5c6e4d39809d9e4923337db2627ea279c6f",
+ "dist/2021-11-30/rustfmt-nightly-powerpc64-unknown-linux-gnu.tar.xz": "e712fa72a41dedcd50c6531433220904b9627fa78bfa15cdd96d97161981cb77",
+ "dist/2021-11-30/rustfmt-nightly-powerpc64le-unknown-linux-gnu.tar.gz": "fc7809520a4a41ccb0ffb303c7bbc96443308387890ebdb65a25c3697a5c3eb4",
+ "dist/2021-11-30/rustfmt-nightly-powerpc64le-unknown-linux-gnu.tar.xz": "84a8fa7468b9e59465f85607f84960e11faf0f37bd766d55b6be985db89d0d17",
+ "dist/2021-11-30/rustfmt-nightly-riscv64gc-unknown-linux-gnu.tar.gz": "2703dff8cb1c0ca08787f1c7715885c5b09919c040783ba98bd74f8fe3af704d",
+ "dist/2021-11-30/rustfmt-nightly-riscv64gc-unknown-linux-gnu.tar.xz": "a3e25cc857e990b467c804f41e23bfbe8ef02630b48703fc1c7fae692e16eb80",
+ "dist/2021-11-30/rustfmt-nightly-s390x-unknown-linux-gnu.tar.gz": "659a9ca0e1296f817cd9f90fed9ccd7d3c7c3e7eea7e9c437bbeb2d951a2669c",
+ "dist/2021-11-30/rustfmt-nightly-s390x-unknown-linux-gnu.tar.xz": "21e83ac3b148f0f690cb9a39b385fb0d5a82d6eea9ec46d4d4445b5a660c6d7c",
+ "dist/2021-11-30/rustfmt-nightly-x86_64-apple-darwin.tar.gz": "c8e3300a426cc4a80ba4f1cf0c6822d9b883f24c486b991f2056938be778d43f",
+ "dist/2021-11-30/rustfmt-nightly-x86_64-apple-darwin.tar.xz": "55f1f7d84828b3cc5d13b10e549a74f2f1df11057ed48e75fbafc0d3538daf03",
+ "dist/2021-11-30/rustfmt-nightly-x86_64-pc-windows-gnu.tar.gz": "99bf70cee39b2ce73dbe5827fe3d93e45241faea284acb3f8004cf7e700e1704",
+ "dist/2021-11-30/rustfmt-nightly-x86_64-pc-windows-gnu.tar.xz": "dfc569d57211eae74a2cde5db180d2f2f44bca04f811655ef1f8d8c2154b97ef",
+ "dist/2021-11-30/rustfmt-nightly-x86_64-pc-windows-msvc.tar.gz": "679d69ba6a4b460f9672f1ec1c2939ac41ee7f911a2a74eaf6db477aa088e6e3",
+ "dist/2021-11-30/rustfmt-nightly-x86_64-pc-windows-msvc.tar.xz": "3b9a899fcf40db84be8bd14e7c767c572c7d8c7c85f90997b8278fe8726413ae",
+ "dist/2021-11-30/rustfmt-nightly-x86_64-unknown-freebsd.tar.gz": "19be469ab711dcee7a7243e865efc5addf8b2cdbdf15150a2c367692c45b9f94",
+ "dist/2021-11-30/rustfmt-nightly-x86_64-unknown-freebsd.tar.xz": "789c7129e235b65860a514fdb38f01ac195af610d4ac6a296d272a6f36d72344",
+ "dist/2021-11-30/rustfmt-nightly-x86_64-unknown-illumos.tar.gz": "18657363783d0967d871ee1ed8905b3db0c3b761910fb06ea10980ec6b5ca082",
+ "dist/2021-11-30/rustfmt-nightly-x86_64-unknown-illumos.tar.xz": "8b272546a9eb8b23724fbec5577fc0c917a23e994befc38ebfa797957df03b9d",
+ "dist/2021-11-30/rustfmt-nightly-x86_64-unknown-linux-gnu.tar.gz": "4e1de312f07fb98845a881b44c2a76ec9abf61e5aba46e8e384de1cd297957a3",
+ "dist/2021-11-30/rustfmt-nightly-x86_64-unknown-linux-gnu.tar.xz": "a13ad29e2d06c9df233882d009ba8354d92d2fb29239cadaf858b9abc8b477d9",
+ "dist/2021-11-30/rustfmt-nightly-x86_64-unknown-linux-musl.tar.gz": "aae38bbf1eb7e0da50eb7f226897dc85e88b5e008ef901a93dadb0550f4055ac",
+ "dist/2021-11-30/rustfmt-nightly-x86_64-unknown-linux-musl.tar.xz": "757564eaa1a339d37b59da304bbc7a846bb883a73c62b78df39dacd947606ec9",
+ "dist/2021-11-30/rustfmt-nightly-x86_64-unknown-netbsd.tar.gz": "5f3a83079cb1fd7d8b9be44d0df7b57c6dc79da8e1762eace67c122cffc2d4ca",
+ "dist/2021-11-30/rustfmt-nightly-x86_64-unknown-netbsd.tar.xz": "e47ee14a1e679ee5f23936ba7d7de13dcba082c7f32e366be7a990503c91f6ad"
}
}
diff --git a/src/test/assembly/asm/arm-modifiers.rs b/src/test/assembly/asm/arm-modifiers.rs
index a6985a3bf5c..88ffeaecfec 100644
--- a/src/test/assembly/asm/arm-modifiers.rs
+++ b/src/test/assembly/asm/arm-modifiers.rs
@@ -59,12 +59,6 @@ macro_rules! check {
// CHECK: @NO_APP
check!(reg "" reg i32 "mov");
-// CHECK-LABEL: reg_thumb:
-// CHECK: @APP
-// CHECK: mov r0, r0
-// CHECK: @NO_APP
-check!(reg_thumb "" reg_thumb i32 "mov");
-
// CHECK-LABEL: sreg:
// CHECK: @APP
// CHECK: vmov.f32 s0, s0
diff --git a/src/test/assembly/asm/arm-types.rs b/src/test/assembly/asm/arm-types.rs
index 0c57b1fc478..5ac1af6afd6 100644
--- a/src/test/assembly/asm/arm-types.rs
+++ b/src/test/assembly/asm/arm-types.rs
@@ -163,36 +163,6 @@ check!(reg_f32 f32 reg "mov");
// CHECK: @NO_APP
check!(reg_ptr ptr reg "mov");
-// CHECK-LABEL: reg_thumb_i8:
-// CHECK: @APP
-// CHECK: mov {{[a-z0-9]+}}, {{[a-z0-9]+}}
-// CHECK: @NO_APP
-check!(reg_thumb_i8 i8 reg_thumb "mov");
-
-// CHECK-LABEL: reg_thumb_i16:
-// CHECK: @APP
-// CHECK: mov {{[a-z0-9]+}}, {{[a-z0-9]+}}
-// CHECK: @NO_APP
-check!(reg_thumb_i16 i16 reg_thumb "mov");
-
-// CHECK-LABEL: reg_thumb_i32:
-// CHECK: @APP
-// CHECK: mov {{[a-z0-9]+}}, {{[a-z0-9]+}}
-// CHECK: @NO_APP
-check!(reg_thumb_i32 i32 reg_thumb "mov");
-
-// CHECK-LABEL: reg_thumb_f32:
-// CHECK: @APP
-// CHECK: mov {{[a-z0-9]+}}, {{[a-z0-9]+}}
-// CHECK: @NO_APP
-check!(reg_thumb_f32 f32 reg_thumb "mov");
-
-// CHECK-LABEL: reg_thumb_ptr:
-// CHECK: @APP
-// CHECK: mov {{[a-z0-9]+}}, {{[a-z0-9]+}}
-// CHECK: @NO_APP
-check!(reg_thumb_ptr ptr reg_thumb "mov");
-
// CHECK-LABEL: sreg_i32:
// CHECK: @APP
// CHECK: vmov.f32 s{{[0-9]+}}, s{{[0-9]+}}
diff --git a/src/test/assembly/asm/avr-modifiers.rs b/src/test/assembly/asm/avr-modifiers.rs
new file mode 100644
index 00000000000..aba4c982c73
--- /dev/null
+++ b/src/test/assembly/asm/avr-modifiers.rs
@@ -0,0 +1,60 @@
+// min-llvm-version: 13.0
+// assembly-output: emit-asm
+// compile-flags: --target avr-unknown-gnu-atmega328
+// needs-llvm-components: avr
+
+#![feature(no_core, lang_items, rustc_attrs, asm_experimental_arch)]
+#![crate_type = "rlib"]
+#![no_core]
+#![allow(non_camel_case_types)]
+
+#[rustc_builtin_macro]
+macro_rules! asm {
+ () => {};
+}
+#[rustc_builtin_macro]
+macro_rules! concat {
+ () => {};
+}
+
+#[lang = "sized"]
+trait Sized {}
+#[lang = "copy"]
+trait Copy {}
+
+type ptr = *const u64;
+
+impl Copy for i8 {}
+impl Copy for i16 {}
+impl Copy for i32 {}
+impl Copy for i64 {}
+impl Copy for ptr {}
+
+macro_rules! check {
+ ($func:ident $hi:literal $lo:literal $reg:tt) => {
+ #[no_mangle]
+ unsafe fn $func() -> i16 {
+ let y;
+ asm!(concat!("mov {0:", $hi, "}, {0:", $lo, "}"), out($reg) y);
+ y
+ }
+ };
+}
+
+// CHECK-LABEL: reg_pair_modifiers:
+// CHECK: ;APP
+// CHECK: mov r{{[1-9]?[13579]}}, r{{[1-9]?[24680]}}
+// CHECK: ;NO_APP
+check!(reg_pair_modifiers "h" "l" reg_pair);
+
+// CHECK-LABEL: reg_iw_modifiers:
+// CHECK: ;APP
+// CHECK: mov r{{[1-9]?[13579]}}, r{{[1-9]?[24680]}}
+// CHECK: ;NO_APP
+check!(reg_iw_modifiers "h" "l" reg_iw);
+
+// CHECK-LABEL: reg_ptr_modifiers:
+// CHECK: ;APP
+// CHECK: mov r{{[1-9]?[13579]}}, r{{[1-9]?[24680]}}
+// CHECK: ;NO_APP
+check!(reg_ptr_modifiers "h" "l" reg_ptr);
diff --git a/src/test/assembly/asm/avr-types.rs b/src/test/assembly/asm/avr-types.rs
new file mode 100644
index 00000000000..53a601e51c8
--- /dev/null
+++ b/src/test/assembly/asm/avr-types.rs
@@ -0,0 +1,222 @@
+// min-llvm-version: 13.0
+// assembly-output: emit-asm
+// compile-flags: --target avr-unknown-gnu-atmega328
+// needs-llvm-components: avr
+
+#![feature(no_core, lang_items, rustc_attrs, asm_sym, asm_experimental_arch)]
+#![crate_type = "rlib"]
+#![no_core]
+#![allow(non_camel_case_types)]
+
+#[rustc_builtin_macro]
+macro_rules! asm {
+ () => {};
+}
+#[rustc_builtin_macro]
+macro_rules! concat {
+ () => {};
+}
+
+#[lang = "sized"]
+trait Sized {}
+#[lang = "copy"]
+trait Copy {}
+
+type ptr = *const u64;
+
+impl Copy for i8 {}
+impl Copy for i16 {}
+impl Copy for i32 {}
+impl Copy for i64 {}
+impl Copy for ptr {}
+
+macro_rules! check {
+ ($func:ident $ty:ident $class:ident) => {
+ #[no_mangle]
+ pub unsafe fn $func(x: $ty) -> $ty {
+ let y;
+ asm!("mov {}, {}", lateout($class) y, in($class) x);
+ y
+ }
+ };
+}
+
+macro_rules! checkw {
+ ($func:ident $ty:ident $class:ident) => {
+ #[no_mangle]
+ pub unsafe fn $func(x: $ty) -> $ty {
+ let y;
+ asm!("movw {}, {}", lateout($class) y, in($class) x);
+ y
+ }
+ };
+}
+
+macro_rules! check_reg {
+ ($func:ident $ty:ident $reg:tt) => {
+ #[no_mangle]
+ pub unsafe fn $func(x: $ty) -> $ty {
+ let y;
+ asm!(concat!("mov ", $reg, ", ", $reg), lateout($reg) y, in($reg) x);
+ y
+ }
+ };
+}
+
+macro_rules! check_regw {
+ ($func:ident $ty:ident $reg:tt $reg_lit:tt) => {
+ #[no_mangle]
+ pub unsafe fn $func(x: $ty) -> $ty {
+ let y;
+ asm!(concat!("movw ", $reg_lit, ", ", $reg_lit), lateout($reg) y, in($reg) x);
+ y
+ }
+ };
+}
+
+extern "C" {
+ fn extern_func();
+ static extern_static: i8;
+}
+
+// CHECK-LABEL: sym_fn
+// CHECK: ;APP
+// CHECK: call extern_func
+// CHECK: ;NO_APP
+#[no_mangle]
+pub unsafe fn sym_fn() {
+ asm!("call {}", sym extern_func);
+}
+
+// CHECK-LABEL: sym_static
+// CHECK: ;APP
+// CHECK: lds r{{[0-9]+}}, extern_static
+// CHECK: ;NO_APP
+#[no_mangle]
+pub unsafe fn sym_static() -> i8 {
+ let y;
+ asm!("lds {}, {}", lateout(reg) y, sym extern_static);
+ y
+}
+
+// CHECK-LABEL: ld_z:
+// CHECK: ;APP
+// CHECK: ld r{{[0-9]+}}, Z
+// CHECK: ;NO_APP
+#[no_mangle]
+pub unsafe fn ld_z(x: i16) -> i8 {
+ let y;
+ asm!("ld {}, Z", out(reg) y, in("Z") x);
+ y
+}
+
+// CHECK-LABEL: ldd_z:
+// CHECK: ;APP
+// CHECK: ldd r{{[0-9]+}}, Z+4
+// CHECK: ;NO_APP
+#[no_mangle]
+pub unsafe fn ldd_z(x: i16) -> i8 {
+ let y;
+ asm!("ldd {}, Z+4", out(reg) y, in("Z") x);
+ y
+}
+
+// CHECK-LABEL: ld_predecrement:
+// CHECK: ;APP
+// CHECK: ld r{{[0-9]+}}, -Z
+// CHECK: ;NO_APP
+#[no_mangle]
+pub unsafe fn ld_predecrement(x: i16) -> i8 {
+ let y;
+ asm!("ld {}, -Z", out(reg) y, in("Z") x);
+ y
+}
+
+// CHECK-LABEL: ld_postincrement:
+// CHECK: ;APP
+// CHECK: ld r{{[0-9]+}}, Z+
+// CHECK: ;NO_APP
+#[no_mangle]
+pub unsafe fn ld_postincrement(x: i16) -> i8 {
+ let y;
+ asm!("ld {}, Z+", out(reg) y, in("Z") x);
+ y
+}
+
+// CHECK-LABEL: muls_clobber:
+// CHECK: ;APP
+// CHECK: muls r{{[0-9]+}}, r{{[0-9]+}}
+// CHECK: movw r{{[0-9]+}}, r0
+// CHECK: ;NO_APP
+#[no_mangle]
+pub unsafe fn muls_clobber(x: i8, y: i8) -> i16 {
+ let z;
+ asm!(
+ "muls {}, {}",
+ "movw {}, r1:r0",
+ out(reg_iw) z,
+ in(reg) x,
+ in(reg) y,
+ );
+ z
+}
+
+// CHECK-LABEL: reg_i8:
+// CHECK: ;APP
+// CHECK: mov r{{[0-9]+}}, r{{[0-9]+}}
+// CHECK: ;NO_APP
+check!(reg_i8 i8 reg);
+
+// CHECK-LABEL: reg_upper_i8:
+// CHECK: ;APP
+// CHECK: mov r{{[1-3][0-9]}}, r{{[1-3][0-9]}}
+// CHECK: ;NO_APP
+check!(reg_upper_i8 i8 reg_upper);
+
+// CHECK-LABEL: reg_pair_i16:
+// CHECK: ;APP
+// CHECK: movw r{{[0-9]+}}, r{{[0-9]+}}
+// CHECK: ;NO_APP
+checkw!(reg_pair_i16 i16 reg_pair);
+
+// CHECK-LABEL: reg_iw_i16:
+// CHECK: ;APP
+// CHECK: movw r{{[0-9]+}}, r{{[0-9]+}}
+// CHECK: ;NO_APP
+checkw!(reg_iw_i16 i16 reg_iw);
+
+// CHECK-LABEL: reg_ptr_i16:
+// CHECK: ;APP
+// CHECK: movw r{{[0-9]+}}, r{{[0-9]+}}
+// CHECK: ;NO_APP
+checkw!(reg_ptr_i16 i16 reg_ptr);
+
+// CHECK-LABEL: r2_i8:
+// CHECK: ;APP
+// CHECK: mov r2, r2
+// CHECK: ;NO_APP
+check_reg!(r2_i8 i8 "r2");
+
+// CHECK-LABEL: xl_i8:
+// CHECK: ;APP
+// CHECK: mov r26, r26
+// CHECK: ;NO_APP
+check_reg!(xl_i8 i8 "XL");
+
+// CHECK-LABEL: xh_i8:
+// CHECK: ;APP
+// CHECK: mov r27, r27
+// CHECK: ;NO_APP
+check_reg!(xh_i8 i8 "XH");
+
+// CHECK-LABEL: x_i16:
+// CHECK: ;APP
+// CHECK: movw r26, r26
+// CHECK: ;NO_APP
+check_regw!(x_i16 i16 "X" "X");
+
+// CHECK-LABEL: r25r24_i16:
+// CHECK: ;APP
+// CHECK: movw r24, r24
+// CHECK: ;NO_APP
+check_regw!(r25r24_i16 i16 "r25r24" "r24");
diff --git a/src/test/assembly/asm/global_asm.rs b/src/test/assembly/asm/global_asm.rs
index 7e48c386abc..0358bc6d27c 100644
--- a/src/test/assembly/asm/global_asm.rs
+++ b/src/test/assembly/asm/global_asm.rs
@@ -2,9 +2,11 @@
// assembly-output: emit-asm
// compile-flags: -C llvm-args=--x86-asm-syntax=intel
-#![feature(global_asm, asm_const)]
+#![feature(asm_const)]
#![crate_type = "rlib"]
+use std::arch::global_asm;
+
// CHECK: mov eax, eax
global_asm!("mov eax, eax");
// CHECK: mov ebx, 5
diff --git a/src/test/assembly/sparc-struct-abi.rs b/src/test/assembly/sparc-struct-abi.rs
new file mode 100644
index 00000000000..dd8e6f614df
--- /dev/null
+++ b/src/test/assembly/sparc-struct-abi.rs
@@ -0,0 +1,64 @@
+// Test SPARC64 ABI
+// - float structure members are passes in floating point registers
+// (#86163)
+
+// assembly-output: emit-asm
+// needs-llvm-components: sparc
+// compile-flags: --target=sparcv9-sun-solaris -Copt-level=3
+#![crate_type = "lib"]
+#![feature(no_core, lang_items)]
+#![no_core]
+
+#[lang = "sized"]
+pub trait Sized {}
+#[lang = "copy"]
+pub trait Copy {}
+
+#[repr(C)]
+pub struct Franta {
+ a: f32,
+ b: f32,
+ c: f32,
+ d: f32,
+}
+
+// NB: due to delay slots the `ld` following the call is actually executed before the call.
+#[no_mangle]
+pub unsafe extern "C" fn callee(arg: Franta) {
+ // CHECK-LABEL: callee:
+ // CHECK: st %f3, [[PLACE_D:.*]]
+ // CHECK: st %f2, [[PLACE_C:.*]]
+ // CHECK: st %f1, [[PLACE_B:.*]]
+ // CHECK: st %f0, [[PLACE_A:.*]]
+ // CHECK: call tst_use
+ // CHECK-NEXT: ld [[PLACE_A]], %f1
+ // CHECK: call tst_use
+ // CHECK-NEXT: ld [[PLACE_B]], %f1
+ // CHECK: call tst_use
+ // CHECK-NEXT: ld [[PLACE_C]], %f1
+ // CHECK: call tst_use
+ // CHECK-NEXT: ld [[PLACE_D]], %f1
+ clobber();
+ tst_use(arg.a);
+ tst_use(arg.b);
+ tst_use(arg.c);
+ tst_use(arg.d);
+}
+
+extern "C" {
+ fn opaque_callee(arg: Franta, intarg: i32);
+ fn tst_use(arg: f32);
+ fn clobber();
+}
+
+#[no_mangle]
+pub unsafe extern "C" fn caller() {
+ // CHECK-LABEL: caller:
+ // CHECK: ld [{{.*}}], %f0
+ // CHECK: ld [{{.*}}], %f1
+ // CHECK: ld [{{.*}}], %f2
+ // CHECK: ld [{{.*}}], %f3
+ // CHECK: call opaque_callee
+ // CHECK: mov 3, %o2
+ opaque_callee(Franta { a: 1.0, b: 2.0, c: 3.0, d: 4.0 }, 3);
+}
diff --git a/src/test/assembly/stack-protector/stack-protector-heuristics-effect.rs b/src/test/assembly/stack-protector/stack-protector-heuristics-effect.rs
new file mode 100644
index 00000000000..530326ab743
--- /dev/null
+++ b/src/test/assembly/stack-protector/stack-protector-heuristics-effect.rs
@@ -0,0 +1,396 @@
+// revisions: all strong basic none missing
+// assembly-output: emit-asm
+// ignore-macos slightly different policy on stack protection of arrays
+// ignore-windows stack check code uses different function names
+// ignore-nvptx64 stack protector is not supported
+// [all] compile-flags: -Z stack-protector=all
+// [strong] compile-flags: -Z stack-protector=strong
+// [basic] compile-flags: -Z stack-protector=basic
+// [none] compile-flags: -Z stack-protector=none
+// compile-flags: -C opt-level=2 -Z merge-functions=disabled
+
+#![crate_type = "lib"]
+
+#![allow(incomplete_features)]
+
+#![feature(unsized_locals, unsized_fn_params)]
+
+
+// CHECK-LABEL: emptyfn:
+#[no_mangle]
+pub fn emptyfn() {
+ // all: __stack_chk_fail
+ // strong-NOT: __stack_chk_fail
+ // basic-NOT: __stack_chk_fail
+ // none-NOT: __stack_chk_fail
+ // missing-NOT: __stack_chk_fail
+}
+
+// CHECK-LABEL: array_char
+#[no_mangle]
+pub fn array_char(f: fn(*const char)) {
+ let a = ['c'; 1];
+ let b = ['d'; 3];
+ let c = ['e'; 15];
+
+ f(&a as *const _);
+ f(&b as *const _);
+ f(&c as *const _);
+
+ // Any type of local array variable leads to stack protection with the
+ // "strong" heuristic. The 'basic' heuristic only adds stack protection to
+ // functions with local array variables of a byte-sized type, however. Since
+ // 'char' is 4 bytes in Rust, this function is not protected by the 'basic'
+ // heuristic
+ //
+ // (This test *also* takes the address of the local stack variables. We
+ // cannot know that this isn't what triggers the `strong` heuristic.
+ // However, the test strategy of passing the address of a stack array to an
+ // external function is sufficient to trigger the `basic` heuristic (see
+ // test `array_u8_large()`). Since the `basic` heuristic only checks for the
+ // presence of stack-local array variables, we can be confident that this
+ // test also captures this part of the `strong` heuristic specification.)
+
+ // all: __stack_chk_fail
+ // strong: __stack_chk_fail
+ // basic-NOT: __stack_chk_fail
+ // none-NOT: __stack_chk_fail
+ // missing-NOT: __stack_chk_fail
+}
+
+// CHECK-LABEL: array_u8_1
+#[no_mangle]
+pub fn array_u8_1(f: fn(*const u8)) {
+ let a = [0u8; 1];
+ f(&a as *const _);
+
+ // The 'strong' heuristic adds stack protection to functions with local
+ // array variables regardless of their size.
+
+ // all: __stack_chk_fail
+ // strong: __stack_chk_fail
+ // basic-NOT: __stack_chk_fail
+ // none-NOT: __stack_chk_fail
+ // missing-NOT: __stack_chk_fail
+}
+
+// CHECK-LABEL: array_u8_small:
+#[no_mangle]
+pub fn array_u8_small(f: fn(*const u8)) {
+ let a = [0u8; 2];
+ let b = [0u8; 8];
+ f(&a as *const _);
+ f(&b as *const _);
+
+ // Small arrays do not lead to stack protection by the 'basic' heuristic.
+
+ // all: __stack_chk_fail
+ // strong: __stack_chk_fail
+ // basic-NOT: __stack_chk_fail
+ // none-NOT: __stack_chk_fail
+ // missing-NOT: __stack_chk_fail
+}
+
+// CHECK-LABEL: array_u8_large:
+#[no_mangle]
+pub fn array_u8_large(f: fn(*const u8)) {
+ let a = [0u8; 9];
+ f(&a as *const _);
+
+ // Since `a` is a byte array with size greater than 8, the basic heuristic
+ // will also protect this function.
+
+ // all: __stack_chk_fail
+ // strong: __stack_chk_fail
+ // basic: __stack_chk_fail
+ // none-NOT: __stack_chk_fail
+ // missing-NOT: __stack_chk_fail
+}
+
+#[derive(Copy, Clone)]
+pub struct ByteSizedNewtype(u8);
+
+// CHECK-LABEL: array_bytesizednewtype_9:
+#[no_mangle]
+pub fn array_bytesizednewtype_9(f: fn(*const ByteSizedNewtype)) {
+ let a = [ByteSizedNewtype(0); 9];
+ f(&a as *const _);
+
+ // Since `a` is a byte array in the LLVM output, the basic heuristic will
+ // also protect this function.
+
+ // all: __stack_chk_fail
+ // strong: __stack_chk_fail
+ // basic: __stack_chk_fail
+ // none-NOT: __stack_chk_fail
+ // missing-NOT: __stack_chk_fail
+}
+
+// CHECK-LABEL: local_var_addr_used_indirectly
+#[no_mangle]
+pub fn local_var_addr_used_indirectly(f: fn(bool)) {
+ let a = 5;
+ let a_addr = &a as *const _ as usize;
+ f(a_addr & 0x10 == 0);
+
+ // This function takes the address of a local variable taken. Although this
+ // address is never used as a way to refer to stack memory, the `strong`
+ // heuristic adds stack smash protection. This is also the case in C++:
+ // ```
+ // cat << EOF | clang++ -O2 -fstack-protector-strong -S -x c++ - -o - | grep stack_chk
+ // #include <cstdint>
+ // void f(void (*g)(bool)) {
+ // int32_t x;
+ // g((reinterpret_cast<uintptr_t>(&x) & 0x10U) == 0);
+ // }
+ // EOF
+ // ```
+
+ // all: __stack_chk_fail
+ // strong: __stack_chk_fail
+ // basic-NOT: __stack_chk_fail
+ // none-NOT: __stack_chk_fail
+ // missing-NOT: __stack_chk_fail
+}
+
+
+// CHECK-LABEL: local_string_addr_taken
+#[no_mangle]
+pub fn local_string_addr_taken(f: fn(&String)) {
+ let x = String::new();
+ f(&x);
+
+ // Taking the address of the local variable `x` leads to stack smash
+ // protection with the `strong` heuristic, but not with the `basic`
+ // heuristic. It does not matter that the reference is not mut.
+ //
+ // An interesting note is that a similar function in C++ *would* be
+ // protected by the `basic` heuristic, because `std::string` has a char
+ // array internally as a small object optimization:
+ // ```
+ // cat <<EOF | clang++ -O2 -fstack-protector -S -x c++ - -o - | grep stack_chk
+ // #include <string>
+ // void f(void (*g)(const std::string&)) {
+ // std::string x;
+ // g(x);
+ // }
+ // EOF
+ // ```
+ //
+
+ // all: __stack_chk_fail
+ // strong: __stack_chk_fail
+ // basic-NOT: __stack_chk_fail
+ // none-NOT: __stack_chk_fail
+ // missing-NOT: __stack_chk_fail
+}
+
+pub trait SelfByRef {
+ fn f(&self) -> i32;
+}
+
+impl SelfByRef for i32 {
+ fn f(&self) -> i32 {
+ return self + 1;
+ }
+}
+
+// CHECK-LABEL: local_var_addr_taken_used_locally_only
+#[no_mangle]
+pub fn local_var_addr_taken_used_locally_only(factory: fn() -> i32, sink: fn(i32)) {
+ let x = factory();
+ let g = x.f();
+ sink(g);
+
+ // Even though the local variable conceptually has its address taken, as
+ // it's passed by reference to the trait function, the use of the reference
+ // is easily inlined. There is therefore no stack smash protection even with
+ // the `strong` heuristic.
+
+ // all: __stack_chk_fail
+ // strong-NOT: __stack_chk_fail
+ // basic-NOT: __stack_chk_fail
+ // none-NOT: __stack_chk_fail
+ // missing-NOT: __stack_chk_fail
+}
+
+pub struct Gigastruct {
+ does: u64,
+ not: u64,
+ have: u64,
+ array: u64,
+ members: u64
+}
+
+// CHECK-LABEL: local_large_var_moved
+#[no_mangle]
+pub fn local_large_var_moved(f: fn(Gigastruct)) {
+ let x = Gigastruct { does: 0, not: 1, have: 2, array: 3, members: 4 };
+ f(x);
+
+ // Even though the local variable conceptually doesn't have its address
+ // taken, it's so large that the "move" is implemented with a reference to a
+ // stack-local variable in the ABI. Consequently, this function *is*
+ // protected by the `strong` heuristic. This is also the case for
+ // rvalue-references in C++, regardless of struct size:
+ // ```
+ // cat <<EOF | clang++ -O2 -fstack-protector-strong -S -x c++ - -o - | grep stack_chk
+ // #include <cstdint>
+ // #include <utility>
+ // void f(void (*g)(uint64_t&&)) {
+ // uint64_t x;
+ // g(std::move(x));
+ // }
+ // EOF
+ // ```
+
+ // all: __stack_chk_fail
+ // strong: __stack_chk_fail
+ // basic-NOT: __stack_chk_fail
+ // none-NOT: __stack_chk_fail
+ // missing-NOT: __stack_chk_fail
+}
+
+// CHECK-LABEL: local_large_var_cloned
+#[no_mangle]
+pub fn local_large_var_cloned(f: fn(Gigastruct)) {
+ f(Gigastruct { does: 0, not: 1, have: 2, array: 3, members: 4 });
+
+ // A new instance of `Gigastruct` is passed to `f()`, without any apparent
+ // connection to this stack frame. Still, since instances of `Gigastruct`
+ // are sufficiently large, it is allocated in the caller stack frame and
+ // passed as a pointer. As such, this function is *also* protected by the
+ // `strong` heuristic, just like `local_large_var_moved`. This is also the
+ // case for pass-by-value of sufficiently large structs in C++:
+ // ```
+ // cat <<EOF | clang++ -O2 -fstack-protector-strong -S -x c++ - -o - | grep stack_chk
+ // #include <cstdint>
+ // #include <utility>
+ // struct Gigastruct { uint64_t a, b, c, d, e; };
+ // void f(void (*g)(Gigastruct)) {
+ // g(Gigastruct{});
+ // }
+ // EOF
+ // ```
+
+
+ // all: __stack_chk_fail
+ // strong: __stack_chk_fail
+ // basic-NOT: __stack_chk_fail
+ // none-NOT: __stack_chk_fail
+ // missing-NOT: __stack_chk_fail
+}
+
+
+extern "C" {
+ // A call to an external `alloca` function is *not* recognized as an
+ // `alloca(3)` operation. This function is a compiler built-in, as the
+ // man page explains. Clang translates it to an LLVM `alloca`
+ // instruction with a count argument, which is also what the LLVM stack
+ // protector heuristics looks for. The man page for `alloca(3)` details
+ // a way to avoid using the compiler built-in: pass a -std=c11
+ // argument, *and* don't include <alloca.h>. Though this leads to an
+ // external alloca() function being called, it doesn't lead to stack
+ // protection being included. It even fails with a linker error
+ // "undefined reference to `alloca'". Example:
+ // ```
+ // cat<<EOF | clang -fstack-protector-strong -x c -std=c11 - -o /dev/null
+ // #include <stdlib.h>
+ // void * alloca(size_t);
+ // void f(void (*g)(void*)) {
+ // void * p = alloca(10);
+ // g(p);
+ // }
+ // int main() { return 0; }
+ // EOF
+ // ```
+ // The following tests demonstrate that calls to an external `alloca`
+ // function in Rust also doesn't trigger stack protection.
+
+ fn alloca(size: usize) -> *mut ();
+}
+
+// CHECK-LABEL: alloca_small_compile_time_constant_arg
+#[no_mangle]
+pub fn alloca_small_compile_time_constant_arg(f: fn(*mut ())) {
+ f(unsafe { alloca(8) });
+
+ // all: __stack_chk_fail
+ // strong-NOT: __stack_chk_fail
+ // basic-NOT: __stack_chk_fail
+ // none-NOT: __stack_chk_fail
+ // missing-NOT: __stack_chk_fail
+}
+
+// CHECK-LABEL: alloca_large_compile_time_constant_arg
+#[no_mangle]
+pub fn alloca_large_compile_time_constant_arg(f: fn(*mut ())) {
+ f(unsafe { alloca(9) });
+
+ // all: __stack_chk_fail
+ // strong-NOT: __stack_chk_fail
+ // basic-NOT: __stack_chk_fail
+ // none-NOT: __stack_chk_fail
+ // missing-NOT: __stack_chk_fail
+}
+
+
+// CHECK-LABEL: alloca_dynamic_arg
+#[no_mangle]
+pub fn alloca_dynamic_arg(f: fn(*mut ()), n: usize) {
+ f(unsafe { alloca(n) });
+
+ // all: __stack_chk_fail
+ // strong-NOT: __stack_chk_fail
+ // basic-NOT: __stack_chk_fail
+ // none-NOT: __stack_chk_fail
+ // missing-NOT: __stack_chk_fail
+}
+
+// The question then is: in what ways can Rust code generate array-`alloca`
+// LLVM instructions? This appears to only be generated by
+// rustc_codegen_ssa::traits::Builder::array_alloca() through
+// rustc_codegen_ssa::mir::operand::OperandValue::store_unsized(). FWICT
+// this is support for the "unsized locals" unstable feature:
+// https://doc.rust-lang.org/unstable-book/language-features/unsized-locals.html.
+
+
+// CHECK-LABEL: unsized_fn_param
+#[no_mangle]
+pub fn unsized_fn_param(s: [u8], l: bool, f: fn([u8])) {
+ let n = if l { 1 } else { 2 };
+ f(*Box::<[u8]>::from(&s[0..n])); // slice-copy with Box::from
+
+ // Even though slices are conceptually passed by-value both into this
+ // function and into `f()`, this is implemented with pass-by-reference
+ // using a suitably constructed fat-pointer (as if the functions
+ // accepted &[u8]). This function therefore doesn't need dynamic array
+ // alloca, and is therefore not protected by the `strong` or `basic`
+ // heuristics.
+
+
+ // all: __stack_chk_fail
+ // strong-NOT: __stack_chk_fail
+ // basic-NOT: __stack_chk_fail
+ // none-NOT: __stack_chk_fail
+ // missing-NOT: __stack_chk_fail
+}
+
+// CHECK-LABEL: unsized_local
+#[no_mangle]
+pub fn unsized_local(s: &[u8], l: bool, f: fn(&mut [u8])) {
+ let n = if l { 1 } else { 2 };
+ let mut a: [u8] = *Box::<[u8]>::from(&s[0..n]); // slice-copy with Box::from
+ f(&mut a);
+
+ // This function allocates a slice as a local variable in its stack
+ // frame. Since the size is not a compile-time constant, an array
+ // alloca is required, and the function is protected by both the
+ // `strong` and `basic` heuristic.
+
+ // all: __stack_chk_fail
+ // strong: __stack_chk_fail
+ // basic: __stack_chk_fail
+ // none-NOT: __stack_chk_fail
+ // missing-NOT: __stack_chk_fail
+}
diff --git a/src/test/assembly/stack-protector/stack-protector-target-support.rs b/src/test/assembly/stack-protector/stack-protector-target-support.rs
new file mode 100644
index 00000000000..5ba46d082e1
--- /dev/null
+++ b/src/test/assembly/stack-protector/stack-protector-target-support.rs
@@ -0,0 +1,286 @@
+// Test that stack smash protection code is emitted for all tier1 and tier2
+// targets, with the exception of nvptx64-nvidia-cuda
+//
+// revisions: r1 r2 r3 r4 r5 r6 r7 r8 r9 r10 r11 r12 r13 r14 r15 r16 r17 r18 r19 r20 r21 r22 r23
+// revisions: r24 r25 r26 r27 r28 r29 r30 r31 r32 r33 r34 r35 r36 r37 r38 r39 r40 r41 r42 r43 r44
+// revisions: r45 r46 r47 r48 r49 r50 r51 r52 r53 r54 r55 r56 r57 r58 r59 r60 r61 r62 r63 r64 r65
+// revisions: r66 r67 r68 r69 r70 r71 r72 r73 r74 r75 r76 r77 r78 r79 r80 r81 r82 r83 r84
+// assembly-output: emit-asm
+// [r1] compile-flags: --target aarch64-unknown-linux-gnu
+// [r1] needs-llvm-components: aarch64
+// [r2] compile-flags: --target i686-pc-windows-gnu
+// [r2] needs-llvm-components: x86
+// [r3] compile-flags: --target i686-pc-windows-msvc
+// [r3] needs-llvm-components: x86
+// [r4] compile-flags: --target i686-unknown-linux-gnu
+// [r4] needs-llvm-components: x86
+// [r5] compile-flags: --target x86_64-apple-darwin
+// [r5] needs-llvm-components: x86
+// [r6] compile-flags: --target x86_64-pc-windows-gnu
+// [r6] needs-llvm-components: x86
+// [r7] compile-flags: --target x86_64-pc-windows-msvc
+// [r7] needs-llvm-components: x86
+// [r8] compile-flags: --target x86_64-unknown-linux-gnu
+// [r8] needs-llvm-components: x86
+// [r9] compile-flags: --target aarch64-apple-darwin
+// [r9] needs-llvm-components: aarch64
+// [r10] compile-flags: --target aarch64-apple-ios
+// [r10] needs-llvm-components: aarch64
+// [r11] compile-flags: --target aarch64-fuchsia
+// [r11] needs-llvm-components: aarch64
+// [r12] compile-flags: --target aarch64-linux-android
+// [r12] needs-llvm-components: aarch64
+// [r13] compile-flags: --target aarch64-pc-windows-msvc
+// [r13] needs-llvm-components: aarch64
+// [r14] compile-flags: --target aarch64-unknown-linux-musl
+// [r14] needs-llvm-components: aarch64
+// [r15] compile-flags: --target aarch64-unknown-none
+// [r15] needs-llvm-components: aarch64
+// [r16] compile-flags: --target aarch64-unknown-none-softfloat
+// [r16] needs-llvm-components: aarch64
+// [r17] compile-flags: --target arm-linux-androideabi
+// [r17] needs-llvm-components: arm
+// [r18] compile-flags: --target arm-unknown-linux-gnueabi
+// [r18] needs-llvm-components: arm
+// [r19] compile-flags: --target arm-unknown-linux-gnueabihf
+// [r19] needs-llvm-components: arm
+// [r20] compile-flags: --target arm-unknown-linux-musleabi
+// [r20] needs-llvm-components: arm
+// [r21] compile-flags: --target arm-unknown-linux-musleabihf
+// [r21] needs-llvm-components: arm
+// [r22] compile-flags: --target armebv7r-none-eabi
+// [r22] needs-llvm-components: arm
+// [r23] compile-flags: --target armebv7r-none-eabihf
+// [r23] needs-llvm-components: arm
+// [r24] compile-flags: --target armv5te-unknown-linux-gnueabi
+// [r24] needs-llvm-components: arm
+// [r25] compile-flags: --target armv5te-unknown-linux-musleabi
+// [r25] needs-llvm-components: arm
+// [r26] compile-flags: --target armv7-linux-androideabi
+// [r26] needs-llvm-components: arm
+// [r27] compile-flags: --target armv7a-none-eabi
+// [r27] needs-llvm-components: arm
+// [r28] compile-flags: --target armv7r-none-eabi
+// [r28] needs-llvm-components: arm
+// [r29] compile-flags: --target armv7r-none-eabihf
+// [r29] needs-llvm-components: arm
+// [r30] compile-flags: --target armv7-unknown-linux-gnueabi
+// [r30] needs-llvm-components: arm
+// [r31] compile-flags: --target armv7-unknown-linux-gnueabihf
+// [r31] needs-llvm-components: arm
+// [r32] compile-flags: --target armv7-unknown-linux-musleabi
+// [r32] needs-llvm-components: arm
+// [r33] compile-flags: --target armv7-unknown-linux-musleabihf
+// [r33] needs-llvm-components: arm
+// [r34] compile-flags: --target asmjs-unknown-emscripten
+// [r34] needs-llvm-components: webassembly
+// [r35] compile-flags: --target i586-pc-windows-msvc
+// [r35] needs-llvm-components: x86
+// [r36] compile-flags: --target i586-unknown-linux-gnu
+// [r36] needs-llvm-components: x86
+// [r37] compile-flags: --target i586-unknown-linux-musl
+// [r37] needs-llvm-components: x86
+// [r38] compile-flags: --target i686-linux-android
+// [r38] needs-llvm-components: x86
+// [r39] compile-flags: --target i686-unknown-freebsd
+// [r39] needs-llvm-components: x86
+// [r40] compile-flags: --target i686-unknown-linux-musl
+// [r40] needs-llvm-components: x86
+// [r41] compile-flags: --target mips-unknown-linux-gnu
+// [r41] needs-llvm-components: mips
+// [r42] compile-flags: --target mips-unknown-linux-musl
+// [r42] needs-llvm-components: mips
+// [r43] compile-flags: --target mips64-unknown-linux-gnuabi64
+// [r43] needs-llvm-components: mips
+// [r44] compile-flags: --target mips64-unknown-linux-muslabi64
+// [r44] needs-llvm-components: mips
+// [r45] compile-flags: --target mips64el-unknown-linux-gnuabi64
+// [r45] needs-llvm-components: mips
+// [r46] compile-flags: --target mips64el-unknown-linux-muslabi64
+// [r46] needs-llvm-components: mips
+// [r47] compile-flags: --target mipsel-unknown-linux-gnu
+// [r47] needs-llvm-components: mips
+// [r48] compile-flags: --target mipsel-unknown-linux-musl
+// [r48] needs-llvm-components: mips
+// [r49] compile-flags: --target nvptx64-nvidia-cuda
+// [r49] needs-llvm-components: nvptx
+// [r50] compile-flags: --target powerpc-unknown-linux-gnu
+// [r50] needs-llvm-components: powerpc
+// [r51] compile-flags: --target powerpc64-unknown-linux-gnu
+// [r51] needs-llvm-components: powerpc
+// [r52] compile-flags: --target powerpc64le-unknown-linux-gnu
+// [r52] needs-llvm-components: powerpc
+// [r53] compile-flags: --target riscv32i-unknown-none-elf
+// [r53] needs-llvm-components: riscv
+// [r54] compile-flags: --target riscv32imac-unknown-none-elf
+// [r54] needs-llvm-components: riscv
+// [r55] compile-flags:--target riscv32imc-unknown-none-elf
+// [r55] needs-llvm-components: riscv
+// [r56] compile-flags:--target riscv64gc-unknown-linux-gnu
+// [r56] needs-llvm-components: riscv
+// [r57] compile-flags:--target riscv64gc-unknown-none-elf
+// [r57] needs-llvm-components: riscv
+// [r58] compile-flags:--target riscv64imac-unknown-none-elf
+// [r58] needs-llvm-components: riscv
+// [r59] compile-flags:--target s390x-unknown-linux-gnu
+// [r59] needs-llvm-components: systemz
+// [r60] compile-flags:--target sparc64-unknown-linux-gnu
+// [r60] needs-llvm-components: sparc
+// [r61] compile-flags:--target sparcv9-sun-solaris
+// [r61] needs-llvm-components: sparc
+// [r62] compile-flags:--target thumbv6m-none-eabi
+// [r62] needs-llvm-components: arm
+// [r63] compile-flags:--target thumbv7em-none-eabi
+// [r63] needs-llvm-components: arm
+// [r64] compile-flags:--target thumbv7em-none-eabihf
+// [r64] needs-llvm-components: arm
+// [r65] compile-flags:--target thumbv7m-none-eabi
+// [r65] needs-llvm-components: arm
+// [r66] compile-flags:--target thumbv7neon-linux-androideabi
+// [r66] needs-llvm-components: arm
+// [r67] compile-flags:--target thumbv7neon-unknown-linux-gnueabihf
+// [r67] needs-llvm-components: arm
+// [r68] compile-flags:--target thumbv8m.base-none-eabi
+// [r68] needs-llvm-components: arm
+// [r69] compile-flags:--target thumbv8m.main-none-eabi
+// [r69] needs-llvm-components: arm
+// [r70] compile-flags:--target thumbv8m.main-none-eabihf
+// [r70] needs-llvm-components: arm
+// [r71] compile-flags:--target wasm32-unknown-emscripten
+// [r71] needs-llvm-components: webassembly
+// [r72] compile-flags:--target wasm32-unknown-unknown
+// [r72] needs-llvm-components: webassembly
+// [r73] compile-flags:--target wasm32-wasi
+// [r73] needs-llvm-components: webassembly
+// [r74] compile-flags:--target x86_64-apple-ios
+// [r74] needs-llvm-components: x86
+// [r75] compile-flags:--target x86_64-fortanix-unknown-sgx
+// [r75] needs-llvm-components: x86
+// [r75] min-llvm-version: 11.0.0
+// [r76] compile-flags:--target x86_64-fuchsia
+// [r76] needs-llvm-components: x86
+// [r77] compile-flags:--target x86_64-linux-android
+// [r77] needs-llvm-components: x86
+// [r78] compile-flags:--target x86_64-sun-solaris
+// [r78] needs-llvm-components: x86
+// [r79] compile-flags:--target x86_64-unknown-freebsd
+// [r79] needs-llvm-components: x86
+// [r80] compile-flags:--target x86_64-unknown-illumos
+// [r80] needs-llvm-components: x86
+// [r81] compile-flags:--target x86_64-unknown-linux-gnux32
+// [r81] needs-llvm-components: x86
+// [r82] compile-flags:--target x86_64-unknown-linux-musl
+// [r82] needs-llvm-components: x86
+// [r83] compile-flags:--target x86_64-unknown-netbsd
+// [r83] needs-llvm-components: x86
+// [r84] compile-flags: --target x86_64-unknown-redox
+// [r84] needs-llvm-components: x86
+// compile-flags: -Z stack-protector=all
+// compile-flags: -C opt-level=2
+
+#![crate_type = "lib"]
+
+#![feature(no_core, lang_items)]
+#![crate_type = "lib"]
+#![no_core]
+
+#[lang = "sized"]
+trait Sized {}
+#[lang = "copy"]
+trait Copy {}
+
+#[no_mangle]
+pub fn foo() {
+ // CHECK: foo{{:|()}}
+
+ // MSVC does the stack checking within a stack-check function:
+ // r3: calll @__security_check_cookie
+ // r7: callq __security_check_cookie
+ // r13: bl __security_check_cookie
+ // r35: calll @__security_check_cookie
+
+ // cuda doesn't support stack-smash protection
+ // r49-NOT: __security_check_cookie
+ // r49-NOT: __stack_chk_fail
+
+ // Other targets do stack checking within the function, and call a failure function on error
+ // r1: __stack_chk_fail
+ // r2: __stack_chk_fail
+ // r4: __stack_chk_fail
+ // r5: __stack_chk_fail
+ // r6: __stack_chk_fail
+ // r8: __stack_chk_fail
+ // r9: __stack_chk_fail
+ // r10: __stack_chk_fail
+ // r11: __stack_chk_fail
+ // r12: __stack_chk_fail
+ // r14: __stack_chk_fail
+ // r15: __stack_chk_fail
+ // r16: __stack_chk_fail
+ // r17: __stack_chk_fail
+ // r18: __stack_chk_fail
+ // r19: __stack_chk_fail
+ // r20: __stack_chk_fail
+ // r21: __stack_chk_fail
+ // r22: __stack_chk_fail
+ // r23: __stack_chk_fail
+ // r24: __stack_chk_fail
+ // r25: __stack_chk_fail
+ // r26: __stack_chk_fail
+ // r27: __stack_chk_fail
+ // r28: __stack_chk_fail
+ // r29: __stack_chk_fail
+ // r30: __stack_chk_fail
+ // r31: __stack_chk_fail
+ // r32: __stack_chk_fail
+ // r33: __stack_chk_fail
+ // r34: __stack_chk_fail
+ // r36: __stack_chk_fail
+ // r37: __stack_chk_fail
+ // r38: __stack_chk_fail
+ // r39: __stack_chk_fail
+ // r40: __stack_chk_fail
+ // r41: __stack_chk_fail
+ // r42: __stack_chk_fail
+ // r43: __stack_chk_fail
+ // r44: __stack_chk_fail
+ // r45: __stack_chk_fail
+ // r46: __stack_chk_fail
+ // r47: __stack_chk_fail
+ // r48: __stack_chk_fail
+ // r50: __stack_chk_fail
+ // r51: __stack_chk_fail
+ // r52: __stack_chk_fail
+ // r53: __stack_chk_fail
+ // r54: __stack_chk_fail
+ // r55: __stack_chk_fail
+ // r56: __stack_chk_fail
+ // r57: __stack_chk_fail
+ // r58: __stack_chk_fail
+ // r59: __stack_chk_fail
+ // r60: __stack_chk_fail
+ // r61: __stack_chk_fail
+ // r62: __stack_chk_fail
+ // r63: __stack_chk_fail
+ // r64: __stack_chk_fail
+ // r65: __stack_chk_fail
+ // r66: __stack_chk_fail
+ // r67: __stack_chk_fail
+ // r68: __stack_chk_fail
+ // r69: __stack_chk_fail
+ // r70: __stack_chk_fail
+ // r71: __stack_chk_fail
+ // r72: __stack_chk_fail
+ // r73: __stack_chk_fail
+ // r74: __stack_chk_fail
+ // r75: __stack_chk_fail
+ // r76: __stack_chk_fail
+ // r77: __stack_chk_fail
+ // r78: __stack_chk_fail
+ // r79: __stack_chk_fail
+ // r80: __stack_chk_fail
+ // r81: __stack_chk_fail
+ // r82: __stack_chk_fail
+ // r83: __stack_chk_fail
+ // r84: __stack_chk_fail
+}
diff --git a/src/test/assembly/x86_64-fortanix-unknown-sgx-lvi-inline-assembly.rs b/src/test/assembly/x86_64-fortanix-unknown-sgx-lvi-inline-assembly.rs
index 7e440169edb..c316379d5b1 100644
--- a/src/test/assembly/x86_64-fortanix-unknown-sgx-lvi-inline-assembly.rs
+++ b/src/test/assembly/x86_64-fortanix-unknown-sgx-lvi-inline-assembly.rs
@@ -4,11 +4,11 @@
// compile-flags: --crate-type staticlib
// only-x86_64-fortanix-unknown-sgx
-#![feature(asm)]
+use std::arch::asm;
#[no_mangle]
-pub extern fn get(ptr: *const u64) -> u64 {
- let value : u64;
+pub extern "C" fn get(ptr: *const u64) -> u64 {
+ let value: u64;
unsafe {
asm!(".start_inline_asm:",
"mov {}, [{}]",
@@ -26,11 +26,13 @@ pub extern fn get(ptr: *const u64) -> u64 {
// CHECK-NEXT: .end_inline_asm
#[no_mangle]
-pub extern fn myret() {
+pub extern "C" fn myret() {
unsafe {
- asm!(".start_myret_inline_asm:
- ret
- .end_myret_inline_asm:");
+ asm!(
+ ".start_myret_inline_asm:",
+ "ret",
+ ".end_myret_inline_asm:",
+ );
}
}
diff --git a/src/test/codegen/asm-clobber_abi.rs b/src/test/codegen/asm-clobber_abi.rs
index d589a7c6688..69e35270266 100644
--- a/src/test/codegen/asm-clobber_abi.rs
+++ b/src/test/codegen/asm-clobber_abi.rs
@@ -2,7 +2,8 @@
// only-x86_64
#![crate_type = "rlib"]
-#![feature(asm)]
+
+use std::arch::asm;
// CHECK-LABEL: @clobber_sysv64
// CHECK: ={ax},={cx},={dx},={si},={di},={r8},={r9},={r10},={r11},={xmm0},={xmm1},={xmm2},={xmm3},={xmm4},={xmm5},={xmm6},={xmm7},={xmm8},={xmm9},={xmm10},={xmm11},={xmm12},={xmm13},={xmm14},={xmm15},~{xmm16},~{xmm17},~{xmm18},~{xmm19},~{xmm20},~{xmm21},~{xmm22},~{xmm23},~{xmm24},~{xmm25},~{xmm26},~{xmm27},~{xmm28},~{xmm29},~{xmm30},~{xmm31},~{k1},~{k2},~{k3},~{k4},~{k5},~{k6},~{k7},~{st},~{st(1)},~{st(2)},~{st(3)},~{st(4)},~{st(5)},~{st(6)},~{st(7)},~{dirflag},~{fpsr},~{flags},~{memory}
diff --git a/src/test/codegen/asm-clobbers.rs b/src/test/codegen/asm-clobbers.rs
index 9d7c8b5f155..2ef10a2837d 100644
--- a/src/test/codegen/asm-clobbers.rs
+++ b/src/test/codegen/asm-clobbers.rs
@@ -2,7 +2,8 @@
// only-x86_64
#![crate_type = "rlib"]
-#![feature(asm)]
+
+use std::arch::asm;
// CHECK-LABEL: @x87_clobber
// CHECK: ~{st},~{st(1)},~{st(2)},~{st(3)},~{st(4)},~{st(5)},~{st(6)},~{st(7)}
diff --git a/src/test/codegen/asm-may_unwind.rs b/src/test/codegen/asm-may_unwind.rs
new file mode 100644
index 00000000000..3b34d79c3a9
--- /dev/null
+++ b/src/test/codegen/asm-may_unwind.rs
@@ -0,0 +1,27 @@
+// min-llvm-version: 13.0.0
+// compile-flags: -O
+// only-x86_64
+
+#![crate_type = "rlib"]
+#![feature(asm_unwind)]
+
+use std::arch::asm;
+
+#[no_mangle]
+pub extern "C" fn panicky() {}
+
+struct Foo;
+
+impl Drop for Foo {
+ fn drop(&mut self) {
+ println!();
+ }
+}
+
+// CHECK-LABEL: @may_unwind
+#[no_mangle]
+pub unsafe fn may_unwind() {
+ let _m = Foo;
+ // CHECK: invoke void asm sideeffect alignstack inteldialect unwind ""
+ asm!("", options(may_unwind));
+}
diff --git a/src/test/codegen/asm-multiple-options.rs b/src/test/codegen/asm-multiple-options.rs
index baf9f3e9bd1..1ae37d627d6 100644
--- a/src/test/codegen/asm-multiple-options.rs
+++ b/src/test/codegen/asm-multiple-options.rs
@@ -2,7 +2,8 @@
// only-x86_64
#![crate_type = "rlib"]
-#![feature(asm)]
+
+use std::arch::asm;
// CHECK-LABEL: @pure
// CHECK-NOT: asm
diff --git a/src/test/codegen/asm-options.rs b/src/test/codegen/asm-options.rs
index 28df0f9b852..963b60cfe35 100644
--- a/src/test/codegen/asm-options.rs
+++ b/src/test/codegen/asm-options.rs
@@ -2,7 +2,8 @@
// only-x86_64
#![crate_type = "rlib"]
-#![feature(asm)]
+
+use std::arch::asm;
// CHECK-LABEL: @pure
// CHECK-NOT: asm
diff --git a/src/test/codegen/asm-target-clobbers.rs b/src/test/codegen/asm-target-clobbers.rs
index f637cdcd234..8845cfbe767 100644
--- a/src/test/codegen/asm-target-clobbers.rs
+++ b/src/test/codegen/asm-target-clobbers.rs
@@ -3,7 +3,8 @@
// [avx512]compile-flags: -C target-feature=+avx512f
#![crate_type = "rlib"]
-#![feature(asm)]
+
+use std::arch::asm;
// CHECK-LABEL: @avx512_clobber
// base: call void asm sideeffect inteldialect "", "~{xmm31}"()
diff --git a/src/test/codegen/auxiliary/thread_local_aux.rs b/src/test/codegen/auxiliary/thread_local_aux.rs
index 29b5e3ca244..bebaa7754dd 100644
--- a/src/test/codegen/auxiliary/thread_local_aux.rs
+++ b/src/test/codegen/auxiliary/thread_local_aux.rs
@@ -1,5 +1,4 @@
#![crate_type = "lib"]
-#![feature(thread_local_const_init)]
use std::cell::Cell;
diff --git a/src/test/codegen/dst-vtable-align-nonzero.rs b/src/test/codegen/dst-vtable-align-nonzero.rs
new file mode 100644
index 00000000000..021c7b19f89
--- /dev/null
+++ b/src/test/codegen/dst-vtable-align-nonzero.rs
@@ -0,0 +1,45 @@
+// compile-flags: -O
+
+#![crate_type = "lib"]
+
+// This test checks that we annotate alignment loads from vtables with nonzero range metadata,
+// and that this allows LLVM to eliminate redundant `align >= 1` checks.
+
+pub trait Trait {
+ fn f(&self);
+}
+
+pub struct WrapperWithAlign1<T: ?Sized> { x: u8, y: T }
+
+pub struct WrapperWithAlign2<T: ?Sized> { x: u16, y: T }
+
+pub struct Struct<W: ?Sized> {
+ _field: i8,
+ dst: W,
+}
+
+// CHECK-LABEL: @eliminates_runtime_check_when_align_1
+#[no_mangle]
+pub fn eliminates_runtime_check_when_align_1(
+ x: &Struct<WrapperWithAlign1<dyn Trait>>
+) -> &WrapperWithAlign1<dyn Trait> {
+ // CHECK: load [[USIZE:i[0-9]+]], {{.+}} !range [[RANGE_META:![0-9]+]]
+ // CHECK-NOT: icmp
+ // CHECK-NOT: select
+ // CHECK: ret
+ &x.dst
+}
+
+// CHECK-LABEL: @does_not_eliminate_runtime_check_when_align_2
+#[no_mangle]
+pub fn does_not_eliminate_runtime_check_when_align_2(
+ x: &Struct<WrapperWithAlign2<dyn Trait>>
+) -> &WrapperWithAlign2<dyn Trait> {
+ // CHECK: [[X0:%[0-9]+]] = load [[USIZE]], {{.+}} !range [[RANGE_META]]
+ // CHECK: [[X1:%[0-9]+]] = icmp {{.+}} [[X0]]
+ // CHECK: [[X2:%[0-9]+]] = select {{.+}} [[X1]]
+ // CHECK: ret
+ &x.dst
+}
+
+// CHECK: [[RANGE_META]] = !{[[USIZE]] 1, [[USIZE]] 0}
diff --git a/src/test/codegen/global_asm.rs b/src/test/codegen/global_asm.rs
index 57d8aeb165b..fab84868fdf 100644
--- a/src/test/codegen/global_asm.rs
+++ b/src/test/codegen/global_asm.rs
@@ -39,18 +39,21 @@
// ignore-emscripten
// compile-flags: -C no-prepopulate-passes
-#![feature(global_asm)]
#![crate_type = "lib"]
+use std::arch::global_asm;
+
// CHECK-LABEL: foo
// CHECK: module asm
// this regex will capture the correct unconditional branch inst.
// CHECK: module asm "{{[[:space:]]+}}jmp baz"
-global_asm!(r#"
+global_asm!(
+ r#"
.global foo
foo:
jmp baz
-"#);
+"#
+);
extern "C" {
fn foo();
diff --git a/src/test/codegen/global_asm_include.rs b/src/test/codegen/global_asm_include.rs
index 44402619c43..02ee916458f 100644
--- a/src/test/codegen/global_asm_include.rs
+++ b/src/test/codegen/global_asm_include.rs
@@ -39,9 +39,10 @@
// ignore-emscripten
// compile-flags: -C no-prepopulate-passes
-#![feature(global_asm)]
#![crate_type = "lib"]
+use std::arch::global_asm;
+
// CHECK-LABEL: foo
// CHECK: module asm
// CHECK: module asm "{{[[:space:]]+}}jmp baz"
diff --git a/src/test/codegen/global_asm_x2.rs b/src/test/codegen/global_asm_x2.rs
index d632d0dde00..bdcf0ea843c 100644
--- a/src/test/codegen/global_asm_x2.rs
+++ b/src/test/codegen/global_asm_x2.rs
@@ -39,9 +39,10 @@
// ignore-emscripten
// compile-flags: -C no-prepopulate-passes
-#![feature(global_asm)]
#![crate_type = "lib"]
-#[no_std]
+#![no_std]
+
+use core::arch::global_asm;
// CHECK-LABEL: foo
// CHECK: module asm
@@ -49,11 +50,13 @@
// any other global_asm will be appended to this first block, so:
// CHECK-LABEL: bar
// CHECK: module asm "{{[[:space:]]+}}jmp quux"
-global_asm!(r#"
+global_asm!(
+ r#"
.global foo
foo:
jmp baz
-"#);
+"#
+);
extern "C" {
fn foo();
@@ -64,11 +67,13 @@ extern "C" {
pub unsafe extern "C" fn baz() {}
// no checks here; this has been appended to the first occurrence
-global_asm!(r#"
+global_asm!(
+ r#"
.global bar
bar:
jmp quux
-"#);
+"#
+);
extern "C" {
fn bar();
diff --git a/src/test/codegen/merge-functions.rs b/src/test/codegen/merge-functions.rs
new file mode 100644
index 00000000000..5eefc0f98f1
--- /dev/null
+++ b/src/test/codegen/merge-functions.rs
@@ -0,0 +1,14 @@
+// compile-flags: -O
+#![crate_type = "lib"]
+
+// CHECK: @func2 = {{.*}}alias{{.*}}@func1
+
+#[no_mangle]
+pub fn func1(c: char) -> bool {
+ c == 's' || c == 'm' || c == 'h' || c == 'd' || c == 'w'
+}
+
+#[no_mangle]
+pub fn func2(c: char) -> bool {
+ matches!(c, 's' | 'm' | 'h' | 'd' | 'w')
+}
diff --git a/src/test/codegen/naked-noinline.rs b/src/test/codegen/naked-noinline.rs
index d576a53826c..e34ccf5c5fe 100644
--- a/src/test/codegen/naked-noinline.rs
+++ b/src/test/codegen/naked-noinline.rs
@@ -3,28 +3,29 @@
// needs-asm-support
// ignore-wasm32
#![crate_type = "lib"]
-#![feature(asm)]
#![feature(naked_functions)]
+use std::arch::asm;
+
#[inline(always)]
#[naked]
#[no_mangle]
pub unsafe extern "C" fn f() {
-// Check that f has naked and noinline attributes.
-//
-// CHECK: define void @f() unnamed_addr [[ATTR:#[0-9]+]]
-// CHECK-NEXT: start:
-// CHECK-NEXT: call void asm
+ // Check that f has naked and noinline attributes.
+ //
+ // CHECK: define void @f() unnamed_addr [[ATTR:#[0-9]+]]
+ // CHECK-NEXT: start:
+ // CHECK-NEXT: call void asm
asm!("", options(noreturn));
}
#[no_mangle]
pub unsafe fn g() {
-// Check that call to f is not inlined.
-//
-// CHECK-LABEL: define void @g()
-// CHECK-NEXT: start:
-// CHECK-NEXT: call void @f()
+ // Check that call to f is not inlined.
+ //
+ // CHECK-LABEL: define void @g()
+ // CHECK-NEXT: start:
+ // CHECK-NEXT: call void @f()
f();
}
diff --git a/src/test/codegen/slice-ref-equality.rs b/src/test/codegen/slice-ref-equality.rs
index 1f99ac7342b..c06554ecdec 100644
--- a/src/test/codegen/slice-ref-equality.rs
+++ b/src/test/codegen/slice-ref-equality.rs
@@ -4,18 +4,31 @@
// #71602 reported a simple array comparison just generating a loop.
// This was originally fixed by ensuring it generates a single bcmp,
-// but we now generate it as a load instead. `is_zero_slice` was
+// but we now generate it as a load+icmp instead. `is_zero_slice` was
// tweaked to still test the case of comparison against a slice,
// and `is_zero_array` tests the new array-specific behaviour.
+// The optimization was then extended to short slice-to-array comparisons,
+// so the first test here now has a long slice to still get the bcmp.
-// CHECK-LABEL: @is_zero_slice
+// CHECK-LABEL: @is_zero_slice_long
#[no_mangle]
-pub fn is_zero_slice(data: &[u8; 4]) -> bool {
+pub fn is_zero_slice_long(data: &[u8; 456]) -> bool {
// CHECK: :
// CHECK-NEXT: %{{.+}} = getelementptr {{.+}}
// CHECK-NEXT: %[[BCMP:.+]] = tail call i32 @{{bcmp|memcmp}}({{.+}})
// CHECK-NEXT: %[[EQ:.+]] = icmp eq i32 %[[BCMP]], 0
// CHECK-NEXT: ret i1 %[[EQ]]
+ &data[..] == [0; 456]
+}
+
+// CHECK-LABEL: @is_zero_slice_short
+#[no_mangle]
+pub fn is_zero_slice_short(data: &[u8; 4]) -> bool {
+ // CHECK: :
+ // CHECK-NEXT: %[[PTR:.+]] = bitcast [4 x i8]* {{.+}} to i32*
+ // CHECK-NEXT: %[[LOAD:.+]] = load i32, i32* %[[PTR]], align 1
+ // CHECK-NEXT: %[[EQ:.+]] = icmp eq i32 %[[LOAD]], 0
+ // CHECK-NEXT: ret i1 %[[EQ]]
&data[..] == [0; 4]
}
diff --git a/src/test/codegen/sparc-struct-abi.rs b/src/test/codegen/sparc-struct-abi.rs
index f228d7c5500..b531dba4607 100644
--- a/src/test/codegen/sparc-struct-abi.rs
+++ b/src/test/codegen/sparc-struct-abi.rs
@@ -1,5 +1,5 @@
// Checks that we correctly codegen extern "C" functions returning structs.
-// See issue #52638.
+// See issues #52638 and #86163.
// compile-flags: -O --target=sparc64-unknown-linux-gnu --crate-type=rlib
// needs-llvm-components: sparc
@@ -25,3 +25,59 @@ pub struct Bool {
pub extern "C" fn structbool() -> Bool {
Bool { b: true }
}
+
+
+#[repr(C)]
+pub struct BoolFloat {
+ b: bool,
+ f: f32,
+}
+
+// CHECK: define inreg { i32, float } @structboolfloat()
+// CHECK-NEXT: start:
+// CHECK-NEXT: ret { i32, float } { i32 16777216, float 0x40091EB860000000 }
+#[no_mangle]
+pub extern "C" fn structboolfloat() -> BoolFloat {
+ BoolFloat { b: true, f: 3.14 }
+}
+
+// CHECK: define void @structboolfloat_input({ i32, float } inreg %0)
+// CHECK-NEXT: start:
+#[no_mangle]
+pub extern "C" fn structboolfloat_input(a: BoolFloat) { }
+
+
+#[repr(C)]
+pub struct ShortDouble {
+ s: i16,
+ d: f64,
+}
+
+// CHECK: define { i64, double } @structshortdouble()
+// CHECK-NEXT: start:
+// CHECK-NEXT: ret { i64, double } { i64 34621422135410688, double 3.140000e+00 }
+#[no_mangle]
+pub extern "C" fn structshortdouble() -> ShortDouble {
+ ShortDouble { s: 123, d: 3.14 }
+}
+
+// CHECK: define void @structshortdouble_input({ i64, double } %0)
+// CHECK-NEXT: start:
+#[no_mangle]
+pub extern "C" fn structshortdouble_input(a: ShortDouble) { }
+
+
+#[repr(C)]
+pub struct FloatLongFloat {
+ f: f32,
+ i: i64,
+ g: f32,
+}
+
+// CHECK: define inreg { float, i32, i64, float, i32 } @structfloatlongfloat()
+// CHECK-NEXT: start:
+// CHECK-NEXT: ret { float, i32, i64, float, i32 } { float 0x3FB99999A0000000, i32 undef, i64 123, float 0x40091EB860000000, i32 undef }
+#[no_mangle]
+pub extern "C" fn structfloatlongfloat() -> FloatLongFloat {
+ FloatLongFloat { f: 0.1, i: 123, g: 3.14 }
+}
diff --git a/src/test/codegen/stack-protector.rs b/src/test/codegen/stack-protector.rs
new file mode 100644
index 00000000000..a24e6f1e4f1
--- /dev/null
+++ b/src/test/codegen/stack-protector.rs
@@ -0,0 +1,34 @@
+// revisions: all strong basic none
+// ignore-nvptx64 stack protector not supported
+// [all] compile-flags: -Z stack-protector=all
+// [strong] compile-flags: -Z stack-protector=strong
+// [basic] compile-flags: -Z stack-protector=basic
+
+#![crate_type = "lib"]
+
+#[no_mangle]
+pub fn foo() {
+ // CHECK: @foo() unnamed_addr #0
+
+ // all-NOT: attributes #0 = { {{.*}} sspstrong {{.*}} }
+ // all-NOT: attributes #0 = { {{.*}} ssp {{.*}} }
+ // all: attributes #0 = { {{.*}} sspreq {{.*}} }
+ // all-NOT: attributes #0 = { {{.*}} sspstrong {{.*}} }
+ // all-NOT: attributes #0 = { {{.*}} ssp {{.*}} }
+
+ // strong-NOT: attributes #0 = { {{.*}} sspreq {{.*}} }
+ // strong-NOT: attributes #0 = { {{.*}} ssp {{.*}} }
+ // strong: attributes #0 = { {{.*}} sspstrong {{.*}} }
+ // strong-NOT: attributes #0 = { {{.*}} sspreq {{.*}} }
+ // strong-NOT: attributes #0 = { {{.*}} ssp {{.*}} }
+
+ // basic-NOT: attributes #0 = { {{.*}} sspreq {{.*}} }
+ // basic-NOT: attributes #0 = { {{.*}} sspstrong {{.*}} }
+ // basic: attributes #0 = { {{.*}} ssp {{.*}} }
+ // basic-NOT: attributes #0 = { {{.*}} sspreq {{.*}} }
+ // basic-NOT: attributes #0 = { {{.*}} sspstrong {{.*}} }
+
+ // none-NOT: attributes #0 = { {{.*}} sspreq {{.*}} }
+ // none-NOT: attributes #0 = { {{.*}} sspstrong {{.*}} }
+ // none-NOT: attributes #0 = { {{.*}} ssp {{.*}} }
+}
diff --git a/src/test/codegen/thread-local.rs b/src/test/codegen/thread-local.rs
index f14368e3990..5ac30d949fa 100644
--- a/src/test/codegen/thread-local.rs
+++ b/src/test/codegen/thread-local.rs
@@ -6,7 +6,6 @@
// ignore-android does not use #[thread_local]
#![crate_type = "lib"]
-#![feature(thread_local_const_init)]
extern crate thread_local_aux as aux;
diff --git a/src/test/debuginfo/rc_arc.rs b/src/test/debuginfo/rc_arc.rs
index 144a746062d..8470ace24b8 100644
--- a/src/test/debuginfo/rc_arc.rs
+++ b/src/test/debuginfo/rc_arc.rs
@@ -1,4 +1,4 @@
-// pretty-printers are not loaded
+// ignore-windows-gnu: pretty-printers are not loaded
// compile-flags:-g
// min-gdb-version: 8.1
diff --git a/src/test/incremental/const-generics/hash-tyvid-regression-2.rs b/src/test/incremental/const-generics/hash-tyvid-regression-2.rs
index bba22bf5dc1..5cdd43cd782 100644
--- a/src/test/incremental/const-generics/hash-tyvid-regression-2.rs
+++ b/src/test/incremental/const-generics/hash-tyvid-regression-2.rs
@@ -1,5 +1,5 @@
// revisions: cfail
-#![feature(generic_const_exprs, adt_const_params, const_generics_defaults)]
+#![feature(generic_const_exprs, adt_const_params)]
#![allow(incomplete_features)]
// regression test for #77650
struct C<T, const N: core::num::NonZeroUsize>([T; N.get()])
diff --git a/src/test/incremental/issue-72386.rs b/src/test/incremental/issue-72386.rs
index 3dc7f502a59..be624faad04 100644
--- a/src/test/incremental/issue-72386.rs
+++ b/src/test/incremental/issue-72386.rs
@@ -4,13 +4,11 @@
// Checks that we don't ICE when switching to an invalid register
// and back again
-#![feature(asm)]
+use std::arch::asm;
#[cfg(any(rpass1, rpass3))]
fn main() {
- unsafe {
- asm!("nop")
- }
+ unsafe { asm!("nop") }
}
#[cfg(cfail1)]
diff --git a/src/test/incremental/issue-85360-eval-obligation-ice.rs b/src/test/incremental/issue-85360-eval-obligation-ice.rs
new file mode 100644
index 00000000000..1796c9d197c
--- /dev/null
+++ b/src/test/incremental/issue-85360-eval-obligation-ice.rs
@@ -0,0 +1,118 @@
+// revisions:cfail1 cfail2
+//[cfail1] compile-flags: --crate-type=lib --edition=2021 -Zassert-incr-state=not-loaded
+//[cfail2] compile-flags: --crate-type=lib --edition=2021 -Zassert-incr-state=loaded
+// build-pass
+
+use core::any::Any;
+use core::marker::PhantomData;
+
+struct DerefWrap<T>(T);
+
+impl<T> core::ops::Deref for DerefWrap<T> {
+ type Target = T;
+ fn deref(&self) -> &Self::Target {
+ &self.0
+ }
+}
+
+struct Storage<T, D> {
+ phantom: PhantomData<(T, D)>,
+}
+
+type ReadStorage<T> = Storage<T, DerefWrap<MaskedStorage<T>>>;
+
+pub trait Component {
+ type Storage;
+}
+
+struct VecStorage;
+
+struct Pos;
+
+impl Component for Pos {
+ type Storage = VecStorage;
+}
+
+struct GenericComp<T> {
+ _t: T,
+}
+
+impl<T: 'static> Component for GenericComp<T> {
+ type Storage = VecStorage;
+}
+struct ReadData {
+ pos_interpdata: ReadStorage<GenericComp<Pos>>,
+}
+
+trait System {
+ type SystemData;
+
+ fn run(data: Self::SystemData, any: Box<dyn Any>);
+}
+
+struct Sys;
+
+impl System for Sys {
+ type SystemData = (ReadData, ReadStorage<Pos>);
+
+ fn run((data, pos): Self::SystemData, any: Box<dyn Any>) {
+ <ReadStorage<GenericComp<Pos>> as SystemData>::setup(any);
+
+ ParJoin::par_join((&pos, &data.pos_interpdata));
+ }
+}
+
+trait ParJoin {
+ fn par_join(self)
+ where
+ Self: Sized,
+ {
+ }
+}
+
+impl<'a, T, D> ParJoin for &'a Storage<T, D>
+where
+ T: Component,
+ D: core::ops::Deref<Target = MaskedStorage<T>>,
+ T::Storage: Sync,
+{
+}
+
+impl<A, B> ParJoin for (A, B)
+where
+ A: ParJoin,
+ B: ParJoin,
+{
+}
+
+pub trait SystemData {
+ fn setup(any: Box<dyn Any>);
+}
+
+impl<T: 'static> SystemData for ReadStorage<T>
+where
+ T: Component,
+{
+ fn setup(any: Box<dyn Any>) {
+ let storage: &MaskedStorage<T> = any.downcast_ref().unwrap();
+
+ <dyn Any as CastFrom<MaskedStorage<T>>>::cast(&storage);
+ }
+}
+
+pub struct MaskedStorage<T: Component> {
+ _inner: T::Storage,
+}
+
+pub unsafe trait CastFrom<T> {
+ fn cast(t: &T) -> &Self;
+}
+
+unsafe impl<T> CastFrom<T> for dyn Any
+where
+ T: Any + 'static,
+{
+ fn cast(t: &T) -> &Self {
+ t
+ }
+}
diff --git a/src/test/mir-opt/const_promotion_extern_static.BAR.PromoteTemps.diff b/src/test/mir-opt/const_promotion_extern_static.BAR.PromoteTemps.diff
index bdd62f1029f..4ae783a7f46 100644
--- a/src/test/mir-opt/const_promotion_extern_static.BAR.PromoteTemps.diff
+++ b/src/test/mir-opt/const_promotion_extern_static.BAR.PromoteTemps.diff
@@ -30,7 +30,7 @@
- _3 = [move _4]; // scope 0 at $DIR/const-promotion-extern-static.rs:9:31: 9:35
- _2 = &_3; // scope 0 at $DIR/const-promotion-extern-static.rs:9:31: 9:44
+ // + span: $DIR/const-promotion-extern-static.rs:9:31: 9:44
-+ // + literal: Const { ty: &[&i32; 1], val: Unevaluated(Unevaluated { def: WithOptConstParam { did: DefId(0:6 ~ const_promotion_extern_static[55e6]::BAR), const_param_did: None }, substs_: Some([]), promoted: Some(promoted[0]) }) }
++ // + literal: Const { ty: &[&i32; 1], val: Unevaluated(Unevaluated { def: WithOptConstParam { did: DefId(0:6 ~ const_promotion_extern_static[HASH]::BAR), const_param_did: None }, substs_: Some([]), promoted: Some(promoted[0]) }) }
+ _2 = &(*_6); // scope 0 at $DIR/const-promotion-extern-static.rs:9:31: 9:44
_1 = move _2 as &[&i32] (Pointer(Unsize)); // scope 0 at $DIR/const-promotion-extern-static.rs:9:31: 9:44
- StorageDead(_4); // scope 0 at $DIR/const-promotion-extern-static.rs:9:34: 9:35
diff --git a/src/test/mir-opt/const_promotion_extern_static.FOO.PromoteTemps.diff b/src/test/mir-opt/const_promotion_extern_static.FOO.PromoteTemps.diff
index 94b337806af..705c2ed06b3 100644
--- a/src/test/mir-opt/const_promotion_extern_static.FOO.PromoteTemps.diff
+++ b/src/test/mir-opt/const_promotion_extern_static.FOO.PromoteTemps.diff
@@ -32,7 +32,7 @@
- _3 = [move _4]; // scope 0 at $DIR/const-promotion-extern-static.rs:13:31: 13:46
- _2 = &_3; // scope 0 at $DIR/const-promotion-extern-static.rs:13:31: 13:55
+ // + span: $DIR/const-promotion-extern-static.rs:13:31: 13:55
-+ // + literal: Const { ty: &[&i32; 1], val: Unevaluated(Unevaluated { def: WithOptConstParam { did: DefId(0:7 ~ const_promotion_extern_static[55e6]::FOO), const_param_did: None }, substs_: Some([]), promoted: Some(promoted[0]) }) }
++ // + literal: Const { ty: &[&i32; 1], val: Unevaluated(Unevaluated { def: WithOptConstParam { did: DefId(0:7 ~ const_promotion_extern_static[HASH]::FOO), const_param_did: None }, substs_: Some([]), promoted: Some(promoted[0]) }) }
+ _2 = &(*_6); // scope 0 at $DIR/const-promotion-extern-static.rs:13:31: 13:55
_1 = move _2 as &[&i32] (Pointer(Unsize)); // scope 0 at $DIR/const-promotion-extern-static.rs:13:31: 13:55
- StorageDead(_4); // scope 0 at $DIR/const-promotion-extern-static.rs:13:45: 13:46
diff --git a/src/test/mir-opt/const_prop/bad_op_unsafe_oob_for_slices.main.ConstProp.32bit.diff b/src/test/mir-opt/const_prop/bad_op_unsafe_oob_for_slices.main.ConstProp.32bit.diff
index f8fd2cc9b0d..7fb954b8356 100644
--- a/src/test/mir-opt/const_prop/bad_op_unsafe_oob_for_slices.main.ConstProp.32bit.diff
+++ b/src/test/mir-opt/const_prop/bad_op_unsafe_oob_for_slices.main.ConstProp.32bit.diff
@@ -31,7 +31,7 @@
// + val: Unevaluated(main, [], Some(promoted[0]))
// mir::Constant
// + span: $DIR/bad_op_unsafe_oob_for_slices.rs:5:25: 5:35
- // + literal: Const { ty: &[i32; 3], val: Unevaluated(Unevaluated { def: WithOptConstParam { did: DefId(0:3 ~ bad_op_unsafe_oob_for_slices[8240]::main), const_param_did: None }, substs_: Some([]), promoted: Some(promoted[0]) }) }
+ // + literal: Const { ty: &[i32; 3], val: Unevaluated(Unevaluated { def: WithOptConstParam { did: DefId(0:3 ~ bad_op_unsafe_oob_for_slices[HASH]::main), const_param_did: None }, substs_: Some([]), promoted: Some(promoted[0]) }) }
_3 = _9; // scope 0 at $DIR/bad_op_unsafe_oob_for_slices.rs:5:25: 5:35
_2 = &raw const (*_3); // scope 0 at $DIR/bad_op_unsafe_oob_for_slices.rs:5:25: 5:35
_1 = move _2 as *const [i32] (Pointer(Unsize)); // scope 0 at $DIR/bad_op_unsafe_oob_for_slices.rs:5:25: 5:35
diff --git a/src/test/mir-opt/const_prop/bad_op_unsafe_oob_for_slices.main.ConstProp.64bit.diff b/src/test/mir-opt/const_prop/bad_op_unsafe_oob_for_slices.main.ConstProp.64bit.diff
index f8fd2cc9b0d..7fb954b8356 100644
--- a/src/test/mir-opt/const_prop/bad_op_unsafe_oob_for_slices.main.ConstProp.64bit.diff
+++ b/src/test/mir-opt/const_prop/bad_op_unsafe_oob_for_slices.main.ConstProp.64bit.diff
@@ -31,7 +31,7 @@
// + val: Unevaluated(main, [], Some(promoted[0]))
// mir::Constant
// + span: $DIR/bad_op_unsafe_oob_for_slices.rs:5:25: 5:35
- // + literal: Const { ty: &[i32; 3], val: Unevaluated(Unevaluated { def: WithOptConstParam { did: DefId(0:3 ~ bad_op_unsafe_oob_for_slices[8240]::main), const_param_did: None }, substs_: Some([]), promoted: Some(promoted[0]) }) }
+ // + literal: Const { ty: &[i32; 3], val: Unevaluated(Unevaluated { def: WithOptConstParam { did: DefId(0:3 ~ bad_op_unsafe_oob_for_slices[HASH]::main), const_param_did: None }, substs_: Some([]), promoted: Some(promoted[0]) }) }
_3 = _9; // scope 0 at $DIR/bad_op_unsafe_oob_for_slices.rs:5:25: 5:35
_2 = &raw const (*_3); // scope 0 at $DIR/bad_op_unsafe_oob_for_slices.rs:5:25: 5:35
_1 = move _2 as *const [i32] (Pointer(Unsize)); // scope 0 at $DIR/bad_op_unsafe_oob_for_slices.rs:5:25: 5:35
diff --git a/src/test/mir-opt/const_prop/const_prop_fails_gracefully.main.ConstProp.diff b/src/test/mir-opt/const_prop/const_prop_fails_gracefully.main.ConstProp.diff
index 49237934223..827a86c2376 100644
--- a/src/test/mir-opt/const_prop/const_prop_fails_gracefully.main.ConstProp.diff
+++ b/src/test/mir-opt/const_prop/const_prop_fails_gracefully.main.ConstProp.diff
@@ -22,7 +22,7 @@
// + val: Unevaluated(FOO, [], None)
// mir::Constant
// + span: $DIR/const_prop_fails_gracefully.rs:7:13: 7:16
- // + literal: Const { ty: &i32, val: Unevaluated(Unevaluated { def: WithOptConstParam { did: DefId(0:5 ~ const_prop_fails_gracefully[2706]::main::FOO), const_param_did: None }, substs_: Some([]), promoted: None }) }
+ // + literal: Const { ty: &i32, val: Unevaluated(Unevaluated { def: WithOptConstParam { did: DefId(0:5 ~ const_prop_fails_gracefully[HASH]::main::FOO), const_param_did: None }, substs_: Some([]), promoted: None }) }
_2 = &raw const (*_3); // scope 0 at $DIR/const_prop_fails_gracefully.rs:7:13: 7:16
_1 = move _2 as usize (Misc); // scope 0 at $DIR/const_prop_fails_gracefully.rs:7:13: 7:39
StorageDead(_2); // scope 0 at $DIR/const_prop_fails_gracefully.rs:7:38: 7:39
diff --git a/src/test/mir-opt/const_prop/ref_deref.main.ConstProp.diff b/src/test/mir-opt/const_prop/ref_deref.main.ConstProp.diff
index 54acae43abc..496b9718c6a 100644
--- a/src/test/mir-opt/const_prop/ref_deref.main.ConstProp.diff
+++ b/src/test/mir-opt/const_prop/ref_deref.main.ConstProp.diff
@@ -17,7 +17,7 @@
// + val: Unevaluated(main, [], Some(promoted[0]))
// mir::Constant
// + span: $DIR/ref_deref.rs:5:6: 5:10
- // + literal: Const { ty: &i32, val: Unevaluated(Unevaluated { def: WithOptConstParam { did: DefId(0:3 ~ ref_deref[cb9b]::main), const_param_did: None }, substs_: Some([]), promoted: Some(promoted[0]) }) }
+ // + literal: Const { ty: &i32, val: Unevaluated(Unevaluated { def: WithOptConstParam { did: DefId(0:3 ~ ref_deref[HASH]::main), const_param_did: None }, substs_: Some([]), promoted: Some(promoted[0]) }) }
_2 = _4; // scope 0 at $DIR/ref_deref.rs:5:6: 5:10
- _1 = (*_2); // scope 0 at $DIR/ref_deref.rs:5:5: 5:10
+ _1 = const 4_i32; // scope 0 at $DIR/ref_deref.rs:5:5: 5:10
diff --git a/src/test/mir-opt/const_prop/ref_deref.main.PromoteTemps.diff b/src/test/mir-opt/const_prop/ref_deref.main.PromoteTemps.diff
index 3b5c86942a7..07c3b0cd58f 100644
--- a/src/test/mir-opt/const_prop/ref_deref.main.PromoteTemps.diff
+++ b/src/test/mir-opt/const_prop/ref_deref.main.PromoteTemps.diff
@@ -20,7 +20,7 @@
+ // + val: Unevaluated(main, [], Some(promoted[0]))
+ // mir::Constant
+ // + span: $DIR/ref_deref.rs:5:6: 5:10
-+ // + literal: Const { ty: &i32, val: Unevaluated(Unevaluated { def: WithOptConstParam { did: DefId(0:3 ~ ref_deref[cb9b]::main), const_param_did: None }, substs_: Some([]), promoted: Some(promoted[0]) }) }
++ // + literal: Const { ty: &i32, val: Unevaluated(Unevaluated { def: WithOptConstParam { did: DefId(0:3 ~ ref_deref[HASH]::main), const_param_did: None }, substs_: Some([]), promoted: Some(promoted[0]) }) }
+ _2 = &(*_4); // scope 0 at $DIR/ref_deref.rs:5:6: 5:10
_1 = (*_2); // scope 0 at $DIR/ref_deref.rs:5:5: 5:10
- StorageDead(_3); // scope 0 at $DIR/ref_deref.rs:5:10: 5:11
diff --git a/src/test/mir-opt/const_prop/ref_deref_project.main.ConstProp.diff b/src/test/mir-opt/const_prop/ref_deref_project.main.ConstProp.diff
index 8590a98491b..2545b89c1d3 100644
--- a/src/test/mir-opt/const_prop/ref_deref_project.main.ConstProp.diff
+++ b/src/test/mir-opt/const_prop/ref_deref_project.main.ConstProp.diff
@@ -17,7 +17,7 @@
// + val: Unevaluated(main, [], Some(promoted[0]))
// mir::Constant
// + span: $DIR/ref_deref_project.rs:5:6: 5:17
- // + literal: Const { ty: &(i32, i32), val: Unevaluated(Unevaluated { def: WithOptConstParam { did: DefId(0:3 ~ ref_deref_project[e8c3]::main), const_param_did: None }, substs_: Some([]), promoted: Some(promoted[0]) }) }
+ // + literal: Const { ty: &(i32, i32), val: Unevaluated(Unevaluated { def: WithOptConstParam { did: DefId(0:3 ~ ref_deref_project[HASH]::main), const_param_did: None }, substs_: Some([]), promoted: Some(promoted[0]) }) }
_2 = &((*_4).1: i32); // scope 0 at $DIR/ref_deref_project.rs:5:6: 5:17
_1 = (*_2); // scope 0 at $DIR/ref_deref_project.rs:5:5: 5:17
StorageDead(_2); // scope 0 at $DIR/ref_deref_project.rs:5:17: 5:18
diff --git a/src/test/mir-opt/const_prop/ref_deref_project.main.PromoteTemps.diff b/src/test/mir-opt/const_prop/ref_deref_project.main.PromoteTemps.diff
index 4e10ae17934..f728d55ba6e 100644
--- a/src/test/mir-opt/const_prop/ref_deref_project.main.PromoteTemps.diff
+++ b/src/test/mir-opt/const_prop/ref_deref_project.main.PromoteTemps.diff
@@ -20,7 +20,7 @@
+ // + val: Unevaluated(main, [], Some(promoted[0]))
+ // mir::Constant
+ // + span: $DIR/ref_deref_project.rs:5:6: 5:17
-+ // + literal: Const { ty: &(i32, i32), val: Unevaluated(Unevaluated { def: WithOptConstParam { did: DefId(0:3 ~ ref_deref_project[e8c3]::main), const_param_did: None }, substs_: Some([]), promoted: Some(promoted[0]) }) }
++ // + literal: Const { ty: &(i32, i32), val: Unevaluated(Unevaluated { def: WithOptConstParam { did: DefId(0:3 ~ ref_deref_project[HASH]::main), const_param_did: None }, substs_: Some([]), promoted: Some(promoted[0]) }) }
+ _2 = &((*_4).1: i32); // scope 0 at $DIR/ref_deref_project.rs:5:6: 5:17
_1 = (*_2); // scope 0 at $DIR/ref_deref_project.rs:5:5: 5:17
- StorageDead(_3); // scope 0 at $DIR/ref_deref_project.rs:5:17: 5:18
diff --git a/src/test/mir-opt/const_prop/slice_len.main.ConstProp.32bit.diff b/src/test/mir-opt/const_prop/slice_len.main.ConstProp.32bit.diff
index dfb5b98d5c9..12c77e0b042 100644
--- a/src/test/mir-opt/const_prop/slice_len.main.ConstProp.32bit.diff
+++ b/src/test/mir-opt/const_prop/slice_len.main.ConstProp.32bit.diff
@@ -25,7 +25,7 @@
// + val: Unevaluated(main, [], Some(promoted[0]))
// mir::Constant
// + span: $DIR/slice_len.rs:5:6: 5:19
- // + literal: Const { ty: &[u32; 3], val: Unevaluated(Unevaluated { def: WithOptConstParam { did: DefId(0:3 ~ slice_len[6547]::main), const_param_did: None }, substs_: Some([]), promoted: Some(promoted[0]) }) }
+ // + literal: Const { ty: &[u32; 3], val: Unevaluated(Unevaluated { def: WithOptConstParam { did: DefId(0:3 ~ slice_len[HASH]::main), const_param_did: None }, substs_: Some([]), promoted: Some(promoted[0]) }) }
_4 = _9; // scope 0 at $DIR/slice_len.rs:5:6: 5:19
_3 = _4; // scope 0 at $DIR/slice_len.rs:5:6: 5:19
StorageLive(_10); // scope 0 at $DIR/slice_len.rs:5:6: 5:19
diff --git a/src/test/mir-opt/const_prop/slice_len.main.ConstProp.64bit.diff b/src/test/mir-opt/const_prop/slice_len.main.ConstProp.64bit.diff
index dfb5b98d5c9..12c77e0b042 100644
--- a/src/test/mir-opt/const_prop/slice_len.main.ConstProp.64bit.diff
+++ b/src/test/mir-opt/const_prop/slice_len.main.ConstProp.64bit.diff
@@ -25,7 +25,7 @@
// + val: Unevaluated(main, [], Some(promoted[0]))
// mir::Constant
// + span: $DIR/slice_len.rs:5:6: 5:19
- // + literal: Const { ty: &[u32; 3], val: Unevaluated(Unevaluated { def: WithOptConstParam { did: DefId(0:3 ~ slice_len[6547]::main), const_param_did: None }, substs_: Some([]), promoted: Some(promoted[0]) }) }
+ // + literal: Const { ty: &[u32; 3], val: Unevaluated(Unevaluated { def: WithOptConstParam { did: DefId(0:3 ~ slice_len[HASH]::main), const_param_did: None }, substs_: Some([]), promoted: Some(promoted[0]) }) }
_4 = _9; // scope 0 at $DIR/slice_len.rs:5:6: 5:19
_3 = _4; // scope 0 at $DIR/slice_len.rs:5:6: 5:19
StorageLive(_10); // scope 0 at $DIR/slice_len.rs:5:6: 5:19
diff --git a/src/test/mir-opt/const_prop/switch_int.main.SimplifyBranches-after-const-prop.diff b/src/test/mir-opt/const_prop/switch_int.main.SimplifyConstCondition-after-const-prop.diff
index 6a5b88c4a7f..f2b02551146 100644
--- a/src/test/mir-opt/const_prop/switch_int.main.SimplifyBranches-after-const-prop.diff
+++ b/src/test/mir-opt/const_prop/switch_int.main.SimplifyConstCondition-after-const-prop.diff
@@ -1,5 +1,5 @@
-- // MIR for `main` before SimplifyBranches-after-const-prop
-+ // MIR for `main` after SimplifyBranches-after-const-prop
+- // MIR for `main` before SimplifyConstCondition-after-const-prop
++ // MIR for `main` after SimplifyConstCondition-after-const-prop
fn main() -> () {
let mut _0: (); // return place in scope 0 at $DIR/switch_int.rs:6:11: 6:11
diff --git a/src/test/mir-opt/const_prop/switch_int.rs b/src/test/mir-opt/const_prop/switch_int.rs
index 9e7c7340448..d7319eca18e 100644
--- a/src/test/mir-opt/const_prop/switch_int.rs
+++ b/src/test/mir-opt/const_prop/switch_int.rs
@@ -2,7 +2,7 @@
fn foo(_: i32) { }
// EMIT_MIR switch_int.main.ConstProp.diff
-// EMIT_MIR switch_int.main.SimplifyBranches-after-const-prop.diff
+// EMIT_MIR switch_int.main.SimplifyConstCondition-after-const-prop.diff
fn main() {
match 1 {
1 => foo(0),
diff --git a/src/test/mir-opt/early_otherwise_branch_68867.rs b/src/test/mir-opt/early_otherwise_branch_68867.rs
index 02221c4cf4a..ca298e9211d 100644
--- a/src/test/mir-opt/early_otherwise_branch_68867.rs
+++ b/src/test/mir-opt/early_otherwise_branch_68867.rs
@@ -11,7 +11,7 @@ pub enum ViewportPercentageLength {
}
// EMIT_MIR early_otherwise_branch_68867.try_sum.EarlyOtherwiseBranch.diff
-// EMIT_MIR early_otherwise_branch_68867.try_sum EarlyOtherwiseBranch.before SimplifyBranches-final.after
+// EMIT_MIR early_otherwise_branch_68867.try_sum EarlyOtherwiseBranch.before SimplifyConstCondition-final.after
#[no_mangle]
pub extern "C" fn try_sum(
x: &ViewportPercentageLength,
diff --git a/src/test/mir-opt/early_otherwise_branch_68867.try_sum.EarlyOtherwiseBranch.before-SimplifyBranches-final.after.diff b/src/test/mir-opt/early_otherwise_branch_68867.try_sum.EarlyOtherwiseBranch.before-SimplifyConstCondition-final.after.diff
index f23d035545e..44294030439 100644
--- a/src/test/mir-opt/early_otherwise_branch_68867.try_sum.EarlyOtherwiseBranch.before-SimplifyBranches-final.after.diff
+++ b/src/test/mir-opt/early_otherwise_branch_68867.try_sum.EarlyOtherwiseBranch.before-SimplifyConstCondition-final.after.diff
@@ -1,5 +1,5 @@
- // MIR for `try_sum` before EarlyOtherwiseBranch
-+ // MIR for `try_sum` after SimplifyBranches-final
++ // MIR for `try_sum` after SimplifyConstCondition-final
fn try_sum(_1: &ViewportPercentageLength, _2: &ViewportPercentageLength) -> Result<ViewportPercentageLength, ()> {
debug x => _1; // in scope 0 at $DIR/early_otherwise_branch_68867.rs:17:5: 17:6
diff --git a/src/test/mir-opt/early_otherwise_branch_noopt.rs b/src/test/mir-opt/early_otherwise_branch_noopt.rs
index aa9ddf485b5..d04e2a0429d 100644
--- a/src/test/mir-opt/early_otherwise_branch_noopt.rs
+++ b/src/test/mir-opt/early_otherwise_branch_noopt.rs
@@ -1,4 +1,4 @@
-// compile-flags: -Z mir-opt-level=4
+// compile-flags: -Z mir-opt-level=4 -Zunsound-mir-opts
// must not optimize as it does not follow the pattern of
// left and right hand side being the same variant
diff --git a/src/test/mir-opt/generator_drop_cleanup.main-{closure#0}.generator_drop.0.mir b/src/test/mir-opt/generator_drop_cleanup.main-{closure#0}.generator_drop.0.mir
index d19229aabad..84ccf25ef75 100644
--- a/src/test/mir-opt/generator_drop_cleanup.main-{closure#0}.generator_drop.0.mir
+++ b/src/test/mir-opt/generator_drop_cleanup.main-{closure#0}.generator_drop.0.mir
@@ -20,21 +20,16 @@ fn main::{closure#0}(_1: *mut [generator@$DIR/generator-drop-cleanup.rs:10:15: 1
let _3: std::string::String; // in scope 0 at $DIR/generator-drop-cleanup.rs:11:13: 11:15
let _4: (); // in scope 0 at $DIR/generator-drop-cleanup.rs:12:9: 12:14
let mut _5: (); // in scope 0 at $DIR/generator-drop-cleanup.rs:12:9: 12:14
- let mut _7: (); // in scope 0 at $DIR/generator-drop-cleanup.rs:10:18: 10:18
- let mut _8: (); // in scope 0 at $DIR/generator-drop-cleanup.rs:10:15: 13:6
- let mut _9: u32; // in scope 0 at $DIR/generator-drop-cleanup.rs:10:15: 13:6
+ let mut _6: (); // in scope 0 at $DIR/generator-drop-cleanup.rs:10:18: 10:18
+ let mut _7: (); // in scope 0 at $DIR/generator-drop-cleanup.rs:10:15: 13:6
+ let mut _8: u32; // in scope 0 at $DIR/generator-drop-cleanup.rs:10:15: 13:6
scope 1 {
debug _s => (((*_1) as variant#3).0: std::string::String); // in scope 1 at $DIR/generator-drop-cleanup.rs:11:13: 11:15
}
- scope 2 (inlined String::new) { // at $DIR/generator-drop-cleanup.rs:11:18: 11:31
- let mut _6: std::vec::Vec<u8>; // in scope 2 at $DIR/generator-drop-cleanup.rs:11:18: 11:31
- scope 3 (inlined Vec::<u8>::new) { // at $DIR/generator-drop-cleanup.rs:11:18: 11:31
- }
- }
bb0: {
- _9 = discriminant((*_1)); // scope 0 at $DIR/generator-drop-cleanup.rs:10:15: 13:6
- switchInt(move _9) -> [0_u32: bb7, 3_u32: bb10, otherwise: bb11]; // scope 0 at $DIR/generator-drop-cleanup.rs:10:15: 13:6
+ _8 = discriminant((*_1)); // scope 0 at $DIR/generator-drop-cleanup.rs:10:15: 13:6
+ switchInt(move _8) -> [0_u32: bb7, 3_u32: bb10, otherwise: bb11]; // scope 0 at $DIR/generator-drop-cleanup.rs:10:15: 13:6
}
bb1: {
diff --git a/src/test/mir-opt/inline/inline_retag.bar.Inline.after.mir b/src/test/mir-opt/inline/inline_retag.bar.Inline.after.mir
index 0ff0e8ea7b1..37f6fc91cf9 100644
--- a/src/test/mir-opt/inline/inline_retag.bar.Inline.after.mir
+++ b/src/test/mir-opt/inline/inline_retag.bar.Inline.after.mir
@@ -38,7 +38,7 @@ fn bar() -> bool {
// + val: Unevaluated(bar, [], Some(promoted[1]))
// mir::Constant
// + span: $DIR/inline-retag.rs:12:7: 12:9
- // + literal: Const { ty: &i32, val: Unevaluated(Unevaluated { def: WithOptConstParam { did: DefId(0:4 ~ inline_retag[a78c]::bar), const_param_did: None }, substs_: Some([]), promoted: Some(promoted[1]) }) }
+ // + literal: Const { ty: &i32, val: Unevaluated(Unevaluated { def: WithOptConstParam { did: DefId(0:4 ~ inline_retag[HASH]::bar), const_param_did: None }, substs_: Some([]), promoted: Some(promoted[1]) }) }
Retag(_10); // scope 1 at $DIR/inline-retag.rs:12:7: 12:9
_4 = &(*_10); // scope 1 at $DIR/inline-retag.rs:12:7: 12:9
Retag(_4); // scope 1 at $DIR/inline-retag.rs:12:7: 12:9
@@ -52,7 +52,7 @@ fn bar() -> bool {
// + val: Unevaluated(bar, [], Some(promoted[0]))
// mir::Constant
// + span: $DIR/inline-retag.rs:12:11: 12:14
- // + literal: Const { ty: &i32, val: Unevaluated(Unevaluated { def: WithOptConstParam { did: DefId(0:4 ~ inline_retag[a78c]::bar), const_param_did: None }, substs_: Some([]), promoted: Some(promoted[0]) }) }
+ // + literal: Const { ty: &i32, val: Unevaluated(Unevaluated { def: WithOptConstParam { did: DefId(0:4 ~ inline_retag[HASH]::bar), const_param_did: None }, substs_: Some([]), promoted: Some(promoted[0]) }) }
Retag(_9); // scope 1 at $DIR/inline-retag.rs:12:11: 12:14
_7 = &(*_9); // scope 1 at $DIR/inline-retag.rs:12:11: 12:14
Retag(_7); // scope 1 at $DIR/inline-retag.rs:12:11: 12:14
diff --git a/src/test/mir-opt/inline/issue_78442.bar.Inline.diff b/src/test/mir-opt/inline/issue_78442.bar.Inline.diff
index 4d9e022d825..045bc720ca7 100644
--- a/src/test/mir-opt/inline/issue_78442.bar.Inline.diff
+++ b/src/test/mir-opt/inline/issue_78442.bar.Inline.diff
@@ -19,16 +19,16 @@
+ _4 = hide_foo() -> [return: bb1, unwind: bb3]; // scope 0 at $DIR/issue-78442.rs:11:5: 11:15
// mir::Constant
// + span: $DIR/issue-78442.rs:11:5: 11:13
- // + literal: Const { ty: fn() -> impl std::ops::Fn<()> {hide_foo}, val: Value(Scalar(<ZST>)) }
+ // + literal: Const { ty: fn() -> impl Fn() {hide_foo}, val: Value(Scalar(<ZST>)) }
}
bb1: {
_3 = &_4; // scope 0 at $DIR/issue-78442.rs:11:5: 11:15
StorageLive(_5); // scope 0 at $DIR/issue-78442.rs:11:5: 11:17
-- _2 = <impl Fn<()> as Fn<()>>::call(move _3, move _5) -> [return: bb2, unwind: bb4]; // scope 0 at $DIR/issue-78442.rs:11:5: 11:17
+- _2 = <impl Fn() as Fn<()>>::call(move _3, move _5) -> [return: bb2, unwind: bb4]; // scope 0 at $DIR/issue-78442.rs:11:5: 11:17
- // mir::Constant
- // + span: $DIR/issue-78442.rs:11:5: 11:15
-- // + literal: Const { ty: for<'r> extern "rust-call" fn(&'r impl std::ops::Fn<()>, ()) -> <impl std::ops::Fn<()> as std::ops::FnOnce<()>>::Output {<impl std::ops::Fn<()> as std::ops::Fn<()>>::call}, val: Value(Scalar(<ZST>)) }
+- // + literal: Const { ty: for<'r> extern "rust-call" fn(&'r impl Fn(), ()) -> <impl Fn() as std::ops::FnOnce<()>>::Output {<impl Fn() as std::ops::Fn<()>>::call}, val: Value(Scalar(<ZST>)) }
+ _2 = move (*_3)() -> [return: bb5, unwind: bb3]; // scope 1 at $DIR/issue-78442.rs:11:5: 11:17
}
diff --git a/src/test/mir-opt/inline/issue_78442.bar.RevealAll.diff b/src/test/mir-opt/inline/issue_78442.bar.RevealAll.diff
index 45b552cc634..3190db52286 100644
--- a/src/test/mir-opt/inline/issue_78442.bar.RevealAll.diff
+++ b/src/test/mir-opt/inline/issue_78442.bar.RevealAll.diff
@@ -5,8 +5,8 @@
debug _baz => _1; // in scope 0 at $DIR/issue-78442.rs:9:5: 9:9
let mut _0: (); // return place in scope 0 at $DIR/issue-78442.rs:10:3: 10:3
let _2: (); // in scope 0 at $DIR/issue-78442.rs:11:5: 11:17
-- let mut _3: &impl std::ops::Fn<()>; // in scope 0 at $DIR/issue-78442.rs:11:5: 11:15
-- let _4: impl std::ops::Fn<()>; // in scope 0 at $DIR/issue-78442.rs:11:5: 11:15
+- let mut _3: &impl Fn(); // in scope 0 at $DIR/issue-78442.rs:11:5: 11:15
+- let _4: impl Fn(); // in scope 0 at $DIR/issue-78442.rs:11:5: 11:15
+ let mut _3: &fn() {foo}; // in scope 0 at $DIR/issue-78442.rs:11:5: 11:15
+ let _4: fn() {foo}; // in scope 0 at $DIR/issue-78442.rs:11:5: 11:15
let mut _5: (); // in scope 0 at $DIR/issue-78442.rs:11:5: 11:17
@@ -18,17 +18,17 @@
_4 = hide_foo() -> [return: bb1, unwind: bb4]; // scope 0 at $DIR/issue-78442.rs:11:5: 11:15
// mir::Constant
// + span: $DIR/issue-78442.rs:11:5: 11:13
- // + literal: Const { ty: fn() -> impl std::ops::Fn<()> {hide_foo}, val: Value(Scalar(<ZST>)) }
+ // + literal: Const { ty: fn() -> impl Fn() {hide_foo}, val: Value(Scalar(<ZST>)) }
}
bb1: {
_3 = &_4; // scope 0 at $DIR/issue-78442.rs:11:5: 11:15
StorageLive(_5); // scope 0 at $DIR/issue-78442.rs:11:5: 11:17
nop; // scope 0 at $DIR/issue-78442.rs:11:5: 11:17
- _2 = <impl Fn<()> as Fn<()>>::call(move _3, move _5) -> [return: bb2, unwind: bb4]; // scope 0 at $DIR/issue-78442.rs:11:5: 11:17
+ _2 = <impl Fn() as Fn<()>>::call(move _3, move _5) -> [return: bb2, unwind: bb4]; // scope 0 at $DIR/issue-78442.rs:11:5: 11:17
// mir::Constant
// + span: $DIR/issue-78442.rs:11:5: 11:15
- // + literal: Const { ty: for<'r> extern "rust-call" fn(&'r impl std::ops::Fn<()>, ()) -> <impl std::ops::Fn<()> as std::ops::FnOnce<()>>::Output {<impl std::ops::Fn<()> as std::ops::Fn<()>>::call}, val: Value(Scalar(<ZST>)) }
+ // + literal: Const { ty: for<'r> extern "rust-call" fn(&'r impl Fn(), ()) -> <impl Fn() as std::ops::FnOnce<()>>::Output {<impl Fn() as std::ops::Fn<()>>::call}, val: Value(Scalar(<ZST>)) }
}
bb2: {
diff --git a/src/test/mir-opt/issue_73223.main.PreCodegen.32bit.diff b/src/test/mir-opt/issue_73223.main.PreCodegen.32bit.diff
index 95632293d99..20e5191310c 100644
--- a/src/test/mir-opt/issue_73223.main.PreCodegen.32bit.diff
+++ b/src/test/mir-opt/issue_73223.main.PreCodegen.32bit.diff
@@ -66,7 +66,7 @@
// + val: Unevaluated(main, [], Some(promoted[0]))
// mir::Constant
// + span: $SRC_DIR/core/src/macros/mod.rs:LL:COL
- // + literal: Const { ty: &i32, val: Unevaluated(Unevaluated { def: WithOptConstParam { did: DefId(0:3 ~ issue_73223[2d0f]::main), const_param_did: None }, substs_: Some([]), promoted: Some(promoted[0]) }) }
+ // + literal: Const { ty: &i32, val: Unevaluated(Unevaluated { def: WithOptConstParam { did: DefId(0:3 ~ issue_73223[HASH]::main), const_param_did: None }, substs_: Some([]), promoted: Some(promoted[0]) }) }
_8 = _20; // scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
(_6.0: &i32) = move _7; // scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
(_6.1: &i32) = move _8; // scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
diff --git a/src/test/mir-opt/issue_73223.main.PreCodegen.64bit.diff b/src/test/mir-opt/issue_73223.main.PreCodegen.64bit.diff
index 95632293d99..20e5191310c 100644
--- a/src/test/mir-opt/issue_73223.main.PreCodegen.64bit.diff
+++ b/src/test/mir-opt/issue_73223.main.PreCodegen.64bit.diff
@@ -66,7 +66,7 @@
// + val: Unevaluated(main, [], Some(promoted[0]))
// mir::Constant
// + span: $SRC_DIR/core/src/macros/mod.rs:LL:COL
- // + literal: Const { ty: &i32, val: Unevaluated(Unevaluated { def: WithOptConstParam { did: DefId(0:3 ~ issue_73223[2d0f]::main), const_param_did: None }, substs_: Some([]), promoted: Some(promoted[0]) }) }
+ // + literal: Const { ty: &i32, val: Unevaluated(Unevaluated { def: WithOptConstParam { did: DefId(0:3 ~ issue_73223[HASH]::main), const_param_did: None }, substs_: Some([]), promoted: Some(promoted[0]) }) }
_8 = _20; // scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
(_6.0: &i32) = move _7; // scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
(_6.1: &i32) = move _8; // scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
diff --git a/src/test/mir-opt/issue_73223.main.SimplifyArmIdentity.32bit.diff b/src/test/mir-opt/issue_73223.main.SimplifyArmIdentity.32bit.diff
index 946aab9c6e8..04e4af70bb7 100644
--- a/src/test/mir-opt/issue_73223.main.SimplifyArmIdentity.32bit.diff
+++ b/src/test/mir-opt/issue_73223.main.SimplifyArmIdentity.32bit.diff
@@ -87,7 +87,7 @@
// + val: Unevaluated(main, [], Some(promoted[0]))
// mir::Constant
// + span: $SRC_DIR/core/src/macros/mod.rs:LL:COL
- // + literal: Const { ty: &i32, val: Unevaluated(Unevaluated { def: WithOptConstParam { did: DefId(0:3 ~ issue_73223[2d0f]::main), const_param_did: None }, substs_: Some([]), promoted: Some(promoted[0]) }) }
+ // + literal: Const { ty: &i32, val: Unevaluated(Unevaluated { def: WithOptConstParam { did: DefId(0:3 ~ issue_73223[HASH]::main), const_param_did: None }, substs_: Some([]), promoted: Some(promoted[0]) }) }
_11 = _28; // scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
(_9.0: &i32) = move _10; // scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
(_9.1: &i32) = move _11; // scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
diff --git a/src/test/mir-opt/issue_73223.main.SimplifyArmIdentity.64bit.diff b/src/test/mir-opt/issue_73223.main.SimplifyArmIdentity.64bit.diff
index 946aab9c6e8..04e4af70bb7 100644
--- a/src/test/mir-opt/issue_73223.main.SimplifyArmIdentity.64bit.diff
+++ b/src/test/mir-opt/issue_73223.main.SimplifyArmIdentity.64bit.diff
@@ -87,7 +87,7 @@
// + val: Unevaluated(main, [], Some(promoted[0]))
// mir::Constant
// + span: $SRC_DIR/core/src/macros/mod.rs:LL:COL
- // + literal: Const { ty: &i32, val: Unevaluated(Unevaluated { def: WithOptConstParam { did: DefId(0:3 ~ issue_73223[2d0f]::main), const_param_did: None }, substs_: Some([]), promoted: Some(promoted[0]) }) }
+ // + literal: Const { ty: &i32, val: Unevaluated(Unevaluated { def: WithOptConstParam { did: DefId(0:3 ~ issue_73223[HASH]::main), const_param_did: None }, substs_: Some([]), promoted: Some(promoted[0]) }) }
_11 = _28; // scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
(_9.0: &i32) = move _10; // scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
(_9.1: &i32) = move _11; // scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
diff --git a/src/test/mir-opt/lower_intrinsics.discriminant.LowerIntrinsics.diff b/src/test/mir-opt/lower_intrinsics.discriminant.LowerIntrinsics.diff
index d9b441a470c..b8f44b7672a 100644
--- a/src/test/mir-opt/lower_intrinsics.discriminant.LowerIntrinsics.diff
+++ b/src/test/mir-opt/lower_intrinsics.discriminant.LowerIntrinsics.diff
@@ -50,7 +50,7 @@
// + val: Unevaluated(discriminant, [T], Some(promoted[2]))
// mir::Constant
// + span: $DIR/lower_intrinsics.rs:75:42: 75:44
- // + literal: Const { ty: &i32, val: Unevaluated(Unevaluated { def: WithOptConstParam { did: DefId(0:29 ~ lower_intrinsics[2872]::discriminant), const_param_did: None }, substs_: Some([T]), promoted: Some(promoted[2]) }) }
+ // + literal: Const { ty: &i32, val: Unevaluated(Unevaluated { def: WithOptConstParam { did: DefId(0:29 ~ lower_intrinsics[HASH]::discriminant), const_param_did: None }, substs_: Some([T]), promoted: Some(promoted[2]) }) }
_7 = &(*_19); // scope 0 at $DIR/lower_intrinsics.rs:75:42: 75:44
_6 = &(*_7); // scope 0 at $DIR/lower_intrinsics.rs:75:42: 75:44
- _5 = discriminant_value::<i32>(move _6) -> bb2; // scope 0 at $DIR/lower_intrinsics.rs:75:5: 75:45
@@ -74,7 +74,7 @@
// + val: Unevaluated(discriminant, [T], Some(promoted[1]))
// mir::Constant
// + span: $DIR/lower_intrinsics.rs:76:42: 76:45
- // + literal: Const { ty: &(), val: Unevaluated(Unevaluated { def: WithOptConstParam { did: DefId(0:29 ~ lower_intrinsics[2872]::discriminant), const_param_did: None }, substs_: Some([T]), promoted: Some(promoted[1]) }) }
+ // + literal: Const { ty: &(), val: Unevaluated(Unevaluated { def: WithOptConstParam { did: DefId(0:29 ~ lower_intrinsics[HASH]::discriminant), const_param_did: None }, substs_: Some([T]), promoted: Some(promoted[1]) }) }
_11 = &(*_18); // scope 0 at $DIR/lower_intrinsics.rs:76:42: 76:45
_10 = &(*_11); // scope 0 at $DIR/lower_intrinsics.rs:76:42: 76:45
- _9 = discriminant_value::<()>(move _10) -> bb3; // scope 0 at $DIR/lower_intrinsics.rs:76:5: 76:46
@@ -98,7 +98,7 @@
// + val: Unevaluated(discriminant, [T], Some(promoted[0]))
// mir::Constant
// + span: $DIR/lower_intrinsics.rs:77:42: 77:47
- // + literal: Const { ty: &E, val: Unevaluated(Unevaluated { def: WithOptConstParam { did: DefId(0:29 ~ lower_intrinsics[2872]::discriminant), const_param_did: None }, substs_: Some([T]), promoted: Some(promoted[0]) }) }
+ // + literal: Const { ty: &E, val: Unevaluated(Unevaluated { def: WithOptConstParam { did: DefId(0:29 ~ lower_intrinsics[HASH]::discriminant), const_param_did: None }, substs_: Some([T]), promoted: Some(promoted[0]) }) }
_15 = &(*_17); // scope 0 at $DIR/lower_intrinsics.rs:77:42: 77:47
_14 = &(*_15); // scope 0 at $DIR/lower_intrinsics.rs:77:42: 77:47
- _13 = discriminant_value::<E>(move _14) -> bb4; // scope 0 at $DIR/lower_intrinsics.rs:77:5: 77:48
diff --git a/src/test/mir-opt/match_false_edges.full_tested_match.PromoteTemps.after.mir b/src/test/mir-opt/match_false_edges.full_tested_match.PromoteTemps.after.mir
index 111549d6f3d..0ef06da0cb7 100644
--- a/src/test/mir-opt/match_false_edges.full_tested_match.PromoteTemps.after.mir
+++ b/src/test/mir-opt/match_false_edges.full_tested_match.PromoteTemps.after.mir
@@ -57,7 +57,7 @@ fn full_tested_match() -> () {
// + val: Unevaluated(full_tested_match, [], Some(promoted[0]))
// mir::Constant
// + span: $DIR/match_false_edges.rs:16:14: 16:15
- // + literal: Const { ty: &std::option::Option<i32>, val: Unevaluated(Unevaluated { def: WithOptConstParam { did: DefId(0:5 ~ match_false_edges[4011]::full_tested_match), const_param_did: None }, substs_: Some([]), promoted: Some(promoted[0]) }) }
+ // + literal: Const { ty: &std::option::Option<i32>, val: Unevaluated(Unevaluated { def: WithOptConstParam { did: DefId(0:5 ~ match_false_edges[HASH]::full_tested_match), const_param_did: None }, substs_: Some([]), promoted: Some(promoted[0]) }) }
_6 = &(((*_11) as Some).0: i32); // scope 0 at $DIR/match_false_edges.rs:16:14: 16:15
_4 = &shallow _2; // scope 0 at $DIR/match_false_edges.rs:15:19: 15:27
StorageLive(_7); // scope 0 at $DIR/match_false_edges.rs:16:20: 16:27
diff --git a/src/test/mir-opt/retag.array_casts.SimplifyCfg-elaborate-drops.after.mir b/src/test/mir-opt/retag.array_casts.SimplifyCfg-elaborate-drops.after.mir
index ee99d033af3..defb04db7de 100644
--- a/src/test/mir-opt/retag.array_casts.SimplifyCfg-elaborate-drops.after.mir
+++ b/src/test/mir-opt/retag.array_casts.SimplifyCfg-elaborate-drops.after.mir
@@ -127,7 +127,7 @@ fn array_casts() -> () {
// + val: Unevaluated(array_casts, [], Some(promoted[0]))
// mir::Constant
// + span: $SRC_DIR/core/src/macros/mod.rs:LL:COL
- // + literal: Const { ty: &usize, val: Unevaluated(Unevaluated { def: WithOptConstParam { did: DefId(0:15 ~ retag[13e7]::array_casts), const_param_did: None }, substs_: Some([]), promoted: Some(promoted[0]) }) }
+ // + literal: Const { ty: &usize, val: Unevaluated(Unevaluated { def: WithOptConstParam { did: DefId(0:15 ~ retag[HASH]::array_casts), const_param_did: None }, substs_: Some([]), promoted: Some(promoted[0]) }) }
Retag(_35); // scope 5 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
_18 = &(*_35); // scope 5 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
Retag(_18); // scope 5 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
diff --git a/src/test/mir-opt/retag.main.SimplifyCfg-elaborate-drops.after.mir b/src/test/mir-opt/retag.main.SimplifyCfg-elaborate-drops.after.mir
index 6bb92c5e6bc..3f35f15a56d 100644
--- a/src/test/mir-opt/retag.main.SimplifyCfg-elaborate-drops.after.mir
+++ b/src/test/mir-opt/retag.main.SimplifyCfg-elaborate-drops.after.mir
@@ -113,7 +113,7 @@ fn main() -> () {
StorageLive(_14); // scope 1 at $DIR/retag.rs:40:31: 43:6
_14 = [closure@main::{closure#0}]; // scope 1 at $DIR/retag.rs:40:31: 43:6
// closure
- // + def_id: DefId(0:14 ~ retag[13e7]::main::{closure#0})
+ // + def_id: DefId(0:14 ~ retag[HASH]::main::{closure#0})
// + substs: [
// i8,
// for<'r> extern "rust-call" fn((&'r i32,)) -> &'r i32,
@@ -153,7 +153,7 @@ fn main() -> () {
// + val: Unevaluated(main, [], Some(promoted[0]))
// mir::Constant
// + span: $DIR/retag.rs:47:21: 47:23
- // + literal: Const { ty: &i32, val: Unevaluated(Unevaluated { def: WithOptConstParam { did: DefId(0:13 ~ retag[13e7]::main), const_param_did: None }, substs_: Some([]), promoted: Some(promoted[0]) }) }
+ // + literal: Const { ty: &i32, val: Unevaluated(Unevaluated { def: WithOptConstParam { did: DefId(0:13 ~ retag[HASH]::main), const_param_did: None }, substs_: Some([]), promoted: Some(promoted[0]) }) }
Retag(_28); // scope 7 at $DIR/retag.rs:47:21: 47:23
_23 = &(*_28); // scope 7 at $DIR/retag.rs:47:21: 47:23
Retag(_23); // scope 7 at $DIR/retag.rs:47:21: 47:23
diff --git a/src/test/mir-opt/separate_const_switch.identity.ConstProp.diff b/src/test/mir-opt/separate_const_switch.identity.ConstProp.diff
index d5190cdb0c7..0a220e6e72c 100644
--- a/src/test/mir-opt/separate_const_switch.identity.ConstProp.diff
+++ b/src/test/mir-opt/separate_const_switch.identity.ConstProp.diff
@@ -15,7 +15,7 @@
scope 1 {
debug residual => _6; // in scope 1 at $DIR/separate_const_switch.rs:29:9: 29:10
scope 2 {
- scope 8 (inlined <Result<i32, i32> as FromResidual<Result<Infallible, i32>>>::from_residual) { // at $DIR/separate_const_switch.rs:29:8: 29:10
+ scope 8 (inlined #[track_caller] <Result<i32, i32> as FromResidual<Result<Infallible, i32>>>::from_residual) { // at $DIR/separate_const_switch.rs:29:8: 29:10
debug residual => _8; // in scope 8 at $DIR/separate_const_switch.rs:29:8: 29:10
let _16: i32; // in scope 8 at $DIR/separate_const_switch.rs:29:8: 29:10
let mut _17: i32; // in scope 8 at $DIR/separate_const_switch.rs:29:8: 29:10
diff --git a/src/test/mir-opt/separate_const_switch.identity.PreCodegen.after.mir b/src/test/mir-opt/separate_const_switch.identity.PreCodegen.after.mir
index dee45c58403..b09527e46af 100644
--- a/src/test/mir-opt/separate_const_switch.identity.PreCodegen.after.mir
+++ b/src/test/mir-opt/separate_const_switch.identity.PreCodegen.after.mir
@@ -12,7 +12,7 @@ fn identity(_1: Result<i32, i32>) -> Result<i32, i32> {
scope 1 {
debug residual => _5; // in scope 1 at $DIR/separate_const_switch.rs:29:9: 29:10
scope 2 {
- scope 8 (inlined <Result<i32, i32> as FromResidual<Result<Infallible, i32>>>::from_residual) { // at $DIR/separate_const_switch.rs:29:8: 29:10
+ scope 8 (inlined #[track_caller] <Result<i32, i32> as FromResidual<Result<Infallible, i32>>>::from_residual) { // at $DIR/separate_const_switch.rs:29:8: 29:10
debug residual => _6; // in scope 8 at $DIR/separate_const_switch.rs:29:8: 29:10
let _14: i32; // in scope 8 at $DIR/separate_const_switch.rs:29:8: 29:10
let mut _15: i32; // in scope 8 at $DIR/separate_const_switch.rs:29:8: 29:10
diff --git a/src/test/mir-opt/separate_const_switch.identity.SeparateConstSwitch.diff b/src/test/mir-opt/separate_const_switch.identity.SeparateConstSwitch.diff
index 69f3bec6fea..bfc74aff207 100644
--- a/src/test/mir-opt/separate_const_switch.identity.SeparateConstSwitch.diff
+++ b/src/test/mir-opt/separate_const_switch.identity.SeparateConstSwitch.diff
@@ -15,7 +15,7 @@
scope 1 {
debug residual => _6; // in scope 1 at $DIR/separate_const_switch.rs:29:9: 29:10
scope 2 {
- scope 8 (inlined <Result<i32, i32> as FromResidual<Result<Infallible, i32>>>::from_residual) { // at $DIR/separate_const_switch.rs:29:8: 29:10
+ scope 8 (inlined #[track_caller] <Result<i32, i32> as FromResidual<Result<Infallible, i32>>>::from_residual) { // at $DIR/separate_const_switch.rs:29:8: 29:10
debug residual => _8; // in scope 8 at $DIR/separate_const_switch.rs:29:8: 29:10
let _16: i32; // in scope 8 at $DIR/separate_const_switch.rs:29:8: 29:10
let mut _17: i32; // in scope 8 at $DIR/separate_const_switch.rs:29:8: 29:10
diff --git a/src/test/mir-opt/simplify_if.main.SimplifyBranches-after-const-prop.diff b/src/test/mir-opt/simplify_if.main.SimplifyConstCondition-after-const-prop.diff
index def6f835131..d11c70b1efe 100644
--- a/src/test/mir-opt/simplify_if.main.SimplifyBranches-after-const-prop.diff
+++ b/src/test/mir-opt/simplify_if.main.SimplifyConstCondition-after-const-prop.diff
@@ -1,5 +1,5 @@
-- // MIR for `main` before SimplifyBranches-after-const-prop
-+ // MIR for `main` after SimplifyBranches-after-const-prop
+- // MIR for `main` before SimplifyConstCondition-after-const-prop
++ // MIR for `main` after SimplifyConstCondition-after-const-prop
fn main() -> () {
let mut _0: (); // return place in scope 0 at $DIR/simplify_if.rs:5:11: 5:11
diff --git a/src/test/mir-opt/simplify_if.rs b/src/test/mir-opt/simplify_if.rs
index 67b2027b710..2d093d9266b 100644
--- a/src/test/mir-opt/simplify_if.rs
+++ b/src/test/mir-opt/simplify_if.rs
@@ -1,7 +1,7 @@
#[inline(never)]
fn noop() {}
-// EMIT_MIR simplify_if.main.SimplifyBranches-after-const-prop.diff
+// EMIT_MIR simplify_if.main.SimplifyConstCondition-after-const-prop.diff
fn main() {
if false {
noop();
diff --git a/src/test/pretty/asm.pp b/src/test/pretty/asm.pp
index a2065039692..5eade2933b8 100644
--- a/src/test/pretty/asm.pp
+++ b/src/test/pretty/asm.pp
@@ -1,15 +1,15 @@
#![feature(prelude_import)]
#![no_std]
-#![feature(asm)]
#[prelude_import]
use ::std::prelude::rust_2015::*;
#[macro_use]
extern crate std;
-
// pretty-mode:expanded
// pp-exact:asm.pp
// only-x86_64
+use std::arch::asm;
+
pub fn main() {
let a: i32;
let mut b = 4i32;
diff --git a/src/test/pretty/asm.rs b/src/test/pretty/asm.rs
index 1156ab769a0..1a3f972c8f2 100644
--- a/src/test/pretty/asm.rs
+++ b/src/test/pretty/asm.rs
@@ -1,9 +1,9 @@
-#![feature(asm)]
-
// pretty-mode:expanded
// pp-exact:asm.pp
// only-x86_64
+use std::arch::asm;
+
pub fn main() {
let a: i32;
let mut b = 4i32;
@@ -20,8 +20,10 @@ pub fn main() {
asm!("inst1 {}, 42", "inst2 {}, 24", in(reg) a, out(reg) b);
asm!("inst2 {1}, 24", "inst1 {0}, 42", in(reg) a, out(reg) b);
asm!("inst1 {}, 42", "inst2 {name}, 24", in(reg) a, name = out(reg) b);
- asm!("inst1
-inst2");
+ asm!(
+ "inst1
+inst2"
+ );
asm!("inst1\ninst2");
asm!("inst1\n\tinst2");
asm!("inst1\ninst2", "inst3\ninst4");
diff --git a/src/test/pretty/ast-stmt-expr-attr.rs b/src/test/pretty/ast-stmt-expr-attr.rs
index 32d1da390c5..e32f5ca24ea 100644
--- a/src/test/pretty/ast-stmt-expr-attr.rs
+++ b/src/test/pretty/ast-stmt-expr-attr.rs
@@ -1,6 +1,6 @@
// pp-exact
-fn main() { }
+fn main() {}
#[cfg(FALSE)]
fn syntax() {
@@ -110,14 +110,14 @@ fn syntax() {
let _ = #[attr] &mut 0;
let _ = #[attr] &#[attr] 0;
let _ = #[attr] &mut #[attr] 0;
- let _ = #[attr] break ;
- let _ = #[attr] continue ;
+ let _ = #[attr] break;
+ let _ = #[attr] continue;
let _ = #[attr] return;
let _ = #[attr] foo!();
let _ = #[attr] foo!(#! [attr]);
let _ = #[attr] foo![];
let _ = #[attr] foo![#! [attr]];
- let _ = #[attr] foo! { };
+ let _ = #[attr] foo! {};
let _ = #[attr] foo! { #! [attr] };
let _ = #[attr] Foo{bar: baz,};
let _ = #[attr] Foo{..foo};
@@ -135,7 +135,7 @@ fn syntax() {
foo!();
#[attr]
- foo! { }
+ foo! {}
#[attr]
foo![];
@@ -170,6 +170,6 @@ fn syntax() {
{
#[attr]
- foo! { }
+ foo! {}
}
}
diff --git a/src/test/pretty/async.rs b/src/test/pretty/async.rs
new file mode 100644
index 00000000000..573e79bffd7
--- /dev/null
+++ b/src/test/pretty/async.rs
@@ -0,0 +1,9 @@
+// pp-exact
+// pretty-compare-only
+// edition:2021
+
+async fn f() {
+ let first = async { 1 };
+ let second = async move { 2 };
+ join(first, second).await
+}
diff --git a/src/test/pretty/attr-derive.rs b/src/test/pretty/attr-derive.rs
index 4ce6d2fbf17..0eb403c6bc8 100644
--- a/src/test/pretty/attr-derive.rs
+++ b/src/test/pretty/attr-derive.rs
@@ -29,4 +29,4 @@ enum Enum {
Qwerty,
}
-fn main() { }
+fn main() {}
diff --git a/src/test/pretty/auto-trait.rs b/src/test/pretty/auto-trait.rs
index 61644e7df09..c3c47cff5ed 100644
--- a/src/test/pretty/auto-trait.rs
+++ b/src/test/pretty/auto-trait.rs
@@ -2,8 +2,8 @@
// pp-exact
-auto trait MyTrait { }
+auto trait MyTrait {}
-unsafe auto trait UnsafeMyTrait { }
+unsafe auto trait UnsafeMyTrait {}
-pub fn main() { }
+pub fn main() {}
diff --git a/src/test/pretty/block-comment-trailing-whitespace2.rs b/src/test/pretty/block-comment-trailing-whitespace2.rs
index b7c42e39557..e53d51e34ce 100644
--- a/src/test/pretty/block-comment-trailing-whitespace2.rs
+++ b/src/test/pretty/block-comment-trailing-whitespace2.rs
@@ -1,9 +1,8 @@
// compile-flags: --crate-type=lib
// pp-exact
-fn f() {
-} /*
- The next line should not be indented.
+fn f() {} /*
+ The next line should not be indented.
- That one. It shouldn't have been indented.
- */
+ That one. It shouldn't have been indented.
+ */
diff --git a/src/test/pretty/closure-reform-pretty.rs b/src/test/pretty/closure-reform-pretty.rs
index ef5189fa13e..1eba1e6bdec 100644
--- a/src/test/pretty/closure-reform-pretty.rs
+++ b/src/test/pretty/closure-reform-pretty.rs
@@ -3,14 +3,14 @@
// pp-exact
-fn call_it(f: Box<FnMut(String) -> String>) { }
+fn call_it(f: Box<FnMut(String) -> String>) {}
-fn call_this<F>(f: F) where F: Fn(&str) + Send { }
+fn call_this<F>(f: F) where F: Fn(&str) + Send {}
-fn call_that<F>(f: F) where F: for<'a> Fn(&'a isize, &'a isize) -> isize { }
+fn call_that<F>(f: F) where F: for<'a> Fn(&'a isize, &'a isize) -> isize {}
-fn call_extern(f: fn() -> isize) { }
+fn call_extern(f: fn() -> isize) {}
-fn call_abid_extern(f: extern "C" fn() -> isize) { }
+fn call_abid_extern(f: extern "C" fn() -> isize) {}
-pub fn main() { }
+pub fn main() {}
diff --git a/src/test/pretty/disamb-stmt-expr.rs b/src/test/pretty/disamb-stmt-expr.rs
index 601ca7bb6de..734f9fa123e 100644
--- a/src/test/pretty/disamb-stmt-expr.rs
+++ b/src/test/pretty/disamb-stmt-expr.rs
@@ -7,4 +7,4 @@
fn id<F>(f: F) -> isize where F: Fn() -> isize { f() }
fn wsucc(_n: isize) -> isize { id(|| { 1 }) - 0 }
-fn main() { }
+fn main() {}
diff --git a/src/test/pretty/enum-variant-vis.rs b/src/test/pretty/enum-variant-vis.rs
index a3e8178aeb3..fc646c2956c 100644
--- a/src/test/pretty/enum-variant-vis.rs
+++ b/src/test/pretty/enum-variant-vis.rs
@@ -2,7 +2,7 @@
// Check that the visibility is printed on an enum variant.
-fn main() { }
+fn main() {}
#[cfg(FALSE)]
enum Foo { pub V, }
diff --git a/src/test/pretty/example1.rs b/src/test/pretty/example1.rs
index 4f7d5e7e71e..8df74e8e1f9 100644
--- a/src/test/pretty/example1.rs
+++ b/src/test/pretty/example1.rs
@@ -1,3 +1,3 @@
// pp-exact
-fn main() { }
+fn main() {}
diff --git a/src/test/pretty/example2.pp b/src/test/pretty/example2.pp
index 852b9f316ce..3f7129afde2 100644
--- a/src/test/pretty/example2.pp
+++ b/src/test/pretty/example2.pp
@@ -1,3 +1,3 @@
// pp-exact:example2.pp
-fn main() { }
+fn main() {}
diff --git a/src/test/pretty/example2.rs b/src/test/pretty/example2.rs
index 852b9f316ce..3f7129afde2 100644
--- a/src/test/pretty/example2.rs
+++ b/src/test/pretty/example2.rs
@@ -1,3 +1,3 @@
// pp-exact:example2.pp
-fn main() { }
+fn main() {}
diff --git a/src/test/pretty/expanded-and-path-remap-80832.pp b/src/test/pretty/expanded-and-path-remap-80832.pp
index 1579ea41cfd..8385c5fa8c9 100644
--- a/src/test/pretty/expanded-and-path-remap-80832.pp
+++ b/src/test/pretty/expanded-and-path-remap-80832.pp
@@ -10,4 +10,4 @@ extern crate std;
// pp-exact:expanded-and-path-remap-80832.pp
// compile-flags: --remap-path-prefix {{src-base}}=the/src
-fn main() { }
+fn main() {}
diff --git a/src/test/pretty/fn-return.rs b/src/test/pretty/fn-return.rs
index 142d852cd6a..b932e83aaf1 100644
--- a/src/test/pretty/fn-return.rs
+++ b/src/test/pretty/fn-return.rs
@@ -1,7 +1,7 @@
// pp-exact
-// Check that `fn f() -> () { }` does not print as `fn f() { }`.
+// Check that `fn f() -> () {}` does not print as `fn f() {}`.
-fn f() -> () { }
+fn f() -> () {}
-fn main() { }
+fn main() {}
diff --git a/src/test/pretty/fn-types.rs b/src/test/pretty/fn-types.rs
index 842138e28c3..f012763c3f6 100644
--- a/src/test/pretty/fn-types.rs
+++ b/src/test/pretty/fn-types.rs
@@ -1,5 +1,5 @@
// pp-exact
-fn from_foreign_fn(_x: fn()) { }
-fn from_stack_closure<F>(_x: F) where F: Fn() { }
-fn main() { }
+fn from_foreign_fn(_x: fn()) {}
+fn from_stack_closure<F>(_x: F) where F: Fn() {}
+fn main() {}
diff --git a/src/test/pretty/fn-variadic.rs b/src/test/pretty/fn-variadic.rs
index d499be42460..59e477cfa8e 100644
--- a/src/test/pretty/fn-variadic.rs
+++ b/src/test/pretty/fn-variadic.rs
@@ -12,4 +12,4 @@ pub unsafe extern "C" fn bar(_: i32, mut ap: ...) -> usize {
ap.arg::<usize>()
}
-fn main() { }
+fn main() {}
diff --git a/src/test/pretty/hir-pretty-loop.pp b/src/test/pretty/hir-pretty-loop.pp
index 19b3a1775cf..9b10fd86c47 100644
--- a/src/test/pretty/hir-pretty-loop.pp
+++ b/src/test/pretty/hir-pretty-loop.pp
@@ -6,4 +6,4 @@ extern crate std;
// pretty-mode:hir
// pp-exact:hir-pretty-loop.pp
-pub fn foo() { loop { break ; } }
+pub fn foo() { loop { break; } }
diff --git a/src/test/pretty/if-attr.rs b/src/test/pretty/if-attr.rs
index 652604fc7f3..7b90b0becac 100644
--- a/src/test/pretty/if-attr.rs
+++ b/src/test/pretty/if-attr.rs
@@ -4,34 +4,34 @@
fn simple_attr() {
#[attr]
- if true { }
+ if true {}
#[allow_warnings]
- if true { }
+ if true {}
}
#[cfg(FALSE)]
fn if_else_chain() {
#[first_attr]
- if true { } else if false { } else { }
+ if true {} else if false {} else {}
}
#[cfg(FALSE)]
fn if_let() {
#[attr]
- if let Some(_) = Some(true) { }
+ if let Some(_) = Some(true) {}
}
#[cfg(FALSE)]
fn let_attr_if() {
- let _ = #[attr] if let _ = 0 { };
- let _ = #[attr] if true { };
+ let _ = #[attr] if let _ = 0 {};
+ let _ = #[attr] if true {};
- let _ = #[attr] if let _ = 0 { } else { };
- let _ = #[attr] if true { } else { };
+ let _ = #[attr] if let _ = 0 {} else {};
+ let _ = #[attr] if true {} else {};
}
-fn main() { }
+fn main() {}
diff --git a/src/test/pretty/issue-12590-a.rs b/src/test/pretty/issue-12590-a.rs
index ca1fef83cff..3c88f5cb8a4 100644
--- a/src/test/pretty/issue-12590-a.rs
+++ b/src/test/pretty/issue-12590-a.rs
@@ -6,4 +6,4 @@
#[path = "issue-12590-b.rs"]
mod issue_12590_b;
-fn main() { }
+fn main() {}
diff --git a/src/test/pretty/issue-12590-c.pp b/src/test/pretty/issue-12590-c.pp
index dd0b8899b2d..07b3f5653d3 100644
--- a/src/test/pretty/issue-12590-c.pp
+++ b/src/test/pretty/issue-12590-c.pp
@@ -13,7 +13,7 @@ extern crate std;
#[path = "issue-12590-b.rs"]
mod issue_12590_b {
- fn b() { }
- fn main() { }
+ fn b() {}
+ fn main() {}
}
-fn main() { }
+fn main() {}
diff --git a/src/test/pretty/issue-12590-c.rs b/src/test/pretty/issue-12590-c.rs
index 2cc444edda3..0ec05f9a805 100644
--- a/src/test/pretty/issue-12590-c.rs
+++ b/src/test/pretty/issue-12590-c.rs
@@ -7,4 +7,4 @@
#[path = "issue-12590-b.rs"]
mod issue_12590_b;
-fn main() { }
+fn main() {}
diff --git a/src/test/pretty/issue-19077.rs b/src/test/pretty/issue-19077.rs
index b4279111305..0d2702804d1 100644
--- a/src/test/pretty/issue-19077.rs
+++ b/src/test/pretty/issue-19077.rs
@@ -4,8 +4,8 @@
fn main() {
match true {
true if true => (),
- false if false => unsafe { },
- true => { }
+ false if false => unsafe {},
+ true => {}
false => (),
}
}
diff --git a/src/test/pretty/issue-30731.rs b/src/test/pretty/issue-30731.rs
index 02951395e70..607cbebee17 100644
--- a/src/test/pretty/issue-30731.rs
+++ b/src/test/pretty/issue-30731.rs
@@ -5,4 +5,4 @@
// pretty-compare-only
// pp-exact
-fn main() { b! { } c }
+fn main() { b! {} c }
diff --git a/src/test/pretty/issue-68710-field-attr-proc-mac-lost.rs b/src/test/pretty/issue-68710-field-attr-proc-mac-lost.rs
index 031a4825959..ed7879001d5 100644
--- a/src/test/pretty/issue-68710-field-attr-proc-mac-lost.rs
+++ b/src/test/pretty/issue-68710-field-attr-proc-mac-lost.rs
@@ -1,6 +1,6 @@
// pp-exact
-fn main() { }
+fn main() {}
struct C {
field: u8,
diff --git a/src/test/pretty/lifetime.rs b/src/test/pretty/lifetime.rs
index bfef51202db..34eae849be4 100644
--- a/src/test/pretty/lifetime.rs
+++ b/src/test/pretty/lifetime.rs
@@ -1,5 +1,5 @@
// pp-exact
-fn f1<'a, 'b, 'c>(_x: &'a u32, _y: &'b u32, _z: &'c u32) where 'c: 'a + 'b { }
+fn f1<'a, 'b, 'c>(_x: &'a u32, _y: &'b u32, _z: &'c u32) where 'c: 'a + 'b {}
-fn main() { }
+fn main() {}
diff --git a/src/test/pretty/macro.rs b/src/test/pretty/macro.rs
index d3865d93a30..b88ae703950 100644
--- a/src/test/pretty/macro.rs
+++ b/src/test/pretty/macro.rs
@@ -4,4 +4,4 @@
pub(crate) macro mac { ($arg : expr) => { $arg + $arg } }
-fn main() { }
+fn main() {}
diff --git a/src/test/pretty/macro_rules.rs b/src/test/pretty/macro_rules.rs
index 3b13f2530dd..fb66e4a7758 100644
--- a/src/test/pretty/macro_rules.rs
+++ b/src/test/pretty/macro_rules.rs
@@ -1,19 +1,19 @@
// pp-exact
-macro_rules! brace { () => { } ; }
+macro_rules! brace { () => {} ; }
-macro_rules! bracket[() => { } ;];
+macro_rules! bracket[() => {} ;];
-macro_rules! paren(() => { } ;);
+macro_rules! paren(() => {} ;);
macro_rules! matcher_brackets {
- (paren) => { } ; (bracket) => { } ; (brace) => { } ;
+ (paren) => {} ; (bracket) => {} ; (brace) => {} ;
}
macro_rules! all_fragments {
($b : block, $e : expr, $i : ident, $it : item, $l : lifetime, $lit :
literal, $m : meta, $p : pat, $pth : path, $s : stmt, $tt : tt, $ty : ty,
- $vis : vis) => { } ;
+ $vis : vis) => {} ;
}
-fn main() { }
+fn main() {}
diff --git a/src/test/pretty/nested-item-vis-defaultness.rs b/src/test/pretty/nested-item-vis-defaultness.rs
index 0a3f2a10c85..f46c0e3f1bc 100644
--- a/src/test/pretty/nested-item-vis-defaultness.rs
+++ b/src/test/pretty/nested-item-vis-defaultness.rs
@@ -2,7 +2,7 @@
// pp-exact
-fn main() { }
+fn main() {}
#[cfg(FALSE)]
extern "C" {
diff --git a/src/test/pretty/path-type-bounds.rs b/src/test/pretty/path-type-bounds.rs
index 3072e416cbe..f1970de6feb 100644
--- a/src/test/pretty/path-type-bounds.rs
+++ b/src/test/pretty/path-type-bounds.rs
@@ -2,9 +2,9 @@
trait Tr {
- fn dummy(&self) { }
+ fn dummy(&self) {}
}
-impl Tr for isize { }
+impl Tr for isize {}
fn foo<'a>(x: Box<Tr + Sync + 'a>) -> Box<Tr + Sync + 'a> { x }
diff --git a/src/test/pretty/qpath-associated-type-bound.rs b/src/test/pretty/qpath-associated-type-bound.rs
index e06885e0388..67a5d1dd8ec 100644
--- a/src/test/pretty/qpath-associated-type-bound.rs
+++ b/src/test/pretty/qpath-associated-type-bound.rs
@@ -8,9 +8,9 @@ mod m {
}
trait Tu {
- fn dummy() { }
+ fn dummy() {}
}
fn foo<T: m::Tr>() { <T as m::Tr>::Ts::dummy(); }
-fn main() { }
+fn main() {}
diff --git a/src/test/pretty/stmt_expr_attributes.rs b/src/test/pretty/stmt_expr_attributes.rs
index e4a3acade87..01533cd8107 100644
--- a/src/test/pretty/stmt_expr_attributes.rs
+++ b/src/test/pretty/stmt_expr_attributes.rs
@@ -4,7 +4,7 @@
#![feature(rustc_attrs)]
#![feature(stmt_expr_attributes)]
-fn main() { }
+fn main() {}
fn _0() {
@@ -35,7 +35,7 @@ fn _2() {
fn _3() {
#[rustc_dummy]
- match () { _ => { } }
+ match () { _ => {} }
}
fn _4() {
@@ -117,13 +117,13 @@ fn _9() {
stmt_mac!();
#[rustc_dummy]
- stmt_mac! { };
+ stmt_mac! {};
#[rustc_dummy]
stmt_mac![];
#[rustc_dummy]
- stmt_mac! { }
+ stmt_mac! {}
let _ = ();
}
@@ -133,7 +133,7 @@ macro_rules! expr_mac { () => { () } }
fn _10() {
let _ = #[rustc_dummy] expr_mac!();
let _ = #[rustc_dummy] expr_mac![];
- let _ = #[rustc_dummy] expr_mac! { };
+ let _ = #[rustc_dummy] expr_mac! {};
}
fn _11() {
@@ -229,13 +229,12 @@ fn _11() {
let _ = #[rustc_dummy] &mut 0;
let _ = #[rustc_dummy] &#[rustc_dummy] 0;
let _ = #[rustc_dummy] &mut #[rustc_dummy] 0;
- // FIXME: pp bug, extra space after keyword?
- while false { let _ = #[rustc_dummy] continue ; }
- while true { let _ = #[rustc_dummy] break ; }
+ while false { let _ = #[rustc_dummy] continue; }
+ while true { let _ = #[rustc_dummy] break; }
|| #[rustc_dummy] return;
let _ = #[rustc_dummy] expr_mac!();
let _ = #[rustc_dummy] expr_mac![];
- let _ = #[rustc_dummy] expr_mac! { };
+ let _ = #[rustc_dummy] expr_mac! {};
let _ = #[rustc_dummy] Foo{data: (),};
let _ = #[rustc_dummy] Foo{..s};
let _ = #[rustc_dummy] Foo{data: (), ..s};
@@ -258,6 +257,6 @@ fn _12() {
}
}
-fn foo() { }
-fn foo3(_: i32, _: (), _: ()) { }
-fn qux(_: i32) { }
+fn foo() {}
+fn foo3(_: i32, _: (), _: ()) {}
+fn qux(_: i32) {}
diff --git a/src/test/pretty/tag-blank-lines.rs b/src/test/pretty/tag-blank-lines.rs
index 28ed4fccaf2..d53f6e4b528 100644
--- a/src/test/pretty/tag-blank-lines.rs
+++ b/src/test/pretty/tag-blank-lines.rs
@@ -5,4 +5,4 @@ enum foo {
baz,
}
-fn main() { }
+fn main() {}
diff --git a/src/test/pretty/trait-inner-attr.rs b/src/test/pretty/trait-inner-attr.rs
index bb4fb1459bd..6cb0e4136b6 100644
--- a/src/test/pretty/trait-inner-attr.rs
+++ b/src/test/pretty/trait-inner-attr.rs
@@ -4,4 +4,4 @@ trait Foo {
#![allow(bar)]
}
-fn main() { }
+fn main() {}
diff --git a/src/test/pretty/trait-polarity.rs b/src/test/pretty/trait-polarity.rs
index df1a7946afb..310506eabca 100644
--- a/src/test/pretty/trait-polarity.rs
+++ b/src/test/pretty/trait-polarity.rs
@@ -4,6 +4,6 @@
struct Test;
-impl !Send for Test { }
+impl !Send for Test {}
-pub fn main() { }
+pub fn main() {}
diff --git a/src/test/pretty/trait-safety.rs b/src/test/pretty/trait-safety.rs
index b2f2d610c31..c4ae7606946 100644
--- a/src/test/pretty/trait-safety.rs
+++ b/src/test/pretty/trait-safety.rs
@@ -5,11 +5,11 @@ unsafe trait UnsafeTrait {
}
unsafe impl UnsafeTrait for isize {
- fn foo(&self) { }
+ fn foo(&self) {}
}
pub unsafe trait PubUnsafeTrait {
fn foo(&self);
}
-fn main() { }
+fn main() {}
diff --git a/src/test/pretty/where-clauses.rs b/src/test/pretty/where-clauses.rs
index 3d6e431a11a..5614a81b0eb 100644
--- a/src/test/pretty/where-clauses.rs
+++ b/src/test/pretty/where-clauses.rs
@@ -2,4 +2,4 @@
fn f<'a, 'b, T>(t: T) -> isize where T: 'a, 'a: 'b, T: Eq { 0 }
-fn main() { }
+fn main() {}
diff --git a/src/test/run-make-fulldeps/coverage-llvmir/Makefile b/src/test/run-make-fulldeps/coverage-llvmir/Makefile
index 8722d9e10d9..3c4df3533e1 100644
--- a/src/test/run-make-fulldeps/coverage-llvmir/Makefile
+++ b/src/test/run-make-fulldeps/coverage-llvmir/Makefile
@@ -1,5 +1,11 @@
# needs-profiler-support
+# Rust coverage maps support LLVM Coverage Mapping Format versions 5 and 6,
+# corresponding with LLVM versions 12 and 13, respectively.
+# When upgrading LLVM versions, consider whether to enforce a minimum LLVM
+# version during testing, with an additional directive at the top of this file
+# that sets, for example: `min-llvm-version: 12.0`
+
-include ../coverage/coverage_tools.mk
BASEDIR=../coverage-llvmir
diff --git a/src/test/run-make-fulldeps/coverage-reports/Makefile b/src/test/run-make-fulldeps/coverage-reports/Makefile
index 4adf02bee0a..9122e0406c2 100644
--- a/src/test/run-make-fulldeps/coverage-reports/Makefile
+++ b/src/test/run-make-fulldeps/coverage-reports/Makefile
@@ -1,6 +1,12 @@
# needs-profiler-support
# ignore-windows-gnu
+# Rust coverage maps support LLVM Coverage Mapping Format versions 5 and 6,
+# corresponding with LLVM versions 12 and 13, respectively.
+# When upgrading LLVM versions, consider whether to enforce a minimum LLVM
+# version during testing, with an additional directive at the top of this file
+# that sets, for example: `min-llvm-version: 12.0`
+
# FIXME(mati865): MinGW GCC miscompiles compiler-rt profiling library but with Clang it works
# properly. Since we only have GCC on the CI ignore the test for now.
@@ -115,6 +121,7 @@ endif
"$(LLVM_BIN_DIR)"/llvm-cov show \
$(DEBUG_FLAG) \
$(LLVM_COV_IGNORE_FILES) \
+ --compilation-dir=. \
--Xdemangler="$(RUST_DEMANGLER)" \
--show-line-counts-or-regions \
--instr-profile="$(TMPDIR)"/$@.profdata \
diff --git a/src/test/run-make-fulldeps/coverage-reports/expected_show_coverage.async.txt b/src/test/run-make-fulldeps/coverage-reports/expected_show_coverage.async.txt
index ae9487473d0..2f69adbd81c 100644
--- a/src/test/run-make-fulldeps/coverage-reports/expected_show_coverage.async.txt
+++ b/src/test/run-make-fulldeps/coverage-reports/expected_show_coverage.async.txt
@@ -41,9 +41,9 @@
41| 1| // executed asynchronously.
42| 1| match x {
43| 1| y if c(x).await == y + 1 => { d().await; }
- ^0 ^0
+ ^0 ^0 ^0 ^0
44| 1| y if f().await == y + 1 => (),
- ^0 ^0
+ ^0 ^0 ^0
45| 1| _ => (),
46| | }
47| 1|}
diff --git a/src/test/run-make-fulldeps/coverage-reports/expected_show_coverage.issue-85461.txt b/src/test/run-make-fulldeps/coverage-reports/expected_show_coverage.issue-85461.txt
new file mode 100644
index 00000000000..2831e9b532a
--- /dev/null
+++ b/src/test/run-make-fulldeps/coverage-reports/expected_show_coverage.issue-85461.txt
@@ -0,0 +1,36 @@
+../coverage/issue-85461.rs:
+ 1| |// Regression test for #85461: MSVC sometimes fail to link with dead code and #[inline(always)]
+ 2| |
+ 3| |extern crate inline_always_with_dead_code;
+ 4| |
+ 5| |use inline_always_with_dead_code::{bar, baz};
+ 6| |
+ 7| 1|fn main() {
+ 8| 1| bar::call_me();
+ 9| 1| baz::call_me();
+ 10| 1|}
+
+../coverage/lib/inline_always_with_dead_code.rs:
+ 1| |// compile-flags: -Zinstrument-coverage -Ccodegen-units=4 -Copt-level=0
+ 2| |
+ 3| |#![allow(dead_code)]
+ 4| |
+ 5| |mod foo {
+ 6| | #[inline(always)]
+ 7| 2| pub fn called() { }
+ 8| |
+ 9| 0| fn uncalled() { }
+ 10| |}
+ 11| |
+ 12| |pub mod bar {
+ 13| 1| pub fn call_me() {
+ 14| 1| super::foo::called();
+ 15| 1| }
+ 16| |}
+ 17| |
+ 18| |pub mod baz {
+ 19| 1| pub fn call_me() {
+ 20| 1| super::foo::called();
+ 21| 1| }
+ 22| |}
+
diff --git a/src/test/run-make-fulldeps/coverage/issue-85461.rs b/src/test/run-make-fulldeps/coverage/issue-85461.rs
new file mode 100644
index 00000000000..a1b9ebb1ed3
--- /dev/null
+++ b/src/test/run-make-fulldeps/coverage/issue-85461.rs
@@ -0,0 +1,10 @@
+// Regression test for #85461: MSVC sometimes fail to link with dead code and #[inline(always)]
+
+extern crate inline_always_with_dead_code;
+
+use inline_always_with_dead_code::{bar, baz};
+
+fn main() {
+ bar::call_me();
+ baz::call_me();
+}
diff --git a/src/test/run-make-fulldeps/coverage/lib/inline_always_with_dead_code.rs b/src/test/run-make-fulldeps/coverage/lib/inline_always_with_dead_code.rs
new file mode 100644
index 00000000000..b567916aea0
--- /dev/null
+++ b/src/test/run-make-fulldeps/coverage/lib/inline_always_with_dead_code.rs
@@ -0,0 +1,22 @@
+// compile-flags: -Zinstrument-coverage -Ccodegen-units=4 -Copt-level=0
+
+#![allow(dead_code)]
+
+mod foo {
+ #[inline(always)]
+ pub fn called() { }
+
+ fn uncalled() { }
+}
+
+pub mod bar {
+ pub fn call_me() {
+ super::foo::called();
+ }
+}
+
+pub mod baz {
+ pub fn call_me() {
+ super::foo::called();
+ }
+}
diff --git a/src/test/run-make-fulldeps/crate-hash-rustc-version/Makefile b/src/test/run-make-fulldeps/crate-hash-rustc-version/Makefile
new file mode 100644
index 00000000000..fd66702db7f
--- /dev/null
+++ b/src/test/run-make-fulldeps/crate-hash-rustc-version/Makefile
@@ -0,0 +1,37 @@
+-include ../../run-make-fulldeps/tools.mk
+
+# Ensure that crates compiled with different rustc versions cannot
+# be dynamically linked.
+
+FLAGS := -Cprefer-dynamic -Zsymbol-mangling-version=v0
+UNAME := $(shell uname)
+ifeq ($(UNAME),Linux)
+ EXT=".so"
+ NM_CMD := nm -D
+endif
+ifeq ($(UNAME),Darwin)
+ EXT=".dylib"
+ NM_CMD := nm
+endif
+
+ifndef NM_CMD
+all:
+ exit 0
+else
+all:
+ # a.rs is a dylib
+ $(RUSTC) a.rs --crate-type=dylib $(FLAGS)
+ # Write symbols to disk.
+ $(NM_CMD) $(call DYLIB,a) > $(TMPDIR)/symbolsbefore
+ # b.rs is a binary
+ $(RUSTC) b.rs --extern a=$(TMPDIR)/liba$(EXT) --crate-type=bin -Crpath $(FLAGS)
+ $(call RUN,b)
+ # Now re-compile a.rs with another rustc version
+ RUSTC_FORCE_INCR_COMP_ARTIFACT_HEADER=deadfeed $(RUSTC) a.rs --crate-type=dylib $(FLAGS)
+ # After compiling with a different rustc version, write symbols to disk again.
+ $(NM_CMD) $(call DYLIB,a) > $(TMPDIR)/symbolsafter
+ # As a sanity check, test if the symbols changed:
+ # If the symbols are identical, there's been an error.
+ if diff $(TMPDIR)/symbolsbefore $(TMPDIR)/symbolsafter; then exit 1; fi
+ $(call FAIL,b)
+endif
diff --git a/src/test/run-make-fulldeps/crate-hash-rustc-version/a.rs b/src/test/run-make-fulldeps/crate-hash-rustc-version/a.rs
new file mode 100644
index 00000000000..d65b5ce8e88
--- /dev/null
+++ b/src/test/run-make-fulldeps/crate-hash-rustc-version/a.rs
@@ -0,0 +1,4 @@
+pub fn foo(mut x: String) -> String {
+ x.push_str(", world!");
+ x
+}
diff --git a/src/test/run-make-fulldeps/crate-hash-rustc-version/b.rs b/src/test/run-make-fulldeps/crate-hash-rustc-version/b.rs
new file mode 100644
index 00000000000..316ac26e73f
--- /dev/null
+++ b/src/test/run-make-fulldeps/crate-hash-rustc-version/b.rs
@@ -0,0 +1,8 @@
+extern crate a;
+
+use a::foo;
+
+fn main() {
+ let x = String::from("Hello");
+ println!("{}", foo(x));
+}
diff --git a/src/test/run-make-fulldeps/extern-fn-reachable/Makefile b/src/test/run-make-fulldeps/extern-fn-reachable/Makefile
index 79a9a3c640f..9231a2b3574 100644
--- a/src/test/run-make-fulldeps/extern-fn-reachable/Makefile
+++ b/src/test/run-make-fulldeps/extern-fn-reachable/Makefile
@@ -1,9 +1,25 @@
-include ../tools.mk
+# ignore-windows-msvc
+
+NM=nm -D
+
+ifeq ($(UNAME),Darwin)
+NM=nm -gU
+endif
+
+ifdef IS_WINDOWS
+NM=nm -g
+endif
+
# This overrides the LD_LIBRARY_PATH for RUN
TARGET_RPATH_DIR:=$(TARGET_RPATH_DIR):$(TMPDIR)
all:
$(RUSTC) dylib.rs -o $(TMPDIR)/libdylib.so -C prefer-dynamic
- $(RUSTC) main.rs -C prefer-dynamic
- $(call RUN,main)
+
+ [ "$$($(NM) $(TMPDIR)/libdylib.so | grep -v __imp_ | grep -c fun1)" -eq "1" ]
+ [ "$$($(NM) $(TMPDIR)/libdylib.so | grep -v __imp_ | grep -c fun2)" -eq "1" ]
+ [ "$$($(NM) $(TMPDIR)/libdylib.so | grep -v __imp_ | grep -c fun3)" -eq "1" ]
+ [ "$$($(NM) $(TMPDIR)/libdylib.so | grep -v __imp_ | grep -c fun4)" -eq "1" ]
+ [ "$$($(NM) $(TMPDIR)/libdylib.so | grep -v __imp_ | grep -c fun5)" -eq "1" ]
diff --git a/src/test/run-make-fulldeps/extern-fn-reachable/main.rs b/src/test/run-make-fulldeps/extern-fn-reachable/main.rs
deleted file mode 100644
index c1de6477585..00000000000
--- a/src/test/run-make-fulldeps/extern-fn-reachable/main.rs
+++ /dev/null
@@ -1,18 +0,0 @@
-#![feature(rustc_private)]
-
-extern crate rustc_metadata;
-
-use rustc_metadata::dynamic_lib::DynamicLibrary;
-use std::path::Path;
-
-pub fn main() {
- unsafe {
- let path = Path::new("libdylib.so");
- let a = DynamicLibrary::open(&path).unwrap();
- assert!(a.symbol::<isize>("fun1").is_ok());
- assert!(a.symbol::<isize>("fun2").is_ok());
- assert!(a.symbol::<isize>("fun3").is_ok());
- assert!(a.symbol::<isize>("fun4").is_ok());
- assert!(a.symbol::<isize>("fun5").is_ok());
- }
-}
diff --git a/src/test/run-make-fulldeps/hotplug_codegen_backend/the_backend.rs b/src/test/run-make-fulldeps/hotplug_codegen_backend/the_backend.rs
index 7c16f7bdaf7..8047a42c2b1 100644
--- a/src/test/run-make-fulldeps/hotplug_codegen_backend/the_backend.rs
+++ b/src/test/run-make-fulldeps/hotplug_codegen_backend/the_backend.rs
@@ -46,6 +46,7 @@ impl CodegenBackend for TheBackend {
&self,
ongoing_codegen: Box<dyn Any>,
_sess: &Session,
+ _outputs: &OutputFilenames,
) -> Result<(CodegenResults, FxHashMap<WorkProductId, WorkProduct>), ErrorReported> {
let codegen_results = ongoing_codegen
.downcast::<CodegenResults>()
diff --git a/src/test/run-make-fulldeps/split-dwarf/Makefile b/src/test/run-make-fulldeps/split-dwarf/Makefile
index ef61ff04501..eef04c767fb 100644
--- a/src/test/run-make-fulldeps/split-dwarf/Makefile
+++ b/src/test/run-make-fulldeps/split-dwarf/Makefile
@@ -2,7 +2,16 @@
# only-linux
-all:
+all: packed remapped
+
+remapped:
+ $(RUSTC) -Z unstable-options -C split-debuginfo=packed -C debuginfo=2 --remap-path-prefix $(TMPDIR)=/a foo.rs -g
+ objdump -Wi $(TMPDIR)/foo | grep DW_AT_GNU_dwo_name | (! grep $(TMPDIR)) || exit 1
+
+ $(RUSTC) -Z unstable-options -C split-debuginfo=unpacked -C debuginfo=2 --remap-path-prefix $(TMPDIR)=/a foo.rs -g
+ objdump -Wi $(TMPDIR)/foo | grep DW_AT_GNU_dwo_name | (! grep $(TMPDIR)) || exit 1
+
+packed:
$(RUSTC) -Z unstable-options -C split-debuginfo=packed -C debuginfo=2 foo.rs -g
rm $(TMPDIR)/foo.dwp
rm $(TMPDIR)/$(call BIN,foo)
diff --git a/src/test/run-make/rustdoc-with-out-dir-option/Makefile b/src/test/run-make/rustdoc-with-out-dir-option/Makefile
new file mode 100644
index 00000000000..f79fce8eeea
--- /dev/null
+++ b/src/test/run-make/rustdoc-with-out-dir-option/Makefile
@@ -0,0 +1,8 @@
+-include ../../run-make-fulldeps/tools.mk
+
+OUTPUT_DIR := "$(TMPDIR)/rustdoc"
+
+all:
+ $(RUSTDOC) src/lib.rs --crate-name foobar --crate-type lib --out-dir $(OUTPUT_DIR)
+
+ $(HTMLDOCCK) $(OUTPUT_DIR) src/lib.rs
diff --git a/src/test/run-make/rustdoc-with-out-dir-option/src/lib.rs b/src/test/run-make/rustdoc-with-out-dir-option/src/lib.rs
new file mode 100644
index 00000000000..044bb6acb19
--- /dev/null
+++ b/src/test/run-make/rustdoc-with-out-dir-option/src/lib.rs
@@ -0,0 +1,2 @@
+// @has foobar/fn.ok.html
+pub fn ok() {}
diff --git a/src/test/run-make/rustdoc-with-output-option/Makefile b/src/test/run-make/rustdoc-with-output-option/Makefile
new file mode 100644
index 00000000000..654f9672588
--- /dev/null
+++ b/src/test/run-make/rustdoc-with-output-option/Makefile
@@ -0,0 +1,8 @@
+-include ../../run-make-fulldeps/tools.mk
+
+OUTPUT_DIR := "$(TMPDIR)/rustdoc"
+
+all:
+ $(RUSTDOC) src/lib.rs --crate-name foobar --crate-type lib --output $(OUTPUT_DIR)
+
+ $(HTMLDOCCK) $(OUTPUT_DIR) src/lib.rs
diff --git a/src/test/run-make/rustdoc-with-output-option/src/lib.rs b/src/test/run-make/rustdoc-with-output-option/src/lib.rs
new file mode 100644
index 00000000000..044bb6acb19
--- /dev/null
+++ b/src/test/run-make/rustdoc-with-output-option/src/lib.rs
@@ -0,0 +1,2 @@
+// @has foobar/fn.ok.html
+pub fn ok() {}
diff --git a/src/test/run-make/rustdoc-with-short-out-dir-option/Makefile b/src/test/run-make/rustdoc-with-short-out-dir-option/Makefile
new file mode 100644
index 00000000000..1e9ba71de26
--- /dev/null
+++ b/src/test/run-make/rustdoc-with-short-out-dir-option/Makefile
@@ -0,0 +1,8 @@
+-include ../../run-make-fulldeps/tools.mk
+
+OUTPUT_DIR := "$(TMPDIR)/rustdoc"
+
+all:
+ $(RUSTDOC) src/lib.rs --crate-name foobar --crate-type lib -o $(OUTPUT_DIR)
+
+ $(HTMLDOCCK) $(OUTPUT_DIR) src/lib.rs
diff --git a/src/test/run-make/rustdoc-with-short-out-dir-option/src/lib.rs b/src/test/run-make/rustdoc-with-short-out-dir-option/src/lib.rs
new file mode 100644
index 00000000000..044bb6acb19
--- /dev/null
+++ b/src/test/run-make/rustdoc-with-short-out-dir-option/src/lib.rs
@@ -0,0 +1,2 @@
+// @has foobar/fn.ok.html
+pub fn ok() {}
diff --git a/src/test/run-make/x86_64-fortanix-unknown-sgx-lvi/enclave/src/main.rs b/src/test/run-make/x86_64-fortanix-unknown-sgx-lvi/enclave/src/main.rs
index 791dec2ed69..cde38aacf7f 100644
--- a/src/test/run-make/x86_64-fortanix-unknown-sgx-lvi/enclave/src/main.rs
+++ b/src/test/run-make/x86_64-fortanix-unknown-sgx-lvi/enclave/src/main.rs
@@ -1,6 +1,5 @@
-#![feature(global_asm)]
-
-global_asm!( r#"
+std::arch::global_asm!(
+ r#"
.text
.global rust_plus_one_global_asm
.type rust_plus_one_global_asm, @function
@@ -8,41 +7,43 @@ rust_plus_one_global_asm:
movl (%rdi), %eax
inc %eax
retq
-"#, options(att_syntax));
+"#,
+ options(att_syntax)
+);
-extern {
- fn cc_plus_one_c(arg : &u32) -> u32;
- fn cc_plus_one_c_asm(arg : &u32) -> u32;
- fn cc_plus_one_cxx(arg : &u32) -> u32;
- fn cc_plus_one_cxx_asm(arg : &u32) -> u32;
- fn cc_plus_one_asm(arg : &u32) -> u32;
- fn cmake_plus_one_c(arg : &u32) -> u32;
- fn cmake_plus_one_c_asm(arg : &u32) -> u32;
- fn cmake_plus_one_cxx(arg : &u32) -> u32;
- fn cmake_plus_one_cxx_asm(arg : &u32) -> u32;
- fn cmake_plus_one_c_global_asm(arg : &u32) -> u32;
- fn cmake_plus_one_cxx_global_asm(arg : &u32) -> u32;
- fn cmake_plus_one_asm(arg : &u32) -> u32;
- fn rust_plus_one_global_asm(arg : &u32) -> u32;
+extern "C" {
+ fn cc_plus_one_c(arg: &u32) -> u32;
+ fn cc_plus_one_c_asm(arg: &u32) -> u32;
+ fn cc_plus_one_cxx(arg: &u32) -> u32;
+ fn cc_plus_one_cxx_asm(arg: &u32) -> u32;
+ fn cc_plus_one_asm(arg: &u32) -> u32;
+ fn cmake_plus_one_c(arg: &u32) -> u32;
+ fn cmake_plus_one_c_asm(arg: &u32) -> u32;
+ fn cmake_plus_one_cxx(arg: &u32) -> u32;
+ fn cmake_plus_one_cxx_asm(arg: &u32) -> u32;
+ fn cmake_plus_one_c_global_asm(arg: &u32) -> u32;
+ fn cmake_plus_one_cxx_global_asm(arg: &u32) -> u32;
+ fn cmake_plus_one_asm(arg: &u32) -> u32;
+ fn rust_plus_one_global_asm(arg: &u32) -> u32;
}
fn main() {
- let value : u32 = 41;
+ let value: u32 = 41;
let question = "Answer to the Ultimate Question of Life, the Universe, and Everything:";
- unsafe{
- println!("{}: {}!", question,rust_plus_one_global_asm(&value));
- println!("{}: {}!", question,cc_plus_one_c(&value));
- println!("{}: {}!", question,cc_plus_one_c_asm(&value));
- println!("{}: {}!", question,cc_plus_one_cxx(&value));
- println!("{}: {}!", question,cc_plus_one_cxx_asm(&value));
- println!("{}: {}!", question,cc_plus_one_asm(&value));
- println!("{}: {}!", question,cmake_plus_one_c(&value));
- println!("{}: {}!", question,cmake_plus_one_c_asm(&value));
- println!("{}: {}!", question,cmake_plus_one_cxx(&value));
- println!("{}: {}!", question,cmake_plus_one_cxx_asm(&value));
- println!("{}: {}!", question,cmake_plus_one_c_global_asm(&value));
- println!("{}: {}!", question,cmake_plus_one_cxx_global_asm(&value));
- println!("{}: {}!", question,cmake_plus_one_asm(&value));
+ unsafe {
+ println!("{}: {}!", question, rust_plus_one_global_asm(&value));
+ println!("{}: {}!", question, cc_plus_one_c(&value));
+ println!("{}: {}!", question, cc_plus_one_c_asm(&value));
+ println!("{}: {}!", question, cc_plus_one_cxx(&value));
+ println!("{}: {}!", question, cc_plus_one_cxx_asm(&value));
+ println!("{}: {}!", question, cc_plus_one_asm(&value));
+ println!("{}: {}!", question, cmake_plus_one_c(&value));
+ println!("{}: {}!", question, cmake_plus_one_c_asm(&value));
+ println!("{}: {}!", question, cmake_plus_one_cxx(&value));
+ println!("{}: {}!", question, cmake_plus_one_cxx_asm(&value));
+ println!("{}: {}!", question, cmake_plus_one_c_global_asm(&value));
+ println!("{}: {}!", question, cmake_plus_one_cxx_global_asm(&value));
+ println!("{}: {}!", question, cmake_plus_one_asm(&value));
}
}
diff --git a/src/test/rustdoc-gui/anchors.goml b/src/test/rustdoc-gui/anchors.goml
new file mode 100644
index 00000000000..2216b3f1c97
--- /dev/null
+++ b/src/test/rustdoc-gui/anchors.goml
@@ -0,0 +1,74 @@
+// This test is to ensure that the anchors (`§`) have the expected color and position.
+goto: file://|DOC_PATH|/test_docs/struct.HeavilyDocumentedStruct.html
+show-text: true
+
+// This is needed to ensure that the text color is computed.
+show-text: true
+
+// Set the theme to light.
+local-storage: {"rustdoc-theme": "light", "rustdoc-use-system-theme": "false"}
+// We reload the page so the local storage settings are being used.
+reload:
+
+assert-css: ("#toggle-all-docs", {"color": "rgb(0, 0, 0)"})
+assert-css: (".fqn .in-band a:nth-of-type(1)", {"color": "rgb(0, 0, 0)"})
+assert-css: (".fqn .in-band a:nth-of-type(2)", {"color": "rgb(173, 68, 142)"})
+assert-css: (".srclink", {"color": "rgb(0, 0, 0)"})
+assert-css: (".srclink", {"color": "rgb(0, 0, 0)"})
+
+assert-css: ("#top-doc-prose-title", {"color": "rgb(0, 0, 0)"})
+
+assert-css: (".sidebar a", {"color": "rgb(0, 0, 0)"})
+assert-css: (".in-band a", {"color": "rgb(0, 0, 0)"})
+
+// We move the cursor over the "Implementations" title so the anchor is displayed.
+move-cursor-to: "h2#implementations"
+assert-css: ("h2#implementations a.anchor", {"color": "rgb(0, 0, 0)"})
+
+// Same thing with the impl block title.
+move-cursor-to: "#impl"
+assert-css: ("#impl a.anchor", {"color": "rgb(0, 0, 0)"})
+
+// Now we check the positions: only the first heading of the top doc comment should
+// have a different position.
+move-cursor-to: ".top-doc .docblock .section-header:first-child"
+assert-css: (
+ ".top-doc .docblock .section-header:first-child > a::before",
+ {"left": "-10px", "padding-right": "10px"},
+)
+// We also check that the heading itself has a different indent.
+assert-css: (".top-doc .docblock .section-header:first-child", {"margin-left": "15px"})
+
+move-cursor-to: ".top-doc .docblock .section-header:not(:first-child)"
+assert-css: (
+ ".top-doc .docblock .section-header:not(:first-child) > a::before",
+ {"left": "-25px", "padding-right": "10px"},
+)
+assert-css: (".top-doc .docblock .section-header:not(:first-child)", {"margin-left": "0px"})
+
+// Now let's check some other docblock headings...
+// First the impl block docs.
+move-cursor-to: "#title-for-struct-impl-doc"
+assert-css: (
+ "#title-for-struct-impl-doc > a::before",
+ {"left": "-25px", "padding-right": "10px"},
+)
+assert-css: ("#title-for-struct-impl-doc", {"margin-left": "0px"})
+// Now a method docs.
+move-cursor-to: "#title-for-struct-impl-item-doc"
+assert-css: (
+ "#title-for-struct-impl-item-doc > a::before",
+ {"left": "-25px", "padding-right": "10px"},
+)
+assert-css: ("#title-for-struct-impl-item-doc", {"margin-left": "0px"})
+
+// Finally, we want to ensure that if the first element of the doc block isn't a heading,
+// if there is a heading afterwards, it won't have the indent.
+goto: file://|DOC_PATH|/test_docs/enum.WhoLetTheDogOut.html
+
+move-cursor-to: ".top-doc .docblock .section-header"
+assert-css: (
+ ".top-doc .docblock .section-header > a::before",
+ {"left": "-25px", "padding-right": "10px"},
+)
+assert-css: (".top-doc .docblock .section-header", {"margin-left": "0px"})
diff --git a/src/test/rustdoc-gui/check-code-blocks-margin.goml b/src/test/rustdoc-gui/check-code-blocks-margin.goml
index 2de47682856..f6266eba75d 100644
--- a/src/test/rustdoc-gui/check-code-blocks-margin.goml
+++ b/src/test/rustdoc-gui/check-code-blocks-margin.goml
@@ -1,6 +1,6 @@
// This test ensures that the docblock elements have the appropriate left margin.
goto: file://|DOC_PATH|/test_docs/fn.foo.html
// The top docblock elements shouldn't have left margin...
-assert-css: ("#main .docblock.item-decl", {"margin-left": "0px"})
+assert-css: ("#main-content .docblock.item-decl", {"margin-left": "0px"})
// ... but all the others should!
-assert-css: ("#main .docblock:not(.item-decl)", {"margin-left": "24px"})
+assert-css: ("#main-content .docblock:not(.item-decl)", {"margin-left": "24px"})
diff --git a/src/test/rustdoc-gui/docblock-code-block-line-number.goml b/src/test/rustdoc-gui/docblock-code-block-line-number.goml
index 7e6607b55ea..baf9651c40d 100644
--- a/src/test/rustdoc-gui/docblock-code-block-line-number.goml
+++ b/src/test/rustdoc-gui/docblock-code-block-line-number.goml
@@ -16,7 +16,7 @@ wait-for: "pre.line-number"
assert-css: ("pre.line-number", {
"margin": "0px",
"padding": "13px 8px",
- "text-align": "right"
+ "text-align": "right",
})
// The first code block has two lines so let's check its `<pre>` elements lists both of them.
assert-text: ("pre.line-number", "1\n2")
diff --git a/src/test/rustdoc-gui/docblock-table-overflow.goml b/src/test/rustdoc-gui/docblock-table-overflow.goml
index 10f516d2dae..1b3006155d8 100644
--- a/src/test/rustdoc-gui/docblock-table-overflow.goml
+++ b/src/test/rustdoc-gui/docblock-table-overflow.goml
@@ -11,7 +11,11 @@ assert-property: (".top-doc .docblock table", {"scrollWidth": "1573"})
// Checking it works on other doc blocks as well...
// Logically, the ".docblock" and the "<p>" should have the same scroll width.
-compare-elements-property: ("#implementations + details .docblock", "#implementations + details .docblock > p", ["scrollWidth"])
+compare-elements-property: (
+ "#implementations + details .docblock",
+ "#implementations + details .docblock > p",
+ ["scrollWidth"],
+)
assert-property: ("#implementations + details .docblock", {"scrollWidth": "816"})
// However, since there is overflow in the <table>, its scroll width is bigger.
assert-property: ("#implementations + details .docblock table", {"scrollWidth": "1573"})
diff --git a/src/test/rustdoc-gui/escape-key.goml b/src/test/rustdoc-gui/escape-key.goml
index 5cf8a5e136e..b65c398405c 100644
--- a/src/test/rustdoc-gui/escape-key.goml
+++ b/src/test/rustdoc-gui/escape-key.goml
@@ -3,15 +3,15 @@ goto: file://|DOC_PATH|/test_docs/index.html
write: (".search-input", "test")
wait-for: "#search > h1" // The search element is empty before the first search
assert-attribute: ("#search", {"class": "content"})
-assert-attribute: ("#main", {"class": "content hidden"})
+assert-attribute: ("#main-content", {"class": "content hidden"})
press-key: "Escape"
assert-attribute: ("#search", {"class": "content hidden"})
-assert-attribute: ("#main", {"class": "content"})
+assert-attribute: ("#main-content", {"class": "content"})
// Check that focusing the search input brings back the search results
focus: ".search-input"
assert-attribute: ("#search", {"class": "content"})
-assert-attribute: ("#main", {"class": "content hidden"})
+assert-attribute: ("#main-content", {"class": "content hidden"})
// Now let's check that when the help popup is displayed and we press Escape, it doesn't
// hide the search results too.
@@ -20,7 +20,7 @@ assert-attribute: ("#help", {"class": ""})
press-key: "Escape"
assert-attribute: ("#help", {"class": "hidden"})
assert-attribute: ("#search", {"class": "content"})
-assert-attribute: ("#main", {"class": "content hidden"})
+assert-attribute: ("#main-content", {"class": "content hidden"})
// Check that Escape hides the search results when a search result is focused.
focus: ".search-input"
@@ -31,4 +31,4 @@ assert: "#results a:focus"
press-key: "Escape"
assert-attribute: ("#help", {"class": "hidden"})
assert-attribute: ("#search", {"class": "content hidden"})
-assert-attribute: ("#main", {"class": "content"})
+assert-attribute: ("#main-content", {"class": "content"})
diff --git a/src/test/rustdoc-gui/font-weight.goml b/src/test/rustdoc-gui/font-weight.goml
index 0459fd4b9c3..c9117e2c101 100644
--- a/src/test/rustdoc-gui/font-weight.goml
+++ b/src/test/rustdoc-gui/font-weight.goml
@@ -1,7 +1,10 @@
goto: file://|DOC_PATH|/lib2/struct.Foo.html
// This test checks that the font weight is correctly applied.
assert-css: ("//*[@class='docblock item-decl']//a[text()='Alias']", {"font-weight": "400"})
-assert-css: ("//*[@class='structfield small-section-header']//a[text()='Alias']", {"font-weight": "400"})
+assert-css: (
+ "//*[@class='structfield small-section-header']//a[text()='Alias']",
+ {"font-weight": "400"},
+)
assert-css: ("#method\.a_method > .code-header", {"font-weight": "600"})
assert-css: ("#associatedtype\.X > .code-header", {"font-weight": "600"})
assert-css: ("#associatedconstant\.Y > .code-header", {"font-weight": "600"})
@@ -25,8 +28,14 @@ goto: file://|DOC_PATH|/lib2/trait.Trait.html
//
// This uses '/parent::*' as a proxy for the style of the text node.
// We can't just select the '<a>' because intermediate tags could be added.
-assert-count: ("//*[@class='docblock item-decl']/pre[@class='rust trait']/code/a[@class='constant']//text()/parent::*", 1)
-assert-css: ("//*[@class='docblock item-decl']/pre[@class='rust trait']/code/a[@class='constant']//text()/parent::*", {"font-weight": "400"})
+assert-count: (
+ "//*[@class='docblock item-decl']/pre[@class='rust trait']/code/a[@class='constant']//text()/parent::*",
+ 1,
+)
+assert-css: (
+ "//*[@class='docblock item-decl']/pre[@class='rust trait']/code/a[@class='constant']//text()/parent::*",
+ {"font-weight": "400"},
+)
assert-count: (".methods .type", 1)
assert-css: (".methods .type", {"font-weight": "600"})
diff --git a/src/test/rustdoc-gui/headers-color.goml b/src/test/rustdoc-gui/headers-color.goml
index b5be31bd2cc..d58ca13a629 100644
--- a/src/test/rustdoc-gui/headers-color.goml
+++ b/src/test/rustdoc-gui/headers-color.goml
@@ -5,30 +5,80 @@ goto: file://|DOC_PATH|/test_docs/struct.Foo.html
show-text: true
// Ayu theme
-local-storage: {"rustdoc-theme": "ayu", "rustdoc-preferred-dark-theme": "ayu", "rustdoc-use-system-theme": "false"}
+local-storage: {
+ "rustdoc-theme": "ayu",
+ "rustdoc-preferred-dark-theme": "ayu",
+ "rustdoc-use-system-theme": "false",
+}
reload:
-assert-css: (".impl", {"color": "rgb(197, 197, 197)", "background-color": "rgba(0, 0, 0, 0)"}, ALL)
-assert-css: (".impl .code-header", {"color": "rgb(230, 225, 207)", "background-color": "rgb(15, 20, 25)"}, ALL)
+assert-css: (
+ ".impl",
+ {"color": "rgb(197, 197, 197)", "background-color": "rgba(0, 0, 0, 0)"},
+ ALL,
+)
+assert-css: (
+ ".impl .code-header",
+ {"color": "rgb(230, 225, 207)", "background-color": "rgb(15, 20, 25)"},
+ ALL,
+)
goto: file://|DOC_PATH|/test_docs/struct.Foo.html#impl
-assert-css: ("#impl", {"color": "rgb(197, 197, 197)", "background-color": "rgba(255, 236, 164, 0.06)"})
+assert-css: (
+ "#impl",
+ {"color": "rgb(197, 197, 197)", "background-color": "rgba(255, 236, 164, 0.06)"},
+)
goto: file://|DOC_PATH|/test_docs/struct.Foo.html#method.must_use
-assert-css: ("#method\.must_use", {"color": "rgb(197, 197, 197)", "background-color": "rgba(255, 236, 164, 0.06)"}, ALL)
+assert-css: (
+ "#method\.must_use",
+ {"color": "rgb(197, 197, 197)", "background-color": "rgba(255, 236, 164, 0.06)"},
+ ALL,
+)
+
+goto: file://|DOC_PATH|/test_docs/index.html
+assert-css: (".small-section-header a", {"color": "rgb(197, 197, 197)"}, ALL)
+
+goto: file://|DOC_PATH|/test_docs/struct.HeavilyDocumentedStruct.html
+assert-css: (".section-header a", {"color": "rgb(57, 175, 215)"}, ALL)
// Dark theme
-local-storage: {"rustdoc-theme": "dark", "rustdoc-preferred-dark-theme": "dark", "rustdoc-use-system-theme": "false"}
+local-storage: {
+ "rustdoc-theme": "dark",
+ "rustdoc-preferred-dark-theme": "dark",
+ "rustdoc-use-system-theme": "false",
+}
goto: file://|DOC_PATH|/test_docs/struct.Foo.html
-assert-css: (".impl", {"color": "rgb(221, 221, 221)", "background-color": "rgba(0, 0, 0, 0)"}, ALL)
-assert-css: (".impl .code-header", {"color": "rgb(221, 221, 221)", "background-color": "rgb(53, 53, 53)"}, ALL)
+assert-css: (
+ ".impl",
+ {"color": "rgb(221, 221, 221)", "background-color": "rgba(0, 0, 0, 0)"},
+ ALL,
+)
+assert-css: (
+ ".impl .code-header",
+ {"color": "rgb(221, 221, 221)", "background-color": "rgb(53, 53, 53)"},
+ ALL,
+)
goto: file://|DOC_PATH|/test_docs/struct.Foo.html#impl
-assert-css: ("#impl", {"color": "rgb(221, 221, 221)", "background-color": "rgb(73, 74, 61)"})
+assert-css: (
+ "#impl",
+ {"color": "rgb(221, 221, 221)", "background-color": "rgb(73, 74, 61)"},
+)
goto: file://|DOC_PATH|/test_docs/struct.Foo.html#method.must_use
-assert-css: ("#method\.must_use", {"color": "rgb(221, 221, 221)", "background-color": "rgb(73, 74, 61)"}, ALL)
+assert-css: (
+ "#method\.must_use",
+ {"color": "rgb(221, 221, 221)", "background-color": "rgb(73, 74, 61)"},
+ ALL,
+)
+
+goto: file://|DOC_PATH|/test_docs/index.html
+assert-css: (".small-section-header a", {"color": "rgb(221, 221, 221)"}, ALL)
+
+goto: file://|DOC_PATH|/test_docs/struct.HeavilyDocumentedStruct.html
+assert-css: (".section-header a", {"color": "rgb(210, 153, 29)"}, ALL)
// Light theme
local-storage: {"rustdoc-theme": "light", "rustdoc-use-system-theme": "false"}
@@ -36,11 +86,29 @@ reload:
goto: file://|DOC_PATH|/test_docs/struct.Foo.html
-assert-css: (".impl", {"color": "rgb(0, 0, 0)", "background-color": "rgba(0, 0, 0, 0)"}, ALL)
-assert-css: (".impl .code-header", {"color": "rgb(0, 0, 0)", "background-color": "rgb(255, 255, 255)"}, ALL)
+assert-css: (
+ ".impl",
+ {"color": "rgb(0, 0, 0)", "background-color": "rgba(0, 0, 0, 0)"},
+ ALL,
+)
+assert-css: (
+ ".impl .code-header",
+ {"color": "rgb(0, 0, 0)", "background-color": "rgb(255, 255, 255)"},
+ ALL,
+)
goto: file://|DOC_PATH|/test_docs/struct.Foo.html#impl
assert-css: ("#impl", {"color": "rgb(0, 0, 0)", "background-color": "rgb(253, 255, 211)"})
goto: file://|DOC_PATH|/test_docs/struct.Foo.html#method.must_use
-assert-css: ("#method\.must_use", {"color": "rgb(0, 0, 0)", "background-color": "rgb(253, 255, 211)"}, ALL)
+assert-css: (
+ "#method\.must_use",
+ {"color": "rgb(0, 0, 0)", "background-color": "rgb(253, 255, 211)"},
+ ALL,
+)
+
+goto: file://|DOC_PATH|/test_docs/index.html
+assert-css: (".small-section-header a", {"color": "rgb(0, 0, 0)"}, ALL)
+
+goto: file://|DOC_PATH|/test_docs/struct.HeavilyDocumentedStruct.html
+assert-css: (".section-header a", {"color": "rgb(56, 115, 173)"}, ALL)
diff --git a/src/test/rustdoc-gui/huge-collection-of-constants.goml b/src/test/rustdoc-gui/huge-collection-of-constants.goml
index 924fab1ea91..4f7fe7a212c 100644
--- a/src/test/rustdoc-gui/huge-collection-of-constants.goml
+++ b/src/test/rustdoc-gui/huge-collection-of-constants.goml
@@ -2,4 +2,8 @@ goto: file://|DOC_PATH|/test_docs/huge_amount_of_consts/index.html
// Make sure that the last two entries are more than 12 pixels apart and not stacked on each other.
-compare-elements-position-near-false: ("//*[@class='item-table']//div[last()-1]", "//*[@class='item-table']//div[last()-3]", {"y": 12})
+compare-elements-position-near-false: (
+ "//*[@class='item-table']//div[last()-1]",
+ "//*[@class='item-table']//div[last()-3]",
+ {"y": 12},
+)
diff --git a/src/test/rustdoc-gui/impl-default-expansion.goml b/src/test/rustdoc-gui/impl-default-expansion.goml
index b268ec68d42..7c4496dc0ca 100644
--- a/src/test/rustdoc-gui/impl-default-expansion.goml
+++ b/src/test/rustdoc-gui/impl-default-expansion.goml
@@ -1,3 +1,3 @@
// This test ensures that the impl blocks are open by default.
goto: file://|DOC_PATH|/test_docs/struct.Foo.html
-assert-attribute: ("#main > details.implementors-toggle", {"open": ""})
+assert-attribute: ("#main-content > details.implementors-toggle", {"open": ""})
diff --git a/src/test/rustdoc-gui/item-info-width.goml b/src/test/rustdoc-gui/item-info-width.goml
index 44b79e60912..cdc00d34114 100644
--- a/src/test/rustdoc-gui/item-info-width.goml
+++ b/src/test/rustdoc-gui/item-info-width.goml
@@ -4,4 +4,4 @@ goto: file://|DOC_PATH|/lib2/struct.Foo.html
size: (1100, 800)
// We check that ".item-info" is bigger than its content.
assert-css: (".item-info", {"width": "807px"})
-assert-css: (".item-info .stab", {"width": "343px"})
+assert-css: (".item-info .stab", {"width": "341px"})
diff --git a/src/test/rustdoc-gui/jump-to-def-background.goml b/src/test/rustdoc-gui/jump-to-def-background.goml
index 3df899e0f26..d17400f5bd9 100644
--- a/src/test/rustdoc-gui/jump-to-def-background.goml
+++ b/src/test/rustdoc-gui/jump-to-def-background.goml
@@ -2,22 +2,42 @@
goto: file://|DOC_PATH|/src/link_to_definition/lib.rs.html
// Set the theme to dark.
-local-storage: {"rustdoc-theme": "dark", "rustdoc-preferred-dark-theme": "dark", "rustdoc-use-system-theme": "false"}
+local-storage: {
+ "rustdoc-theme": "dark",
+ "rustdoc-preferred-dark-theme": "dark",
+ "rustdoc-use-system-theme": "false",
+}
// We reload the page so the local storage settings are being used.
reload:
-assert-css: ("body.source .example-wrap pre.rust a", {"background-color": "rgb(51, 51, 51)"}, ALL)
+assert-css: (
+ "body.source .example-wrap pre.rust a",
+ {"background-color": "rgb(51, 51, 51)"},
+ ALL,
+)
// Set the theme to ayu.
-local-storage: {"rustdoc-theme": "ayu", "rustdoc-preferred-dark-theme": "ayu", "rustdoc-use-system-theme": "false"}
+local-storage: {
+ "rustdoc-theme": "ayu",
+ "rustdoc-preferred-dark-theme": "ayu",
+ "rustdoc-use-system-theme": "false",
+}
// We reload the page so the local storage settings are being used.
reload:
-assert-css: ("body.source .example-wrap pre.rust a", {"background-color": "rgb(51, 51, 51)"}, ALL)
+assert-css: (
+ "body.source .example-wrap pre.rust a",
+ {"background-color": "rgb(51, 51, 51)"},
+ ALL,
+)
// Set the theme to light.
local-storage: {"rustdoc-theme": "light", "rustdoc-use-system-theme": "false"}
// We reload the page so the local storage settings are being used.
reload:
-assert-css: ("body.source .example-wrap pre.rust a", {"background-color": "rgb(238, 238, 238)"}, ALL)
+assert-css: (
+ "body.source .example-wrap pre.rust a",
+ {"background-color": "rgb(238, 238, 238)"},
+ ALL,
+)
diff --git a/src/test/rustdoc-gui/label-next-to-symbol.goml b/src/test/rustdoc-gui/label-next-to-symbol.goml
index 4fef4e655fd..ca3994a08b2 100644
--- a/src/test/rustdoc-gui/label-next-to-symbol.goml
+++ b/src/test/rustdoc-gui/label-next-to-symbol.goml
@@ -8,29 +8,71 @@ assert: (".stab.deprecated")
assert: (".stab.portability")
// make sure that deprecated and portability are different colours
-assert-css: (".item-table .item-left .stab.deprecated", { "background-color": "rgb(255, 196, 196)" })
-assert-css: (".item-table .item-left .stab.portability", { "background-color": "rgb(243, 223, 255)" })
+assert-css: (
+ ".item-table .item-left .stab.deprecated",
+ { "background-color": "rgb(255, 196, 196)" },
+)
+assert-css: (
+ ".item-table .item-left .stab.portability",
+ { "background-color": "rgb(243, 223, 255)" },
+)
// table like view
assert-css: (".item-right.docblock-short", { "padding-left": "0px" })
-compare-elements-position-near: ("//*[@class='item-left module-item']//a[text()='replaced_function']", ".item-left .stab.deprecated", {"y": 2})
-compare-elements-position: (".item-left .stab.deprecated", ".item-left .stab.portability", ("y"))
+compare-elements-position-near: (
+ "//*[@class='item-left module-item']//a[text()='replaced_function']",
+ ".item-left .stab.deprecated",
+ {"y": 2},
+)
+compare-elements-position: (
+ ".item-left .stab.deprecated",
+ ".item-left .stab.portability",
+ ("y"),
+)
// Ensure no wrap
-compare-elements-position-near: ("//*[@class='item-left module-item']//a[text()='replaced_function']", "//*[@class='item-right docblock-short']//p[text()='a thing with a label']", {"y": 2})
+compare-elements-position-near: (
+ "//*[@class='item-left module-item']//a[text()='replaced_function']",
+ "//*[@class='item-right docblock-short']//p[text()='a thing with a label']",
+ {"y": 2},
+)
// compare parent elements
-compare-elements-position: ("//*[@class='item-left module-item']//a[text()='replaced_function']/..", "//*[@class='item-right docblock-short']//p[text()='a thing with a label']/..", ("y"))
+compare-elements-position: (
+ "//*[@class='item-left module-item']//a[text()='replaced_function']/..",
+ "//*[@class='item-right docblock-short']//p[text()='a thing with a label']/..",
+ ("y"),
+)
// Mobile view
size: (600, 600)
// staggered layout with 2em spacing
assert-css: (".item-right.docblock-short", { "padding-left": "32px" })
-compare-elements-position-near: ("//*[@class='item-left module-item']//a[text()='replaced_function']", ".item-left .stab.deprecated", {"y": 1})
-compare-elements-position: (".item-left .stab.deprecated", ".item-left .stab.portability", ("y"))
+compare-elements-position-near: (
+ "//*[@class='item-left module-item']//a[text()='replaced_function']",
+ ".item-left .stab.deprecated",
+ {"y": 1},
+)
+compare-elements-position: (
+ ".item-left .stab.deprecated",
+ ".item-left .stab.portability",
+ ("y"),
+)
// Ensure wrap
-compare-elements-position-near-false: ("//*[@class='item-left module-item']//a[text()='replaced_function']", "//*[@class='item-right docblock-short']//p[text()='a thing with a label']", {"y": 12})
+compare-elements-position-near-false: (
+ "//*[@class='item-left module-item']//a[text()='replaced_function']",
+ "//*[@class='item-right docblock-short']//p[text()='a thing with a label']",
+ {"y": 12},
+)
// compare parent elements
-compare-elements-position-false: ("//*[@class='item-left module-item']//a[text()='replaced_function']/..", "//*[@class='item-right docblock-short']//p[text()='a thing with a label']/..", ("y"))
-compare-elements-position-false: (".item-left .stab.deprecated", "//*[@class='item-right docblock-short']//p[text()='a thing with a label']", ("y"))
+compare-elements-position-false: (
+ "//*[@class='item-left module-item']//a[text()='replaced_function']/..",
+ "//*[@class='item-right docblock-short']//p[text()='a thing with a label']/..",
+ ("y"),
+)
+compare-elements-position-false: (
+ ".item-left .stab.deprecated",
+ "//*[@class='item-right docblock-short']//p[text()='a thing with a label']",
+ ("y"),
+)
diff --git a/src/test/rustdoc-gui/module-items-font.goml b/src/test/rustdoc-gui/module-items-font.goml
index 0316172ee14..758ee391ae4 100644
--- a/src/test/rustdoc-gui/module-items-font.goml
+++ b/src/test/rustdoc-gui/module-items-font.goml
@@ -1,23 +1,67 @@
// This test checks that the correct font is used on module items (in index.html pages).
goto: file://|DOC_PATH|/test_docs/index.html
-assert-css: (".item-table .module-item a", {"font-family": '"Fira Sans", Arial, NanumBarunGothic, sans-serif'}, ALL)
-assert-css: (".item-table .docblock-short", {"font-family": '"Source Serif 4", NanumBarunGothic, serif'}, ALL)
+assert-css: (
+ ".item-table .module-item a",
+ {"font-family": '"Fira Sans", Arial, NanumBarunGothic, sans-serif'},
+ ALL,
+)
+assert-css: (
+ ".item-table .docblock-short",
+ {"font-family": '"Source Serif 4", NanumBarunGothic, serif'},
+ ALL,
+)
// modules
-assert-css: ("#modules + .item-table .item-left a", {"font-family": '"Fira Sans", Arial, NanumBarunGothic, sans-serif'})
-assert-css: ("#modules + .item-table .item-right.docblock-short", {"font-family": '"Source Serif 4", NanumBarunGothic, serif'})
+assert-css: (
+ "#modules + .item-table .item-left a",
+ {"font-family": '"Fira Sans", Arial, NanumBarunGothic, sans-serif'},
+)
+assert-css: (
+ "#modules + .item-table .item-right.docblock-short",
+ {"font-family": '"Source Serif 4", NanumBarunGothic, serif'},
+)
// structs
-assert-css: ("#structs + .item-table .item-left a", {"font-family": '"Fira Sans", Arial, NanumBarunGothic, sans-serif'})
-assert-css: ("#structs + .item-table .item-right.docblock-short", {"font-family": '"Source Serif 4", NanumBarunGothic, serif'})
+assert-css: (
+ "#structs + .item-table .item-left a",
+ {"font-family": '"Fira Sans", Arial, NanumBarunGothic, sans-serif'},
+)
+assert-css: (
+ "#structs + .item-table .item-right.docblock-short",
+ {"font-family": '"Source Serif 4", NanumBarunGothic, serif'},
+)
// enums
-assert-css: ("#enums + .item-table .item-left a", {"font-family": '"Fira Sans", Arial, NanumBarunGothic, sans-serif'})
-assert-css: ("#enums + .item-table .item-right.docblock-short", {"font-family": '"Source Serif 4", NanumBarunGothic, serif'})
+assert-css: (
+ "#enums + .item-table .item-left a",
+ {"font-family": '"Fira Sans", Arial, NanumBarunGothic, sans-serif'},
+)
+assert-css: (
+ "#enums + .item-table .item-right.docblock-short",
+ {"font-family": '"Source Serif 4", NanumBarunGothic, serif'},
+)
// traits
-assert-css: ("#traits + .item-table .item-left a", {"font-family": '"Fira Sans", Arial, NanumBarunGothic, sans-serif'})
-assert-css: ("#traits + .item-table .item-right.docblock-short", {"font-family": '"Source Serif 4", NanumBarunGothic, serif'})
+assert-css: (
+ "#traits + .item-table .item-left a",
+ {"font-family": '"Fira Sans", Arial, NanumBarunGothic, sans-serif'},
+)
+assert-css: (
+ "#traits + .item-table .item-right.docblock-short",
+ {"font-family": '"Source Serif 4", NanumBarunGothic, serif'},
+)
// functions
-assert-css: ("#functions + .item-table .item-left a", {"font-family": '"Fira Sans", Arial, NanumBarunGothic, sans-serif'})
-assert-css: ("#functions + .item-table .item-right.docblock-short", {"font-family": '"Source Serif 4", NanumBarunGothic, serif'})
+assert-css: (
+ "#functions + .item-table .item-left a",
+ {"font-family": '"Fira Sans", Arial, NanumBarunGothic, sans-serif'},
+)
+assert-css: (
+ "#functions + .item-table .item-right.docblock-short",
+ {"font-family": '"Source Serif 4", NanumBarunGothic, serif'},
+)
// keywords
-assert-css: ("#keywords + .item-table .item-left a", {"font-family": '"Fira Sans", Arial, NanumBarunGothic, sans-serif'})
-assert-css: ("#keywords + .item-table .item-right.docblock-short", {"font-family": '"Source Serif 4", NanumBarunGothic, serif'})
+assert-css: (
+ "#keywords + .item-table .item-left a",
+ {"font-family": '"Fira Sans", Arial, NanumBarunGothic, sans-serif'},
+)
+assert-css: (
+ "#keywords + .item-table .item-right.docblock-short",
+ {"font-family": '"Source Serif 4", NanumBarunGothic, serif'},
+)
diff --git a/src/test/rustdoc-gui/search-filter.goml b/src/test/rustdoc-gui/search-filter.goml
index a098dbd9f12..7a8f8ca5311 100644
--- a/src/test/rustdoc-gui/search-filter.goml
+++ b/src/test/rustdoc-gui/search-filter.goml
@@ -1,9 +1,11 @@
goto: file://|DOC_PATH|/test_docs/index.html
+show-text: true
write: (".search-input", "test")
// Waiting for the search results to appear...
wait-for: "#titles"
assert-text: ("#results .externcrate", "test_docs")
-text: (".search-input", "")
+
+goto: file://|DOC_PATH|/test_docs/index.html
// We now want to change the crate filter.
click: "#crate-search"
// We select "lib2" option then press enter to change the filter.
diff --git a/src/test/rustdoc-gui/search-result-color.goml b/src/test/rustdoc-gui/search-result-color.goml
index bb8ecb98fa3..ffa9362755d 100644
--- a/src/test/rustdoc-gui/search-result-color.goml
+++ b/src/test/rustdoc-gui/search-result-color.goml
@@ -5,28 +5,54 @@ goto: file://|DOC_PATH|/test_docs/index.html?search=coo
show-text: true
// Ayu theme
-local-storage: {"rustdoc-theme": "ayu", "rustdoc-preferred-dark-theme": "ayu", "rustdoc-use-system-theme": "false"}
+local-storage: {
+ "rustdoc-theme": "ayu",
+ "rustdoc-preferred-dark-theme": "ayu",
+ "rustdoc-use-system-theme": "false",
+}
reload:
// Waiting for the search results to appear...
wait-for: "#titles"
-assert-css: ("//*[@class='desc']//*[text()='Just a normal struct.']", {"color": "rgb(197, 197, 197)"})
-assert-css: ("//*[@class='result-name']/*[text()='test_docs::']", {"color": "rgb(0, 150, 207)"})
+assert-css: (
+ "//*[@class='desc']//*[text()='Just a normal struct.']",
+ {"color": "rgb(197, 197, 197)"},
+)
+assert-css: (
+ "//*[@class='result-name']/*[text()='test_docs::']",
+ {"color": "rgb(0, 150, 207)"},
+)
// Checking the color for "keyword".
-assert-css: ("//*[@class='result-name']//*[text()='(keyword)']", {"color": "rgb(120, 135, 151)"})
+assert-css: (
+ "//*[@class='result-name']//*[text()='(keyword)']",
+ {"color": "rgb(120, 135, 151)"},
+)
// Dark theme
-local-storage: {"rustdoc-theme": "dark", "rustdoc-preferred-dark-theme": "dark", "rustdoc-use-system-theme": "false"}
+local-storage: {
+ "rustdoc-theme": "dark",
+ "rustdoc-preferred-dark-theme": "dark",
+ "rustdoc-use-system-theme": "false",
+}
reload:
// Waiting for the search results to appear...
wait-for: "#titles"
-assert-css: ("//*[@class='desc']//*[text()='Just a normal struct.']", {"color": "rgb(221, 221, 221)"})
-assert-css: ("//*[@class='result-name']/*[text()='test_docs::']", {"color": "rgb(221, 221, 221)"})
+assert-css: (
+ "//*[@class='desc']//*[text()='Just a normal struct.']",
+ {"color": "rgb(221, 221, 221)"},
+)
+assert-css: (
+ "//*[@class='result-name']/*[text()='test_docs::']",
+ {"color": "rgb(221, 221, 221)"},
+)
// Checking the color for "keyword".
-assert-css: ("//*[@class='result-name']//*[text()='(keyword)']", {"color": "rgb(221, 221, 221)"})
+assert-css: (
+ "//*[@class='result-name']//*[text()='(keyword)']",
+ {"color": "rgb(221, 221, 221)"},
+)
// Light theme
local-storage: {"rustdoc-theme": "light", "rustdoc-use-system-theme": "false"}
@@ -34,8 +60,17 @@ reload:
// Waiting for the search results to appear...
wait-for: "#titles"
-assert-css: ("//*[@class='desc']//*[text()='Just a normal struct.']", {"color": "rgb(0, 0, 0)"})
-assert-css: ("//*[@class='result-name']/*[text()='test_docs::']", {"color": "rgb(0, 0, 0)"})
+assert-css: (
+ "//*[@class='desc']//*[text()='Just a normal struct.']",
+ {"color": "rgb(0, 0, 0)"},
+)
+assert-css: (
+ "//*[@class='result-name']/*[text()='test_docs::']",
+ {"color": "rgb(0, 0, 0)"},
+)
// Checking the color for "keyword".
-assert-css: ("//*[@class='result-name']//*[text()='(keyword)']", {"color": "rgb(0, 0, 0)"})
+assert-css: (
+ "//*[@class='result-name']//*[text()='(keyword)']",
+ {"color": "rgb(0, 0, 0)"},
+)
diff --git a/src/test/rustdoc-gui/search-result-colors.goml b/src/test/rustdoc-gui/search-result-colors.goml
index daf8bc9dea3..b4eb896af1c 100644
--- a/src/test/rustdoc-gui/search-result-colors.goml
+++ b/src/test/rustdoc-gui/search-result-colors.goml
@@ -1,7 +1,11 @@
goto: file://|DOC_PATH|/test_docs/index.html
// We set the theme so we're sure that the correct values will be used, whatever the computer
// this test is running on.
-local-storage: {"rustdoc-theme": "dark", "rustdoc-preferred-dark-theme": "dark", "rustdoc-use-system-theme": "false"}
+local-storage: {
+ "rustdoc-theme": "dark",
+ "rustdoc-preferred-dark-theme": "dark",
+ "rustdoc-use-system-theme": "false",
+}
// If the text isn't displayed, the browser doesn't compute color style correctly...
show-text: true
// We reload the page so the local storage settings are being used.
diff --git a/src/test/rustdoc-gui/search-result-go-to-first.goml b/src/test/rustdoc-gui/search-result-go-to-first.goml
index 5d709f65881..cadd7f6a3f3 100644
--- a/src/test/rustdoc-gui/search-result-go-to-first.goml
+++ b/src/test/rustdoc-gui/search-result-go-to-first.goml
@@ -11,7 +11,7 @@ goto: file://|DOC_PATH|/test_docs/index.html?search=struct%3AFoo
wait-for: "#titles"
assert-text-false: (".fqn .in-band", "Struct test_docs::Foo")
// Ensure that the search results are displayed, not the "normal" content.
-assert-css: ("#main", {"display": "none"})
+assert-css: ("#main-content", {"display": "none"})
// Now we can check that the feature is working as expected!
goto: file://|DOC_PATH|/test_docs/index.html?search=struct%3AFoo&go_to_first=true
diff --git a/src/test/rustdoc-gui/sidebar-source-code.goml b/src/test/rustdoc-gui/sidebar-source-code.goml
new file mode 100644
index 00000000000..98f4fdf4233
--- /dev/null
+++ b/src/test/rustdoc-gui/sidebar-source-code.goml
@@ -0,0 +1,32 @@
+// The goal of this test is to ensure that the sidebar is working as expected in the source
+// code pages.
+goto: file://|DOC_PATH|/src/test_docs/lib.rs.html
+// First: desktop mode.
+size: (1100, 800)
+// We check that the sidebar isn't expanded and has the expected width.
+assert-css: ("nav.sidebar", {"width": "50px"})
+// We now click on the button to expand the sidebar.
+click: (10, 10)
+// We wait for the sidebar to be expanded (there is a 0.5s animation).
+wait-for: 600
+assert-css: ("nav.sidebar.expanded", {"width": "300px"})
+// We collapse the sidebar.
+click: (10, 10)
+// We wait for the sidebar to be collapsed (there is a 0.5s animation).
+wait-for: 600
+// We ensure that the class has been removed.
+assert-false: "nav.sidebar.expanded"
+assert: "nav.sidebar"
+
+// We now switch to mobile mode.
+size: (600, 600)
+// We check that the sidebar has the expected width (0 and 1px for the border).
+assert-css: ("nav.sidebar", {"width": "1px"})
+// We expand the sidebar.
+click: "#sidebar-toggle"
+assert-css: ("nav.sidebar.expanded", {"width": "600px"})
+// We collapse the sidebar.
+click: (10, 10)
+// We ensure that the class has been removed.
+assert-false: "nav.sidebar.expanded"
+assert: "nav.sidebar"
diff --git a/src/test/rustdoc-gui/source-code-page.goml b/src/test/rustdoc-gui/source-code-page.goml
index 5a49807e180..f3682f59d21 100644
--- a/src/test/rustdoc-gui/source-code-page.goml
+++ b/src/test/rustdoc-gui/source-code-page.goml
@@ -1,6 +1,6 @@
goto: file://|DOC_PATH|/src/test_docs/lib.rs.html
// Check that we can click on the line number.
-click: (40, 224) // This is the position of the span for line 4.
+click: ".line-numbers > span:nth-child(4)" // This is the span for line 4.
// Unfortunately, "#4" isn't a valid query selector, so we have to go around that limitation
// by instead getting the nth span.
assert-attribute: (".line-numbers > span:nth-child(4)", {"class": "line-highlighted"})
diff --git a/src/test/rustdoc-gui/src/lib2/lib.rs b/src/test/rustdoc-gui/src/lib2/lib.rs
index f2e76b546c4..79354ec8745 100644
--- a/src/test/rustdoc-gui/src/lib2/lib.rs
+++ b/src/test/rustdoc-gui/src/lib2/lib.rs
@@ -22,6 +22,8 @@ pub struct Foo {
}
impl Foo {
+ /// Some documentation
+ /// # A Heading
pub fn a_method(&self) {}
}
diff --git a/src/test/rustdoc-gui/src/test_docs/lib.rs b/src/test/rustdoc-gui/src/test_docs/lib.rs
index 14d8b186130..9b37703dded 100644
--- a/src/test/rustdoc-gui/src/test_docs/lib.rs
+++ b/src/test/rustdoc-gui/src/test_docs/lib.rs
@@ -2,7 +2,7 @@
//! documentation generated so we can test each different features.
#![crate_name = "test_docs"]
-#![feature(doc_keyword)]
+#![feature(rustdoc_internals)]
#![feature(doc_cfg)]
use std::convert::AsRef;
@@ -47,6 +47,8 @@ impl AsRef<str> for Foo {
}
/// Just a normal enum.
+///
+/// # title!
#[doc(alias = "ThisIsAnAlias")]
pub enum WhoLetTheDogOut {
/// Woof!
diff --git a/src/test/rustdoc-gui/toggle-click-deadspace.goml b/src/test/rustdoc-gui/toggle-click-deadspace.goml
new file mode 100644
index 00000000000..7bc3c563157
--- /dev/null
+++ b/src/test/rustdoc-gui/toggle-click-deadspace.goml
@@ -0,0 +1,12 @@
+// This test ensures that clicking on a method summary, but not on the "[-]",
+// doesn't toggle the <details>.
+goto: file://|DOC_PATH|/lib2/struct.Foo.html
+assert-attribute: (".impl-items .rustdoc-toggle", {"open": ""})
+click: "h4.code-header" // This is the position of "pub" in "pub fn a_method"
+assert-attribute: (".impl-items .rustdoc-toggle", {"open": ""})
+click: ".impl-items .rustdoc-toggle summary::before" // This is the position of "[-]" next to that pub fn.
+assert-attribute-false: (".impl-items .rustdoc-toggle", {"open": ""})
+
+// Click the "Trait" part of "impl Trait" and verify it navigates.
+click: "#impl-Trait h3 a:first-of-type"
+assert-text: (".fqn .in-band", "Trait lib2::Trait")
diff --git a/src/test/rustdoc-gui/toggle-docs.goml b/src/test/rustdoc-gui/toggle-docs.goml
index 136868f3175..eaa4c554d5a 100644
--- a/src/test/rustdoc-gui/toggle-docs.goml
+++ b/src/test/rustdoc-gui/toggle-docs.goml
@@ -1,10 +1,10 @@
goto: file://|DOC_PATH|/test_docs/index.html
-assert-attribute: ("#main > details.top-doc", {"open": ""})
+assert-attribute: ("#main-content > details.top-doc", {"open": ""})
click: "#toggle-all-docs"
wait-for: 1000
// This is now collapsed so there shouldn't be the "open" attribute on details.
-assert-attribute-false: ("#main > details.top-doc", {"open": ""})
+assert-attribute-false: ("#main-content > details.top-doc", {"open": ""})
click: "#toggle-all-docs"
wait-for: 1000
// Not collapsed anymore so the "open" attribute should be back.
-assert-attribute: ("#main > details.top-doc", {"open": ""})
+assert-attribute: ("#main-content > details.top-doc", {"open": ""})
diff --git a/src/test/rustdoc-gui/type-declation-overflow.goml b/src/test/rustdoc-gui/type-declation-overflow.goml
index 63ab867fb17..bb24d0ce792 100644
--- a/src/test/rustdoc-gui/type-declation-overflow.goml
+++ b/src/test/rustdoc-gui/type-declation-overflow.goml
@@ -11,7 +11,7 @@ assert-property: (".item-decl pre", {"scrollWidth": "1324"})
goto: file://|DOC_PATH|/lib2/too_long/type.ReallyLongTypeNameLongLongLong.html
assert-property: ("body", {"scrollWidth": "1100"})
// We now check that the section width hasn't grown because of it.
-assert-property: ("#main", {"scrollWidth": "840"})
+assert-property: ("#main-content", {"scrollWidth": "840"})
// And now checking that it has scrollable content.
assert-property: (".item-decl pre", {"scrollWidth": "1103"})
@@ -20,6 +20,6 @@ assert-property: (".item-decl pre", {"scrollWidth": "1103"})
goto: file://|DOC_PATH|/lib2/too_long/constant.ReallyLongTypeNameLongLongLongConstBecauseWhyNotAConstRightGigaGigaSupraLong.html
assert-property: ("body", {"scrollWidth": "1100"})
// We now check that the section width hasn't grown because of it.
-assert-property: ("#main", {"scrollWidth": "840"})
+assert-property: ("#main-content", {"scrollWidth": "840"})
// And now checking that it has scrollable content.
assert-property: (".item-decl pre", {"scrollWidth": "950"})
diff --git a/src/test/rustdoc-js/summaries.rs b/src/test/rustdoc-js/summaries.rs
index 418c9f8d0ed..1ee1c34aa15 100644
--- a/src/test/rustdoc-js/summaries.rs
+++ b/src/test/rustdoc-js/summaries.rs
@@ -1,6 +1,8 @@
#![crate_type = "lib"]
#![crate_name = "summaries"]
+#![allow(rustdoc::broken_intra_doc_links)]
+
//! This *summary* has a [link], [`code`], and [`Sidebar2`] intra-doc.
//!
//! This is the second paragraph. It should not be rendered.
diff --git a/src/test/rustdoc-json/primitive.rs b/src/test/rustdoc-json/primitive.rs
index 3a7d6d18c1b..b84c2f7c6ac 100644
--- a/src/test/rustdoc-json/primitive.rs
+++ b/src/test/rustdoc-json/primitive.rs
@@ -1,6 +1,6 @@
// edition:2018
-#![feature(doc_primitive)]
+#![feature(rustdoc_internals)]
#[doc(primitive = "usize")]
mod usize {}
diff --git a/src/test/rustdoc-ui/auxiliary/empty-fn.rs b/src/test/rustdoc-ui/auxiliary/empty-fn.rs
new file mode 100644
index 00000000000..877810f15d7
--- /dev/null
+++ b/src/test/rustdoc-ui/auxiliary/empty-fn.rs
@@ -0,0 +1,3 @@
+// no-prefer-dynamic
+#![crate_type = "lib"]
+pub fn empty() {}
diff --git a/src/test/rustdoc-ui/auxiliary/overflow.rs b/src/test/rustdoc-ui/auxiliary/overflow.rs
new file mode 100644
index 00000000000..ff65936bec9
--- /dev/null
+++ b/src/test/rustdoc-ui/auxiliary/overflow.rs
@@ -0,0 +1,20 @@
+pub struct B0;
+pub struct B1;
+use std::ops::Shl;
+use std::ops::Sub;
+pub type Shleft<A, B> = <A as Shl<B>>::Output;
+pub type Sub1<A> = <A as Sub<B1>>::Output;
+pub struct UInt<U, B> {
+ pub(crate) msb: U,
+ pub(crate) lsb: B,
+}
+impl<U, B, Ur, Br> Shl<UInt<Ur, Br>> for UInt<U, B>
+where
+ UInt<Ur, Br>: Sub<B1>,
+ UInt<UInt<U, B>, B0>: Shl<Sub1<UInt<Ur, Br>>>,
+{
+ type Output = Shleft<UInt<UInt<U, B>, B0>, Sub1<UInt<Ur, Br>>>;
+ fn shl(self, rhs: UInt<Ur, Br>) -> Self::Output {
+ unimplemented!()
+ }
+}
diff --git a/src/test/rustdoc-ui/coverage/exotic.rs b/src/test/rustdoc-ui/coverage/exotic.rs
index 18f2014d9e4..72b70d6980b 100644
--- a/src/test/rustdoc-ui/coverage/exotic.rs
+++ b/src/test/rustdoc-ui/coverage/exotic.rs
@@ -1,8 +1,7 @@
// compile-flags:-Z unstable-options --show-coverage
// check-pass
-#![feature(doc_keyword)]
-#![feature(doc_primitive)]
+#![feature(rustdoc_internals)]
//! the features only used in std also have entries in the table, so make sure those get pulled out
//! properly as well
diff --git a/src/test/rustdoc-ui/display-output.rs b/src/test/rustdoc-ui/display-output.rs
index 5e390029dca..c40d99c9d4c 100644
--- a/src/test/rustdoc-ui/display-output.rs
+++ b/src/test/rustdoc-ui/display-output.rs
@@ -1,9 +1,15 @@
+// Test that `--show-output` has an effect and `allow(unused)` can be overriden.
+
// check-pass
-// compile-flags:-Zunstable-options --display-doctest-warnings --test
+// edition:2018
+// compile-flags:--test --test-args=--show-output
// normalize-stdout-test: "src/test/rustdoc-ui" -> "$$DIR"
// normalize-stdout-test "finished in \d+\.\d+s" -> "finished in $$TIME"
/// ```
+/// #![warn(unused)]
/// let x = 12;
+///
+/// fn foo(x: &dyn std::fmt::Display) {}
/// ```
pub fn foo() {}
diff --git a/src/test/rustdoc-ui/display-output.stdout b/src/test/rustdoc-ui/display-output.stdout
index 00467b9359e..41c1f41f2cf 100644
--- a/src/test/rustdoc-ui/display-output.stdout
+++ b/src/test/rustdoc-ui/display-output.stdout
@@ -1,24 +1,48 @@
running 1 test
-test $DIR/display-output.rs - foo (line 6) ... ok
+test $DIR/display-output.rs - foo (line 9) ... ok
successes:
----- $DIR/display-output.rs - foo (line 6) stdout ----
+---- $DIR/display-output.rs - foo (line 9) stdout ----
warning: unused variable: `x`
- --> $DIR/display-output.rs:7:5
+ --> $DIR/display-output.rs:11:5
|
LL | let x = 12;
| ^ help: if this is intentional, prefix it with an underscore: `_x`
|
- = note: `#[warn(unused_variables)]` on by default
+note: the lint level is defined here
+ --> $DIR/display-output.rs:9:9
+ |
+LL | #![warn(unused)]
+ | ^^^^^^
+ = note: `#[warn(unused_variables)]` implied by `#[warn(unused)]`
+
+warning: unused variable: `x`
+ --> $DIR/display-output.rs:13:8
+ |
+LL | fn foo(x: &dyn std::fmt::Display) {}
+ | ^ help: if this is intentional, prefix it with an underscore: `_x`
+
+warning: function is never used: `foo`
+ --> $DIR/display-output.rs:13:4
+ |
+LL | fn foo(x: &dyn std::fmt::Display) {}
+ | ^^^
+ |
+note: the lint level is defined here
+ --> $DIR/display-output.rs:9:9
+ |
+LL | #![warn(unused)]
+ | ^^^^^^
+ = note: `#[warn(dead_code)]` implied by `#[warn(unused)]`
-warning: 1 warning emitted
+warning: 3 warnings emitted
successes:
- $DIR/display-output.rs - foo (line 6)
+ $DIR/display-output.rs - foo (line 9)
test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in $TIME
diff --git a/src/test/rustdoc/intra-doc/auxiliary/through-proc-macro-aux.rs b/src/test/rustdoc-ui/intra-doc/auxiliary/through-proc-macro-aux.rs
index 5c4a01ee3a7..5c4a01ee3a7 100644
--- a/src/test/rustdoc/intra-doc/auxiliary/through-proc-macro-aux.rs
+++ b/src/test/rustdoc-ui/intra-doc/auxiliary/through-proc-macro-aux.rs
diff --git a/src/test/rustdoc/intra-doc/through-proc-macro.rs b/src/test/rustdoc-ui/intra-doc/through-proc-macro.rs
index 613410871f0..7628c3928fe 100644
--- a/src/test/rustdoc/intra-doc/through-proc-macro.rs
+++ b/src/test/rustdoc-ui/intra-doc/through-proc-macro.rs
@@ -1,11 +1,17 @@
+// check-pass
// aux-build:through-proc-macro-aux.rs
// build-aux-docs
-#![warn(broken_intra_doc_links)]
+
+// Ensure rustdoc doesn't panic on this code.
+
+#![warn(rustdoc::broken_intra_doc_links)]
+
extern crate some_macros;
#[some_macros::second]
pub enum Boom {
/// [Oooops]
+ //~^ WARNING unresolved link to `Oooops`
Bam,
}
diff --git a/src/test/rustdoc-ui/intra-doc/through-proc-macro.stderr b/src/test/rustdoc-ui/intra-doc/through-proc-macro.stderr
new file mode 100644
index 00000000000..f0a7ed1785b
--- /dev/null
+++ b/src/test/rustdoc-ui/intra-doc/through-proc-macro.stderr
@@ -0,0 +1,15 @@
+warning: unresolved link to `Oooops`
+ --> $DIR/through-proc-macro.rs:13:10
+ |
+LL | /// [Oooops]
+ | ^^^^^^ no item named `Oooops` in scope
+ |
+note: the lint level is defined here
+ --> $DIR/through-proc-macro.rs:7:9
+ |
+LL | #![warn(rustdoc::broken_intra_doc_links)]
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ = help: to escape `[` and `]` characters, add '\' before them like `\[` or `\]`
+
+warning: 1 warning emitted
+
diff --git a/src/test/rustdoc-ui/invalid-keyword.rs b/src/test/rustdoc-ui/invalid-keyword.rs
index ce2abc69bbd..2d70471c85e 100644
--- a/src/test/rustdoc-ui/invalid-keyword.rs
+++ b/src/test/rustdoc-ui/invalid-keyword.rs
@@ -1,4 +1,4 @@
-#![feature(doc_keyword)]
+#![feature(rustdoc_internals)]
#[doc(keyword = "foo df")] //~ ERROR
mod foo {}
diff --git a/src/test/rustdoc-ui/issue-91134.rs b/src/test/rustdoc-ui/issue-91134.rs
new file mode 100644
index 00000000000..d2ff3a25226
--- /dev/null
+++ b/src/test/rustdoc-ui/issue-91134.rs
@@ -0,0 +1,14 @@
+// compile-flags: --test --crate-name=empty_fn --extern=empty_fn --test-args=--test-threads=1
+// aux-build:empty-fn.rs
+// check-pass
+// normalize-stdout-test: "src/test/rustdoc-ui" -> "$$DIR"
+// normalize-stdout-test "finished in \d+\.\d+s" -> "finished in $$TIME"
+// edition:2021
+
+/// <https://github.com/rust-lang/rust/issues/91134>
+///
+/// ```
+/// extern crate empty_fn;
+/// empty_fn::empty();
+/// ```
+pub struct Something;
diff --git a/src/test/rustdoc-ui/issue-91134.stdout b/src/test/rustdoc-ui/issue-91134.stdout
new file mode 100644
index 00000000000..084062743da
--- /dev/null
+++ b/src/test/rustdoc-ui/issue-91134.stdout
@@ -0,0 +1,6 @@
+
+running 1 test
+test $DIR/issue-91134.rs - Something (line 10) ... ok
+
+test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in $TIME
+
diff --git a/src/test/rustdoc-ui/issue-91713.rs b/src/test/rustdoc-ui/issue-91713.rs
new file mode 100644
index 00000000000..b7057d868c2
--- /dev/null
+++ b/src/test/rustdoc-ui/issue-91713.rs
@@ -0,0 +1,3 @@
+// check-pass
+// compile-flags: --passes list
+// error-pattern: the `passes` flag is deprecated
diff --git a/src/test/rustdoc-ui/issue-91713.stderr b/src/test/rustdoc-ui/issue-91713.stderr
new file mode 100644
index 00000000000..70c22b3c01e
--- /dev/null
+++ b/src/test/rustdoc-ui/issue-91713.stderr
@@ -0,0 +1,4 @@
+warning: the `passes` flag is deprecated
+ |
+ = note: see issue #44136 <https://github.com/rust-lang/rust/issues/44136> for more information
+
diff --git a/src/test/rustdoc-ui/issue-91713.stdout b/src/test/rustdoc-ui/issue-91713.stdout
new file mode 100644
index 00000000000..d0372d4945f
--- /dev/null
+++ b/src/test/rustdoc-ui/issue-91713.stdout
@@ -0,0 +1,31 @@
+Available passes for running rustdoc:
+check_doc_test_visibility - run various visibility-related lints on doctests
+ strip-hidden - strips all `#[doc(hidden)]` items from the output
+ unindent-comments - removes excess indentation on comments in order for markdown to like it
+ strip-private - strips all private items from a crate which cannot be seen externally, implies strip-priv-imports
+ strip-priv-imports - strips all private import statements (`use`, `extern crate`) from a crate
+ propagate-doc-cfg - propagates `#[doc(cfg(...))]` to child items
+collect-intra-doc-links - resolves intra-doc links
+check-code-block-syntax - validates syntax inside Rust code blocks
+ collect-trait-impls - retrieves trait impls for items in the crate
+calculate-doc-coverage - counts the number of items with and without documentation
+check-invalid-html-tags - detects invalid HTML tags in doc comments
+ check-bare-urls - detects URLs that are not hyperlinks
+
+Default passes for rustdoc:
+ collect-trait-impls
+ unindent-comments
+check_doc_test_visibility
+ strip-hidden (when not --document-hidden-items)
+ strip-private (when not --document-private-items)
+ strip-priv-imports (when --document-private-items)
+collect-intra-doc-links
+check-code-block-syntax
+check-invalid-html-tags
+ propagate-doc-cfg
+ check-bare-urls
+
+Passes run with `--show-coverage`:
+ strip-hidden (when not --document-hidden-items)
+ strip-private (when not --document-private-items)
+calculate-doc-coverage
diff --git a/src/test/rustdoc-ui/normalize-cycle.rs b/src/test/rustdoc-ui/normalize-cycle.rs
new file mode 100644
index 00000000000..f48cad373cd
--- /dev/null
+++ b/src/test/rustdoc-ui/normalize-cycle.rs
@@ -0,0 +1,25 @@
+// check-pass
+// Regresion test for <https://github.com/rust-lang/rust/issues/79459>.
+pub trait Query {}
+
+pub trait AsQuery {
+ type Query;
+}
+
+impl<T: Query> AsQuery for T {
+ type Query = T;
+}
+
+pub trait SelectDsl<Selection> {
+ type Output;
+}
+
+impl<T, Selection> SelectDsl<Selection> for T
+where
+ T: AsQuery,
+ T::Query: SelectDsl<Selection>,
+{
+ type Output = <T::Query as SelectDsl<Selection>>::Output;
+}
+
+pub type Select<Source, Selection> = <Source as SelectDsl<Selection>>::Output;
diff --git a/src/test/rustdoc-ui/normalize-overflow.rs b/src/test/rustdoc-ui/normalize-overflow.rs
new file mode 100644
index 00000000000..0cdcc88e314
--- /dev/null
+++ b/src/test/rustdoc-ui/normalize-overflow.rs
@@ -0,0 +1,3 @@
+// aux-crate:overflow=overflow.rs
+// check-pass
+// Regression test for <https://github.com/rust-lang/rust/issues/79506>.
diff --git a/src/test/rustdoc-ui/scrape-examples-ice.rs b/src/test/rustdoc-ui/scrape-examples-ice.rs
new file mode 100644
index 00000000000..d629b62a724
--- /dev/null
+++ b/src/test/rustdoc-ui/scrape-examples-ice.rs
@@ -0,0 +1,4 @@
+// compile-flags: -Z unstable-options --scrape-examples-output-path {{build-base}}/t.calls --scrape-examples-target-crate foobar
+// check-pass
+#![no_std]
+use core as _;
diff --git a/src/test/rustdoc-ui/use_both_out_dir_and_output_options.rs b/src/test/rustdoc-ui/use_both_out_dir_and_output_options.rs
new file mode 100644
index 00000000000..5037043f19a
--- /dev/null
+++ b/src/test/rustdoc-ui/use_both_out_dir_and_output_options.rs
@@ -0,0 +1 @@
+// compile-flags: --output ./foo
diff --git a/src/test/rustdoc-ui/use_both_out_dir_and_output_options.stderr b/src/test/rustdoc-ui/use_both_out_dir_and_output_options.stderr
new file mode 100644
index 00000000000..96d2295ac3e
--- /dev/null
+++ b/src/test/rustdoc-ui/use_both_out_dir_and_output_options.stderr
@@ -0,0 +1,2 @@
+error: cannot use both 'out-dir' and 'output' at once
+
diff --git a/src/test/rustdoc/asm-foreign.rs b/src/test/rustdoc/asm-foreign.rs
index 570ed043dd9..d7550ca5aca 100644
--- a/src/test/rustdoc/asm-foreign.rs
+++ b/src/test/rustdoc/asm-foreign.rs
@@ -1,6 +1,6 @@
// Make sure rustdoc accepts asm! for a foreign architecture.
-#![feature(asm)]
+use std::arch::asm;
// @has asm_foreign/fn.aarch64.html
pub unsafe fn aarch64(a: f64, b: f64) -> f64 {
diff --git a/src/test/rustdoc/asm-foreign2.rs b/src/test/rustdoc/asm-foreign2.rs
index 34e313e7eac..87306901eb7 100644
--- a/src/test/rustdoc/asm-foreign2.rs
+++ b/src/test/rustdoc/asm-foreign2.rs
@@ -1,7 +1,7 @@
// only-aarch64
// Make sure rustdoc accepts options(att_syntax) asm! on non-x86 targets.
-#![feature(asm)]
+use std::arch::asm;
// @has asm_foreign2/fn.x86.html
pub unsafe fn x86(x: i64) -> i64 {
diff --git a/src/test/rustdoc/auto-impl-primitive.rs b/src/test/rustdoc/auto-impl-primitive.rs
index 83631b89f28..172333d445d 100644
--- a/src/test/rustdoc/auto-impl-primitive.rs
+++ b/src/test/rustdoc/auto-impl-primitive.rs
@@ -1,4 +1,7 @@
+#![feature(rustdoc_internals)]
+
#![crate_name = "foo"]
+
pub use std::fs::File;
// @has 'foo/primitive.i16.html' '//h2[@id="synthetic-implementations"]' 'Auto Trait Implementation'
diff --git a/src/test/rustdoc/auxiliary/reexports.rs b/src/test/rustdoc/auxiliary/reexports.rs
index e04b786a864..4336993a36e 100644
--- a/src/test/rustdoc/auxiliary/reexports.rs
+++ b/src/test/rustdoc/auxiliary/reexports.rs
@@ -4,39 +4,63 @@ pub macro addr_of($place:expr) {
&raw const $place
}
+pub macro addr_of_crate($place:expr) {
+ &raw const $place
+}
+
+pub macro addr_of_super($place:expr) {
+ &raw const $place
+}
+
pub macro addr_of_self($place:expr) {
&raw const $place
}
-pub macro addr_of_crate($place:expr) {
+pub macro addr_of_local($place:expr) {
&raw const $place
}
pub struct Foo;
-pub struct FooSelf;
pub struct FooCrate;
+pub struct FooSuper;
+pub struct FooSelf;
+pub struct FooLocal;
pub enum Bar { Foo, }
-pub enum BarSelf { Foo, }
pub enum BarCrate { Foo, }
+pub enum BarSuper { Foo, }
+pub enum BarSelf { Foo, }
+pub enum BarLocal { Foo, }
pub fn foo() {}
-pub fn foo_self() {}
pub fn foo_crate() {}
+pub fn foo_super() {}
+pub fn foo_self() {}
+pub fn foo_local() {}
pub type Type = i32;
-pub type TypeSelf = i32;
pub type TypeCrate = i32;
+pub type TypeSuper = i32;
+pub type TypeSelf = i32;
+pub type TypeLocal = i32;
pub union Union {
a: i8,
b: i8,
}
+pub union UnionCrate {
+ a: i8,
+ b: i8,
+}
+pub union UnionSuper {
+ a: i8,
+ b: i8,
+}
pub union UnionSelf {
a: i8,
b: i8,
}
-pub union UnionCrate {
+pub union UnionLocal {
a: i8,
b: i8,
}
diff --git a/src/test/rustdoc/bad-codeblock-syntax.rs b/src/test/rustdoc/bad-codeblock-syntax.rs
index 920877028d0..9ec089fd7ad 100644
--- a/src/test/rustdoc/bad-codeblock-syntax.rs
+++ b/src/test/rustdoc/bad-codeblock-syntax.rs
@@ -1,3 +1,5 @@
+#![allow(rustdoc::invalid_rust_codeblocks)]
+
// @has bad_codeblock_syntax/fn.foo.html
// @has - '//*[@class="docblock"]' '\_'
/// ```
diff --git a/src/test/rustdoc/check-source-code-urls-to-def.rs b/src/test/rustdoc/check-source-code-urls-to-def.rs
index 0cb8e423016..ca4179d403d 100644
--- a/src/test/rustdoc/check-source-code-urls-to-def.rs
+++ b/src/test/rustdoc/check-source-code-urls-to-def.rs
@@ -2,6 +2,8 @@
// aux-build:source_code.rs
// build-aux-docs
+#![feature(rustdoc_internals)]
+
#![crate_name = "foo"]
extern crate source_code;
@@ -29,21 +31,20 @@ fn babar() {}
// @has - '//a/@href' '/struct.String.html'
// @has - '//a/@href' '/primitive.u32.html'
// @has - '//a/@href' '/primitive.str.html'
-// @count - '//a[@href="../../src/foo/check-source-code-urls-to-def.rs.html#21"]' 5
+// @count - '//a[@href="../../src/foo/check-source-code-urls-to-def.rs.html#23"]' 5
// @has - '//a[@href="../../source_code/struct.SourceCode.html"]' 'source_code::SourceCode'
pub fn foo(a: u32, b: &str, c: String, d: Foo, e: bar::Bar, f: source_code::SourceCode) {
let x = 12;
let y: Foo = Foo;
let z: Bar = bar::Bar { field: Foo };
babar();
- // @has - '//a[@href="../../src/foo/check-source-code-urls-to-def.rs.html#24"]' 'hello'
+ // @has - '//a[@href="../../src/foo/check-source-code-urls-to-def.rs.html#26"]' 'hello'
y.hello();
}
// @has - '//a[@href="../../src/foo/auxiliary/source-code-bar.rs.html#14-16"]' 'bar::sub::Trait'
// @has - '//a[@href="../../src/foo/auxiliary/source-code-bar.rs.html#14-16"]' 'Trait'
-pub fn foo2<T: bar::sub::Trait, V: Trait>(t: &T, v: &V, b: bool) {
-}
+pub fn foo2<T: bar::sub::Trait, V: Trait>(t: &T, v: &V, b: bool) {}
// @has - '//a[@href="../../foo/primitive.bool.html"]' 'bool'
#[doc(primitive = "bool")]
diff --git a/src/test/rustdoc/const-generics/const-generic-defaults.rs b/src/test/rustdoc/const-generics/const-generic-defaults.rs
index efe35bf7aa4..8035f826775 100644
--- a/src/test/rustdoc/const-generics/const-generic-defaults.rs
+++ b/src/test/rustdoc/const-generics/const-generic-defaults.rs
@@ -1,5 +1,4 @@
#![crate_name = "foo"]
-#![feature(const_generics_defaults)]
// @has foo/struct.Foo.html '//pre[@class="rust struct"]' \
// 'pub struct Foo<const M: usize = 10_usize, const N: usize = M, T = i32>(_);'
diff --git a/src/test/rustdoc/const-generics/const-impl.rs b/src/test/rustdoc/const-generics/const-impl.rs
index fed37f6c9a2..cda900773ab 100644
--- a/src/test/rustdoc/const-generics/const-impl.rs
+++ b/src/test/rustdoc/const-generics/const-impl.rs
@@ -1,3 +1,5 @@
+#![allow(incomplete_features)]
+
#![feature(adt_const_params)]
#![crate_name = "foo"]
@@ -15,15 +17,15 @@ pub struct VSet<T, const ORDER: Order> {
inner: Vec<T>,
}
-// @has foo/struct.VSet.html '//div[@id="impl"]/h3[@class="code-header in-band"]' 'impl<T> VSet<T, {Order::Sorted}>'
-impl <T> VSet<T, {Order::Sorted}> {
+// @has foo/struct.VSet.html '//div[@id="impl"]/h3[@class="code-header in-band"]' 'impl<T> VSet<T, { Order::Sorted }>'
+impl<T> VSet<T, { Order::Sorted }> {
pub fn new() -> Self {
Self { inner: Vec::new() }
}
}
-// @has foo/struct.VSet.html '//div[@id="impl-1"]/h3[@class="code-header in-band"]' 'impl<T> VSet<T, {Order::Unsorted}>'
-impl <T> VSet<T, {Order::Unsorted}> {
+// @has foo/struct.VSet.html '//div[@id="impl-1"]/h3[@class="code-header in-band"]' 'impl<T> VSet<T, { Order::Unsorted }>'
+impl<T> VSet<T, { Order::Unsorted }> {
pub fn new() -> Self {
Self { inner: Vec::new() }
}
@@ -31,7 +33,7 @@ impl <T> VSet<T, {Order::Unsorted}> {
pub struct Escape<const S: &'static str>;
-// @has foo/struct.Escape.html '//div[@id="impl"]/h3[@class="code-header in-band"]' 'impl Escape<{ r#"<script>alert("Escape");</script>"# }>'
-impl Escape<{ r#"<script>alert("Escape");</script>"# }> {
+// @has foo/struct.Escape.html '//div[@id="impl"]/h3[@class="code-header in-band"]' 'impl Escape<r#"<script>alert("Escape");</script>"#>'
+impl Escape<r#"<script>alert("Escape");</script>"#> {
pub fn f() {}
}
diff --git a/src/test/rustdoc/default-trait-method.rs b/src/test/rustdoc/default-trait-method.rs
index 3d6ebef5a1d..6d0e339c48d 100644
--- a/src/test/rustdoc/default-trait-method.rs
+++ b/src/test/rustdoc/default-trait-method.rs
@@ -1,4 +1,4 @@
-#![feature(specialization)]
+#![feature(min_specialization)]
// @has default_trait_method/trait.Item.html
// @has - '//*[@id="tymethod.foo"]' 'fn foo()'
diff --git a/src/test/rustdoc/deref-const-fn.rs b/src/test/rustdoc/deref-const-fn.rs
new file mode 100644
index 00000000000..ca51f3c7b5a
--- /dev/null
+++ b/src/test/rustdoc/deref-const-fn.rs
@@ -0,0 +1,38 @@
+// This test ensures that the const methods from Deref aren't shown as const.
+// For more information, see https://github.com/rust-lang/rust/issues/90855.
+
+#![crate_name = "foo"]
+
+#![feature(staged_api)]
+
+#![stable(feature = "rust1", since = "1.0.0")]
+
+// @has 'foo/struct.Bar.html'
+#[stable(feature = "rust1", since = "1.0.0")]
+pub struct Bar;
+
+impl Bar {
+ // @has - '//*[@id="method.len"]' 'pub const fn len(&self) -> usize'
+ // @has - '//*[@id="method.len"]//span[@class="since"]' '1.0.0 (const: 1.0.0)'
+ #[stable(feature = "rust1", since = "1.0.0")]
+ #[rustc_const_stable(feature = "rust1", since = "1.0.0")]
+ pub const fn len(&self) -> usize { 0 }
+}
+
+#[stable(feature = "rust1", since = "1.0.0")]
+pub struct Foo {
+ value: Bar,
+}
+
+// @has 'foo/struct.Foo.html'
+// @has - '//*[@id="method.len"]' 'pub fn len(&self) -> usize'
+// @!has - '//*[@id="method.len"]//span[@class="since"]' '1.0.0'
+// @!has - '//*[@id="method.len"]//span[@class="since"]' '(const: 1.0.0)'
+#[stable(feature = "rust1", since = "1.0.0")]
+impl std::ops::Deref for Foo {
+ type Target = Bar;
+
+ fn deref(&self) -> &Self::Target {
+ &self.value
+ }
+}
diff --git a/src/test/rustdoc/doc-cfg.rs b/src/test/rustdoc/doc-cfg.rs
index 416ffb60098..9465c8a35c8 100644
--- a/src/test/rustdoc/doc-cfg.rs
+++ b/src/test/rustdoc/doc-cfg.rs
@@ -2,7 +2,7 @@
#![feature(target_feature, cfg_target_feature)]
// @has doc_cfg/struct.Portable.html
-// @!has - '//*[@id="main"]/*[@class="item-info"]/*[@class="stab portability"]' ''
+// @!has - '//*[@id="main-content"]/*[@class="item-info"]/*[@class="stab portability"]' ''
// @has - '//*[@id="method.unix_and_arm_only_function"]' 'fn unix_and_arm_only_function()'
// @has - '//*[@class="stab portability"]' 'This is supported on Unix and ARM only.'
// @has - '//*[@id="method.wasi_and_wasm32_only_function"]' 'fn wasi_and_wasm32_only_function()'
@@ -10,14 +10,14 @@
pub struct Portable;
// @has doc_cfg/unix_only/index.html \
-// '//*[@id="main"]/*[@class="item-info"]/*[@class="stab portability"]' \
+// '//*[@id="main-content"]/*[@class="item-info"]/*[@class="stab portability"]' \
// 'This is supported on Unix only.'
// @matches - '//*[@class="item-left module-item"]//*[@class="stab portability"]' '\AARM\Z'
// @count - '//*[@class="stab portability"]' 2
#[doc(cfg(unix))]
pub mod unix_only {
// @has doc_cfg/unix_only/fn.unix_only_function.html \
- // '//*[@id="main"]/*[@class="item-info"]/*[@class="stab portability"]' \
+ // '//*[@id="main-content"]/*[@class="item-info"]/*[@class="stab portability"]' \
// 'This is supported on Unix only.'
// @count - '//*[@class="stab portability"]' 1
pub fn unix_only_function() {
@@ -25,7 +25,7 @@ pub mod unix_only {
}
// @has doc_cfg/unix_only/trait.ArmOnly.html \
- // '//*[@id="main"]/*[@class="item-info"]/*[@class="stab portability"]' \
+ // '//*[@id="main-content"]/*[@class="item-info"]/*[@class="stab portability"]' \
// 'This is supported on Unix and ARM only.'
// @count - '//*[@class="stab portability"]' 1
#[doc(cfg(target_arch = "arm"))]
@@ -40,14 +40,14 @@ pub mod unix_only {
}
// @has doc_cfg/wasi_only/index.html \
-// '//*[@id="main"]/*[@class="item-info"]/*[@class="stab portability"]' \
+// '//*[@id="main-content"]/*[@class="item-info"]/*[@class="stab portability"]' \
// 'This is supported on WASI only.'
// @matches - '//*[@class="item-left module-item"]//*[@class="stab portability"]' '\AWebAssembly\Z'
// @count - '//*[@class="stab portability"]' 2
#[doc(cfg(target_os = "wasi"))]
pub mod wasi_only {
// @has doc_cfg/wasi_only/fn.wasi_only_function.html \
- // '//*[@id="main"]/*[@class="item-info"]/*[@class="stab portability"]' \
+ // '//*[@id="main-content"]/*[@class="item-info"]/*[@class="stab portability"]' \
// 'This is supported on WASI only.'
// @count - '//*[@class="stab portability"]' 1
pub fn wasi_only_function() {
@@ -55,7 +55,7 @@ pub mod wasi_only {
}
// @has doc_cfg/wasi_only/trait.Wasm32Only.html \
- // '//*[@id="main"]/*[@class="item-info"]/*[@class="stab portability"]' \
+ // '//*[@id="main-content"]/*[@class="item-info"]/*[@class="stab portability"]' \
// 'This is supported on WASI and WebAssembly only.'
// @count - '//*[@class="stab portability"]' 1
#[doc(cfg(target_arch = "wasm32"))]
@@ -77,7 +77,7 @@ pub mod wasi_only {
// @matches - '//*[@class="item-left module-item"]//*[@class="stab portability"]' '\Aavx\Z'
// @has doc_cfg/fn.uses_target_feature.html
-// @has - '//*[@id="main"]/*[@class="item-info"]/*[@class="stab portability"]' \
+// @has - '//*[@id="main-content"]/*[@class="item-info"]/*[@class="stab portability"]' \
// 'This is supported with target feature avx only.'
#[target_feature(enable = "avx")]
pub unsafe fn uses_target_feature() {
@@ -85,7 +85,7 @@ pub unsafe fn uses_target_feature() {
}
// @has doc_cfg/fn.uses_cfg_target_feature.html
-// @has - '//*[@id="main"]/*[@class="item-info"]/*[@class="stab portability"]' \
+// @has - '//*[@id="main-content"]/*[@class="item-info"]/*[@class="stab portability"]' \
// 'This is supported with target feature avx only.'
#[doc(cfg(target_feature = "avx"))]
pub fn uses_cfg_target_feature() {
@@ -94,8 +94,8 @@ pub fn uses_cfg_target_feature() {
// multiple attributes should be allowed
// @has doc_cfg/fn.multiple_attrs.html \
-// '//*[@id="main"]/*[@class="item-info"]/*[@class="stab portability"]' \
+// '//*[@id="main-content"]/*[@class="item-info"]/*[@class="stab portability"]' \
// 'This is supported on x and y and z only.'
-#[doc(inline, cfg(x))]
+#[doc(cfg(x))]
#[doc(cfg(y), cfg(z))]
pub fn multiple_attrs() {}
diff --git a/src/test/rustdoc/doc-notable_trait-mut_t_is_not_an_iterator.rs b/src/test/rustdoc/doc-notable_trait-mut_t_is_not_an_iterator.rs
new file mode 100644
index 00000000000..bfce46cf444
--- /dev/null
+++ b/src/test/rustdoc/doc-notable_trait-mut_t_is_not_an_iterator.rs
@@ -0,0 +1,23 @@
+//! Test case for [#80737].
+//!
+//! A SomeTrait that is implemented for `&mut T where T: SomeTrait`
+//! should not be marked as "notable" for return values that do not
+//! have bounds on the trait itself.
+//!
+//! [#80737]: https://github.com/rust-lang/rust/issues/80737
+
+#![feature(rustdoc_internals)]
+#![no_std]
+
+#[doc(primitive = "reference")]
+/// Some useless docs, wouhou!
+///
+/// We need to put this in here, because notable traits
+/// that are implemented on foreign types don't show up.
+mod reference {}
+
+// @has doc_notable_trait_mut_t_is_not_an_iterator/fn.fn_no_matches.html
+// @!has - '//code[@class="content"]' 'Iterator'
+pub fn fn_no_matches<'a, T: 'a>() -> &'a mut T {
+ panic!()
+}
diff --git a/src/test/rustdoc/doc-notable_trait-mut_t_is_not_ref_t.rs b/src/test/rustdoc/doc-notable_trait-mut_t_is_not_ref_t.rs
new file mode 100644
index 00000000000..b359dcea0ff
--- /dev/null
+++ b/src/test/rustdoc/doc-notable_trait-mut_t_is_not_ref_t.rs
@@ -0,0 +1,21 @@
+//! Test case for [#78160].
+//!
+//! A SomeTrait that is implemented for `&mut T` should not be marked as
+//! "notable" for return values that are `&T`.
+//!
+//! [#78160]: https://github.com/rust-lang/rust/issues/78160
+
+#![feature(rustdoc_internals)]
+
+#[doc(primitive = "reference")]
+/// Some useless docs, wouhou!
+///
+/// We need to put this in here, because notable traits
+/// that are implemented on foreign types don't show up.
+mod reference {}
+
+// @has doc_notable_trait_mut_t_is_not_ref_t/fn.fn_no_matches.html
+// @!has - '//code[@class="content"]' "impl<'_, I> Iterator for &'_ mut I"
+pub fn fn_no_matches<'a, T: Iterator + 'a>() -> &'a T {
+ loop {}
+}
diff --git a/src/test/rustdoc/doc-notable_trait-slice.rs b/src/test/rustdoc/doc-notable_trait-slice.rs
new file mode 100644
index 00000000000..b0d41402721
--- /dev/null
+++ b/src/test/rustdoc/doc-notable_trait-slice.rs
@@ -0,0 +1,20 @@
+#![feature(doc_notable_trait)]
+
+#[doc(notable_trait)]
+pub trait SomeTrait {}
+
+pub struct SomeStruct;
+pub struct OtherStruct;
+impl SomeTrait for &[SomeStruct] {}
+
+// @has doc_notable_trait_slice/fn.bare_fn_matches.html
+// @has - '//code[@class="content"]' 'impl SomeTrait for &[SomeStruct]'
+pub fn bare_fn_matches() -> &'static [SomeStruct] {
+ &[]
+}
+
+// @has doc_notable_trait_slice/fn.bare_fn_no_matches.html
+// @!has - '//code[@class="content"]' 'impl SomeTrait for &[SomeStruct]'
+pub fn bare_fn_no_matches() -> &'static [OtherStruct] {
+ &[]
+}
diff --git a/src/test/rustdoc/duplicate_impls/issue-33054.rs b/src/test/rustdoc/duplicate_impls/issue-33054.rs
index 7ace13fe3a6..b018dd6cda5 100644
--- a/src/test/rustdoc/duplicate_impls/issue-33054.rs
+++ b/src/test/rustdoc/duplicate_impls/issue-33054.rs
@@ -2,7 +2,7 @@
// @has - '//h3[@class="code-header in-band"]' 'impl Foo'
// @has - '//h3[@class="code-header in-band"]' 'impl Bar for Foo'
// @count - '//*[@id="trait-implementations-list"]//*[@class="impl has-srclink"]' 1
-// @count - '//*[@id="main"]/details/summary/*[@class="impl has-srclink"]' 1
+// @count - '//*[@id="main-content"]/details/summary/*[@class="impl has-srclink"]' 1
// @has issue_33054/impls/bar/trait.Bar.html
// @has - '//h3[@class="code-header in-band"]' 'impl Bar for Foo'
// @count - '//*[@class="struct"]' 1
diff --git a/src/test/rustdoc/impl-everywhere.rs b/src/test/rustdoc/impl-everywhere.rs
index 74281326258..44885d4301f 100644
--- a/src/test/rustdoc/impl-everywhere.rs
+++ b/src/test/rustdoc/impl-everywhere.rs
@@ -8,23 +8,23 @@ pub struct Bar;
impl Foo for Bar {}
impl Foo2 for Bar {}
-// @has foo/fn.foo.html '//section[@id="main"]//pre' "x: &'x impl Foo"
-// @has foo/fn.foo.html '//section[@id="main"]//pre' "-> &'x impl Foo"
+// @has foo/fn.foo.html '//section[@id="main-content"]//pre' "x: &'x impl Foo"
+// @has foo/fn.foo.html '//section[@id="main-content"]//pre' "-> &'x impl Foo"
pub fn foo<'x>(x: &'x impl Foo) -> &'x impl Foo {
x
}
-// @has foo/fn.foo2.html '//section[@id="main"]//pre' "x: &'x impl Foo"
-// @has foo/fn.foo2.html '//section[@id="main"]//pre' '-> impl Foo2'
+// @has foo/fn.foo2.html '//section[@id="main-content"]//pre' "x: &'x impl Foo"
+// @has foo/fn.foo2.html '//section[@id="main-content"]//pre' '-> impl Foo2'
pub fn foo2<'x>(_x: &'x impl Foo) -> impl Foo2 {
Bar
}
-// @has foo/fn.foo_foo.html '//section[@id="main"]//pre' '-> impl Foo + Foo2'
+// @has foo/fn.foo_foo.html '//section[@id="main-content"]//pre' '-> impl Foo + Foo2'
pub fn foo_foo() -> impl Foo + Foo2 {
Bar
}
-// @has foo/fn.foo_foo_foo.html '//section[@id="main"]//pre' "x: &'x impl Foo + Foo2"
+// @has foo/fn.foo_foo_foo.html '//section[@id="main-content"]//pre' "x: &'x impl Foo + Foo2"
pub fn foo_foo_foo<'x>(_x: &'x (impl Foo + Foo2)) {
}
diff --git a/src/test/rustdoc/intra-doc/associated-defaults.rs b/src/test/rustdoc/intra-doc/associated-defaults.rs
index 68647127fe8..c7e66c826be 100644
--- a/src/test/rustdoc/intra-doc/associated-defaults.rs
+++ b/src/test/rustdoc/intra-doc/associated-defaults.rs
@@ -1,4 +1,4 @@
-#![deny(intra_doc_link_resolution_failure)]
+#![deny(rustdoc::broken_intra_doc_links)]
#![feature(associated_type_defaults)]
pub trait TraitWithDefault {
diff --git a/src/test/rustdoc/intra-doc/associated-items.rs b/src/test/rustdoc/intra-doc/associated-items.rs
index d9fed2d6951..9b70ea054ad 100644
--- a/src/test/rustdoc/intra-doc/associated-items.rs
+++ b/src/test/rustdoc/intra-doc/associated-items.rs
@@ -1,4 +1,4 @@
-#![deny(intra_doc_link_resolution_failure)]
+#![deny(rustdoc::broken_intra_doc_links)]
/// [`std::collections::BTreeMap::into_iter`]
/// [`String::from`] is ambiguous as to which `From` impl
diff --git a/src/test/rustdoc/intra-doc/auxiliary/my-core.rs b/src/test/rustdoc/intra-doc/auxiliary/my-core.rs
index 92cfd46188b..bb70073fc69 100644
--- a/src/test/rustdoc/intra-doc/auxiliary/my-core.rs
+++ b/src/test/rustdoc/intra-doc/auxiliary/my-core.rs
@@ -1,4 +1,4 @@
-#![feature(no_core, lang_items)]
+#![feature(no_core, lang_items, rustdoc_internals)]
#![no_core]
#![crate_type="rlib"]
diff --git a/src/test/rustdoc/intra-doc/cross-crate/additional_doc.rs b/src/test/rustdoc/intra-doc/cross-crate/additional_doc.rs
index 85c5866ca7e..e52fb9b1c9f 100644
--- a/src/test/rustdoc/intra-doc/cross-crate/additional_doc.rs
+++ b/src/test/rustdoc/intra-doc/cross-crate/additional_doc.rs
@@ -1,6 +1,6 @@
// aux-build:additional_doc.rs
// build-aux-docs
-#![deny(broken_intra_doc_links)]
+#![deny(rustdoc::broken_intra_doc_links)]
extern crate my_rand;
diff --git a/src/test/rustdoc/intra-doc/cross-crate/auxiliary/additional_doc.rs b/src/test/rustdoc/intra-doc/cross-crate/auxiliary/additional_doc.rs
index 849d2568733..684fdd449b8 100644
--- a/src/test/rustdoc/intra-doc/cross-crate/auxiliary/additional_doc.rs
+++ b/src/test/rustdoc/intra-doc/cross-crate/auxiliary/additional_doc.rs
@@ -1,5 +1,5 @@
#![crate_name = "my_rand"]
-#![deny(broken_intra_doc_links)]
+#![deny(rustdoc::broken_intra_doc_links)]
pub trait RngCore {}
/// Rng extends [`RngCore`].
diff --git a/src/test/rustdoc/intra-doc/cross-crate/auxiliary/hidden.rs b/src/test/rustdoc/intra-doc/cross-crate/auxiliary/hidden.rs
index b543ae764c0..34f4e9f635f 100644
--- a/src/test/rustdoc/intra-doc/cross-crate/auxiliary/hidden.rs
+++ b/src/test/rustdoc/intra-doc/cross-crate/auxiliary/hidden.rs
@@ -1,5 +1,5 @@
#![crate_name = "hidden_dep"]
-#![deny(broken_intra_doc_links)]
+#![deny(rustdoc::broken_intra_doc_links)]
#[doc(hidden)]
pub mod __reexport {
diff --git a/src/test/rustdoc/intra-doc/cross-crate/auxiliary/intra-doc-basic.rs b/src/test/rustdoc/intra-doc/cross-crate/auxiliary/intra-doc-basic.rs
index 5342baecbc4..d6a82996689 100644
--- a/src/test/rustdoc/intra-doc/cross-crate/auxiliary/intra-doc-basic.rs
+++ b/src/test/rustdoc/intra-doc/cross-crate/auxiliary/intra-doc-basic.rs
@@ -1,5 +1,5 @@
#![crate_name = "a"]
-#![deny(broken_intra_doc_links)]
+#![deny(rustdoc::broken_intra_doc_links)]
pub struct Foo;
diff --git a/src/test/rustdoc/intra-doc/cross-crate/auxiliary/macro_inner.rs b/src/test/rustdoc/intra-doc/cross-crate/auxiliary/macro_inner.rs
index a94f9e5dcca..cb7a8afb60e 100644
--- a/src/test/rustdoc/intra-doc/cross-crate/auxiliary/macro_inner.rs
+++ b/src/test/rustdoc/intra-doc/cross-crate/auxiliary/macro_inner.rs
@@ -1,5 +1,5 @@
#![crate_name = "macro_inner"]
-#![deny(broken_intra_doc_links)]
+#![deny(rustdoc::broken_intra_doc_links)]
pub struct Foo;
diff --git a/src/test/rustdoc/intra-doc/cross-crate/auxiliary/module.rs b/src/test/rustdoc/intra-doc/cross-crate/auxiliary/module.rs
index b7e3913f108..018fdedd9ed 100644
--- a/src/test/rustdoc/intra-doc/cross-crate/auxiliary/module.rs
+++ b/src/test/rustdoc/intra-doc/cross-crate/auxiliary/module.rs
@@ -1,5 +1,5 @@
#![crate_name = "module_inner"]
-#![deny(broken_intra_doc_links)]
+#![deny(rustdoc::broken_intra_doc_links)]
/// [SomeType] links to [bar]
pub struct SomeType;
pub trait SomeTrait {}
diff --git a/src/test/rustdoc/intra-doc/cross-crate/auxiliary/submodule-inner.rs b/src/test/rustdoc/intra-doc/cross-crate/auxiliary/submodule-inner.rs
index 8ae0f6c16b3..0612f53d6a7 100644
--- a/src/test/rustdoc/intra-doc/cross-crate/auxiliary/submodule-inner.rs
+++ b/src/test/rustdoc/intra-doc/cross-crate/auxiliary/submodule-inner.rs
@@ -1,5 +1,5 @@
#![crate_name = "a"]
-#![deny(broken_intra_doc_links)]
+#![deny(rustdoc::broken_intra_doc_links)]
pub mod bar {
pub struct Bar;
diff --git a/src/test/rustdoc/intra-doc/cross-crate/auxiliary/submodule-outer.rs b/src/test/rustdoc/intra-doc/cross-crate/auxiliary/submodule-outer.rs
index d90c529e385..105eb8e1120 100644
--- a/src/test/rustdoc/intra-doc/cross-crate/auxiliary/submodule-outer.rs
+++ b/src/test/rustdoc/intra-doc/cross-crate/auxiliary/submodule-outer.rs
@@ -1,5 +1,5 @@
#![crate_name = "bar"]
-#![deny(broken_intra_doc_links)]
+#![deny(rustdoc::broken_intra_doc_links)]
pub trait Foo {
/// [`Bar`] [`Baz`]
diff --git a/src/test/rustdoc/intra-doc/cross-crate/basic.rs b/src/test/rustdoc/intra-doc/cross-crate/basic.rs
index 6ab9140c3c3..ad7454918b4 100644
--- a/src/test/rustdoc/intra-doc/cross-crate/basic.rs
+++ b/src/test/rustdoc/intra-doc/cross-crate/basic.rs
@@ -1,6 +1,6 @@
// aux-build:intra-doc-basic.rs
// build-aux-docs
-#![deny(broken_intra_doc_links)]
+#![deny(rustdoc::broken_intra_doc_links)]
// from https://github.com/rust-lang/rust/issues/65983
extern crate a;
diff --git a/src/test/rustdoc/intra-doc/cross-crate/hidden.rs b/src/test/rustdoc/intra-doc/cross-crate/hidden.rs
index 31337f20f18..4f7d075ba48 100644
--- a/src/test/rustdoc/intra-doc/cross-crate/hidden.rs
+++ b/src/test/rustdoc/intra-doc/cross-crate/hidden.rs
@@ -1,6 +1,6 @@
// aux-build:hidden.rs
// build-aux-docs
-#![deny(broken_intra_doc_links)]
+#![deny(rustdoc::broken_intra_doc_links)]
// tests https://github.com/rust-lang/rust/issues/73363
diff --git a/src/test/rustdoc/intra-doc/cross-crate/macro.rs b/src/test/rustdoc/intra-doc/cross-crate/macro.rs
index 62659ce689a..32f0a55d3c6 100644
--- a/src/test/rustdoc/intra-doc/cross-crate/macro.rs
+++ b/src/test/rustdoc/intra-doc/cross-crate/macro.rs
@@ -1,7 +1,7 @@
// aux-build:macro_inner.rs
// aux-build:proc_macro.rs
// build-aux-docs
-#![deny(broken_intra_doc_links)]
+#![deny(rustdoc::broken_intra_doc_links)]
extern crate macro_inner;
extern crate proc_macro_inner;
diff --git a/src/test/rustdoc/intra-doc/cross-crate/module.rs b/src/test/rustdoc/intra-doc/cross-crate/module.rs
index 9039e344f7b..fde9322657d 100644
--- a/src/test/rustdoc/intra-doc/cross-crate/module.rs
+++ b/src/test/rustdoc/intra-doc/cross-crate/module.rs
@@ -1,7 +1,7 @@
// outer.rs
// aux-build: module.rs
// build-aux-docs
-#![deny(broken_intra_doc_links)]
+#![deny(rustdoc::broken_intra_doc_links)]
extern crate module_inner;
// @has 'module/bar/index.html' '//a[@href="../../module_inner/trait.SomeTrait.html"]' 'SomeTrait'
// @has 'module/bar/index.html' '//a[@href="../../module_inner/struct.SomeType.html"]' 'SomeType'
diff --git a/src/test/rustdoc/intra-doc/cross-crate/submodule-inner.rs b/src/test/rustdoc/intra-doc/cross-crate/submodule-inner.rs
index e1465816368..577fe78a508 100644
--- a/src/test/rustdoc/intra-doc/cross-crate/submodule-inner.rs
+++ b/src/test/rustdoc/intra-doc/cross-crate/submodule-inner.rs
@@ -1,6 +1,6 @@
// aux-build:submodule-inner.rs
// build-aux-docs
-#![deny(broken_intra_doc_links)]
+#![deny(rustdoc::broken_intra_doc_links)]
extern crate a;
diff --git a/src/test/rustdoc/intra-doc/cross-crate/submodule-outer.rs b/src/test/rustdoc/intra-doc/cross-crate/submodule-outer.rs
index db7952b5ace..d0c0b7e85ae 100644
--- a/src/test/rustdoc/intra-doc/cross-crate/submodule-outer.rs
+++ b/src/test/rustdoc/intra-doc/cross-crate/submodule-outer.rs
@@ -1,6 +1,6 @@
// aux-build:submodule-outer.rs
// edition:2018
-#![deny(broken_intra_doc_links)]
+#![deny(rustdoc::broken_intra_doc_links)]
extern crate bar as bar_;
diff --git a/src/test/rustdoc/intra-doc/cross-crate/traits.rs b/src/test/rustdoc/intra-doc/cross-crate/traits.rs
index 68f5cb3a092..7b9554bfdb0 100644
--- a/src/test/rustdoc/intra-doc/cross-crate/traits.rs
+++ b/src/test/rustdoc/intra-doc/cross-crate/traits.rs
@@ -1,6 +1,6 @@
// aux-build:traits.rs
// build-aux-docs
-#![deny(broken_intra_doc_links)]
+#![deny(rustdoc::broken_intra_doc_links)]
extern crate inner;
use inner::SomeTrait;
diff --git a/src/test/rustdoc/intra-doc/disambiguators-removed.rs b/src/test/rustdoc/intra-doc/disambiguators-removed.rs
index d782c5cf5dc..331a314130a 100644
--- a/src/test/rustdoc/intra-doc/disambiguators-removed.rs
+++ b/src/test/rustdoc/intra-doc/disambiguators-removed.rs
@@ -1,4 +1,4 @@
-#![deny(intra_doc_link_resolution_failure)]
+#![deny(rustdoc::broken_intra_doc_links)]
// first try backticks
/// Trait: [`trait@Name`], fn: [`fn@Name`], [`Name`][`macro@Name`]
// @has disambiguators_removed/struct.AtDisambiguator.html
diff --git a/src/test/rustdoc/intra-doc/email-address.rs b/src/test/rustdoc/intra-doc/email-address.rs
index c407eb80da2..ae74fbbc892 100644
--- a/src/test/rustdoc/intra-doc/email-address.rs
+++ b/src/test/rustdoc/intra-doc/email-address.rs
@@ -1,3 +1,5 @@
+#![allow(rustdoc::broken_intra_doc_links)]
+
//! Email me at <hello@example.com>.
//! Email me at <hello-world@example.com>.
//! Email me at <hello@localhost> (this warns but will still become a link).
diff --git a/src/test/rustdoc/intra-doc/extern-crate.rs b/src/test/rustdoc/intra-doc/extern-crate.rs
index 193bca704bf..4e4438dea03 100644
--- a/src/test/rustdoc/intra-doc/extern-crate.rs
+++ b/src/test/rustdoc/intra-doc/extern-crate.rs
@@ -4,6 +4,6 @@
// though they would never actually get displayed. This tripped intra-doc-link resolution failures,
// for items that aren't under our control, and not actually getting documented!
-#![deny(broken_intra_doc_links)]
+#![deny(rustdoc::broken_intra_doc_links)]
extern crate inner;
diff --git a/src/test/rustdoc/intra-doc/external-traits.rs b/src/test/rustdoc/intra-doc/external-traits.rs
index de76f29476c..a0a66f242c9 100644
--- a/src/test/rustdoc/intra-doc/external-traits.rs
+++ b/src/test/rustdoc/intra-doc/external-traits.rs
@@ -2,7 +2,7 @@
// ignore-cross-compile
#![crate_name = "outer"]
-#![deny(broken_intra_doc_links)]
+#![deny(rustdoc::broken_intra_doc_links)]
// using a trait that has intra-doc links on it from another crate (whether re-exporting or just
// implementing it) used to give spurious resolution failure warnings
diff --git a/src/test/rustdoc/intra-doc/in-bodies.rs b/src/test/rustdoc/intra-doc/in-bodies.rs
index ec965a99dc2..55169e5d3c4 100644
--- a/src/test/rustdoc/intra-doc/in-bodies.rs
+++ b/src/test/rustdoc/intra-doc/in-bodies.rs
@@ -1,6 +1,6 @@
// we need to make sure that intra-doc links on trait impls get resolved in the right scope
-#![deny(broken_intra_doc_links)]
+#![deny(rustdoc::broken_intra_doc_links)]
pub mod inner {
pub struct SomethingOutOfScope;
diff --git a/src/test/rustdoc/intra-doc/issue-82209.rs b/src/test/rustdoc/intra-doc/issue-82209.rs
index 68a5672a8d2..a5fe855cb36 100644
--- a/src/test/rustdoc/intra-doc/issue-82209.rs
+++ b/src/test/rustdoc/intra-doc/issue-82209.rs
@@ -1,5 +1,5 @@
#![crate_name = "foo"]
-#![deny(broken_intra_doc_links)]
+#![deny(rustdoc::broken_intra_doc_links)]
pub enum Foo {
Bar {
abc: i32,
diff --git a/src/test/rustdoc/intra-doc/libstd-re-export.rs b/src/test/rustdoc/intra-doc/libstd-re-export.rs
index fc0ff904389..6c41eb2b5b7 100644
--- a/src/test/rustdoc/intra-doc/libstd-re-export.rs
+++ b/src/test/rustdoc/intra-doc/libstd-re-export.rs
@@ -1,4 +1,4 @@
-#![deny(broken_intra_doc_links)]
+#![deny(rustdoc::broken_intra_doc_links)]
#![feature(intra_doc_pointers)]
pub use std::*;
diff --git a/src/test/rustdoc/intra-doc/mod-ambiguity.rs b/src/test/rustdoc/intra-doc/mod-ambiguity.rs
index 24b9dc30a9e..0c7acbaf093 100644
--- a/src/test/rustdoc/intra-doc/mod-ambiguity.rs
+++ b/src/test/rustdoc/intra-doc/mod-ambiguity.rs
@@ -1,4 +1,4 @@
-#![deny(broken_intra_doc_links)]
+#![deny(rustdoc::broken_intra_doc_links)]
pub fn foo() {
diff --git a/src/test/rustdoc/intra-doc/prim-assoc.rs b/src/test/rustdoc/intra-doc/prim-assoc.rs
index c73140420ff..dfa7db8a558 100644
--- a/src/test/rustdoc/intra-doc/prim-assoc.rs
+++ b/src/test/rustdoc/intra-doc/prim-assoc.rs
@@ -1,4 +1,4 @@
-#![deny(broken_intra_doc_links)]
+#![deny(rustdoc::broken_intra_doc_links)]
//! [i32::MAX]
// @has prim_assoc/index.html '//a[@href="{{channel}}/std/primitive.i32.html#associatedconstant.MAX"]' "i32::MAX"
diff --git a/src/test/rustdoc/intra-doc/prim-methods-external-core.rs b/src/test/rustdoc/intra-doc/prim-methods-external-core.rs
index 9d869984bbd..c3340af33d5 100644
--- a/src/test/rustdoc/intra-doc/prim-methods-external-core.rs
+++ b/src/test/rustdoc/intra-doc/prim-methods-external-core.rs
@@ -3,14 +3,14 @@
// ignore-cross-compile
// only-linux
-#![deny(broken_intra_doc_links)]
+#![deny(rustdoc::broken_intra_doc_links)]
#![feature(no_core, lang_items)]
#![no_core]
#![crate_type = "rlib"]
// @has prim_methods_external_core/index.html
-// @has - '//*[@id="main"]//a[@href="../my_core/primitive.char.html"]' 'char'
-// @has - '//*[@id="main"]//a[@href="../my_core/primitive.char.html#method.len_utf8"]' 'char::len_utf8'
+// @has - '//*[@id="main-content"]//a[@href="../my_core/primitive.char.html"]' 'char'
+// @has - '//*[@id="main-content"]//a[@href="../my_core/primitive.char.html#method.len_utf8"]' 'char::len_utf8'
//! A [`char`] and its [`char::len_utf8`].
diff --git a/src/test/rustdoc/intra-doc/prim-methods-local.rs b/src/test/rustdoc/intra-doc/prim-methods-local.rs
index cfb3c3842ab..fd0b1b97c6e 100644
--- a/src/test/rustdoc/intra-doc/prim-methods-local.rs
+++ b/src/test/rustdoc/intra-doc/prim-methods-local.rs
@@ -1,12 +1,11 @@
-#![deny(broken_intra_doc_links)]
-#![feature(no_core, lang_items)]
+#![deny(rustdoc::broken_intra_doc_links)]
+#![feature(no_core, lang_items, rustdoc_internals)]
#![no_core]
#![crate_type = "rlib"]
-
// @has prim_methods_local/index.html
-// @has - '//*[@id="main"]//a[@href="primitive.char.html"]' 'char'
-// @has - '//*[@id="main"]//a[@href="primitive.char.html#method.len_utf8"]' 'char::len_utf8'
+// @has - '//*[@id="main-content"]//a[@href="primitive.char.html"]' 'char'
+// @has - '//*[@id="main-content"]//a[@href="primitive.char.html#method.len_utf8"]' 'char::len_utf8'
//! A [prim@`char`] and its [`char::len_utf8`].
diff --git a/src/test/rustdoc/intra-doc/prim-methods.rs b/src/test/rustdoc/intra-doc/prim-methods.rs
index 076117359d2..a412a23fda8 100644
--- a/src/test/rustdoc/intra-doc/prim-methods.rs
+++ b/src/test/rustdoc/intra-doc/prim-methods.rs
@@ -1,8 +1,7 @@
-#![deny(broken_intra_doc_links)]
-
+#![deny(rustdoc::broken_intra_doc_links)]
// @has prim_methods/index.html
-// @has - '//*[@id="main"]//a[@href="{{channel}}/std/primitive.char.html"]' 'char'
-// @has - '//*[@id="main"]//a[@href="{{channel}}/std/primitive.char.html#method.len_utf8"]' 'char::len_utf8'
+// @has - '//*[@id="main-content"]//a[@href="{{channel}}/std/primitive.char.html"]' 'char'
+// @has - '//*[@id="main-content"]//a[@href="{{channel}}/std/primitive.char.html#method.len_utf8"]' 'char::len_utf8'
//! A [`char`] and its [`char::len_utf8`].
diff --git a/src/test/rustdoc/intra-doc/prim-precedence.rs b/src/test/rustdoc/intra-doc/prim-precedence.rs
index fcd86a99f1d..25625b95277 100644
--- a/src/test/rustdoc/intra-doc/prim-precedence.rs
+++ b/src/test/rustdoc/intra-doc/prim-precedence.rs
@@ -1,4 +1,4 @@
-#![deny(broken_intra_doc_links)]
+#![deny(rustdoc::broken_intra_doc_links)]
pub mod char {
/// [char]
diff --git a/src/test/rustdoc/intra-doc/primitive-disambiguators.rs b/src/test/rustdoc/intra-doc/primitive-disambiguators.rs
index 9b3b6983240..adcab767d0b 100644
--- a/src/test/rustdoc/intra-doc/primitive-disambiguators.rs
+++ b/src/test/rustdoc/intra-doc/primitive-disambiguators.rs
@@ -1,4 +1,4 @@
-#![deny(broken_intra_doc_links)]
+#![deny(rustdoc::broken_intra_doc_links)]
// @has primitive_disambiguators/index.html
// @has - '//a/@href' '{{channel}}/std/primitive.str.html#method.trim'
//! [str::trim()]
diff --git a/src/test/rustdoc/intra-doc/primitive-non-default-impl.rs b/src/test/rustdoc/intra-doc/primitive-non-default-impl.rs
index f8a824bd08f..474bf347750 100644
--- a/src/test/rustdoc/intra-doc/primitive-non-default-impl.rs
+++ b/src/test/rustdoc/intra-doc/primitive-non-default-impl.rs
@@ -1,4 +1,4 @@
-#![deny(broken_intra_doc_links)]
+#![deny(rustdoc::broken_intra_doc_links)]
// @has primitive_non_default_impl/fn.str_methods.html
diff --git a/src/test/rustdoc/intra-doc/private-failures-ignored.rs b/src/test/rustdoc/intra-doc/private-failures-ignored.rs
index cf8bc0b1586..b272bfb5a4d 100644
--- a/src/test/rustdoc/intra-doc/private-failures-ignored.rs
+++ b/src/test/rustdoc/intra-doc/private-failures-ignored.rs
@@ -2,7 +2,7 @@
// These failures were legitimate, but not truly relevant - the docs in question couldn't be
// checked for accuracy anyway.
-#![deny(broken_intra_doc_links)]
+#![deny(rustdoc::broken_intra_doc_links)]
/// ooh, i'm a [rebel] just for kicks
struct SomeStruct;
diff --git a/src/test/rustdoc/intra-doc/private.rs b/src/test/rustdoc/intra-doc/private.rs
index 2756a7998e8..349091e9300 100644
--- a/src/test/rustdoc/intra-doc/private.rs
+++ b/src/test/rustdoc/intra-doc/private.rs
@@ -1,8 +1,11 @@
-#![crate_name = "private"]
// compile-flags: --document-private-items
// make sure to update `rustdoc-ui/intra-doc/private.rs` if you update this file
+#![allow(rustdoc::private_intra_doc_links)]
+
+#![crate_name = "private"]
+
/// docs [DontDocMe] [DontDocMe::f] [DontDocMe::x]
// @has private/struct.DocMe.html '//*a[@href="struct.DontDocMe.html"]' 'DontDocMe'
// @has private/struct.DocMe.html '//*a[@href="struct.DontDocMe.html#method.f"]' 'DontDocMe::f'
diff --git a/src/test/rustdoc/intra-doc/proc-macro.rs b/src/test/rustdoc/intra-doc/proc-macro.rs
index fce10a130be..78379a90285 100644
--- a/src/test/rustdoc/intra-doc/proc-macro.rs
+++ b/src/test/rustdoc/intra-doc/proc-macro.rs
@@ -1,6 +1,6 @@
// aux-build:proc-macro-macro.rs
// build-aux-docs
-#![deny(broken_intra_doc_links)]
+#![deny(rustdoc::broken_intra_doc_links)]
extern crate proc_macro_macro;
diff --git a/src/test/rustdoc/intra-doc/pub-use.rs b/src/test/rustdoc/intra-doc/pub-use.rs
index b4f2d6b0617..0c70cdee914 100644
--- a/src/test/rustdoc/intra-doc/pub-use.rs
+++ b/src/test/rustdoc/intra-doc/pub-use.rs
@@ -1,5 +1,5 @@
// aux-build: intra-link-pub-use.rs
-#![deny(broken_intra_doc_links)]
+#![deny(rustdoc::broken_intra_doc_links)]
#![crate_name = "outer"]
extern crate inner;
diff --git a/src/test/rustdoc/intra-doc/raw-ident-self.rs b/src/test/rustdoc/intra-doc/raw-ident-self.rs
index 177c3016fb1..1ed33db9300 100644
--- a/src/test/rustdoc/intra-doc/raw-ident-self.rs
+++ b/src/test/rustdoc/intra-doc/raw-ident-self.rs
@@ -1,4 +1,4 @@
-#![deny(broken_intra_doc_links)]
+#![deny(rustdoc::broken_intra_doc_links)]
pub mod r#impl {
pub struct S;
diff --git a/src/test/rustdoc/intra-doc/trait-item.rs b/src/test/rustdoc/intra-doc/trait-item.rs
index 0be368d051e..e95dba33b5f 100644
--- a/src/test/rustdoc/intra-doc/trait-item.rs
+++ b/src/test/rustdoc/intra-doc/trait-item.rs
@@ -1,4 +1,4 @@
-#![deny(broken_intra_doc_links)]
+#![deny(rustdoc::broken_intra_doc_links)]
/// Link to [S::assoc_fn()]
/// Link to [Default::default()]
diff --git a/src/test/rustdoc/intra-doc/true-false.rs b/src/test/rustdoc/intra-doc/true-false.rs
index 44aac688413..e02be9cabd2 100644
--- a/src/test/rustdoc/intra-doc/true-false.rs
+++ b/src/test/rustdoc/intra-doc/true-false.rs
@@ -1,9 +1,8 @@
-#![deny(broken_intra_doc_links)]
+#![deny(rustdoc::broken_intra_doc_links)]
#![crate_name = "foo"]
-
// @has foo/index.html
-// @has - '//*[@id="main"]//a[@href="{{channel}}/std/primitive.bool.html"]' 'true'
-// @has - '//*[@id="main"]//a[@href="{{channel}}/std/primitive.bool.html"]' 'false'
+// @has - '//*[@id="main-content"]//a[@href="{{channel}}/std/primitive.bool.html"]' 'true'
+// @has - '//*[@id="main-content"]//a[@href="{{channel}}/std/primitive.bool.html"]' 'false'
//! A `bool` is either [`true`] or [`false`].
diff --git a/src/test/rustdoc/intra-doc/type-alias.rs b/src/test/rustdoc/intra-doc/type-alias.rs
index f3609ccd0a1..6c52082a277 100644
--- a/src/test/rustdoc/intra-doc/type-alias.rs
+++ b/src/test/rustdoc/intra-doc/type-alias.rs
@@ -1,6 +1,6 @@
// Regression test for issue #86120.
-#![deny(broken_intra_doc_links)]
+#![deny(rustdoc::broken_intra_doc_links)]
#![crate_name = "foo"]
pub struct Foo;
diff --git a/src/test/rustdoc/intra-link-prim-self.rs b/src/test/rustdoc/intra-link-prim-self.rs
index 8c47f7ef77e..8a564acf2ca 100644
--- a/src/test/rustdoc/intra-link-prim-self.rs
+++ b/src/test/rustdoc/intra-link-prim-self.rs
@@ -1,6 +1,7 @@
-#![deny(broken_intra_doc_links)]
+#![deny(rustdoc::broken_intra_doc_links)]
#![feature(lang_items)]
#![feature(no_core)]
+#![feature(rustdoc_internals)]
#![no_core]
#[lang = "usize"]
diff --git a/src/test/rustdoc/issue-12834.rs b/src/test/rustdoc/issue-12834.rs
index 558009e6937..9605a1e78c1 100644
--- a/src/test/rustdoc/issue-12834.rs
+++ b/src/test/rustdoc/issue-12834.rs
@@ -1,6 +1,7 @@
// Tests that failing to syntax highlight a rust code-block doesn't cause
// rustdoc to fail, while still rendering the code-block (without highlighting).
+#![allow(rustdoc::invalid_rust_codeblocks)]
// @has issue_12834/fn.foo.html
// @has - //pre 'a + b '
diff --git a/src/test/rustdoc/issue-15318-3.rs b/src/test/rustdoc/issue-15318-3.rs
index 1f7443a6572..2fadc26b006 100644
--- a/src/test/rustdoc/issue-15318-3.rs
+++ b/src/test/rustdoc/issue-15318-3.rs
@@ -1,3 +1,5 @@
+#![feature(rustdoc_internals)]
+
// @has issue_15318_3/primitive.pointer.html
/// dox
diff --git a/src/test/rustdoc/issue-23511.rs b/src/test/rustdoc/issue-23511.rs
index 4972a9fb47f..6d421f3c253 100644
--- a/src/test/rustdoc/issue-23511.rs
+++ b/src/test/rustdoc/issue-23511.rs
@@ -1,4 +1,5 @@
#![feature(lang_items)]
+#![feature(rustdoc_internals)]
#![no_std]
pub mod str {
diff --git a/src/test/rustdoc/issue-32374.rs b/src/test/rustdoc/issue-32374.rs
index 4e92ae49a20..7654a561527 100644
--- a/src/test/rustdoc/issue-32374.rs
+++ b/src/test/rustdoc/issue-32374.rs
@@ -1,7 +1,6 @@
#![feature(staged_api)]
#![doc(issue_tracker_base_url = "https://issue_url/")]
-
-#![unstable(feature="test", issue = "32374")]
+#![unstable(feature = "test", issue = "32374")]
// @matches issue_32374/index.html '//*[@class="item-left unstable deprecated module-item"]/span[@class="stab deprecated"]' \
// 'Deprecated'
@@ -23,12 +22,6 @@ pub struct T;
// '👎 Deprecated since 1.0.0: deprecated'
// @has issue_32374/struct.U.html '//*[@class="stab unstable"]' \
// '🔬 This is a nightly-only experimental API. (test #32374)'
-// @has issue_32374/struct.U.html '//details' \
-// '🔬 This is a nightly-only experimental API. (test #32374)'
-// @has issue_32374/struct.U.html '//summary' \
-// '🔬 This is a nightly-only experimental API. (test #32374)'
-// @has issue_32374/struct.U.html '//details/p' \
-// 'unstable'
#[rustc_deprecated(since = "1.0.0", reason = "deprecated")]
#[unstable(feature = "test", issue = "32374", reason = "unstable")]
pub struct U;
diff --git a/src/test/rustdoc/issue-42760.rs b/src/test/rustdoc/issue-42760.rs
index 4944f815701..a5394c7d92a 100644
--- a/src/test/rustdoc/issue-42760.rs
+++ b/src/test/rustdoc/issue-42760.rs
@@ -1,3 +1,5 @@
+#![allow(rustdoc::invalid_rust_codeblocks)]
+
// @has issue_42760/struct.NonGen.html
// @has - '//h2' 'Example'
diff --git a/src/test/rustdoc/issue-43869.rs b/src/test/rustdoc/issue-43869.rs
index 44356848fbf..767d09d8558 100644
--- a/src/test/rustdoc/issue-43869.rs
+++ b/src/test/rustdoc/issue-43869.rs
@@ -2,6 +2,7 @@ pub fn g() -> impl Iterator<Item=u8> {
Some(1u8).into_iter()
}
+#[allow(unused_parens)]
pub fn h() -> (impl Iterator<Item=u8>) {
Some(1u8).into_iter()
}
diff --git a/src/test/rustdoc/issue-55364.rs b/src/test/rustdoc/issue-55364.rs
index 70aa10767b2..14a6f5041f2 100644
--- a/src/test/rustdoc/issue-55364.rs
+++ b/src/test/rustdoc/issue-55364.rs
@@ -2,19 +2,19 @@
// @has issue_55364/subone/index.html
// These foo/bar links in the module's documentation should refer inside `subone`
-// @has - '//section[@id="main"]/details[@open=""]/div[@class="docblock"]//a[@href="fn.foo.html"]' 'foo'
-// @has - '//section[@id="main"]/details[@open=""]/div[@class="docblock"]//a[@href="fn.bar.html"]' 'bar'
+// @has - '//section[@id="main-content"]/details[@open=""]/div[@class="docblock"]//a[@href="fn.foo.html"]' 'foo'
+// @has - '//section[@id="main-content"]/details[@open=""]/div[@class="docblock"]//a[@href="fn.bar.html"]' 'bar'
pub mod subone {
//! See either [foo] or [bar].
// This should refer to subone's `bar`
// @has issue_55364/subone/fn.foo.html
- // @has - '//section[@id="main"]/details/div[@class="docblock"]//a[@href="fn.bar.html"]' 'bar'
+ // @has - '//section[@id="main-content"]/details/div[@class="docblock"]//a[@href="fn.bar.html"]' 'bar'
/// See [bar]
pub fn foo() {}
// This should refer to subone's `foo`
// @has issue_55364/subone/fn.bar.html
- // @has - '//section[@id="main"]/details/div[@class="docblock"]//a[@href="fn.foo.html"]' 'foo'
+ // @has - '//section[@id="main-content"]/details/div[@class="docblock"]//a[@href="fn.foo.html"]' 'foo'
/// See [foo]
pub fn bar() {}
}
@@ -23,27 +23,27 @@ pub mod subone {
// @has issue_55364/subtwo/index.html
// These foo/bar links in the module's documentation should not reference inside `subtwo`
-// @!has - '//section[@id="main"]/div[@class="docblock"]//a[@href="fn.foo.html"]' 'foo'
-// @!has - '//section[@id="main"]/div[@class="docblock"]//a[@href="fn.bar.html"]' 'bar'
+// @!has - '//section[@id="main-content"]/div[@class="docblock"]//a[@href="fn.foo.html"]' 'foo'
+// @!has - '//section[@id="main-content"]/div[@class="docblock"]//a[@href="fn.bar.html"]' 'bar'
// Instead it should be referencing the top level functions
-// @has - '//section[@id="main"]/details/div[@class="docblock"]//a[@href="../fn.foo.html"]' 'foo'
-// @has - '//section[@id="main"]/details/div[@class="docblock"]//a[@href="../fn.bar.html"]' 'bar'
+// @has - '//section[@id="main-content"]/details/div[@class="docblock"]//a[@href="../fn.foo.html"]' 'foo'
+// @has - '//section[@id="main-content"]/details/div[@class="docblock"]//a[@href="../fn.bar.html"]' 'bar'
// Though there should be such links later
-// @has - '//section[@id="main"]/div[@class="item-table"]//div[@class="item-left module-item"]/a[@class="fn"][@href="fn.foo.html"]' 'foo'
-// @has - '//section[@id="main"]/div[@class="item-table"]//div[@class="item-left module-item"]/a[@class="fn"][@href="fn.bar.html"]' 'bar'
+// @has - '//section[@id="main-content"]/div[@class="item-table"]//div[@class="item-left module-item"]/a[@class="fn"][@href="fn.foo.html"]' 'foo'
+// @has - '//section[@id="main-content"]/div[@class="item-table"]//div[@class="item-left module-item"]/a[@class="fn"][@href="fn.bar.html"]' 'bar'
/// See either [foo] or [bar].
pub mod subtwo {
// Despite the module's docs referring to the top level foo/bar,
// this should refer to subtwo's `bar`
// @has issue_55364/subtwo/fn.foo.html
- // @has - '//section[@id="main"]/details/div[@class="docblock"]//a[@href="fn.bar.html"]' 'bar'
+ // @has - '//section[@id="main-content"]/details/div[@class="docblock"]//a[@href="fn.bar.html"]' 'bar'
/// See [bar]
pub fn foo() {}
// Despite the module's docs referring to the top level foo/bar,
// this should refer to subtwo's `foo`
// @has issue_55364/subtwo/fn.bar.html
- // @has - '//section[@id="main"]/details/div[@class="docblock"]//a[@href="fn.foo.html"]' 'foo'
+ // @has - '//section[@id="main-content"]/details/div[@class="docblock"]//a[@href="fn.foo.html"]' 'foo'
/// See [foo]
pub fn bar() {}
}
@@ -59,8 +59,8 @@ pub fn bar() {}
// @has issue_55364/subthree/index.html
// This module should also refer to the top level foo/bar
-// @has - '//section[@id="main"]/details/div[@class="docblock"]//a[@href="../fn.foo.html"]' 'foo'
-// @has - '//section[@id="main"]/details/div[@class="docblock"]//a[@href="../fn.bar.html"]' 'bar'
+// @has - '//section[@id="main-content"]/details/div[@class="docblock"]//a[@href="../fn.foo.html"]' 'foo'
+// @has - '//section[@id="main-content"]/details/div[@class="docblock"]//a[@href="../fn.bar.html"]' 'bar'
pub mod subthree {
//! See either [foo][super::foo] or [bar][super::bar]
}
@@ -68,8 +68,8 @@ pub mod subthree {
// Next we go *deeper* - In order to ensure it's not just "this or parent"
// we test `crate::` and a `super::super::...` chain
// @has issue_55364/subfour/subfive/subsix/subseven/subeight/index.html
-// @has - '//section[@id="main"]/div[@class="item-table"]//div[@class="item-right docblock-short"]//a[@href="../../../../../subone/fn.foo.html"]' 'other foo'
-// @has - '//section[@id="main"]/div[@class="item-table"]//div[@class="item-right docblock-short"]//a[@href="../../../../../subtwo/fn.bar.html"]' 'other bar'
+// @has - '//section[@id="main-content"]/div[@class="item-table"]//div[@class="item-right docblock-short"]//a[@href="../../../../../subone/fn.foo.html"]' 'other foo'
+// @has - '//section[@id="main-content"]/div[@class="item-table"]//div[@class="item-right docblock-short"]//a[@href="../../../../../subtwo/fn.bar.html"]' 'other bar'
pub mod subfour {
pub mod subfive {
pub mod subsix {
diff --git a/src/test/rustdoc/keyword.rs b/src/test/rustdoc/keyword.rs
index 652517c5c90..29ceda4f7c1 100644
--- a/src/test/rustdoc/keyword.rs
+++ b/src/test/rustdoc/keyword.rs
@@ -1,6 +1,6 @@
#![crate_name = "foo"]
-#![feature(doc_keyword)]
+#![feature(rustdoc_internals)]
// @has foo/index.html '//h2[@id="keywords"]' 'Keywords'
// @has foo/index.html '//a[@href="keyword.match.html"]' 'match'
@@ -8,7 +8,7 @@
// @has foo/index.html '//div[@class="sidebar-elems"]//li/a/@href' '#keywords'
// @has foo/keyword.match.html '//a[@class="keyword"]' 'match'
// @has foo/keyword.match.html '//span[@class="in-band"]' 'Keyword match'
-// @has foo/keyword.match.html '//section[@id="main"]//div[@class="docblock"]//p' 'this is a test!'
+// @has foo/keyword.match.html '//section[@id="main-content"]//div[@class="docblock"]//p' 'this is a test!'
// @has foo/index.html '//a/@href' '../foo/index.html'
// @!has foo/foo/index.html
// @!has-dir foo/foo
@@ -16,7 +16,7 @@
/// this is a test!
mod foo{}
-// @has foo/keyword.foo.html '//section[@id="main"]//div[@class="docblock"]//p' 'hello'
+// @has foo/keyword.foo.html '//section[@id="main-content"]//div[@class="docblock"]//p' 'hello'
#[doc(keyword = "foo")]
/// hello
mod bar {}
diff --git a/src/test/rustdoc/legacy-const-generic.rs b/src/test/rustdoc/legacy-const-generic.rs
new file mode 100644
index 00000000000..46a50e2fc30
--- /dev/null
+++ b/src/test/rustdoc/legacy-const-generic.rs
@@ -0,0 +1,16 @@
+#![crate_name = "foo"]
+#![feature(rustc_attrs)]
+
+// @has 'foo/fn.foo.html'
+// @has - '//*[@class="rust fn"]' 'fn foo(x: usize, const Y: usize, z: usize) -> [usize; 3]'
+#[rustc_legacy_const_generics(1)]
+pub fn foo<const Y: usize>(x: usize, z: usize) -> [usize; 3] {
+ [x, Y, z]
+}
+
+// @has 'foo/fn.bar.html'
+// @has - '//*[@class="rust fn"]' 'fn bar(x: usize, const Y: usize, const Z: usize) -> [usize; 3]'
+#[rustc_legacy_const_generics(1, 2)]
+pub fn bar<const Y: usize, const Z: usize>(x: usize) -> [usize; 3] {
+ [x, Y, z]
+}
diff --git a/src/test/rustdoc/link-title-escape.rs b/src/test/rustdoc/link-title-escape.rs
index 29e82cba98d..01aa8d00b70 100644
--- a/src/test/rustdoc/link-title-escape.rs
+++ b/src/test/rustdoc/link-title-escape.rs
@@ -1,3 +1,5 @@
+#![allow(rustdoc::broken_intra_doc_links)]
+
#![crate_name = "foo"]
//! hello [foo]
diff --git a/src/test/rustdoc/logo-class-default.rs b/src/test/rustdoc/logo-class-default.rs
new file mode 100644
index 00000000000..a7016d227b1
--- /dev/null
+++ b/src/test/rustdoc/logo-class-default.rs
@@ -0,0 +1,4 @@
+// Note: this test is paired with logo-class.rs.
+// @has logo_class_default/struct.SomeStruct.html '//*[@class="logo-container"]/img[@class="rust-logo"]' ''
+// @has logo_class_default/struct.SomeStruct.html '//*[@class="sub-logo-container"]/img[@class="rust-logo"]' ''
+pub struct SomeStruct;
diff --git a/src/test/rustdoc/logo-class.rs b/src/test/rustdoc/logo-class.rs
new file mode 100644
index 00000000000..f071f356a6d
--- /dev/null
+++ b/src/test/rustdoc/logo-class.rs
@@ -0,0 +1,10 @@
+#![doc(html_logo_url =
+ "https://raw.githubusercontent.com/sagebind/isahc/master/media/isahc.svg.png")]
+// Note: this test is paired with logo-class-default.rs.
+
+// @has logo_class/struct.SomeStruct.html '//*[@class="logo-container"]/img[@src="https://raw.githubusercontent.com/sagebind/isahc/master/media/isahc.svg.png"]' ''
+// @!has logo_class/struct.SomeStruct.html '//*[@class="logo-container"]/img[@class="rust-logo"]' ''
+//
+// @has logo_class/struct.SomeStruct.html '//*[@class="sub-logo-container"]/img[@src="https://raw.githubusercontent.com/sagebind/isahc/master/media/isahc.svg.png"]' ''
+// @!has logo_class/struct.SomeStruct.html '//*[@class="sub-logo-container"]/img[@class="rust-logo"]' ''
+pub struct SomeStruct;
diff --git a/src/test/rustdoc/mixing-doc-comments-and-attrs.S1_top-doc.html b/src/test/rustdoc/mixing-doc-comments-and-attrs.S1_top-doc.html
new file mode 100644
index 00000000000..69d647a92e8
--- /dev/null
+++ b/src/test/rustdoc/mixing-doc-comments-and-attrs.S1_top-doc.html
@@ -0,0 +1,4 @@
+<div class="docblock"><p>Hello world!
+Goodbye!
+Hello again!</p>
+</div> \ No newline at end of file
diff --git a/src/test/rustdoc/mixing-doc-comments-and-attrs.S2_top-doc.html b/src/test/rustdoc/mixing-doc-comments-and-attrs.S2_top-doc.html
new file mode 100644
index 00000000000..8ff114b993e
--- /dev/null
+++ b/src/test/rustdoc/mixing-doc-comments-and-attrs.S2_top-doc.html
@@ -0,0 +1,4 @@
+<div class="docblock"><p>Hello world!</p>
+<p>Goodbye!
+Hello again!</p>
+</div> \ No newline at end of file
diff --git a/src/test/rustdoc/mixing-doc-comments-and-attrs.rs b/src/test/rustdoc/mixing-doc-comments-and-attrs.rs
new file mode 100644
index 00000000000..1aedd4d107c
--- /dev/null
+++ b/src/test/rustdoc/mixing-doc-comments-and-attrs.rs
@@ -0,0 +1,18 @@
+#![crate_name = "foo"]
+
+// @has 'foo/struct.S1.html'
+// @snapshot S1_top-doc - '//details[@class="rustdoc-toggle top-doc"]/div[@class="docblock"]'
+
+#[doc = "Hello world!\n\n"]
+/// Goodbye!
+#[doc = " Hello again!\n"]
+pub struct S1;
+
+// @has 'foo/struct.S2.html'
+// @snapshot S2_top-doc - '//details[@class="rustdoc-toggle top-doc"]/div[@class="docblock"]'
+
+/// Hello world!
+///
+#[doc = "Goodbye!"]
+/// Hello again!
+pub struct S2;
diff --git a/src/test/rustdoc/primitive-generic-impl.rs b/src/test/rustdoc/primitive-generic-impl.rs
deleted file mode 100644
index 0bf6157fed3..00000000000
--- a/src/test/rustdoc/primitive-generic-impl.rs
+++ /dev/null
@@ -1,5 +0,0 @@
-#![crate_name = "foo"]
-
-include!("primitive/primitive-generic-impl.rs");
-
-// @has foo/primitive.i32.html '//div[@id="impl-ToString"]//h3[@class="code-header in-band"]' 'impl<T> ToString for T'
diff --git a/src/test/rustdoc/primitive/primitive-generic-impl.rs b/src/test/rustdoc/primitive/primitive-generic-impl.rs
index b9c56be0fcf..f9737240c70 100644
--- a/src/test/rustdoc/primitive/primitive-generic-impl.rs
+++ b/src/test/rustdoc/primitive/primitive-generic-impl.rs
@@ -1,3 +1,9 @@
+#![feature(rustdoc_internals)]
+
+#![crate_name = "foo"]
+
+// @has foo/primitive.i32.html '//div[@id="impl-ToString"]//h3[@class="code-header in-band"]' 'impl<T> ToString for T'
+
#[doc(primitive = "i32")]
/// Some useless docs, wouhou!
mod i32 {}
diff --git a/src/test/rustdoc/proc-macro.rs b/src/test/rustdoc/proc-macro.rs
index f6d1f2cf91b..10acb7ac495 100644
--- a/src/test/rustdoc/proc-macro.rs
+++ b/src/test/rustdoc/proc-macro.rs
@@ -8,7 +8,7 @@
// @has some_macros/index.html
// @has - '//a/[@href="attr.some_proc_attr.html"]' 'some_proc_attr'
-//! include a link to [some_proc_macro] to make sure it works.
+//! include a link to [some_proc_macro!] to make sure it works.
extern crate proc_macro;
diff --git a/src/test/rustdoc/range-arg-pattern.rs b/src/test/rustdoc/range-arg-pattern.rs
index c08faaad0ec..756939ae377 100644
--- a/src/test/rustdoc/range-arg-pattern.rs
+++ b/src/test/rustdoc/range-arg-pattern.rs
@@ -2,4 +2,4 @@
// @has foo/fn.f.html
// @has - '//*[@class="rust fn"]' 'pub fn f(_: u8)'
-pub fn f(0u8...255: u8) {}
+pub fn f(0u8..=255: u8) {}
diff --git a/src/test/rustdoc/raw-ident-eliminate-r-hashtag.rs b/src/test/rustdoc/raw-ident-eliminate-r-hashtag.rs
index ad190361267..7dbe63854f3 100644
--- a/src/test/rustdoc/raw-ident-eliminate-r-hashtag.rs
+++ b/src/test/rustdoc/raw-ident-eliminate-r-hashtag.rs
@@ -2,6 +2,7 @@
pub mod internal {
// @has 'raw_ident_eliminate_r_hashtag/internal/struct.mod.html'
+ #[allow(non_camel_case_types)]
pub struct r#mod;
/// See [name], [other name]
diff --git a/src/test/rustdoc/reexports-priv.rs b/src/test/rustdoc/reexports-priv.rs
index 509457f6c96..95f74180749 100644
--- a/src/test/rustdoc/reexports-priv.rs
+++ b/src/test/rustdoc/reexports-priv.rs
@@ -7,47 +7,129 @@ extern crate reexports;
// @has 'foo/macro.addr_of.html' '//*[@class="docblock item-decl"]' 'pub macro addr_of($place : expr) {'
pub use reexports::addr_of;
-// @has 'foo/macro.addr_of_crate.html' '//*[@class="docblock item-decl"]' 'pub(crate) macro addr_of_crate($place : expr) {'
+// @!has 'foo/macro.addr_of_crate.html'
pub(crate) use reexports::addr_of_crate;
-// @has 'foo/macro.addr_of_self.html' '//*[@class="docblock item-decl"]' 'pub(crate) macro addr_of_self($place : expr) {'
+// @!has 'foo/macro.addr_of_self.html'
pub(self) use reexports::addr_of_self;
+// @!has 'foo/macro.addr_of_local.html'
+use reexports::addr_of_local;
// @has 'foo/struct.Foo.html' '//*[@class="docblock item-decl"]' 'pub struct Foo;'
pub use reexports::Foo;
-// @has 'foo/struct.FooCrate.html' '//*[@class="docblock item-decl"]' 'pub(crate) struct FooCrate;'
+// @!has 'foo/struct.FooCrate.html'
pub(crate) use reexports::FooCrate;
-// @has 'foo/struct.FooSelf.html' '//*[@class="docblock item-decl"]' 'pub(crate) struct FooSelf;'
+// @!has 'foo/struct.FooSelf.html'
pub(self) use reexports::FooSelf;
+// @!has 'foo/struct.FooLocal.html'
+use reexports::FooLocal;
// @has 'foo/enum.Bar.html' '//*[@class="docblock item-decl"]' 'pub enum Bar {'
pub use reexports::Bar;
-// @has 'foo/enum.BarCrate.html' '//*[@class="docblock item-decl"]' 'pub(crate) enum BarCrate {'
+// @!has 'foo/enum.BarCrate.html'
pub(crate) use reexports::BarCrate;
-// @has 'foo/enum.BarSelf.html' '//*[@class="docblock item-decl"]' 'pub(crate) enum BarSelf {'
+// @!has 'foo/enum.BarSelf.html'
pub(self) use reexports::BarSelf;
+// @!has 'foo/enum.BarLocal.html'
+use reexports::BarLocal;
// @has 'foo/fn.foo.html' '//*[@class="rust fn"]' 'pub fn foo()'
pub use reexports::foo;
-// @has 'foo/fn.foo_crate.html' '//*[@class="rust fn"]' 'pub(crate) fn foo_crate()'
+// @!has 'foo/fn.foo_crate.html'
pub(crate) use reexports::foo_crate;
-// @has 'foo/fn.foo_self.html' '//*[@class="rust fn"]' 'pub(crate) fn foo_self()'
+// @!has 'foo/fn.foo_self.html'
pub(self) use reexports::foo_self;
+// @!has 'foo/fn.foo_local.html'
+use reexports::foo_local;
// @has 'foo/type.Type.html' '//*[@class="rust typedef"]' 'pub type Type ='
pub use reexports::Type;
-// @has 'foo/type.TypeCrate.html' '//*[@class="rust typedef"]' 'pub(crate) type TypeCrate ='
+// @!has 'foo/type.TypeCrate.html'
pub(crate) use reexports::TypeCrate;
-// @has 'foo/type.TypeSelf.html' '//*[@class="rust typedef"]' 'pub(crate) type TypeSelf ='
+// @!has 'foo/type.TypeSelf.html'
pub(self) use reexports::TypeSelf;
+// @!has 'foo/type.TypeLocal.html'
+use reexports::TypeLocal;
// @has 'foo/union.Union.html' '//*[@class="docblock item-decl"]' 'pub union Union {'
pub use reexports::Union;
-// @has 'foo/union.UnionCrate.html' '//*[@class="docblock item-decl"]' 'pub(crate) union UnionCrate {'
+// @!has 'foo/union.UnionCrate.html'
pub(crate) use reexports::UnionCrate;
-// @has 'foo/union.UnionSelf.html' '//*[@class="docblock item-decl"]' 'pub(crate) union UnionSelf {'
+// @!has 'foo/union.UnionSelf.html'
pub(self) use reexports::UnionSelf;
+// @!has 'foo/union.UnionLocal.html'
+use reexports::UnionLocal;
-pub mod foo {
- // @!has 'foo/foo/union.Union.html'
- use crate::reexports::Union;
+pub mod outer {
+ pub mod inner {
+ // @has 'foo/outer/inner/macro.addr_of.html' '//*[@class="docblock item-decl"]' 'pub macro addr_of($place : expr) {'
+ pub use reexports::addr_of;
+ // @has 'foo/outer/inner/macro.addr_of_crate.html' '//*[@class="docblock item-decl"]' 'pub(crate) macro addr_of_crate($place : expr) {'
+ pub(crate) use reexports::addr_of_crate;
+ // @has 'foo/outer/inner/macro.addr_of_super.html' '//*[@class="docblock item-decl"]' 'pub(in outer) macro addr_of_super($place : expr) {'
+ pub(super) use reexports::addr_of_super;
+ // @!has 'foo/outer/inner/macro.addr_of_self.html'
+ pub(self) use reexports::addr_of_self;
+ // @!has 'foo/outer/inner/macro.addr_of_local.html'
+ use reexports::addr_of_local;
+
+ // @has 'foo/outer/inner/struct.Foo.html' '//*[@class="docblock item-decl"]' 'pub struct Foo;'
+ pub use reexports::Foo;
+ // @has 'foo/outer/inner/struct.FooCrate.html' '//*[@class="docblock item-decl"]' 'pub(crate) struct FooCrate;'
+ pub(crate) use reexports::FooCrate;
+ // @has 'foo/outer/inner/struct.FooSuper.html' '//*[@class="docblock item-decl"]' 'pub(in outer) struct FooSuper;'
+ pub(super) use reexports::FooSuper;
+ // @!has 'foo/outer/inner/struct.FooSelf.html'
+ pub(self) use reexports::FooSelf;
+ // @!has 'foo/outer/inner/struct.FooLocal.html'
+ use reexports::FooLocal;
+
+ // @has 'foo/outer/inner/enum.Bar.html' '//*[@class="docblock item-decl"]' 'pub enum Bar {'
+ pub use reexports::Bar;
+ // @has 'foo/outer/inner/enum.BarCrate.html' '//*[@class="docblock item-decl"]' 'pub(crate) enum BarCrate {'
+ pub(crate) use reexports::BarCrate;
+ // @has 'foo/outer/inner/enum.BarSuper.html' '//*[@class="docblock item-decl"]' 'pub(in outer) enum BarSuper {'
+ pub(super) use reexports::BarSuper;
+ // @!has 'foo/outer/inner/enum.BarSelf.html'
+ pub(self) use reexports::BarSelf;
+ // @!has 'foo/outer/inner/enum.BarLocal.html'
+ use reexports::BarLocal;
+
+ // @has 'foo/outer/inner/fn.foo.html' '//*[@class="rust fn"]' 'pub fn foo()'
+ pub use reexports::foo;
+ // @has 'foo/outer/inner/fn.foo_crate.html' '//*[@class="rust fn"]' 'pub(crate) fn foo_crate()'
+ pub(crate) use reexports::foo_crate;
+ // @has 'foo/outer/inner/fn.foo_super.html' '//*[@class="rust fn"]' 'pub(in outer) fn foo_super()'
+ pub(super) use::reexports::foo_super;
+ // @!has 'foo/outer/inner/fn.foo_self.html'
+ pub(self) use reexports::foo_self;
+ // @!has 'foo/outer/inner/fn.foo_local.html'
+ use reexports::foo_local;
+
+ // @has 'foo/outer/inner/type.Type.html' '//*[@class="rust typedef"]' 'pub type Type ='
+ pub use reexports::Type;
+ // @has 'foo/outer/inner/type.TypeCrate.html' '//*[@class="rust typedef"]' 'pub(crate) type TypeCrate ='
+ pub(crate) use reexports::TypeCrate;
+ // @has 'foo/outer/inner/type.TypeSuper.html' '//*[@class="rust typedef"]' 'pub(in outer) type TypeSuper ='
+ pub(super) use reexports::TypeSuper;
+ // @!has 'foo/outer/inner/type.TypeSelf.html'
+ pub(self) use reexports::TypeSelf;
+ // @!has 'foo/outer/inner/type.TypeLocal.html'
+ use reexports::TypeLocal;
+
+ // @has 'foo/outer/inner/union.Union.html' '//*[@class="docblock item-decl"]' 'pub union Union {'
+ pub use reexports::Union;
+ // @has 'foo/outer/inner/union.UnionCrate.html' '//*[@class="docblock item-decl"]' 'pub(crate) union UnionCrate {'
+ pub(crate) use reexports::UnionCrate;
+ // @has 'foo/outer/inner/union.UnionSuper.html' '//*[@class="docblock item-decl"]' 'pub(in outer) union UnionSuper {'
+ pub(super) use reexports::UnionSuper;
+ // @!has 'foo/outer/inner/union.UnionSelf.html'
+ pub(self) use reexports::UnionSelf;
+ // @!has 'foo/outer/inner/union.UnionLocal.html'
+ use reexports::UnionLocal;
+ }
+}
+
+mod re_re_exports {
+ // @!has 'foo/re_re_exports/union.Union.html'
+ use crate::reexports::Union;
}
diff --git a/src/test/rustdoc/reexports.rs b/src/test/rustdoc/reexports.rs
index c308d0c2f05..3b315308470 100644
--- a/src/test/rustdoc/reexports.rs
+++ b/src/test/rustdoc/reexports.rs
@@ -10,6 +10,8 @@ pub use reexports::addr_of;
pub(crate) use reexports::addr_of_crate;
// @!has 'foo/macro.addr_of_self.html'
pub(self) use reexports::addr_of_self;
+// @!has 'foo/macro.addr_of_local.html'
+use reexports::addr_of_local;
// @has 'foo/struct.Foo.html' '//*[@class="docblock item-decl"]' 'pub struct Foo;'
pub use reexports::Foo;
@@ -17,6 +19,8 @@ pub use reexports::Foo;
pub(crate) use reexports::FooCrate;
// @!has 'foo/struct.FooSelf.html'
pub(self) use reexports::FooSelf;
+// @!has 'foo/struct.FooLocal.html'
+use reexports::FooLocal;
// @has 'foo/enum.Bar.html' '//*[@class="docblock item-decl"]' 'pub enum Bar {'
pub use reexports::Bar;
@@ -24,6 +28,8 @@ pub use reexports::Bar;
pub(crate) use reexports::BarCrate;
// @!has 'foo/enum.BarSelf.html'
pub(self) use reexports::BarSelf;
+// @!has 'foo/enum.BarLocal.html'
+use reexports::BarLocal;
// @has 'foo/fn.foo.html' '//*[@class="rust fn"]' 'pub fn foo()'
pub use reexports::foo;
@@ -31,6 +37,8 @@ pub use reexports::foo;
pub(crate) use reexports::foo_crate;
// @!has 'foo/fn.foo_self.html'
pub(self) use reexports::foo_self;
+// @!has 'foo/fn.foo_local.html'
+use reexports::foo_local;
// @has 'foo/type.Type.html' '//*[@class="rust typedef"]' 'pub type Type ='
pub use reexports::Type;
@@ -38,6 +46,8 @@ pub use reexports::Type;
pub(crate) use reexports::TypeCrate;
// @!has 'foo/type.TypeSelf.html'
pub(self) use reexports::TypeSelf;
+// @!has 'foo/type.TypeLocal.html'
+use reexports::TypeLocal;
// @has 'foo/union.Union.html' '//*[@class="docblock item-decl"]' 'pub union Union {'
pub use reexports::Union;
@@ -45,3 +55,75 @@ pub use reexports::Union;
pub(crate) use reexports::UnionCrate;
// @!has 'foo/union.UnionSelf.html'
pub(self) use reexports::UnionSelf;
+// @!has 'foo/union.UnionLocal.html'
+use reexports::UnionLocal;
+
+pub mod outer {
+ pub mod inner {
+ // @has 'foo/outer/inner/macro.addr_of.html' '//*[@class="docblock item-decl"]' 'pub macro addr_of($place : expr) {'
+ pub use reexports::addr_of;
+ // @!has 'foo/outer/inner/macro.addr_of_crate.html'
+ pub(crate) use reexports::addr_of_crate;
+ // @!has 'foo/outer/inner/macro.addr_of_super.html'
+ pub(super) use reexports::addr_of_super;
+ // @!has 'foo/outer/inner/macro.addr_of_self.html'
+ pub(self) use reexports::addr_of_self;
+ // @!has 'foo/outer/inner/macro.addr_of_local.html'
+ use reexports::addr_of_local;
+
+ // @has 'foo/outer/inner/struct.Foo.html' '//*[@class="docblock item-decl"]' 'pub struct Foo;'
+ pub use reexports::Foo;
+ // @!has 'foo/outer/inner/struct.FooCrate.html'
+ pub(crate) use reexports::FooCrate;
+ // @!has 'foo/outer/inner/struct.FooSuper.html'
+ pub(super) use reexports::FooSuper;
+ // @!has 'foo/outer/inner/struct.FooSelf.html'
+ pub(self) use reexports::FooSelf;
+ // @!has 'foo/outer/inner/struct.FooLocal.html'
+ use reexports::FooLocal;
+
+ // @has 'foo/outer/inner/enum.Bar.html' '//*[@class="docblock item-decl"]' 'pub enum Bar {'
+ pub use reexports::Bar;
+ // @!has 'foo/outer/inner/enum.BarCrate.html'
+ pub(crate) use reexports::BarCrate;
+ // @!has 'foo/outer/inner/enum.BarSuper.html'
+ pub(super) use reexports::BarSuper;
+ // @!has 'foo/outer/inner/enum.BarSelf.html'
+ pub(self) use reexports::BarSelf;
+ // @!has 'foo/outer/inner/enum.BarLocal.html'
+ use reexports::BarLocal;
+
+ // @has 'foo/outer/inner/fn.foo.html' '//*[@class="rust fn"]' 'pub fn foo()'
+ pub use reexports::foo;
+ // @!has 'foo/outer/inner/fn.foo_crate.html'
+ pub(crate) use reexports::foo_crate;
+ // @!has 'foo/outer/inner/fn.foo_super.html'
+ pub(super) use::reexports::foo_super;
+ // @!has 'foo/outer/inner/fn.foo_self.html'
+ pub(self) use reexports::foo_self;
+ // @!has 'foo/outer/inner/fn.foo_local.html'
+ use reexports::foo_local;
+
+ // @has 'foo/outer/inner/type.Type.html' '//*[@class="rust typedef"]' 'pub type Type ='
+ pub use reexports::Type;
+ // @!has 'foo/outer/inner/type.TypeCrate.html'
+ pub(crate) use reexports::TypeCrate;
+ // @!has 'foo/outer/inner/type.TypeSuper.html'
+ pub(super) use reexports::TypeSuper;
+ // @!has 'foo/outer/inner/type.TypeSelf.html'
+ pub(self) use reexports::TypeSelf;
+ // @!has 'foo/outer/inner/type.TypeLocal.html'
+ use reexports::TypeLocal;
+
+ // @has 'foo/outer/inner/union.Union.html' '//*[@class="docblock item-decl"]' 'pub union Union {'
+ pub use reexports::Union;
+ // @!has 'foo/outer/inner/union.UnionCrate.html'
+ pub(crate) use reexports::UnionCrate;
+ // @!has 'foo/outer/inner/union.UnionSuper.html'
+ pub(super) use reexports::UnionSuper;
+ // @!has 'foo/outer/inner/union.UnionSelf.html'
+ pub(self) use reexports::UnionSelf;
+ // @!has 'foo/outer/inner/union.UnionLocal.html'
+ use reexports::UnionLocal;
+ }
+}
diff --git a/src/test/rustdoc/sidebar-items.rs b/src/test/rustdoc/sidebar-items.rs
index 5da660b4df3..ee670e88b5c 100644
--- a/src/test/rustdoc/sidebar-items.rs
+++ b/src/test/rustdoc/sidebar-items.rs
@@ -30,11 +30,11 @@ pub struct Bar {
// @has foo/enum.En.html
// @has - '//*[@class="sidebar-title"]/a[@href="#variants"]' 'Variants'
-// @has - '//*[@class="sidebar-links"]/a' 'foo'
-// @has - '//*[@class="sidebar-links"]/a' 'bar'
+// @has - '//*[@class="sidebar-links"]/a' 'Foo'
+// @has - '//*[@class="sidebar-links"]/a' 'Bar'
pub enum En {
- foo,
- bar,
+ Foo,
+ Bar,
}
// @has foo/union.MyUnion.html
diff --git a/src/test/rustdoc/static-root-path.rs b/src/test/rustdoc/static-root-path.rs
index 2f7c89c5f1e..f1d49b9fcb2 100644
--- a/src/test/rustdoc/static-root-path.rs
+++ b/src/test/rustdoc/static-root-path.rs
@@ -3,7 +3,7 @@
// @has static_root_path/struct.SomeStruct.html
// @matches - '"/cache/main\.js"'
// @!matches - '"\.\./main\.js"'
-// @matches - '"\.\./search-index\.js"'
+// @matches - 'data-root-path="\.\./"'
// @!matches - '"/cache/search-index\.js"'
pub struct SomeStruct;
diff --git a/src/test/rustdoc/struct-implementations-title.rs b/src/test/rustdoc/struct-implementations-title.rs
index 96eb11311d6..5468796f669 100644
--- a/src/test/rustdoc/struct-implementations-title.rs
+++ b/src/test/rustdoc/struct-implementations-title.rs
@@ -3,7 +3,7 @@
pub struct Struc;
// @has foo/struct.Struc.html
-// @has - '//*[@id="main"]/h2[@id="implementations"]' "Implementations"
+// @has - '//*[@id="main-content"]/h2[@id="implementations"]' "Implementations"
impl Struc {
pub const S: u64 = 0;
}
diff --git a/src/test/rustdoc/tab_title.rs b/src/test/rustdoc/tab_title.rs
index 7dce6092dea..0cc4f147e1c 100644
--- a/src/test/rustdoc/tab_title.rs
+++ b/src/test/rustdoc/tab_title.rs
@@ -1,5 +1,5 @@
#![crate_name = "foo"]
-#![feature(doc_keyword)]
+#![feature(rustdoc_internals)]
// tests for the html <title> element
diff --git a/src/test/rustdoc/titles.rs b/src/test/rustdoc/titles.rs
index 2084e851799..016ec7bfaa3 100644
--- a/src/test/rustdoc/titles.rs
+++ b/src/test/rustdoc/titles.rs
@@ -1,5 +1,7 @@
#![crate_name = "foo"]
+#![feature(rustdoc_internals)]
+
// @matches 'foo/index.html' '//h1' 'Crate foo'
// @matches 'foo/foo_mod/index.html' '//h1' 'Module foo::foo_mod'
diff --git a/src/test/rustdoc/trait_alias.rs b/src/test/rustdoc/trait_alias.rs
index c9fccf5a77c..dec7fe3f6a5 100644
--- a/src/test/rustdoc/trait_alias.rs
+++ b/src/test/rustdoc/trait_alias.rs
@@ -14,13 +14,13 @@ use std::fmt::Debug;
// @has foo/index.html '//a[@class="traitalias"]' 'Foo'
// @has foo/traitalias.CopyAlias.html
-// @has - '//section[@id="main"]/div[@class="docblock item-decl"]/pre' 'trait CopyAlias = Copy;'
+// @has - '//section[@id="main-content"]/div[@class="docblock item-decl"]/pre' 'trait CopyAlias = Copy;'
pub trait CopyAlias = Copy;
// @has foo/traitalias.Alias2.html
-// @has - '//section[@id="main"]/div[@class="docblock item-decl"]/pre' 'trait Alias2 = Copy + Debug;'
+// @has - '//section[@id="main-content"]/div[@class="docblock item-decl"]/pre' 'trait Alias2 = Copy + Debug;'
pub trait Alias2 = Copy + Debug;
// @has foo/traitalias.Foo.html
-// @has - '//section[@id="main"]/div[@class="docblock item-decl"]/pre' 'trait Foo<T> = Into<T> + Debug;'
+// @has - '//section[@id="main-content"]/div[@class="docblock item-decl"]/pre' 'trait Foo<T> = Into<T> + Debug;'
pub trait Foo<T> = Into<T> + Debug;
// @has foo/fn.bar.html '//a[@href="traitalias.Alias2.html"]' 'Alias2'
pub fn bar<T>() where T: Alias2 {}
diff --git a/src/test/rustdoc/tuple-struct-fields-doc.rs b/src/test/rustdoc/tuple-struct-fields-doc.rs
index 139c5b4391a..2e339fe8264 100644
--- a/src/test/rustdoc/tuple-struct-fields-doc.rs
+++ b/src/test/rustdoc/tuple-struct-fields-doc.rs
@@ -4,11 +4,11 @@
// @has - '//h2[@id="fields"]' 'Tuple Fields'
// @has - '//h3[@class="sidebar-title"]/a[@href="#fields"]' 'Tuple Fields'
// @has - '//*[@id="structfield.0"]' '0: u32'
-// @has - '//*[@id="main"]/div[@class="docblock"]' 'hello'
+// @has - '//*[@id="main-content"]/div[@class="docblock"]' 'hello'
// @!has - '//*[@id="structfield.1"]'
// @has - '//*[@id="structfield.2"]' '2: char'
// @has - '//*[@id="structfield.3"]' '3: i8'
-// @has - '//*[@id="main"]/div[@class="docblock"]' 'not hello'
+// @has - '//*[@id="main-content"]/div[@class="docblock"]' 'not hello'
pub struct Foo(
/// hello
pub u32,
diff --git a/src/test/rustdoc/type-layout.rs b/src/test/rustdoc/type-layout.rs
index 0868486fa59..4eea9809ac5 100644
--- a/src/test/rustdoc/type-layout.rs
+++ b/src/test/rustdoc/type-layout.rs
@@ -50,6 +50,18 @@ pub struct GenericLifetimes<'a>(&'a str);
// @has - '(unsized)'
pub struct Unsized([u8]);
+// @has type_layout/type.TypeAlias.html 'Size: '
+// @has - ' bytes'
+pub type TypeAlias = X;
+
+// @has type_layout/type.GenericTypeAlias.html 'Size: '
+// @has - '8 bytes'
+pub type GenericTypeAlias = (Generic<(u32, ())>, Generic<u32>);
+
+// Regression test for the rustdoc equivalent of #85103.
+// @has type_layout/type.Edges.html 'Encountered an error during type layout; the type failed to be normalized.'
+pub type Edges<'a, E> = std::borrow::Cow<'a, [E]>;
+
// @!has type_layout/trait.MyTrait.html 'Size: '
pub trait MyTrait {}
diff --git a/src/test/ui-fulldeps/auxiliary/issue-40001-plugin.rs b/src/test/ui-fulldeps/auxiliary/issue-40001-plugin.rs
index 8051c58898e..de0df0aae82 100644
--- a/src/test/ui-fulldeps/auxiliary/issue-40001-plugin.rs
+++ b/src/test/ui-fulldeps/auxiliary/issue-40001-plugin.rs
@@ -7,8 +7,8 @@ extern crate rustc_hir;
extern crate rustc_lint;
#[macro_use]
extern crate rustc_session;
-extern crate rustc_span;
extern crate rustc_ast;
+extern crate rustc_span;
use rustc_ast_pretty::pprust;
use rustc_driver::plugin::Registry;
@@ -44,7 +44,7 @@ impl<'tcx> LateLintPass<'tcx> for MissingAllowedAttrPass {
) {
let item = match cx.tcx.hir().get(id) {
Node::Item(item) => item,
- _ => cx.tcx.hir().expect_item(cx.tcx.hir().get_parent_item(id)),
+ _ => cx.tcx.hir().expect_item(cx.tcx.hir().get_parent_item(id).expect_owner()),
};
let allowed = |attr| pprust::attribute_to_string(attr).contains("allowed_attr");
diff --git a/src/test/ui-fulldeps/internal-lints/existing_doc_keyword.rs b/src/test/ui-fulldeps/internal-lints/existing_doc_keyword.rs
index 053712a4b4e..7783dc40fcf 100644
--- a/src/test/ui-fulldeps/internal-lints/existing_doc_keyword.rs
+++ b/src/test/ui-fulldeps/internal-lints/existing_doc_keyword.rs
@@ -1,7 +1,7 @@
// compile-flags: -Z unstable-options
#![feature(rustc_private)]
-#![feature(doc_keyword)]
+#![feature(rustdoc_internals)]
#![crate_type = "lib"]
diff --git a/src/test/ui/abi/stack-protector.rs b/src/test/ui/abi/stack-protector.rs
new file mode 100644
index 00000000000..24bd2e21943
--- /dev/null
+++ b/src/test/ui/abi/stack-protector.rs
@@ -0,0 +1,99 @@
+// run-pass
+// only-x86_64-unknown-linux-gnu
+// revisions: ssp no-ssp
+// [ssp] compile-flags: -Z stack-protector=all
+// compile-flags: -C opt-level=2
+// compile-flags: -g
+
+use std::env;
+use std::process::{Command, ExitStatus};
+
+fn main() {
+ if env::args().len() == 1 {
+ // The test is initially run without arguments. Start the process again,
+ // this time *with* an argument; in this configuration, the test program
+ // will deliberately smash the stack.
+ let cur_argv0 = env::current_exe().unwrap();
+ let mut child = Command::new(&cur_argv0);
+ child.arg("stacksmash");
+
+ if cfg!(ssp) {
+ assert_stack_smash_prevented(&mut child);
+ } else {
+ assert_stack_smashed(&mut child);
+ }
+ } else {
+ vulnerable_function();
+ // If we return here the test is broken: it should either have called
+ // malicious_code() which terminates the process, or be caught by the
+ // stack check which also terminates the process.
+ panic!("TEST BUG: stack smash unsuccessful");
+ }
+}
+
+// Avoid inlining to make sure the return address is pushed to stack.
+#[inline(never)]
+fn vulnerable_function() {
+ let mut x = 5usize;
+ let stackaddr = &mut x as *mut usize;
+ let bad_code_ptr = malicious_code as usize;
+ // Overwrite the on-stack return address with the address of `malicious_code()`,
+ // thereby jumping to that function when returning from `vulnerable_function()`.
+ unsafe { fill(stackaddr, bad_code_ptr, 20); }
+}
+
+// Use an uninlined function with its own stack frame to make sure that we don't
+// clobber e.g. the counter or address local variable.
+#[inline(never)]
+unsafe fn fill(addr: *mut usize, val: usize, count: usize) {
+ let mut addr = addr;
+ for _ in 0..count {
+ *addr = val;
+ addr = addr.add(1);
+ }
+}
+
+// We jump to malicious_code() having wreaked havoc with the previous stack
+// frame and not setting up a new one. This function is therefore constrained,
+// e.g. both println!() and std::process::exit() segfaults if called. We
+// therefore keep the amount of work to a minimum by calling POSIX functions
+// directly.
+// The function is un-inlined just to make it possible to set a breakpoint here.
+#[inline(never)]
+fn malicious_code() {
+ let msg = [112u8, 119u8, 110u8, 101u8, 100u8, 33u8, 0u8]; // "pwned!\0" ascii
+ unsafe {
+ write(1, &msg as *const u8, msg.len());
+ _exit(0);
+ }
+}
+extern "C" {
+ fn write(fd: i32, buf: *const u8, count: usize) -> isize;
+ fn _exit(status: i32) -> !;
+}
+
+
+fn assert_stack_smash_prevented(cmd: &mut Command) {
+ let (status, stdout, stderr) = run(cmd);
+ assert!(!status.success());
+ assert!(stdout.is_empty());
+ assert!(stderr.contains("stack smashing detected"));
+}
+
+fn assert_stack_smashed(cmd: &mut Command) {
+ let (status, stdout, stderr) = run(cmd);
+ assert!(status.success());
+ assert!(stdout.contains("pwned!"));
+ assert!(stderr.is_empty());
+}
+
+
+fn run(cmd: &mut Command) -> (ExitStatus, String, String) {
+ let output = cmd.output().unwrap();
+ let stdout = String::from_utf8_lossy(&output.stdout);
+ let stderr = String::from_utf8_lossy(&output.stderr);
+ println!("status: {}", output.status);
+ println!("stdout: {}", stdout);
+ println!("stderr: {}", stderr);
+ (output.status, stdout.to_string(), stderr.to_string())
+}
diff --git a/src/test/ui/array-slice-vec/box-of-array-of-drop-1.rs b/src/test/ui/array-slice-vec/box-of-array-of-drop-1.rs
index c8559d24728..2b3ece67b34 100644
--- a/src/test/ui/array-slice-vec/box-of-array-of-drop-1.rs
+++ b/src/test/ui/array-slice-vec/box-of-array-of-drop-1.rs
@@ -1,4 +1,5 @@
// run-pass
+// needs-unwind
#![allow(overflowing_literals)]
// Test that we cleanup a fixed size Box<[D; k]> properly when D has a
diff --git a/src/test/ui/array-slice-vec/box-of-array-of-drop-2.rs b/src/test/ui/array-slice-vec/box-of-array-of-drop-2.rs
index e75051caabc..c0ca4587507 100644
--- a/src/test/ui/array-slice-vec/box-of-array-of-drop-2.rs
+++ b/src/test/ui/array-slice-vec/box-of-array-of-drop-2.rs
@@ -1,4 +1,5 @@
// run-pass
+// needs-unwind
#![allow(overflowing_literals)]
// Test that we cleanup dynamic sized Box<[D]> properly when D has a
diff --git a/src/test/ui/array-slice-vec/nested-vec-3.rs b/src/test/ui/array-slice-vec/nested-vec-3.rs
index 96497a53d30..b3ae683a8a6 100644
--- a/src/test/ui/array-slice-vec/nested-vec-3.rs
+++ b/src/test/ui/array-slice-vec/nested-vec-3.rs
@@ -1,4 +1,5 @@
// run-pass
+// needs-unwind
#![allow(overflowing_literals)]
// ignore-emscripten no threads support
diff --git a/src/test/ui/array-slice-vec/slice-panic-1.rs b/src/test/ui/array-slice-vec/slice-panic-1.rs
index 4134c623778..3829078aba5 100644
--- a/src/test/ui/array-slice-vec/slice-panic-1.rs
+++ b/src/test/ui/array-slice-vec/slice-panic-1.rs
@@ -1,4 +1,5 @@
// run-pass
+// needs-unwind
// ignore-emscripten no threads support
diff --git a/src/test/ui/array-slice-vec/slice-panic-2.rs b/src/test/ui/array-slice-vec/slice-panic-2.rs
index 2f7178fb3e1..d83c611d3bb 100644
--- a/src/test/ui/array-slice-vec/slice-panic-2.rs
+++ b/src/test/ui/array-slice-vec/slice-panic-2.rs
@@ -1,4 +1,5 @@
// run-pass
+// needs-unwind
// ignore-emscripten no threads support
diff --git a/src/test/ui/asm/aarch64/bad-options.rs b/src/test/ui/asm/aarch64/bad-options.rs
index 8775eba4a78..6172027a2fa 100644
--- a/src/test/ui/asm/aarch64/bad-options.rs
+++ b/src/test/ui/asm/aarch64/bad-options.rs
@@ -1,6 +1,6 @@
// only-aarch64
-#![feature(asm, global_asm)]
+use std::arch::{asm, global_asm};
fn main() {
let mut foo = 0;
diff --git a/src/test/ui/asm/aarch64/bad-options.stderr b/src/test/ui/asm/aarch64/bad-options.stderr
index 21bcc4a9c7b..867e0433eae 100644
--- a/src/test/ui/asm/aarch64/bad-options.stderr
+++ b/src/test/ui/asm/aarch64/bad-options.stderr
@@ -36,41 +36,41 @@ LL | asm!("{}", out(reg) foo, clobber_abi("C"));
| |
| generic outputs
-error: expected one of `)`, `att_syntax`, or `raw`, found `nomem`
+error: expected one of `)`, `att_syntax`, `may_unwind`, or `raw`, found `nomem`
--> $DIR/bad-options.rs:28:25
|
LL | global_asm!("", options(nomem));
- | ^^^^^ expected one of `)`, `att_syntax`, or `raw`
+ | ^^^^^ expected one of `)`, `att_syntax`, `may_unwind`, or `raw`
-error: expected one of `)`, `att_syntax`, or `raw`, found `readonly`
+error: expected one of `)`, `att_syntax`, `may_unwind`, or `raw`, found `readonly`
--> $DIR/bad-options.rs:30:25
|
LL | global_asm!("", options(readonly));
- | ^^^^^^^^ expected one of `)`, `att_syntax`, or `raw`
+ | ^^^^^^^^ expected one of `)`, `att_syntax`, `may_unwind`, or `raw`
-error: expected one of `)`, `att_syntax`, or `raw`, found `noreturn`
+error: expected one of `)`, `att_syntax`, `may_unwind`, or `raw`, found `noreturn`
--> $DIR/bad-options.rs:32:25
|
LL | global_asm!("", options(noreturn));
- | ^^^^^^^^ expected one of `)`, `att_syntax`, or `raw`
+ | ^^^^^^^^ expected one of `)`, `att_syntax`, `may_unwind`, or `raw`
-error: expected one of `)`, `att_syntax`, or `raw`, found `pure`
+error: expected one of `)`, `att_syntax`, `may_unwind`, or `raw`, found `pure`
--> $DIR/bad-options.rs:34:25
|
LL | global_asm!("", options(pure));
- | ^^^^ expected one of `)`, `att_syntax`, or `raw`
+ | ^^^^ expected one of `)`, `att_syntax`, `may_unwind`, or `raw`
-error: expected one of `)`, `att_syntax`, or `raw`, found `nostack`
+error: expected one of `)`, `att_syntax`, `may_unwind`, or `raw`, found `nostack`
--> $DIR/bad-options.rs:36:25
|
LL | global_asm!("", options(nostack));
- | ^^^^^^^ expected one of `)`, `att_syntax`, or `raw`
+ | ^^^^^^^ expected one of `)`, `att_syntax`, `may_unwind`, or `raw`
-error: expected one of `)`, `att_syntax`, or `raw`, found `preserves_flags`
+error: expected one of `)`, `att_syntax`, `may_unwind`, or `raw`, found `preserves_flags`
--> $DIR/bad-options.rs:38:25
|
LL | global_asm!("", options(preserves_flags));
- | ^^^^^^^^^^^^^^^ expected one of `)`, `att_syntax`, or `raw`
+ | ^^^^^^^^^^^^^^^ expected one of `)`, `att_syntax`, `may_unwind`, or `raw`
error: invalid ABI for `clobber_abi`
--> $DIR/bad-options.rs:20:18
diff --git a/src/test/ui/asm/aarch64/bad-reg.rs b/src/test/ui/asm/aarch64/bad-reg.rs
index 4d7a7fd31fe..8619b3960a6 100644
--- a/src/test/ui/asm/aarch64/bad-reg.rs
+++ b/src/test/ui/asm/aarch64/bad-reg.rs
@@ -1,7 +1,9 @@
// only-aarch64
// compile-flags: -C target-feature=+fp
-#![feature(asm, asm_const, asm_sym)]
+#![feature(asm_const, asm_sym)]
+
+use std::arch::asm;
fn main() {
let mut foo = 0;
@@ -29,8 +31,6 @@ fn main() {
//~^ ERROR invalid register `sp`: the stack pointer cannot be used as an operand
asm!("", in("xzr") foo);
//~^ ERROR invalid register `xzr`: the zero register cannot be used as an operand
- asm!("", in("x18") foo);
- //~^ ERROR invalid register `x18`: x18 is used as a reserved register on some targets and cannot be used as an operand for inline asm
asm!("", in("x19") foo);
//~^ ERROR invalid register `x19`: x19 is used internally by LLVM and cannot be used as an operand for inline asm
diff --git a/src/test/ui/asm/aarch64/bad-reg.stderr b/src/test/ui/asm/aarch64/bad-reg.stderr
index 091e6077ef4..e3316b85193 100644
--- a/src/test/ui/asm/aarch64/bad-reg.stderr
+++ b/src/test/ui/asm/aarch64/bad-reg.stderr
@@ -1,17 +1,17 @@
error: invalid register class `foo`: unknown register class
- --> $DIR/bad-reg.rs:12:20
+ --> $DIR/bad-reg.rs:14:20
|
LL | asm!("{}", in(foo) foo);
| ^^^^^^^^^^^
error: invalid register `foo`: unknown register
- --> $DIR/bad-reg.rs:14:18
+ --> $DIR/bad-reg.rs:16:18
|
LL | asm!("", in("foo") foo);
| ^^^^^^^^^^^^^
error: invalid asm template modifier for this register class
- --> $DIR/bad-reg.rs:16:15
+ --> $DIR/bad-reg.rs:18:15
|
LL | asm!("{:z}", in(reg) foo);
| ^^^^ ----------- argument
@@ -21,7 +21,7 @@ LL | asm!("{:z}", in(reg) foo);
= note: the `reg` register class supports the following template modifiers: `w`, `x`
error: invalid asm template modifier for this register class
- --> $DIR/bad-reg.rs:18:15
+ --> $DIR/bad-reg.rs:20:15
|
LL | asm!("{:r}", in(vreg) foo);
| ^^^^ ------------ argument
@@ -31,7 +31,7 @@ LL | asm!("{:r}", in(vreg) foo);
= note: the `vreg` register class supports the following template modifiers: `b`, `h`, `s`, `d`, `q`, `v`
error: invalid asm template modifier for this register class
- --> $DIR/bad-reg.rs:20:15
+ --> $DIR/bad-reg.rs:22:15
|
LL | asm!("{:r}", in(vreg_low16) foo);
| ^^^^ ------------------ argument
@@ -41,7 +41,7 @@ LL | asm!("{:r}", in(vreg_low16) foo);
= note: the `vreg_low16` register class supports the following template modifiers: `b`, `h`, `s`, `d`, `q`, `v`
error: asm template modifiers are not allowed for `const` arguments
- --> $DIR/bad-reg.rs:22:15
+ --> $DIR/bad-reg.rs:24:15
|
LL | asm!("{:a}", const 0);
| ^^^^ ------- argument
@@ -49,7 +49,7 @@ LL | asm!("{:a}", const 0);
| template modifier
error: asm template modifiers are not allowed for `sym` arguments
- --> $DIR/bad-reg.rs:24:15
+ --> $DIR/bad-reg.rs:26:15
|
LL | asm!("{:a}", sym main);
| ^^^^ -------- argument
@@ -57,27 +57,21 @@ LL | asm!("{:a}", sym main);
| template modifier
error: invalid register `x29`: the frame pointer cannot be used as an operand for inline asm
- --> $DIR/bad-reg.rs:26:18
+ --> $DIR/bad-reg.rs:28:18
|
LL | asm!("", in("x29") foo);
| ^^^^^^^^^^^^^
error: invalid register `sp`: the stack pointer cannot be used as an operand for inline asm
- --> $DIR/bad-reg.rs:28:18
+ --> $DIR/bad-reg.rs:30:18
|
LL | asm!("", in("sp") foo);
| ^^^^^^^^^^^^
error: invalid register `xzr`: the zero register cannot be used as an operand for inline asm
- --> $DIR/bad-reg.rs:30:18
- |
-LL | asm!("", in("xzr") foo);
- | ^^^^^^^^^^^^^
-
-error: invalid register `x18`: x18 is used as a reserved register on some targets and cannot be used as an operand for inline asm
--> $DIR/bad-reg.rs:32:18
|
-LL | asm!("", in("x18") foo);
+LL | asm!("", in("xzr") foo);
| ^^^^^^^^^^^^^
error: invalid register `x19`: x19 is used internally by LLVM and cannot be used as an operand for inline asm
@@ -148,5 +142,5 @@ help: use `lateout` instead of `out` to avoid conflict
LL | asm!("", in("v0") foo, out("q0") bar);
| ^^^^^^^^^^^^
-error: aborting due to 19 previous errors
+error: aborting due to 18 previous errors
diff --git a/src/test/ui/asm/aarch64/const.rs b/src/test/ui/asm/aarch64/const.rs
index 49fe48600c2..73512dcc446 100644
--- a/src/test/ui/asm/aarch64/const.rs
+++ b/src/test/ui/asm/aarch64/const.rs
@@ -3,7 +3,9 @@
// revisions: mirunsafeck thirunsafeck
// [thirunsafeck]compile-flags: -Z thir-unsafeck
-#![feature(asm, global_asm, asm_const)]
+#![feature(asm_const)]
+
+use std::arch::{asm, global_asm};
fn const_generic<const X: usize>() -> usize {
unsafe {
diff --git a/src/test/ui/asm/aarch64/duplicate-options.fixed b/src/test/ui/asm/aarch64/duplicate-options.fixed
index d95c646e9f9..a78e6867bd3 100644
--- a/src/test/ui/asm/aarch64/duplicate-options.fixed
+++ b/src/test/ui/asm/aarch64/duplicate-options.fixed
@@ -1,7 +1,7 @@
// only-aarch64
// run-rustfix
-#![feature(asm, global_asm)]
+use std::arch::asm;
fn main() {
unsafe {
@@ -19,8 +19,8 @@ fn main() {
"",
options(nomem, noreturn),
options(preserves_flags, ), //~ ERROR the `noreturn` option was already provided
- options( nostack), //~ ERROR the `nomem` option was already provided
- options(), //~ ERROR the `noreturn` option was already provided
+ options( nostack), //~ ERROR the `nomem` option was already provided
+ options(), //~ ERROR the `noreturn` option was already provided
);
}
}
diff --git a/src/test/ui/asm/aarch64/duplicate-options.rs b/src/test/ui/asm/aarch64/duplicate-options.rs
index eec356463d4..bd1f1570136 100644
--- a/src/test/ui/asm/aarch64/duplicate-options.rs
+++ b/src/test/ui/asm/aarch64/duplicate-options.rs
@@ -1,7 +1,7 @@
// only-aarch64
// run-rustfix
-#![feature(asm, global_asm)]
+use std::arch::asm;
fn main() {
unsafe {
@@ -19,8 +19,8 @@ fn main() {
"",
options(nomem, noreturn),
options(preserves_flags, noreturn), //~ ERROR the `noreturn` option was already provided
- options(nomem, nostack), //~ ERROR the `nomem` option was already provided
- options(noreturn), //~ ERROR the `noreturn` option was already provided
+ options(nomem, nostack), //~ ERROR the `nomem` option was already provided
+ options(noreturn), //~ ERROR the `noreturn` option was already provided
);
}
}
diff --git a/src/test/ui/asm/aarch64/interpolated-idents.rs b/src/test/ui/asm/aarch64/interpolated-idents.rs
index 1cdf0965667..ece62ce3930 100644
--- a/src/test/ui/asm/aarch64/interpolated-idents.rs
+++ b/src/test/ui/asm/aarch64/interpolated-idents.rs
@@ -1,6 +1,6 @@
// only-aarch64
-#![feature(asm)]
+use std::arch::asm;
macro_rules! m {
($in:ident $out:ident $lateout:ident $inout:ident $inlateout:ident $const:ident $sym:ident
diff --git a/src/test/ui/asm/aarch64/may_unwind.rs b/src/test/ui/asm/aarch64/may_unwind.rs
new file mode 100644
index 00000000000..ac8cc62027e
--- /dev/null
+++ b/src/test/ui/asm/aarch64/may_unwind.rs
@@ -0,0 +1,38 @@
+// min-llvm-version: 13.0.0
+// only-aarch64
+// run-pass
+// needs-asm-support
+
+#![feature(asm_sym, asm_unwind)]
+
+use std::arch::asm;
+use std::panic::{catch_unwind, resume_unwind, AssertUnwindSafe};
+
+struct Foo<'a>(&'a mut bool);
+
+impl Drop for Foo<'_> {
+ fn drop(&mut self) {
+ *self.0 = false;
+ }
+}
+
+extern "C" fn panicky() {
+ resume_unwind(Box::new(()));
+}
+
+fn main() {
+ let flag = &mut true;
+ catch_unwind(AssertUnwindSafe(|| {
+ let _foo = Foo(flag);
+ unsafe {
+ asm!(
+ "bl {}",
+ sym panicky,
+ clobber_abi("C"),
+ options(may_unwind)
+ );
+ }
+ }))
+ .expect_err("expected a panic");
+ assert_eq!(*flag, false);
+}
diff --git a/src/test/ui/asm/aarch64/parse-error.rs b/src/test/ui/asm/aarch64/parse-error.rs
index bc0aed8fe55..59d6b28d0fd 100644
--- a/src/test/ui/asm/aarch64/parse-error.rs
+++ b/src/test/ui/asm/aarch64/parse-error.rs
@@ -1,6 +1,8 @@
// only-aarch64
-#![feature(asm, global_asm, asm_const)]
+#![feature(asm_const)]
+
+use std::arch::{asm, global_asm};
fn main() {
let mut foo = 0;
diff --git a/src/test/ui/asm/aarch64/parse-error.stderr b/src/test/ui/asm/aarch64/parse-error.stderr
index 3d88cef5c7d..d80ab921fb8 100644
--- a/src/test/ui/asm/aarch64/parse-error.stderr
+++ b/src/test/ui/asm/aarch64/parse-error.stderr
@@ -1,89 +1,89 @@
error: requires at least a template string argument
- --> $DIR/parse-error.rs:9:9
+ --> $DIR/parse-error.rs:11:9
|
LL | asm!();
| ^^^^^^
error: asm template must be a string literal
- --> $DIR/parse-error.rs:11:14
+ --> $DIR/parse-error.rs:13:14
|
LL | asm!(foo);
| ^^^
error: expected token: `,`
- --> $DIR/parse-error.rs:13:19
+ --> $DIR/parse-error.rs:15:19
|
LL | asm!("{}" foo);
| ^^^ expected `,`
error: expected operand, clobber_abi, options, or additional template string
- --> $DIR/parse-error.rs:15:20
+ --> $DIR/parse-error.rs:17:20
|
LL | asm!("{}", foo);
| ^^^ expected operand, clobber_abi, options, or additional template string
error: expected `(`, found `foo`
- --> $DIR/parse-error.rs:17:23
+ --> $DIR/parse-error.rs:19:23
|
LL | asm!("{}", in foo);
| ^^^ expected `(`
error: expected `)`, found `foo`
- --> $DIR/parse-error.rs:19:27
+ --> $DIR/parse-error.rs:21:27
|
LL | asm!("{}", in(reg foo));
| ^^^ expected `)`
error: expected expression, found end of macro arguments
- --> $DIR/parse-error.rs:21:27
+ --> $DIR/parse-error.rs:23:27
|
LL | asm!("{}", in(reg));
| ^ expected expression
error: expected register class or explicit register
- --> $DIR/parse-error.rs:23:26
+ --> $DIR/parse-error.rs:25:26
|
LL | asm!("{}", inout(=) foo => bar);
| ^
error: expected expression, found end of macro arguments
- --> $DIR/parse-error.rs:25:37
+ --> $DIR/parse-error.rs:27:37
|
LL | asm!("{}", inout(reg) foo =>);
| ^ expected expression
error: expected one of `!`, `,`, `.`, `::`, `?`, `{`, or an operator, found `=>`
- --> $DIR/parse-error.rs:27:32
+ --> $DIR/parse-error.rs:29:32
|
LL | asm!("{}", in(reg) foo => bar);
| ^^ expected one of 7 possible tokens
error: argument to `sym` must be a path expression
- --> $DIR/parse-error.rs:29:24
+ --> $DIR/parse-error.rs:31:24
|
LL | asm!("{}", sym foo + bar);
| ^^^^^^^^^
-error: expected one of `)`, `att_syntax`, `nomem`, `noreturn`, `nostack`, `preserves_flags`, `pure`, `raw`, or `readonly`, found `foo`
- --> $DIR/parse-error.rs:31:26
+error: expected one of `)`, `att_syntax`, `may_unwind`, `nomem`, `noreturn`, `nostack`, `preserves_flags`, `pure`, `raw`, or `readonly`, found `foo`
+ --> $DIR/parse-error.rs:33:26
|
LL | asm!("", options(foo));
- | ^^^ expected one of 9 possible tokens
+ | ^^^ expected one of 10 possible tokens
error: expected one of `)` or `,`, found `foo`
- --> $DIR/parse-error.rs:33:32
+ --> $DIR/parse-error.rs:35:32
|
LL | asm!("", options(nomem foo));
| ^^^ expected one of `)` or `,`
-error: expected one of `)`, `att_syntax`, `nomem`, `noreturn`, `nostack`, `preserves_flags`, `pure`, `raw`, or `readonly`, found `foo`
- --> $DIR/parse-error.rs:35:33
+error: expected one of `)`, `att_syntax`, `may_unwind`, `nomem`, `noreturn`, `nostack`, `preserves_flags`, `pure`, `raw`, or `readonly`, found `foo`
+ --> $DIR/parse-error.rs:37:33
|
LL | asm!("", options(nomem, foo));
- | ^^^ expected one of 9 possible tokens
+ | ^^^ expected one of 10 possible tokens
error: arguments are not allowed after options
- --> $DIR/parse-error.rs:37:31
+ --> $DIR/parse-error.rs:39:31
|
LL | asm!("{}", options(), const foo);
| --------- ^^^^^^^^^ argument
@@ -91,25 +91,25 @@ LL | asm!("{}", options(), const foo);
| previous options
error: expected string literal
- --> $DIR/parse-error.rs:40:30
+ --> $DIR/parse-error.rs:42:30
|
LL | asm!("", clobber_abi(foo));
| ^^^ not a string literal
error: expected one of `)` or `,`, found `foo`
- --> $DIR/parse-error.rs:42:34
+ --> $DIR/parse-error.rs:44:34
|
LL | asm!("", clobber_abi("C" foo));
| ^^^ expected one of `)` or `,`
error: expected string literal
- --> $DIR/parse-error.rs:44:35
+ --> $DIR/parse-error.rs:46:35
|
LL | asm!("", clobber_abi("C", foo));
| ^^^ not a string literal
error: arguments are not allowed after clobber_abi
- --> $DIR/parse-error.rs:46:38
+ --> $DIR/parse-error.rs:48:38
|
LL | asm!("{}", clobber_abi("C"), const foo);
| ---------------- ^^^^^^^^^ argument
@@ -117,7 +117,7 @@ LL | asm!("{}", clobber_abi("C"), const foo);
| clobber_abi
error: clobber_abi is not allowed after options
- --> $DIR/parse-error.rs:49:29
+ --> $DIR/parse-error.rs:51:29
|
LL | asm!("", options(), clobber_abi("C"));
| --------- ^^^^^^^^^^^^^^^^
@@ -125,7 +125,7 @@ LL | asm!("", options(), clobber_abi("C"));
| options
error: clobber_abi is not allowed after options
- --> $DIR/parse-error.rs:51:31
+ --> $DIR/parse-error.rs:53:31
|
LL | asm!("{}", options(), clobber_abi("C"), const foo);
| --------- ^^^^^^^^^^^^^^^^
@@ -133,7 +133,7 @@ LL | asm!("{}", options(), clobber_abi("C"), const foo);
| options
error: duplicate argument named `a`
- --> $DIR/parse-error.rs:53:36
+ --> $DIR/parse-error.rs:55:36
|
LL | asm!("{a}", a = const foo, a = const bar);
| ------------- ^^^^^^^^^^^^^ duplicate argument
@@ -141,7 +141,7 @@ LL | asm!("{a}", a = const foo, a = const bar);
| previously here
error: argument never used
- --> $DIR/parse-error.rs:53:36
+ --> $DIR/parse-error.rs:55:36
|
LL | asm!("{a}", a = const foo, a = const bar);
| ^^^^^^^^^^^^^ argument never used
@@ -149,13 +149,13 @@ LL | asm!("{a}", a = const foo, a = const bar);
= help: if this argument is intentionally unused, consider using it in an asm comment: `"/* {1} */"`
error: explicit register arguments cannot have names
- --> $DIR/parse-error.rs:58:18
+ --> $DIR/parse-error.rs:60:18
|
LL | asm!("", a = in("x0") foo);
| ^^^^^^^^^^^^^^^^
error: named arguments cannot follow explicit register arguments
- --> $DIR/parse-error.rs:60:35
+ --> $DIR/parse-error.rs:62:35
|
LL | asm!("{a}", in("x0") foo, a = const bar);
| ------------ ^^^^^^^^^^^^^ named argument
@@ -163,7 +163,7 @@ LL | asm!("{a}", in("x0") foo, a = const bar);
| explicit register argument
error: named arguments cannot follow explicit register arguments
- --> $DIR/parse-error.rs:63:35
+ --> $DIR/parse-error.rs:65:35
|
LL | asm!("{a}", in("x0") foo, a = const bar);
| ------------ ^^^^^^^^^^^^^ named argument
@@ -171,7 +171,7 @@ LL | asm!("{a}", in("x0") foo, a = const bar);
| explicit register argument
error: positional arguments cannot follow named arguments or explicit register arguments
- --> $DIR/parse-error.rs:66:35
+ --> $DIR/parse-error.rs:68:35
|
LL | asm!("{1}", in("x0") foo, const bar);
| ------------ ^^^^^^^^^ positional argument
@@ -179,19 +179,19 @@ LL | asm!("{1}", in("x0") foo, const bar);
| explicit register argument
error: expected one of `clobber_abi`, `const`, `in`, `inlateout`, `inout`, `lateout`, `options`, `out`, or `sym`, found `""`
- --> $DIR/parse-error.rs:69:29
+ --> $DIR/parse-error.rs:71:29
|
LL | asm!("", options(), "");
| ^^ expected one of 9 possible tokens
error: expected one of `clobber_abi`, `const`, `in`, `inlateout`, `inout`, `lateout`, `options`, `out`, or `sym`, found `"{}"`
- --> $DIR/parse-error.rs:71:33
+ --> $DIR/parse-error.rs:73:33
|
LL | asm!("{}", in(reg) foo, "{}", out(reg) foo);
| ^^^^ expected one of 9 possible tokens
error: asm template must be a string literal
- --> $DIR/parse-error.rs:73:14
+ --> $DIR/parse-error.rs:75:14
|
LL | asm!(format!("{{{}}}", 0), in(reg) foo);
| ^^^^^^^^^^^^^^^^^^^^
@@ -199,7 +199,7 @@ LL | asm!(format!("{{{}}}", 0), in(reg) foo);
= note: this error originates in the macro `format` (in Nightly builds, run with -Z macro-backtrace for more info)
error: asm template must be a string literal
- --> $DIR/parse-error.rs:75:21
+ --> $DIR/parse-error.rs:77:21
|
LL | asm!("{1}", format!("{{{}}}", 0), in(reg) foo, out(reg) bar);
| ^^^^^^^^^^^^^^^^^^^^
@@ -207,79 +207,79 @@ LL | asm!("{1}", format!("{{{}}}", 0), in(reg) foo, out(reg) bar);
= note: this error originates in the macro `format` (in Nightly builds, run with -Z macro-backtrace for more info)
error: _ cannot be used for input operands
- --> $DIR/parse-error.rs:77:28
+ --> $DIR/parse-error.rs:79:28
|
LL | asm!("{}", in(reg) _);
| ^
error: _ cannot be used for input operands
- --> $DIR/parse-error.rs:79:31
+ --> $DIR/parse-error.rs:81:31
|
LL | asm!("{}", inout(reg) _);
| ^
error: _ cannot be used for input operands
- --> $DIR/parse-error.rs:81:35
+ --> $DIR/parse-error.rs:83:35
|
LL | asm!("{}", inlateout(reg) _);
| ^
error: requires at least a template string argument
- --> $DIR/parse-error.rs:88:1
+ --> $DIR/parse-error.rs:90:1
|
LL | global_asm!();
| ^^^^^^^^^^^^^
error: asm template must be a string literal
- --> $DIR/parse-error.rs:90:13
+ --> $DIR/parse-error.rs:92:13
|
LL | global_asm!(FOO);
| ^^^
error: expected token: `,`
- --> $DIR/parse-error.rs:92:18
+ --> $DIR/parse-error.rs:94:18
|
LL | global_asm!("{}" FOO);
| ^^^ expected `,`
error: expected operand, options, or additional template string
- --> $DIR/parse-error.rs:94:19
+ --> $DIR/parse-error.rs:96:19
|
LL | global_asm!("{}", FOO);
| ^^^ expected operand, options, or additional template string
error: expected expression, found end of macro arguments
- --> $DIR/parse-error.rs:96:24
+ --> $DIR/parse-error.rs:98:24
|
LL | global_asm!("{}", const);
| ^ expected expression
error: expected one of `,`, `.`, `?`, or an operator, found `FOO`
- --> $DIR/parse-error.rs:98:30
+ --> $DIR/parse-error.rs:100:30
|
LL | global_asm!("{}", const(reg) FOO);
| ^^^ expected one of `,`, `.`, `?`, or an operator
-error: expected one of `)`, `att_syntax`, or `raw`, found `FOO`
- --> $DIR/parse-error.rs:100:25
+error: expected one of `)`, `att_syntax`, `may_unwind`, or `raw`, found `FOO`
+ --> $DIR/parse-error.rs:102:25
|
LL | global_asm!("", options(FOO));
- | ^^^ expected one of `)`, `att_syntax`, or `raw`
+ | ^^^ expected one of `)`, `att_syntax`, `may_unwind`, or `raw`
-error: expected one of `)`, `att_syntax`, or `raw`, found `nomem`
- --> $DIR/parse-error.rs:102:25
+error: expected one of `)`, `att_syntax`, `may_unwind`, or `raw`, found `nomem`
+ --> $DIR/parse-error.rs:104:25
|
LL | global_asm!("", options(nomem FOO));
- | ^^^^^ expected one of `)`, `att_syntax`, or `raw`
+ | ^^^^^ expected one of `)`, `att_syntax`, `may_unwind`, or `raw`
-error: expected one of `)`, `att_syntax`, or `raw`, found `nomem`
- --> $DIR/parse-error.rs:104:25
+error: expected one of `)`, `att_syntax`, `may_unwind`, or `raw`, found `nomem`
+ --> $DIR/parse-error.rs:106:25
|
LL | global_asm!("", options(nomem, FOO));
- | ^^^^^ expected one of `)`, `att_syntax`, or `raw`
+ | ^^^^^ expected one of `)`, `att_syntax`, `may_unwind`, or `raw`
error: arguments are not allowed after options
- --> $DIR/parse-error.rs:106:30
+ --> $DIR/parse-error.rs:108:30
|
LL | global_asm!("{}", options(), const FOO);
| --------- ^^^^^^^^^ argument
@@ -287,25 +287,25 @@ LL | global_asm!("{}", options(), const FOO);
| previous options
error: expected string literal
- --> $DIR/parse-error.rs:108:29
+ --> $DIR/parse-error.rs:110:29
|
LL | global_asm!("", clobber_abi(FOO));
| ^^^ not a string literal
error: expected one of `)` or `,`, found `FOO`
- --> $DIR/parse-error.rs:110:33
+ --> $DIR/parse-error.rs:112:33
|
LL | global_asm!("", clobber_abi("C" FOO));
| ^^^ expected one of `)` or `,`
error: expected string literal
- --> $DIR/parse-error.rs:112:34
+ --> $DIR/parse-error.rs:114:34
|
LL | global_asm!("", clobber_abi("C", FOO));
| ^^^ not a string literal
error: arguments are not allowed after clobber_abi
- --> $DIR/parse-error.rs:114:37
+ --> $DIR/parse-error.rs:116:37
|
LL | global_asm!("{}", clobber_abi("C"), const FOO);
| ---------------- ^^^^^^^^^ argument
@@ -313,13 +313,13 @@ LL | global_asm!("{}", clobber_abi("C"), const FOO);
| clobber_abi
error: `clobber_abi` cannot be used with `global_asm!`
- --> $DIR/parse-error.rs:114:19
+ --> $DIR/parse-error.rs:116:19
|
LL | global_asm!("{}", clobber_abi("C"), const FOO);
| ^^^^^^^^^^^^^^^^
error: clobber_abi is not allowed after options
- --> $DIR/parse-error.rs:117:28
+ --> $DIR/parse-error.rs:119:28
|
LL | global_asm!("", options(), clobber_abi("C"));
| --------- ^^^^^^^^^^^^^^^^
@@ -327,7 +327,7 @@ LL | global_asm!("", options(), clobber_abi("C"));
| options
error: clobber_abi is not allowed after options
- --> $DIR/parse-error.rs:119:30
+ --> $DIR/parse-error.rs:121:30
|
LL | global_asm!("{}", options(), clobber_abi("C"), const FOO);
| --------- ^^^^^^^^^^^^^^^^
@@ -335,7 +335,7 @@ LL | global_asm!("{}", options(), clobber_abi("C"), const FOO);
| options
error: duplicate argument named `a`
- --> $DIR/parse-error.rs:121:35
+ --> $DIR/parse-error.rs:123:35
|
LL | global_asm!("{a}", a = const FOO, a = const BAR);
| ------------- ^^^^^^^^^^^^^ duplicate argument
@@ -343,7 +343,7 @@ LL | global_asm!("{a}", a = const FOO, a = const BAR);
| previously here
error: argument never used
- --> $DIR/parse-error.rs:121:35
+ --> $DIR/parse-error.rs:123:35
|
LL | global_asm!("{a}", a = const FOO, a = const BAR);
| ^^^^^^^^^^^^^ argument never used
@@ -351,19 +351,19 @@ LL | global_asm!("{a}", a = const FOO, a = const BAR);
= help: if this argument is intentionally unused, consider using it in an asm comment: `"/* {1} */"`
error: expected one of `clobber_abi`, `const`, or `options`, found `""`
- --> $DIR/parse-error.rs:124:28
+ --> $DIR/parse-error.rs:126:28
|
LL | global_asm!("", options(), "");
| ^^ expected one of `clobber_abi`, `const`, or `options`
error: expected one of `clobber_abi`, `const`, or `options`, found `"{}"`
- --> $DIR/parse-error.rs:126:30
+ --> $DIR/parse-error.rs:128:30
|
LL | global_asm!("{}", const FOO, "{}", const FOO);
| ^^^^ expected one of `clobber_abi`, `const`, or `options`
error: asm template must be a string literal
- --> $DIR/parse-error.rs:128:13
+ --> $DIR/parse-error.rs:130:13
|
LL | global_asm!(format!("{{{}}}", 0), const FOO);
| ^^^^^^^^^^^^^^^^^^^^
@@ -371,7 +371,7 @@ LL | global_asm!(format!("{{{}}}", 0), const FOO);
= note: this error originates in the macro `format` (in Nightly builds, run with -Z macro-backtrace for more info)
error: asm template must be a string literal
- --> $DIR/parse-error.rs:130:20
+ --> $DIR/parse-error.rs:132:20
|
LL | global_asm!("{1}", format!("{{{}}}", 0), const FOO, const BAR);
| ^^^^^^^^^^^^^^^^^^^^
@@ -379,7 +379,7 @@ LL | global_asm!("{1}", format!("{{{}}}", 0), const FOO, const BAR);
= note: this error originates in the macro `format` (in Nightly builds, run with -Z macro-backtrace for more info)
error[E0435]: attempt to use a non-constant value in a constant
- --> $DIR/parse-error.rs:37:37
+ --> $DIR/parse-error.rs:39:37
|
LL | let mut foo = 0;
| ---------- help: consider using `const` instead of `let`: `const foo`
@@ -388,7 +388,7 @@ LL | asm!("{}", options(), const foo);
| ^^^ non-constant value
error[E0435]: attempt to use a non-constant value in a constant
- --> $DIR/parse-error.rs:46:44
+ --> $DIR/parse-error.rs:48:44
|
LL | let mut foo = 0;
| ---------- help: consider using `const` instead of `let`: `const foo`
@@ -397,7 +397,7 @@ LL | asm!("{}", clobber_abi("C"), const foo);
| ^^^ non-constant value
error[E0435]: attempt to use a non-constant value in a constant
- --> $DIR/parse-error.rs:53:31
+ --> $DIR/parse-error.rs:55:31
|
LL | let mut foo = 0;
| ---------- help: consider using `const` instead of `let`: `const foo`
@@ -406,7 +406,7 @@ LL | asm!("{a}", a = const foo, a = const bar);
| ^^^ non-constant value
error[E0435]: attempt to use a non-constant value in a constant
- --> $DIR/parse-error.rs:53:46
+ --> $DIR/parse-error.rs:55:46
|
LL | let mut bar = 0;
| ---------- help: consider using `const` instead of `let`: `const bar`
@@ -415,7 +415,7 @@ LL | asm!("{a}", a = const foo, a = const bar);
| ^^^ non-constant value
error[E0435]: attempt to use a non-constant value in a constant
- --> $DIR/parse-error.rs:60:45
+ --> $DIR/parse-error.rs:62:45
|
LL | let mut bar = 0;
| ---------- help: consider using `const` instead of `let`: `const bar`
@@ -424,7 +424,7 @@ LL | asm!("{a}", in("x0") foo, a = const bar);
| ^^^ non-constant value
error[E0435]: attempt to use a non-constant value in a constant
- --> $DIR/parse-error.rs:63:45
+ --> $DIR/parse-error.rs:65:45
|
LL | let mut bar = 0;
| ---------- help: consider using `const` instead of `let`: `const bar`
@@ -433,7 +433,7 @@ LL | asm!("{a}", in("x0") foo, a = const bar);
| ^^^ non-constant value
error[E0435]: attempt to use a non-constant value in a constant
- --> $DIR/parse-error.rs:66:41
+ --> $DIR/parse-error.rs:68:41
|
LL | let mut bar = 0;
| ---------- help: consider using `const` instead of `let`: `const bar`
diff --git a/src/test/ui/asm/aarch64/srcloc.rs b/src/test/ui/asm/aarch64/srcloc.rs
index 143ed182403..609f5e80d24 100644
--- a/src/test/ui/asm/aarch64/srcloc.rs
+++ b/src/test/ui/asm/aarch64/srcloc.rs
@@ -1,7 +1,8 @@
// only-aarch64
// build-fail
// compile-flags: -Ccodegen-units=1
-#![feature(asm)]
+
+use std::arch::asm;
// Checks that inline asm errors are mapped to the correct line in the source code.
diff --git a/src/test/ui/asm/aarch64/srcloc.stderr b/src/test/ui/asm/aarch64/srcloc.stderr
index f03fbf28d31..96dab1bce0b 100644
--- a/src/test/ui/asm/aarch64/srcloc.stderr
+++ b/src/test/ui/asm/aarch64/srcloc.stderr
@@ -1,5 +1,5 @@
error: unrecognized instruction mnemonic
- --> $DIR/srcloc.rs:10:15
+ --> $DIR/srcloc.rs:11:15
|
LL | asm!("invalid_instruction");
| ^
@@ -11,7 +11,7 @@ LL | invalid_instruction
| ^
error: unrecognized instruction mnemonic
- --> $DIR/srcloc.rs:14:13
+ --> $DIR/srcloc.rs:15:13
|
LL | invalid_instruction
| ^
@@ -23,7 +23,7 @@ LL | invalid_instruction
| ^
error: unrecognized instruction mnemonic
- --> $DIR/srcloc.rs:19:13
+ --> $DIR/srcloc.rs:20:13
|
LL | invalid_instruction
| ^
@@ -35,7 +35,7 @@ LL | invalid_instruction
| ^
error: unrecognized instruction mnemonic
- --> $DIR/srcloc.rs:25:13
+ --> $DIR/srcloc.rs:26:13
|
LL | invalid_instruction
| ^
@@ -47,7 +47,7 @@ LL | invalid_instruction
| ^
error: unrecognized instruction mnemonic
- --> $DIR/srcloc.rs:32:13
+ --> $DIR/srcloc.rs:33:13
|
LL | invalid_instruction
| ^
@@ -59,7 +59,7 @@ LL | invalid_instruction
| ^
error: unrecognized instruction mnemonic
- --> $DIR/srcloc.rs:37:14
+ --> $DIR/srcloc.rs:38:14
|
LL | asm!(concat!("invalid", "_", "instruction"));
| ^
@@ -71,7 +71,7 @@ LL | invalid_instruction
| ^
error: unrecognized instruction mnemonic
- --> $DIR/srcloc.rs:41:14
+ --> $DIR/srcloc.rs:42:14
|
LL | "invalid_instruction",
| ^
@@ -83,7 +83,7 @@ LL | invalid_instruction
| ^
error: unrecognized instruction mnemonic
- --> $DIR/srcloc.rs:47:14
+ --> $DIR/srcloc.rs:48:14
|
LL | "invalid_instruction",
| ^
@@ -95,7 +95,7 @@ LL | invalid_instruction
| ^
error: unrecognized instruction mnemonic
- --> $DIR/srcloc.rs:54:14
+ --> $DIR/srcloc.rs:55:14
|
LL | "invalid_instruction",
| ^
@@ -107,7 +107,7 @@ LL | invalid_instruction
| ^
error: unrecognized instruction mnemonic
- --> $DIR/srcloc.rs:61:13
+ --> $DIR/srcloc.rs:62:13
|
LL | concat!("invalid", "_", "instruction"),
| ^
@@ -119,7 +119,7 @@ LL | invalid_instruction
| ^
error: unrecognized instruction mnemonic
- --> $DIR/srcloc.rs:68:13
+ --> $DIR/srcloc.rs:69:13
|
LL | concat!("invalid", "_", "instruction"),
| ^
@@ -131,7 +131,7 @@ LL | invalid_instruction
| ^
error: unrecognized instruction mnemonic
- --> $DIR/srcloc.rs:75:14
+ --> $DIR/srcloc.rs:76:14
|
LL | "invalid_instruction1",
| ^
@@ -143,7 +143,7 @@ LL | invalid_instruction1
| ^
error: unrecognized instruction mnemonic
- --> $DIR/srcloc.rs:76:14
+ --> $DIR/srcloc.rs:77:14
|
LL | "invalid_instruction2",
| ^
@@ -155,7 +155,7 @@ LL | invalid_instruction2
| ^
error: unrecognized instruction mnemonic
- --> $DIR/srcloc.rs:82:13
+ --> $DIR/srcloc.rs:83:13
|
LL | concat!(
| ^
@@ -167,7 +167,7 @@ LL | invalid_instruction1
| ^
error: unrecognized instruction mnemonic
- --> $DIR/srcloc.rs:82:13
+ --> $DIR/srcloc.rs:83:13
|
LL | concat!(
| ^
@@ -179,7 +179,7 @@ LL | invalid_instruction2
| ^
error: unrecognized instruction mnemonic
- --> $DIR/srcloc.rs:91:13
+ --> $DIR/srcloc.rs:92:13
|
LL | concat!(
| ^
@@ -191,7 +191,7 @@ LL | invalid_instruction1
| ^
error: unrecognized instruction mnemonic
- --> $DIR/srcloc.rs:91:13
+ --> $DIR/srcloc.rs:92:13
|
LL | concat!(
| ^
@@ -203,7 +203,7 @@ LL | invalid_instruction2
| ^
error: unrecognized instruction mnemonic
- --> $DIR/srcloc.rs:95:13
+ --> $DIR/srcloc.rs:96:13
|
LL | concat!(
| ^
@@ -215,7 +215,7 @@ LL | invalid_instruction3
| ^
error: unrecognized instruction mnemonic
- --> $DIR/srcloc.rs:95:13
+ --> $DIR/srcloc.rs:96:13
|
LL | concat!(
| ^
@@ -227,7 +227,7 @@ LL | invalid_instruction4
| ^
error: unrecognized instruction mnemonic
- --> $DIR/srcloc.rs:106:13
+ --> $DIR/srcloc.rs:107:13
|
LL | concat!(
| ^
@@ -239,7 +239,7 @@ LL | invalid_instruction1
| ^
error: unrecognized instruction mnemonic
- --> $DIR/srcloc.rs:106:13
+ --> $DIR/srcloc.rs:107:13
|
LL | concat!(
| ^
@@ -251,7 +251,7 @@ LL | invalid_instruction2
| ^
error: unrecognized instruction mnemonic
- --> $DIR/srcloc.rs:110:13
+ --> $DIR/srcloc.rs:111:13
|
LL | concat!(
| ^
@@ -263,7 +263,7 @@ LL | invalid_instruction3
| ^
error: unrecognized instruction mnemonic
- --> $DIR/srcloc.rs:110:13
+ --> $DIR/srcloc.rs:111:13
|
LL | concat!(
| ^
diff --git a/src/test/ui/asm/aarch64/sym.rs b/src/test/ui/asm/aarch64/sym.rs
index b0dd143a0a1..4fd31070ec7 100644
--- a/src/test/ui/asm/aarch64/sym.rs
+++ b/src/test/ui/asm/aarch64/sym.rs
@@ -2,7 +2,9 @@
// only-linux
// run-pass
-#![feature(asm, thread_local, asm_sym)]
+#![feature(thread_local, asm_sym)]
+
+use std::arch::asm;
extern "C" fn f1() -> i32 {
111
diff --git a/src/test/ui/asm/aarch64/type-check-2.rs b/src/test/ui/asm/aarch64/type-check-2.rs
index e1e8a91dda6..1b91f5d0678 100644
--- a/src/test/ui/asm/aarch64/type-check-2.rs
+++ b/src/test/ui/asm/aarch64/type-check-2.rs
@@ -1,6 +1,8 @@
// only-aarch64
-#![feature(asm, repr_simd, never_type, asm_sym)]
+#![feature(repr_simd, never_type, asm_sym)]
+
+use std::arch::asm;
#[repr(simd)]
#[derive(Clone, Copy)]
diff --git a/src/test/ui/asm/aarch64/type-check-2.stderr b/src/test/ui/asm/aarch64/type-check-2.stderr
index cea26d73ab1..beb301c7c74 100644
--- a/src/test/ui/asm/aarch64/type-check-2.stderr
+++ b/src/test/ui/asm/aarch64/type-check-2.stderr
@@ -1,13 +1,13 @@
error: arguments for inline assembly must be copyable
- --> $DIR/type-check-2.rs:46:31
+ --> $DIR/type-check-2.rs:48:31
|
LL | asm!("{:v}", in(vreg) SimdNonCopy(0.0, 0.0, 0.0, 0.0));
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
= note: `SimdNonCopy` does not implement the Copy trait
-error: cannot use value of type `[closure@$DIR/type-check-2.rs:58:28: 58:38]` for inline assembly
- --> $DIR/type-check-2.rs:58:28
+error: cannot use value of type `[closure@$DIR/type-check-2.rs:60:28: 60:38]` for inline assembly
+ --> $DIR/type-check-2.rs:60:28
|
LL | asm!("{}", in(reg) |x: i32| x);
| ^^^^^^^^^^
@@ -15,7 +15,7 @@ LL | asm!("{}", in(reg) |x: i32| x);
= note: only integers, floats, SIMD vectors, pointers and function pointers can be used as arguments for inline assembly
error: cannot use value of type `Vec<i32>` for inline assembly
- --> $DIR/type-check-2.rs:60:28
+ --> $DIR/type-check-2.rs:62:28
|
LL | asm!("{}", in(reg) vec![0]);
| ^^^^^^^
@@ -24,7 +24,7 @@ LL | asm!("{}", in(reg) vec![0]);
= note: this error originates in the macro `vec` (in Nightly builds, run with -Z macro-backtrace for more info)
error: cannot use value of type `(i32, i32, i32)` for inline assembly
- --> $DIR/type-check-2.rs:62:28
+ --> $DIR/type-check-2.rs:64:28
|
LL | asm!("{}", in(reg) (1, 2, 3));
| ^^^^^^^^^
@@ -32,7 +32,7 @@ LL | asm!("{}", in(reg) (1, 2, 3));
= note: only integers, floats, SIMD vectors, pointers and function pointers can be used as arguments for inline assembly
error: cannot use value of type `[i32; 3]` for inline assembly
- --> $DIR/type-check-2.rs:64:28
+ --> $DIR/type-check-2.rs:66:28
|
LL | asm!("{}", in(reg) [1, 2, 3]);
| ^^^^^^^^^
@@ -40,7 +40,7 @@ LL | asm!("{}", in(reg) [1, 2, 3]);
= note: only integers, floats, SIMD vectors, pointers and function pointers can be used as arguments for inline assembly
error: cannot use value of type `fn() {main}` for inline assembly
- --> $DIR/type-check-2.rs:72:31
+ --> $DIR/type-check-2.rs:74:31
|
LL | asm!("{}", inout(reg) f);
| ^
@@ -48,7 +48,7 @@ LL | asm!("{}", inout(reg) f);
= note: only integers, floats, SIMD vectors, pointers and function pointers can be used as arguments for inline assembly
error: cannot use value of type `&mut i32` for inline assembly
- --> $DIR/type-check-2.rs:75:31
+ --> $DIR/type-check-2.rs:77:31
|
LL | asm!("{}", inout(reg) r);
| ^
@@ -56,31 +56,31 @@ LL | asm!("{}", inout(reg) r);
= note: only integers, floats, SIMD vectors, pointers and function pointers can be used as arguments for inline assembly
error: asm `sym` operand must point to a fn or static
- --> $DIR/type-check-2.rs:39:24
+ --> $DIR/type-check-2.rs:41:24
|
LL | asm!("{}", sym C);
| ^
error: asm `sym` operand must point to a fn or static
- --> $DIR/type-check-2.rs:41:24
+ --> $DIR/type-check-2.rs:43:24
|
LL | asm!("{}", sym x);
| ^
error[E0381]: use of possibly-uninitialized variable: `x`
- --> $DIR/type-check-2.rs:17:28
+ --> $DIR/type-check-2.rs:19:28
|
LL | asm!("{}", in(reg) x);
| ^ use of possibly-uninitialized `x`
error[E0381]: use of possibly-uninitialized variable: `y`
- --> $DIR/type-check-2.rs:20:9
+ --> $DIR/type-check-2.rs:22:9
|
LL | asm!("{}", inout(reg) y);
| ^^^^^^^^^^^^^^^^^^^^^^^^ use of possibly-uninitialized `y`
error[E0596]: cannot borrow `v` as mutable, as it is not declared as mutable
- --> $DIR/type-check-2.rs:28:29
+ --> $DIR/type-check-2.rs:30:29
|
LL | let v: Vec<u64> = vec![0, 1, 2];
| - help: consider changing this to be mutable: `mut v`
@@ -89,7 +89,7 @@ LL | asm!("{}", out(reg) v[0]);
| ^ cannot borrow as mutable
error[E0596]: cannot borrow `v` as mutable, as it is not declared as mutable
- --> $DIR/type-check-2.rs:30:31
+ --> $DIR/type-check-2.rs:32:31
|
LL | let v: Vec<u64> = vec![0, 1, 2];
| - help: consider changing this to be mutable: `mut v`
diff --git a/src/test/ui/asm/aarch64/type-check-3.rs b/src/test/ui/asm/aarch64/type-check-3.rs
index fc1831a520a..8cac18b8052 100644
--- a/src/test/ui/asm/aarch64/type-check-3.rs
+++ b/src/test/ui/asm/aarch64/type-check-3.rs
@@ -1,9 +1,10 @@
// only-aarch64
// compile-flags: -C target-feature=+neon
-#![feature(asm, global_asm, repr_simd, stdsimd, asm_const)]
+#![feature(repr_simd, stdsimd, asm_const)]
use std::arch::aarch64::float64x2_t;
+use std::arch::{asm, global_asm};
#[repr(simd)]
#[derive(Copy, Clone)]
diff --git a/src/test/ui/asm/aarch64/type-check-3.stderr b/src/test/ui/asm/aarch64/type-check-3.stderr
index ed9d3147b9f..c31a62ae791 100644
--- a/src/test/ui/asm/aarch64/type-check-3.stderr
+++ b/src/test/ui/asm/aarch64/type-check-3.stderr
@@ -1,5 +1,5 @@
warning: formatting may not be suitable for sub-register argument
- --> $DIR/type-check-3.rs:47:15
+ --> $DIR/type-check-3.rs:48:15
|
LL | asm!("{}", in(reg) 0u8);
| ^^ --- for this argument
@@ -9,7 +9,7 @@ LL | asm!("{}", in(reg) 0u8);
= help: or use the `x` modifier to keep the default formatting of `x0`
warning: formatting may not be suitable for sub-register argument
- --> $DIR/type-check-3.rs:49:15
+ --> $DIR/type-check-3.rs:50:15
|
LL | asm!("{}", in(reg) 0u16);
| ^^ ---- for this argument
@@ -18,7 +18,7 @@ LL | asm!("{}", in(reg) 0u16);
= help: or use the `x` modifier to keep the default formatting of `x0`
warning: formatting may not be suitable for sub-register argument
- --> $DIR/type-check-3.rs:51:15
+ --> $DIR/type-check-3.rs:52:15
|
LL | asm!("{}", in(reg) 0i32);
| ^^ ---- for this argument
@@ -27,7 +27,7 @@ LL | asm!("{}", in(reg) 0i32);
= help: or use the `x` modifier to keep the default formatting of `x0`
warning: formatting may not be suitable for sub-register argument
- --> $DIR/type-check-3.rs:53:15
+ --> $DIR/type-check-3.rs:54:15
|
LL | asm!("{}", in(reg) 0f32);
| ^^ ---- for this argument
@@ -36,7 +36,7 @@ LL | asm!("{}", in(reg) 0f32);
= help: or use the `x` modifier to keep the default formatting of `x0`
warning: formatting may not be suitable for sub-register argument
- --> $DIR/type-check-3.rs:56:15
+ --> $DIR/type-check-3.rs:57:15
|
LL | asm!("{}", in(vreg) 0i16);
| ^^ ---- for this argument
@@ -45,7 +45,7 @@ LL | asm!("{}", in(vreg) 0i16);
= help: or use the `v` modifier to keep the default formatting of `v0`
warning: formatting may not be suitable for sub-register argument
- --> $DIR/type-check-3.rs:58:15
+ --> $DIR/type-check-3.rs:59:15
|
LL | asm!("{}", in(vreg) 0f32);
| ^^ ---- for this argument
@@ -54,7 +54,7 @@ LL | asm!("{}", in(vreg) 0f32);
= help: or use the `v` modifier to keep the default formatting of `v0`
warning: formatting may not be suitable for sub-register argument
- --> $DIR/type-check-3.rs:60:15
+ --> $DIR/type-check-3.rs:61:15
|
LL | asm!("{}", in(vreg) 0f64);
| ^^ ---- for this argument
@@ -63,7 +63,7 @@ LL | asm!("{}", in(vreg) 0f64);
= help: or use the `v` modifier to keep the default formatting of `v0`
warning: formatting may not be suitable for sub-register argument
- --> $DIR/type-check-3.rs:62:15
+ --> $DIR/type-check-3.rs:63:15
|
LL | asm!("{}", in(vreg_low16) 0f64);
| ^^ ---- for this argument
@@ -72,7 +72,7 @@ LL | asm!("{}", in(vreg_low16) 0f64);
= help: or use the `v` modifier to keep the default formatting of `v0`
warning: formatting may not be suitable for sub-register argument
- --> $DIR/type-check-3.rs:65:15
+ --> $DIR/type-check-3.rs:66:15
|
LL | asm!("{0} {0}", in(reg) 0i16);
| ^^^ ^^^ ---- for this argument
@@ -81,7 +81,7 @@ LL | asm!("{0} {0}", in(reg) 0i16);
= help: or use the `x` modifier to keep the default formatting of `x0`
warning: formatting may not be suitable for sub-register argument
- --> $DIR/type-check-3.rs:67:15
+ --> $DIR/type-check-3.rs:68:15
|
LL | asm!("{0} {0:x}", in(reg) 0i16);
| ^^^ ---- for this argument
@@ -90,7 +90,7 @@ LL | asm!("{0} {0:x}", in(reg) 0i16);
= help: or use the `x` modifier to keep the default formatting of `x0`
error: type `i128` cannot be used with this register class
- --> $DIR/type-check-3.rs:72:28
+ --> $DIR/type-check-3.rs:73:28
|
LL | asm!("{}", in(reg) 0i128);
| ^^^^^
@@ -98,7 +98,7 @@ LL | asm!("{}", in(reg) 0i128);
= note: register class `reg` supports these types: i8, i16, i32, i64, f32, f64
error: type `float64x2_t` cannot be used with this register class
- --> $DIR/type-check-3.rs:74:28
+ --> $DIR/type-check-3.rs:75:28
|
LL | asm!("{}", in(reg) f64x2);
| ^^^^^
@@ -106,7 +106,7 @@ LL | asm!("{}", in(reg) f64x2);
= note: register class `reg` supports these types: i8, i16, i32, i64, f32, f64
error: type `Simd256bit` cannot be used with this register class
- --> $DIR/type-check-3.rs:76:29
+ --> $DIR/type-check-3.rs:77:29
|
LL | asm!("{}", in(vreg) f64x4);
| ^^^^^
@@ -114,7 +114,7 @@ LL | asm!("{}", in(vreg) f64x4);
= note: register class `vreg` supports these types: i8, i16, i32, i64, f32, f64, i8x8, i16x4, i32x2, i64x1, f32x2, f64x1, i8x16, i16x8, i32x4, i64x2, f32x4, f64x2
error: incompatible types for asm inout argument
- --> $DIR/type-check-3.rs:87:33
+ --> $DIR/type-check-3.rs:88:33
|
LL | asm!("{:x}", inout(reg) 0u32 => val_f32);
| ^^^^ ^^^^^^^ type `f32`
@@ -124,7 +124,7 @@ LL | asm!("{:x}", inout(reg) 0u32 => val_f32);
= note: asm inout arguments must have the same type, unless they are both pointers or integers of the same size
error: incompatible types for asm inout argument
- --> $DIR/type-check-3.rs:89:33
+ --> $DIR/type-check-3.rs:90:33
|
LL | asm!("{:x}", inout(reg) 0u32 => val_ptr);
| ^^^^ ^^^^^^^ type `*mut u8`
@@ -134,7 +134,7 @@ LL | asm!("{:x}", inout(reg) 0u32 => val_ptr);
= note: asm inout arguments must have the same type, unless they are both pointers or integers of the same size
error: incompatible types for asm inout argument
- --> $DIR/type-check-3.rs:91:33
+ --> $DIR/type-check-3.rs:92:33
|
LL | asm!("{:x}", inout(reg) main => val_u32);
| ^^^^ ^^^^^^^ type `u32`
@@ -144,7 +144,7 @@ LL | asm!("{:x}", inout(reg) main => val_u32);
= note: asm inout arguments must have the same type, unless they are both pointers or integers of the same size
error[E0013]: constants cannot refer to statics
- --> $DIR/type-check-3.rs:107:25
+ --> $DIR/type-check-3.rs:108:25
|
LL | global_asm!("{}", const S);
| ^
@@ -152,7 +152,7 @@ LL | global_asm!("{}", const S);
= help: consider extracting the value of the `static` to a `const`, and referring to that
error[E0013]: constants cannot refer to statics
- --> $DIR/type-check-3.rs:110:35
+ --> $DIR/type-check-3.rs:111:35
|
LL | global_asm!("{}", const const_foo(S));
| ^
@@ -160,7 +160,7 @@ LL | global_asm!("{}", const const_foo(S));
= help: consider extracting the value of the `static` to a `const`, and referring to that
error[E0013]: constants cannot refer to statics
- --> $DIR/type-check-3.rs:113:35
+ --> $DIR/type-check-3.rs:114:35
|
LL | global_asm!("{}", const const_bar(S));
| ^
diff --git a/src/test/ui/asm/issue-72570.rs b/src/test/ui/asm/issue-72570.rs
index 960f7427e34..bb13816348d 100644
--- a/src/test/ui/asm/issue-72570.rs
+++ b/src/test/ui/asm/issue-72570.rs
@@ -2,7 +2,7 @@
// needs-asm-support
// Also test for #72960
-#![feature(asm)]
+use std::arch::asm;
fn main() {
unsafe {
diff --git a/src/test/ui/asm/issue-87802.rs b/src/test/ui/asm/issue-87802.rs
index 5b6453c42c6..5b2e636c29f 100644
--- a/src/test/ui/asm/issue-87802.rs
+++ b/src/test/ui/asm/issue-87802.rs
@@ -4,7 +4,7 @@
// ignore-wasm32
// Make sure rustc doesn't ICE on asm! when output type is !.
-#![feature(asm)]
+use std::arch::asm;
fn hmm() -> ! {
let x;
diff --git a/src/test/ui/asm/issue-89305.rs b/src/test/ui/asm/issue-89305.rs
index a4b22e21028..05677912dff 100644
--- a/src/test/ui/asm/issue-89305.rs
+++ b/src/test/ui/asm/issue-89305.rs
@@ -4,9 +4,10 @@
// check-pass
// needs-asm-support
-#![feature(asm)]
#![warn(unused)]
+use std::arch::asm;
+
fn main() {
unsafe {
let x: () = asm!("nop");
diff --git a/src/test/ui/asm/issue-89305.stderr b/src/test/ui/asm/issue-89305.stderr
index 3fb1526183b..7efc5102042 100644
--- a/src/test/ui/asm/issue-89305.stderr
+++ b/src/test/ui/asm/issue-89305.stderr
@@ -1,11 +1,11 @@
warning: unused variable: `x`
- --> $DIR/issue-89305.rs:12:13
+ --> $DIR/issue-89305.rs:13:13
|
LL | let x: () = asm!("nop");
| ^ help: if this is intentional, prefix it with an underscore: `_x`
|
note: the lint level is defined here
- --> $DIR/issue-89305.rs:8:9
+ --> $DIR/issue-89305.rs:7:9
|
LL | #![warn(unused)]
| ^^^^^^
diff --git a/src/test/ui/asm/may_unwind.rs b/src/test/ui/asm/may_unwind.rs
new file mode 100644
index 00000000000..117c0a63aa4
--- /dev/null
+++ b/src/test/ui/asm/may_unwind.rs
@@ -0,0 +1,11 @@
+// min-llvm-version: 13.0.0
+// run-pass
+// needs-asm-support
+
+#![feature(asm_unwind)]
+
+use std::arch::asm;
+
+fn main() {
+ unsafe { asm!("", options(may_unwind)) };
+}
diff --git a/src/test/ui/asm/naked-functions-ffi.rs b/src/test/ui/asm/naked-functions-ffi.rs
index f6725605b92..c8bee504d02 100644
--- a/src/test/ui/asm/naked-functions-ffi.rs
+++ b/src/test/ui/asm/naked-functions-ffi.rs
@@ -1,12 +1,15 @@
// check-pass
// needs-asm-support
-#![feature(asm)]
#![feature(naked_functions)]
#![crate_type = "lib"]
+use std::arch::asm;
+
#[naked]
pub extern "C" fn naked(p: char) -> u128 {
//~^ WARN uses type `char`
//~| WARN uses type `u128`
- unsafe { asm!("", options(noreturn)); }
+ unsafe {
+ asm!("", options(noreturn));
+ }
}
diff --git a/src/test/ui/asm/naked-functions-ffi.stderr b/src/test/ui/asm/naked-functions-ffi.stderr
index a6772badeb6..ac743551311 100644
--- a/src/test/ui/asm/naked-functions-ffi.stderr
+++ b/src/test/ui/asm/naked-functions-ffi.stderr
@@ -1,5 +1,5 @@
warning: `extern` fn uses type `char`, which is not FFI-safe
- --> $DIR/naked-functions-ffi.rs:8:28
+ --> $DIR/naked-functions-ffi.rs:9:28
|
LL | pub extern "C" fn naked(p: char) -> u128 {
| ^^^^ not FFI-safe
@@ -9,7 +9,7 @@ LL | pub extern "C" fn naked(p: char) -> u128 {
= note: the `char` type has no C equivalent
warning: `extern` fn uses type `u128`, which is not FFI-safe
- --> $DIR/naked-functions-ffi.rs:8:37
+ --> $DIR/naked-functions-ffi.rs:9:37
|
LL | pub extern "C" fn naked(p: char) -> u128 {
| ^^^^ not FFI-safe
diff --git a/src/test/ui/asm/naked-functions-unused.aarch64.stderr b/src/test/ui/asm/naked-functions-unused.aarch64.stderr
index a898ab19a73..cf4a1d9174e 100644
--- a/src/test/ui/asm/naked-functions-unused.aarch64.stderr
+++ b/src/test/ui/asm/naked-functions-unused.aarch64.stderr
@@ -1,5 +1,5 @@
error: unused variable: `a`
- --> $DIR/naked-functions-unused.rs:15:32
+ --> $DIR/naked-functions-unused.rs:16:32
|
LL | pub extern "C" fn function(a: usize, b: usize) -> usize {
| ^ help: if this is intentional, prefix it with an underscore: `_a`
@@ -12,55 +12,55 @@ LL | #![deny(unused)]
= note: `#[deny(unused_variables)]` implied by `#[deny(unused)]`
error: unused variable: `b`
- --> $DIR/naked-functions-unused.rs:15:42
+ --> $DIR/naked-functions-unused.rs:16:42
|
LL | pub extern "C" fn function(a: usize, b: usize) -> usize {
| ^ help: if this is intentional, prefix it with an underscore: `_b`
error: unused variable: `a`
- --> $DIR/naked-functions-unused.rs:24:38
+ --> $DIR/naked-functions-unused.rs:25:38
|
LL | pub extern "C" fn associated(a: usize, b: usize) -> usize {
| ^ help: if this is intentional, prefix it with an underscore: `_a`
error: unused variable: `b`
- --> $DIR/naked-functions-unused.rs:24:48
+ --> $DIR/naked-functions-unused.rs:25:48
|
LL | pub extern "C" fn associated(a: usize, b: usize) -> usize {
| ^ help: if this is intentional, prefix it with an underscore: `_b`
error: unused variable: `a`
- --> $DIR/naked-functions-unused.rs:30:41
+ --> $DIR/naked-functions-unused.rs:31:41
|
LL | pub extern "C" fn method(&self, a: usize, b: usize) -> usize {
| ^ help: if this is intentional, prefix it with an underscore: `_a`
error: unused variable: `b`
- --> $DIR/naked-functions-unused.rs:30:51
+ --> $DIR/naked-functions-unused.rs:31:51
|
LL | pub extern "C" fn method(&self, a: usize, b: usize) -> usize {
| ^ help: if this is intentional, prefix it with an underscore: `_b`
error: unused variable: `a`
- --> $DIR/naked-functions-unused.rs:38:40
+ --> $DIR/naked-functions-unused.rs:39:40
|
LL | extern "C" fn trait_associated(a: usize, b: usize) -> usize {
| ^ help: if this is intentional, prefix it with an underscore: `_a`
error: unused variable: `b`
- --> $DIR/naked-functions-unused.rs:38:50
+ --> $DIR/naked-functions-unused.rs:39:50
|
LL | extern "C" fn trait_associated(a: usize, b: usize) -> usize {
| ^ help: if this is intentional, prefix it with an underscore: `_b`
error: unused variable: `a`
- --> $DIR/naked-functions-unused.rs:44:43
+ --> $DIR/naked-functions-unused.rs:45:43
|
LL | extern "C" fn trait_method(&self, a: usize, b: usize) -> usize {
| ^ help: if this is intentional, prefix it with an underscore: `_a`
error: unused variable: `b`
- --> $DIR/naked-functions-unused.rs:44:53
+ --> $DIR/naked-functions-unused.rs:45:53
|
LL | extern "C" fn trait_method(&self, a: usize, b: usize) -> usize {
| ^ help: if this is intentional, prefix it with an underscore: `_b`
diff --git a/src/test/ui/asm/naked-functions-unused.rs b/src/test/ui/asm/naked-functions-unused.rs
index 4c5c2ac1c19..4360d9addf0 100644
--- a/src/test/ui/asm/naked-functions-unused.rs
+++ b/src/test/ui/asm/naked-functions-unused.rs
@@ -2,7 +2,6 @@
//[x86_64] only-x86_64
//[aarch64] only-aarch64
#![deny(unused)]
-#![feature(asm)]
#![feature(naked_functions)]
#![crate_type = "lib"]
@@ -12,6 +11,8 @@ pub trait Trait {
}
pub mod normal {
+ use std::arch::asm;
+
pub extern "C" fn function(a: usize, b: usize) -> usize {
//~^ ERROR unused variable: `a`
//~| ERROR unused variable: `b`
@@ -50,6 +51,8 @@ pub mod normal {
}
pub mod naked {
+ use std::arch::asm;
+
#[naked]
pub extern "C" fn function(a: usize, b: usize) -> usize {
unsafe { asm!("", options(noreturn)); }
diff --git a/src/test/ui/asm/naked-functions-unused.x86_64.stderr b/src/test/ui/asm/naked-functions-unused.x86_64.stderr
index a898ab19a73..cf4a1d9174e 100644
--- a/src/test/ui/asm/naked-functions-unused.x86_64.stderr
+++ b/src/test/ui/asm/naked-functions-unused.x86_64.stderr
@@ -1,5 +1,5 @@
error: unused variable: `a`
- --> $DIR/naked-functions-unused.rs:15:32
+ --> $DIR/naked-functions-unused.rs:16:32
|
LL | pub extern "C" fn function(a: usize, b: usize) -> usize {
| ^ help: if this is intentional, prefix it with an underscore: `_a`
@@ -12,55 +12,55 @@ LL | #![deny(unused)]
= note: `#[deny(unused_variables)]` implied by `#[deny(unused)]`
error: unused variable: `b`
- --> $DIR/naked-functions-unused.rs:15:42
+ --> $DIR/naked-functions-unused.rs:16:42
|
LL | pub extern "C" fn function(a: usize, b: usize) -> usize {
| ^ help: if this is intentional, prefix it with an underscore: `_b`
error: unused variable: `a`
- --> $DIR/naked-functions-unused.rs:24:38
+ --> $DIR/naked-functions-unused.rs:25:38
|
LL | pub extern "C" fn associated(a: usize, b: usize) -> usize {
| ^ help: if this is intentional, prefix it with an underscore: `_a`
error: unused variable: `b`
- --> $DIR/naked-functions-unused.rs:24:48
+ --> $DIR/naked-functions-unused.rs:25:48
|
LL | pub extern "C" fn associated(a: usize, b: usize) -> usize {
| ^ help: if this is intentional, prefix it with an underscore: `_b`
error: unused variable: `a`
- --> $DIR/naked-functions-unused.rs:30:41
+ --> $DIR/naked-functions-unused.rs:31:41
|
LL | pub extern "C" fn method(&self, a: usize, b: usize) -> usize {
| ^ help: if this is intentional, prefix it with an underscore: `_a`
error: unused variable: `b`
- --> $DIR/naked-functions-unused.rs:30:51
+ --> $DIR/naked-functions-unused.rs:31:51
|
LL | pub extern "C" fn method(&self, a: usize, b: usize) -> usize {
| ^ help: if this is intentional, prefix it with an underscore: `_b`
error: unused variable: `a`
- --> $DIR/naked-functions-unused.rs:38:40
+ --> $DIR/naked-functions-unused.rs:39:40
|
LL | extern "C" fn trait_associated(a: usize, b: usize) -> usize {
| ^ help: if this is intentional, prefix it with an underscore: `_a`
error: unused variable: `b`
- --> $DIR/naked-functions-unused.rs:38:50
+ --> $DIR/naked-functions-unused.rs:39:50
|
LL | extern "C" fn trait_associated(a: usize, b: usize) -> usize {
| ^ help: if this is intentional, prefix it with an underscore: `_b`
error: unused variable: `a`
- --> $DIR/naked-functions-unused.rs:44:43
+ --> $DIR/naked-functions-unused.rs:45:43
|
LL | extern "C" fn trait_method(&self, a: usize, b: usize) -> usize {
| ^ help: if this is intentional, prefix it with an underscore: `_a`
error: unused variable: `b`
- --> $DIR/naked-functions-unused.rs:44:53
+ --> $DIR/naked-functions-unused.rs:45:53
|
LL | extern "C" fn trait_method(&self, a: usize, b: usize) -> usize {
| ^ help: if this is intentional, prefix it with an underscore: `_b`
diff --git a/src/test/ui/asm/naked-functions.rs b/src/test/ui/asm/naked-functions.rs
index 7154ce26efc..b44204b9005 100644
--- a/src/test/ui/asm/naked-functions.rs
+++ b/src/test/ui/asm/naked-functions.rs
@@ -3,7 +3,6 @@
// ignore-spirv
// ignore-wasm32
-#![feature(asm)]
#![feature(llvm_asm)]
#![feature(naked_functions)]
#![feature(or_patterns)]
@@ -11,6 +10,8 @@
#![crate_type = "lib"]
#![allow(deprecated)] // llvm_asm!
+use std::arch::asm;
+
#[repr(C)]
pub struct P {
x: u8,
diff --git a/src/test/ui/asm/naked-functions.stderr b/src/test/ui/asm/naked-functions.stderr
index e4ddb97ca27..8e177f5a52c 100644
--- a/src/test/ui/asm/naked-functions.stderr
+++ b/src/test/ui/asm/naked-functions.stderr
@@ -1,35 +1,35 @@
error: asm with the `pure` option must have at least one output
- --> $DIR/naked-functions.rs:135:14
+ --> $DIR/naked-functions.rs:136:14
|
LL | asm!("", options(readonly, nostack), options(pure));
| ^^^^^^^^^^^^^^^^^^^^^^^^^^ ^^^^^^^^^^^^^
error: patterns not allowed in naked function parameters
- --> $DIR/naked-functions.rs:22:5
+ --> $DIR/naked-functions.rs:23:5
|
LL | mut a: u32,
| ^^^^^
error: patterns not allowed in naked function parameters
- --> $DIR/naked-functions.rs:24:5
+ --> $DIR/naked-functions.rs:25:5
|
LL | &b: &i32,
| ^^
error: patterns not allowed in naked function parameters
- --> $DIR/naked-functions.rs:26:6
+ --> $DIR/naked-functions.rs:27:6
|
LL | (None | Some(_)): Option<std::ptr::NonNull<u8>>,
| ^^^^^^^^^^^^^^
error: patterns not allowed in naked function parameters
- --> $DIR/naked-functions.rs:28:5
+ --> $DIR/naked-functions.rs:29:5
|
LL | P { x, y }: P,
| ^^^^^^^^^^
error: referencing function parameters is not allowed in naked functions
- --> $DIR/naked-functions.rs:38:5
+ --> $DIR/naked-functions.rs:39:5
|
LL | a + 1
| ^
@@ -37,7 +37,7 @@ LL | a + 1
= help: follow the calling convention in asm block to use parameters
warning: naked functions must contain a single asm block
- --> $DIR/naked-functions.rs:35:1
+ --> $DIR/naked-functions.rs:36:1
|
LL | / pub unsafe extern "C" fn inc(a: u32) -> u32 {
LL | |
@@ -53,7 +53,7 @@ LL | | }
= note: for more information, see issue #32408 <https://github.com/rust-lang/rust/issues/32408>
error: referencing function parameters is not allowed in naked functions
- --> $DIR/naked-functions.rs:44:31
+ --> $DIR/naked-functions.rs:45:31
|
LL | asm!("/* {0} */", in(reg) a, options(noreturn));
| ^
@@ -61,7 +61,7 @@ LL | asm!("/* {0} */", in(reg) a, options(noreturn));
= help: follow the calling convention in asm block to use parameters
warning: only `const` and `sym` operands are supported in naked functions
- --> $DIR/naked-functions.rs:44:23
+ --> $DIR/naked-functions.rs:45:23
|
LL | asm!("/* {0} */", in(reg) a, options(noreturn));
| ^^^^^^^^^
@@ -70,7 +70,7 @@ LL | asm!("/* {0} */", in(reg) a, options(noreturn));
= note: for more information, see issue #32408 <https://github.com/rust-lang/rust/issues/32408>
warning: naked functions must contain a single asm block
- --> $DIR/naked-functions.rs:51:1
+ --> $DIR/naked-functions.rs:52:1
|
LL | / pub unsafe extern "C" fn inc_closure(a: u32) -> u32 {
LL | |
@@ -84,7 +84,7 @@ LL | | }
= note: for more information, see issue #32408 <https://github.com/rust-lang/rust/issues/32408>
warning: only `const` and `sym` operands are supported in naked functions
- --> $DIR/naked-functions.rs:71:10
+ --> $DIR/naked-functions.rs:72:10
|
LL | in(reg) a,
| ^^^^^^^^^
@@ -102,7 +102,7 @@ LL | out(reg) e,
= note: for more information, see issue #32408 <https://github.com/rust-lang/rust/issues/32408>
warning: asm in naked functions must use `noreturn` option
- --> $DIR/naked-functions.rs:68:5
+ --> $DIR/naked-functions.rs:69:5
|
LL | / asm!("/* {0} {1} {2} {3} {4} {5} {6} */",
LL | |
@@ -117,7 +117,7 @@ LL | | );
= note: for more information, see issue #32408 <https://github.com/rust-lang/rust/issues/32408>
warning: naked functions must contain a single asm block
- --> $DIR/naked-functions.rs:58:1
+ --> $DIR/naked-functions.rs:59:1
|
LL | / pub unsafe extern "C" fn unsupported_operands() {
LL | |
@@ -141,7 +141,7 @@ LL | | }
= note: for more information, see issue #32408 <https://github.com/rust-lang/rust/issues/32408>
warning: naked functions must contain a single asm block
- --> $DIR/naked-functions.rs:84:1
+ --> $DIR/naked-functions.rs:85:1
|
LL | / pub extern "C" fn missing_assembly() {
LL | |
@@ -153,7 +153,7 @@ LL | | }
= note: for more information, see issue #32408 <https://github.com/rust-lang/rust/issues/32408>
warning: asm in naked functions must use `noreturn` option
- --> $DIR/naked-functions.rs:93:5
+ --> $DIR/naked-functions.rs:94:5
|
LL | asm!("");
| ^^^^^^^^
@@ -162,7 +162,7 @@ LL | asm!("");
= note: for more information, see issue #32408 <https://github.com/rust-lang/rust/issues/32408>
warning: asm in naked functions must use `noreturn` option
- --> $DIR/naked-functions.rs:96:5
+ --> $DIR/naked-functions.rs:97:5
|
LL | asm!("");
| ^^^^^^^^
@@ -171,7 +171,7 @@ LL | asm!("");
= note: for more information, see issue #32408 <https://github.com/rust-lang/rust/issues/32408>
warning: asm in naked functions must use `noreturn` option
- --> $DIR/naked-functions.rs:99:5
+ --> $DIR/naked-functions.rs:100:5
|
LL | asm!("");
| ^^^^^^^^
@@ -180,7 +180,7 @@ LL | asm!("");
= note: for more information, see issue #32408 <https://github.com/rust-lang/rust/issues/32408>
warning: naked functions must contain a single asm block
- --> $DIR/naked-functions.rs:90:1
+ --> $DIR/naked-functions.rs:91:1
|
LL | / pub extern "C" fn too_many_asm_blocks() {
LL | |
@@ -202,7 +202,7 @@ LL | | }
= note: for more information, see issue #32408 <https://github.com/rust-lang/rust/issues/32408>
error: referencing function parameters is not allowed in naked functions
- --> $DIR/naked-functions.rs:110:11
+ --> $DIR/naked-functions.rs:111:11
|
LL | *&y
| ^
@@ -210,7 +210,7 @@ LL | *&y
= help: follow the calling convention in asm block to use parameters
warning: naked functions must contain a single asm block
- --> $DIR/naked-functions.rs:107:5
+ --> $DIR/naked-functions.rs:108:5
|
LL | / pub extern "C" fn inner(y: usize) -> usize {
LL | |
@@ -225,7 +225,7 @@ LL | | }
= note: for more information, see issue #32408 <https://github.com/rust-lang/rust/issues/32408>
warning: the LLVM-style inline assembly is unsupported in naked functions
- --> $DIR/naked-functions.rs:120:5
+ --> $DIR/naked-functions.rs:121:5
|
LL | llvm_asm!("");
| ^^^^^^^^^^^^^
@@ -236,7 +236,7 @@ LL | llvm_asm!("");
= note: this warning originates in the macro `llvm_asm` (in Nightly builds, run with -Z macro-backtrace for more info)
warning: naked functions must contain a single asm block
- --> $DIR/naked-functions.rs:117:1
+ --> $DIR/naked-functions.rs:118:1
|
LL | / unsafe extern "C" fn llvm() -> ! {
LL | |
@@ -252,7 +252,7 @@ LL | | }
= note: for more information, see issue #32408 <https://github.com/rust-lang/rust/issues/32408>
warning: asm options unsupported in naked functions: `nomem`, `preserves_flags`
- --> $DIR/naked-functions.rs:128:5
+ --> $DIR/naked-functions.rs:129:5
|
LL | asm!("", options(nomem, preserves_flags, noreturn));
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -261,7 +261,7 @@ LL | asm!("", options(nomem, preserves_flags, noreturn));
= note: for more information, see issue #32408 <https://github.com/rust-lang/rust/issues/32408>
warning: asm options unsupported in naked functions: `nostack`, `pure`, `readonly`
- --> $DIR/naked-functions.rs:135:5
+ --> $DIR/naked-functions.rs:136:5
|
LL | asm!("", options(readonly, nostack), options(pure));
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -270,7 +270,7 @@ LL | asm!("", options(readonly, nostack), options(pure));
= note: for more information, see issue #32408 <https://github.com/rust-lang/rust/issues/32408>
warning: asm in naked functions must use `noreturn` option
- --> $DIR/naked-functions.rs:135:5
+ --> $DIR/naked-functions.rs:136:5
|
LL | asm!("", options(readonly, nostack), options(pure));
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -279,7 +279,7 @@ LL | asm!("", options(readonly, nostack), options(pure));
= note: for more information, see issue #32408 <https://github.com/rust-lang/rust/issues/32408>
warning: Rust ABI is unsupported in naked functions
- --> $DIR/naked-functions.rs:144:15
+ --> $DIR/naked-functions.rs:145:15
|
LL | pub unsafe fn default_abi() {
| ^^^^^^^^^^^
@@ -287,13 +287,13 @@ LL | pub unsafe fn default_abi() {
= note: `#[warn(undefined_naked_function_abi)]` on by default
warning: Rust ABI is unsupported in naked functions
- --> $DIR/naked-functions.rs:150:15
+ --> $DIR/naked-functions.rs:151:15
|
LL | pub unsafe fn rust_abi() {
| ^^^^^^^^
warning: naked functions cannot be inlined
- --> $DIR/naked-functions.rs:190:1
+ --> $DIR/naked-functions.rs:191:1
|
LL | #[inline]
| ^^^^^^^^^
@@ -302,7 +302,7 @@ LL | #[inline]
= note: for more information, see issue #32408 <https://github.com/rust-lang/rust/issues/32408>
warning: naked functions cannot be inlined
- --> $DIR/naked-functions.rs:198:1
+ --> $DIR/naked-functions.rs:199:1
|
LL | #[inline(always)]
| ^^^^^^^^^^^^^^^^^
@@ -311,7 +311,7 @@ LL | #[inline(always)]
= note: for more information, see issue #32408 <https://github.com/rust-lang/rust/issues/32408>
warning: naked functions cannot be inlined
- --> $DIR/naked-functions.rs:206:1
+ --> $DIR/naked-functions.rs:207:1
|
LL | #[inline(never)]
| ^^^^^^^^^^^^^^^^
@@ -320,7 +320,7 @@ LL | #[inline(never)]
= note: for more information, see issue #32408 <https://github.com/rust-lang/rust/issues/32408>
warning: naked functions cannot be inlined
- --> $DIR/naked-functions.rs:214:1
+ --> $DIR/naked-functions.rs:215:1
|
LL | #[inline]
| ^^^^^^^^^
@@ -329,7 +329,7 @@ LL | #[inline]
= note: for more information, see issue #32408 <https://github.com/rust-lang/rust/issues/32408>
warning: naked functions cannot be inlined
- --> $DIR/naked-functions.rs:217:1
+ --> $DIR/naked-functions.rs:218:1
|
LL | #[inline(always)]
| ^^^^^^^^^^^^^^^^^
@@ -338,7 +338,7 @@ LL | #[inline(always)]
= note: for more information, see issue #32408 <https://github.com/rust-lang/rust/issues/32408>
warning: naked functions cannot be inlined
- --> $DIR/naked-functions.rs:220:1
+ --> $DIR/naked-functions.rs:221:1
|
LL | #[inline(never)]
| ^^^^^^^^^^^^^^^^
diff --git a/src/test/ui/asm/naked-invalid-attr.rs b/src/test/ui/asm/naked-invalid-attr.rs
index 2576d1124c8..ea8f560ff5d 100644
--- a/src/test/ui/asm/naked-invalid-attr.rs
+++ b/src/test/ui/asm/naked-invalid-attr.rs
@@ -1,10 +1,11 @@
// Checks that #[naked] attribute can be placed on function definitions only.
//
// needs-asm-support
-#![feature(asm)]
#![feature(naked_functions)]
#![naked] //~ ERROR should be applied to a function definition
+use std::arch::asm;
+
extern "C" {
#[naked] //~ ERROR should be applied to a function definition
fn f();
diff --git a/src/test/ui/asm/naked-invalid-attr.stderr b/src/test/ui/asm/naked-invalid-attr.stderr
index 565c2986a66..58344be9334 100644
--- a/src/test/ui/asm/naked-invalid-attr.stderr
+++ b/src/test/ui/asm/naked-invalid-attr.stderr
@@ -1,5 +1,5 @@
error: attribute should be applied to a function definition
- --> $DIR/naked-invalid-attr.rs:13:1
+ --> $DIR/naked-invalid-attr.rs:14:1
|
LL | #[naked]
| ^^^^^^^^
@@ -11,13 +11,13 @@ LL | | }
| |_- not a function definition
error: attribute should be applied to a function definition
- --> $DIR/naked-invalid-attr.rs:50:5
+ --> $DIR/naked-invalid-attr.rs:51:5
|
LL | #[naked] || {};
| ^^^^^^^^ ----- not a function definition
error: attribute should be applied to a function definition
- --> $DIR/naked-invalid-attr.rs:21:5
+ --> $DIR/naked-invalid-attr.rs:22:5
|
LL | #[naked]
| ^^^^^^^^
@@ -25,7 +25,7 @@ LL | extern "C" fn invoke(&self);
| ---------------------------- not a function definition
error: attribute should be applied to a function definition
- --> $DIR/naked-invalid-attr.rs:9:5
+ --> $DIR/naked-invalid-attr.rs:10:5
|
LL | #[naked]
| ^^^^^^^^
@@ -33,7 +33,7 @@ LL | fn f();
| ------- not a function definition
error: attribute should be applied to a function definition
- --> $DIR/naked-invalid-attr.rs:6:1
+ --> $DIR/naked-invalid-attr.rs:5:1
|
LL | #![naked]
| ^^^^^^^^^
diff --git a/src/test/ui/asm/named-asm-labels.rs b/src/test/ui/asm/named-asm-labels.rs
index c87188e46a2..160dbf617c4 100644
--- a/src/test/ui/asm/named-asm-labels.rs
+++ b/src/test/ui/asm/named-asm-labels.rs
@@ -11,7 +11,9 @@
// which causes less readable LLVM errors and in the worst cases causes ICEs
// or segfaults based on system dependent behavior and codegen flags.
-#![feature(asm, global_asm, naked_functions, asm_const)]
+#![feature(naked_functions, asm_const)]
+
+use std::arch::{asm, global_asm};
#[no_mangle]
pub static FOO: usize = 42;
diff --git a/src/test/ui/asm/named-asm-labels.stderr b/src/test/ui/asm/named-asm-labels.stderr
index 75c848cdc57..b8ff42d86b5 100644
--- a/src/test/ui/asm/named-asm-labels.stderr
+++ b/src/test/ui/asm/named-asm-labels.stderr
@@ -1,141 +1,126 @@
error: avoid using named labels in inline assembly
- --> $DIR/named-asm-labels.rs:22:15
+ --> $DIR/named-asm-labels.rs:24:15
|
LL | asm!("bar: nop");
| ^^^
|
= note: `#[deny(named_asm_labels)]` on by default
= help: only local labels of the form `<number>:` should be used in inline asm
- = note: see the asm section of the unstable book <https://doc.rust-lang.org/nightly/unstable-book/library-features/asm.html#labels> for more information
error: avoid using named labels in inline assembly
- --> $DIR/named-asm-labels.rs:25:15
+ --> $DIR/named-asm-labels.rs:27:15
|
LL | asm!("abcd:");
| ^^^^
|
= help: only local labels of the form `<number>:` should be used in inline asm
- = note: see the asm section of the unstable book <https://doc.rust-lang.org/nightly/unstable-book/library-features/asm.html#labels> for more information
error: avoid using named labels in inline assembly
- --> $DIR/named-asm-labels.rs:28:15
+ --> $DIR/named-asm-labels.rs:30:15
|
LL | asm!("foo: bar1: nop");
| ^^^ ^^^^
|
= help: only local labels of the form `<number>:` should be used in inline asm
- = note: see the asm section of the unstable book <https://doc.rust-lang.org/nightly/unstable-book/library-features/asm.html#labels> for more information
error: avoid using named labels in inline assembly
- --> $DIR/named-asm-labels.rs:32:15
+ --> $DIR/named-asm-labels.rs:34:15
|
LL | asm!("foo1: nop", "nop");
| ^^^^
|
= help: only local labels of the form `<number>:` should be used in inline asm
- = note: see the asm section of the unstable book <https://doc.rust-lang.org/nightly/unstable-book/library-features/asm.html#labels> for more information
error: avoid using named labels in inline assembly
- --> $DIR/named-asm-labels.rs:33:15
+ --> $DIR/named-asm-labels.rs:35:15
|
LL | asm!("foo2: foo3: nop", "nop");
| ^^^^ ^^^^
|
= help: only local labels of the form `<number>:` should be used in inline asm
- = note: see the asm section of the unstable book <https://doc.rust-lang.org/nightly/unstable-book/library-features/asm.html#labels> for more information
error: avoid using named labels in inline assembly
- --> $DIR/named-asm-labels.rs:35:22
+ --> $DIR/named-asm-labels.rs:37:22
|
LL | asm!("nop", "foo4: nop");
| ^^^^
|
= help: only local labels of the form `<number>:` should be used in inline asm
- = note: see the asm section of the unstable book <https://doc.rust-lang.org/nightly/unstable-book/library-features/asm.html#labels> for more information
error: avoid using named labels in inline assembly
- --> $DIR/named-asm-labels.rs:36:15
+ --> $DIR/named-asm-labels.rs:38:15
|
LL | asm!("foo5: nop", "foo6: nop");
| ^^^^
|
= help: only local labels of the form `<number>:` should be used in inline asm
- = note: see the asm section of the unstable book <https://doc.rust-lang.org/nightly/unstable-book/library-features/asm.html#labels> for more information
error: avoid using named labels in inline assembly
- --> $DIR/named-asm-labels.rs:36:28
+ --> $DIR/named-asm-labels.rs:38:28
|
LL | asm!("foo5: nop", "foo6: nop");
| ^^^^
|
= help: only local labels of the form `<number>:` should be used in inline asm
- = note: see the asm section of the unstable book <https://doc.rust-lang.org/nightly/unstable-book/library-features/asm.html#labels> for more information
error: avoid using named labels in inline assembly
- --> $DIR/named-asm-labels.rs:41:15
+ --> $DIR/named-asm-labels.rs:43:15
|
LL | asm!("foo7: nop; foo8: nop");
| ^^^^ ^^^^
|
= help: only local labels of the form `<number>:` should be used in inline asm
- = note: see the asm section of the unstable book <https://doc.rust-lang.org/nightly/unstable-book/library-features/asm.html#labels> for more information
error: avoid using named labels in inline assembly
- --> $DIR/named-asm-labels.rs:43:15
+ --> $DIR/named-asm-labels.rs:45:15
|
LL | asm!("foo9: nop; nop");
| ^^^^
|
= help: only local labels of the form `<number>:` should be used in inline asm
- = note: see the asm section of the unstable book <https://doc.rust-lang.org/nightly/unstable-book/library-features/asm.html#labels> for more information
error: avoid using named labels in inline assembly
- --> $DIR/named-asm-labels.rs:44:20
+ --> $DIR/named-asm-labels.rs:46:20
|
LL | asm!("nop; foo10: nop");
| ^^^^^
|
= help: only local labels of the form `<number>:` should be used in inline asm
- = note: see the asm section of the unstable book <https://doc.rust-lang.org/nightly/unstable-book/library-features/asm.html#labels> for more information
error: avoid using named labels in inline assembly
- --> $DIR/named-asm-labels.rs:47:15
+ --> $DIR/named-asm-labels.rs:49:15
|
LL | asm!("bar2: nop\n bar3: nop");
| ^^^^ ^^^^
|
= help: only local labels of the form `<number>:` should be used in inline asm
- = note: see the asm section of the unstable book <https://doc.rust-lang.org/nightly/unstable-book/library-features/asm.html#labels> for more information
error: avoid using named labels in inline assembly
- --> $DIR/named-asm-labels.rs:49:15
+ --> $DIR/named-asm-labels.rs:51:15
|
LL | asm!("bar4: nop\n nop");
| ^^^^
|
= help: only local labels of the form `<number>:` should be used in inline asm
- = note: see the asm section of the unstable book <https://doc.rust-lang.org/nightly/unstable-book/library-features/asm.html#labels> for more information
error: avoid using named labels in inline assembly
- --> $DIR/named-asm-labels.rs:50:21
+ --> $DIR/named-asm-labels.rs:52:21
|
LL | asm!("nop\n bar5: nop");
| ^^^^
|
= help: only local labels of the form `<number>:` should be used in inline asm
- = note: see the asm section of the unstable book <https://doc.rust-lang.org/nightly/unstable-book/library-features/asm.html#labels> for more information
error: avoid using named labels in inline assembly
- --> $DIR/named-asm-labels.rs:51:21
+ --> $DIR/named-asm-labels.rs:53:21
|
LL | asm!("nop\n bar6: bar7: nop");
| ^^^^ ^^^^
|
= help: only local labels of the form `<number>:` should be used in inline asm
- = note: see the asm section of the unstable book <https://doc.rust-lang.org/nightly/unstable-book/library-features/asm.html#labels> for more information
error: avoid using named labels in inline assembly
- --> $DIR/named-asm-labels.rs:57:13
+ --> $DIR/named-asm-labels.rs:59:13
|
LL | blah2: nop
| ^^^^^
@@ -143,192 +128,171 @@ LL | blah3: nop
| ^^^^^
|
= help: only local labels of the form `<number>:` should be used in inline asm
- = note: see the asm section of the unstable book <https://doc.rust-lang.org/nightly/unstable-book/library-features/asm.html#labels> for more information
error: avoid using named labels in inline assembly
- --> $DIR/named-asm-labels.rs:66:19
+ --> $DIR/named-asm-labels.rs:68:19
|
LL | nop ; blah4: nop
| ^^^^^
|
= help: only local labels of the form `<number>:` should be used in inline asm
- = note: see the asm section of the unstable book <https://doc.rust-lang.org/nightly/unstable-book/library-features/asm.html#labels> for more information
error: avoid using named labels in inline assembly
- --> $DIR/named-asm-labels.rs:80:15
+ --> $DIR/named-asm-labels.rs:82:15
|
LL | asm!("blah1: 2bar: nop");
| ^^^^^
|
= help: only local labels of the form `<number>:` should be used in inline asm
- = note: see the asm section of the unstable book <https://doc.rust-lang.org/nightly/unstable-book/library-features/asm.html#labels> for more information
error: avoid using named labels in inline assembly
- --> $DIR/named-asm-labels.rs:83:15
+ --> $DIR/named-asm-labels.rs:85:15
|
LL | asm!("def: def: nop");
| ^^^
|
= help: only local labels of the form `<number>:` should be used in inline asm
- = note: see the asm section of the unstable book <https://doc.rust-lang.org/nightly/unstable-book/library-features/asm.html#labels> for more information
error: avoid using named labels in inline assembly
- --> $DIR/named-asm-labels.rs:84:15
+ --> $DIR/named-asm-labels.rs:86:15
|
LL | asm!("def: nop\ndef: nop");
| ^^^
|
= help: only local labels of the form `<number>:` should be used in inline asm
- = note: see the asm section of the unstable book <https://doc.rust-lang.org/nightly/unstable-book/library-features/asm.html#labels> for more information
error: avoid using named labels in inline assembly
- --> $DIR/named-asm-labels.rs:85:15
+ --> $DIR/named-asm-labels.rs:87:15
|
LL | asm!("def: nop; def: nop");
| ^^^
|
= help: only local labels of the form `<number>:` should be used in inline asm
- = note: see the asm section of the unstable book <https://doc.rust-lang.org/nightly/unstable-book/library-features/asm.html#labels> for more information
error: avoid using named labels in inline assembly
- --> $DIR/named-asm-labels.rs:93:15
+ --> $DIR/named-asm-labels.rs:95:15
|
LL | asm!("fooo\u{003A} nop");
| ^^^^^^^^^^^^^^^^
|
= help: only local labels of the form `<number>:` should be used in inline asm
- = note: see the asm section of the unstable book <https://doc.rust-lang.org/nightly/unstable-book/library-features/asm.html#labels> for more information
error: avoid using named labels in inline assembly
- --> $DIR/named-asm-labels.rs:94:15
+ --> $DIR/named-asm-labels.rs:96:15
|
LL | asm!("foooo\x3A nop");
| ^^^^^^^^^^^^^
|
= help: only local labels of the form `<number>:` should be used in inline asm
- = note: see the asm section of the unstable book <https://doc.rust-lang.org/nightly/unstable-book/library-features/asm.html#labels> for more information
error: avoid using named labels in inline assembly
- --> $DIR/named-asm-labels.rs:97:15
+ --> $DIR/named-asm-labels.rs:99:15
|
LL | asm!("fooooo:\u{000A} nop");
| ^^^^^^
|
= help: only local labels of the form `<number>:` should be used in inline asm
- = note: see the asm section of the unstable book <https://doc.rust-lang.org/nightly/unstable-book/library-features/asm.html#labels> for more information
error: avoid using named labels in inline assembly
- --> $DIR/named-asm-labels.rs:98:15
+ --> $DIR/named-asm-labels.rs:100:15
|
LL | asm!("foooooo:\x0A nop");
| ^^^^^^^
|
= help: only local labels of the form `<number>:` should be used in inline asm
- = note: see the asm section of the unstable book <https://doc.rust-lang.org/nightly/unstable-book/library-features/asm.html#labels> for more information
error: avoid using named labels in inline assembly
- --> $DIR/named-asm-labels.rs:102:14
+ --> $DIR/named-asm-labels.rs:104:14
|
LL | asm!("\x41\x42\x43\x3A\x20\x6E\x6F\x70");
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
= help: only local labels of the form `<number>:` should be used in inline asm
- = note: see the asm section of the unstable book <https://doc.rust-lang.org/nightly/unstable-book/library-features/asm.html#labels> for more information
error: avoid using named labels in inline assembly
- --> $DIR/named-asm-labels.rs:110:13
+ --> $DIR/named-asm-labels.rs:112:13
|
LL | ab: nop // ab: does foo
| ^^
|
= help: only local labels of the form `<number>:` should be used in inline asm
- = note: see the asm section of the unstable book <https://doc.rust-lang.org/nightly/unstable-book/library-features/asm.html#labels> for more information
error: avoid using named labels in inline assembly
- --> $DIR/named-asm-labels.rs:122:14
+ --> $DIR/named-asm-labels.rs:124:14
|
LL | asm!(include_str!("named-asm-labels.s"));
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
= help: only local labels of the form `<number>:` should be used in inline asm
- = note: see the asm section of the unstable book <https://doc.rust-lang.org/nightly/unstable-book/library-features/asm.html#labels> for more information
warning: avoid using named labels in inline assembly
- --> $DIR/named-asm-labels.rs:132:19
+ --> $DIR/named-asm-labels.rs:134:19
|
LL | asm!("warned: nop");
| ^^^^^^
|
note: the lint level is defined here
- --> $DIR/named-asm-labels.rs:130:16
+ --> $DIR/named-asm-labels.rs:132:16
|
LL | #[warn(named_asm_labels)]
| ^^^^^^^^^^^^^^^^
= help: only local labels of the form `<number>:` should be used in inline asm
- = note: see the asm section of the unstable book <https://doc.rust-lang.org/nightly/unstable-book/library-features/asm.html#labels> for more information
error: avoid using named labels in inline assembly
- --> $DIR/named-asm-labels.rs:141:20
+ --> $DIR/named-asm-labels.rs:143:20
|
LL | unsafe { asm!(".Lfoo: mov rax, {}; ret;", "nop", const 1, options(noreturn)) }
| ^^^^^
|
= help: only local labels of the form `<number>:` should be used in inline asm
- = note: see the asm section of the unstable book <https://doc.rust-lang.org/nightly/unstable-book/library-features/asm.html#labels> for more information
error: avoid using named labels in inline assembly
- --> $DIR/named-asm-labels.rs:147:20
+ --> $DIR/named-asm-labels.rs:149:20
|
LL | unsafe { asm!(".Lbar: mov rax, {}; ret;", "nop", const 1, options(noreturn)) }
| ^^^^^
|
= help: only local labels of the form `<number>:` should be used in inline asm
- = note: see the asm section of the unstable book <https://doc.rust-lang.org/nightly/unstable-book/library-features/asm.html#labels> for more information
error: avoid using named labels in inline assembly
- --> $DIR/named-asm-labels.rs:155:20
+ --> $DIR/named-asm-labels.rs:157:20
|
LL | unsafe { asm!(".Laaa: nop; ret;", options(noreturn)) }
| ^^^^^
|
= help: only local labels of the form `<number>:` should be used in inline asm
- = note: see the asm section of the unstable book <https://doc.rust-lang.org/nightly/unstable-book/library-features/asm.html#labels> for more information
error: avoid using named labels in inline assembly
- --> $DIR/named-asm-labels.rs:165:24
+ --> $DIR/named-asm-labels.rs:167:24
|
LL | unsafe { asm!(".Lbbb: nop; ret;", options(noreturn)) }
| ^^^^^
|
= help: only local labels of the form `<number>:` should be used in inline asm
- = note: see the asm section of the unstable book <https://doc.rust-lang.org/nightly/unstable-book/library-features/asm.html#labels> for more information
error: avoid using named labels in inline assembly
- --> $DIR/named-asm-labels.rs:174:15
+ --> $DIR/named-asm-labels.rs:176:15
|
LL | asm!("closure1: nop");
| ^^^^^^^^
|
= help: only local labels of the form `<number>:` should be used in inline asm
- = note: see the asm section of the unstable book <https://doc.rust-lang.org/nightly/unstable-book/library-features/asm.html#labels> for more information
error: avoid using named labels in inline assembly
- --> $DIR/named-asm-labels.rs:178:15
+ --> $DIR/named-asm-labels.rs:180:15
|
LL | asm!("closure2: nop");
| ^^^^^^^^
|
= help: only local labels of the form `<number>:` should be used in inline asm
- = note: see the asm section of the unstable book <https://doc.rust-lang.org/nightly/unstable-book/library-features/asm.html#labels> for more information
error: avoid using named labels in inline assembly
- --> $DIR/named-asm-labels.rs:188:19
+ --> $DIR/named-asm-labels.rs:190:19
|
LL | asm!("closure3: nop");
| ^^^^^^^^
|
= help: only local labels of the form `<number>:` should be used in inline asm
- = note: see the asm section of the unstable book <https://doc.rust-lang.org/nightly/unstable-book/library-features/asm.html#labels> for more information
error: aborting due to 35 previous errors; 1 warning emitted
diff --git a/src/test/ui/asm/noreturn.rs b/src/test/ui/asm/noreturn.rs
index cb92ff0ad1d..03fa087ae37 100644
--- a/src/test/ui/asm/noreturn.rs
+++ b/src/test/ui/asm/noreturn.rs
@@ -1,9 +1,11 @@
// needs-asm-support
// check-pass
-#![feature(asm, never_type)]
+#![feature(never_type)]
#![crate_type = "rlib"]
+use std::arch::asm;
+
pub unsafe fn asm1() {
let _: () = asm!("");
}
diff --git a/src/test/ui/asm/rustfix-asm.fixed b/src/test/ui/asm/rustfix-asm.fixed
deleted file mode 100644
index 1d5d2038aa8..00000000000
--- a/src/test/ui/asm/rustfix-asm.fixed
+++ /dev/null
@@ -1,17 +0,0 @@
-// run-rustfix
-// needs-asm-support
-
-#![feature(asm, llvm_asm)]
-#![allow(deprecated)] // llvm_asm!
-
-fn main() {
- unsafe {
- let x = 1;
- let y: i32;
- llvm_asm!("" :: "r" (x));
- //~^ ERROR the legacy LLVM-style asm! syntax is no longer supported
- llvm_asm!("" : "=r" (y));
- //~^ ERROR the legacy LLVM-style asm! syntax is no longer supported
- let _ = y;
- }
-}
diff --git a/src/test/ui/asm/rustfix-asm.rs b/src/test/ui/asm/rustfix-asm.rs
deleted file mode 100644
index 12be0e666ee..00000000000
--- a/src/test/ui/asm/rustfix-asm.rs
+++ /dev/null
@@ -1,17 +0,0 @@
-// run-rustfix
-// needs-asm-support
-
-#![feature(asm, llvm_asm)]
-#![allow(deprecated)] // llvm_asm!
-
-fn main() {
- unsafe {
- let x = 1;
- let y: i32;
- asm!("" :: "r" (x));
- //~^ ERROR the legacy LLVM-style asm! syntax is no longer supported
- asm!("" : "=r" (y));
- //~^ ERROR the legacy LLVM-style asm! syntax is no longer supported
- let _ = y;
- }
-}
diff --git a/src/test/ui/asm/rustfix-asm.stderr b/src/test/ui/asm/rustfix-asm.stderr
deleted file mode 100644
index babb154ccf4..00000000000
--- a/src/test/ui/asm/rustfix-asm.stderr
+++ /dev/null
@@ -1,24 +0,0 @@
-error: the legacy LLVM-style asm! syntax is no longer supported
- --> $DIR/rustfix-asm.rs:11:9
- |
-LL | asm!("" :: "r" (x));
- | ----^^^^^^^^^^^^^^^
- | |
- | help: replace with: `llvm_asm!`
- |
- = note: consider migrating to the new asm! syntax specified in RFC 2873
- = note: alternatively, switch to llvm_asm! to keep your code working as it is
-
-error: the legacy LLVM-style asm! syntax is no longer supported
- --> $DIR/rustfix-asm.rs:13:9
- |
-LL | asm!("" : "=r" (y));
- | ----^^^^^^^^^^^^^^^
- | |
- | help: replace with: `llvm_asm!`
- |
- = note: consider migrating to the new asm! syntax specified in RFC 2873
- = note: alternatively, switch to llvm_asm! to keep your code working as it is
-
-error: aborting due to 2 previous errors
-
diff --git a/src/test/ui/asm/type-check-1.rs b/src/test/ui/asm/type-check-1.rs
index 1e463107b18..695fd27efd4 100644
--- a/src/test/ui/asm/type-check-1.rs
+++ b/src/test/ui/asm/type-check-1.rs
@@ -3,7 +3,9 @@
// ignore-spirv
// ignore-wasm32
-#![feature(asm, global_asm, asm_const)]
+#![feature(asm_const)]
+
+use std::arch::{asm, global_asm};
fn main() {
unsafe {
diff --git a/src/test/ui/asm/type-check-1.stderr b/src/test/ui/asm/type-check-1.stderr
index c9080a3c030..d774c78ca9a 100644
--- a/src/test/ui/asm/type-check-1.stderr
+++ b/src/test/ui/asm/type-check-1.stderr
@@ -1,5 +1,5 @@
error[E0435]: attempt to use a non-constant value in a constant
- --> $DIR/type-check-1.rs:37:26
+ --> $DIR/type-check-1.rs:39:26
|
LL | let x = 0;
| ----- help: consider using `const` instead of `let`: `const x`
@@ -8,7 +8,7 @@ LL | asm!("{}", const x);
| ^ non-constant value
error[E0435]: attempt to use a non-constant value in a constant
- --> $DIR/type-check-1.rs:40:36
+ --> $DIR/type-check-1.rs:42:36
|
LL | let x = 0;
| ----- help: consider using `const` instead of `let`: `const x`
@@ -17,7 +17,7 @@ LL | asm!("{}", const const_foo(x));
| ^ non-constant value
error[E0435]: attempt to use a non-constant value in a constant
- --> $DIR/type-check-1.rs:43:36
+ --> $DIR/type-check-1.rs:45:36
|
LL | let x = 0;
| ----- help: consider using `const` instead of `let`: `const x`
@@ -26,13 +26,13 @@ LL | asm!("{}", const const_bar(x));
| ^ non-constant value
error[E0308]: mismatched types
- --> $DIR/type-check-1.rs:51:26
+ --> $DIR/type-check-1.rs:53:26
|
LL | asm!("{}", const 0f32);
| ^^^^ expected integer, found `f32`
error[E0308]: mismatched types
- --> $DIR/type-check-1.rs:53:26
+ --> $DIR/type-check-1.rs:55:26
|
LL | asm!("{}", const 0 as *mut u8);
| ^^^^^^^^^^^^ expected integer, found *-ptr
@@ -41,7 +41,7 @@ LL | asm!("{}", const 0 as *mut u8);
found raw pointer `*mut u8`
error[E0308]: mismatched types
- --> $DIR/type-check-1.rs:55:26
+ --> $DIR/type-check-1.rs:57:26
|
LL | asm!("{}", const &0);
| ^^ expected integer, found `&{integer}`
@@ -53,19 +53,19 @@ LL + asm!("{}", const 0);
|
error: invalid asm output
- --> $DIR/type-check-1.rs:13:29
+ --> $DIR/type-check-1.rs:15:29
|
LL | asm!("{}", out(reg) 1 + 2);
| ^^^^^ cannot assign to this expression
error: invalid asm output
- --> $DIR/type-check-1.rs:15:31
+ --> $DIR/type-check-1.rs:17:31
|
LL | asm!("{}", inout(reg) 1 + 2);
| ^^^^^ cannot assign to this expression
error[E0277]: the size for values of type `[u64]` cannot be known at compilation time
- --> $DIR/type-check-1.rs:21:28
+ --> $DIR/type-check-1.rs:23:28
|
LL | asm!("{}", in(reg) v[..]);
| ^^^^^ doesn't have a size known at compile-time
@@ -74,7 +74,7 @@ LL | asm!("{}", in(reg) v[..]);
= note: all inline asm arguments must have a statically known size
error[E0277]: the size for values of type `[u64]` cannot be known at compilation time
- --> $DIR/type-check-1.rs:23:29
+ --> $DIR/type-check-1.rs:25:29
|
LL | asm!("{}", out(reg) v[..]);
| ^^^^^ doesn't have a size known at compile-time
@@ -83,7 +83,7 @@ LL | asm!("{}", out(reg) v[..]);
= note: all inline asm arguments must have a statically known size
error[E0277]: the size for values of type `[u64]` cannot be known at compilation time
- --> $DIR/type-check-1.rs:25:31
+ --> $DIR/type-check-1.rs:27:31
|
LL | asm!("{}", inout(reg) v[..]);
| ^^^^^ doesn't have a size known at compile-time
@@ -92,13 +92,13 @@ LL | asm!("{}", inout(reg) v[..]);
= note: all inline asm arguments must have a statically known size
error[E0308]: mismatched types
- --> $DIR/type-check-1.rs:65:25
+ --> $DIR/type-check-1.rs:67:25
|
LL | global_asm!("{}", const 0f32);
| ^^^^ expected integer, found `f32`
error[E0308]: mismatched types
- --> $DIR/type-check-1.rs:67:25
+ --> $DIR/type-check-1.rs:69:25
|
LL | global_asm!("{}", const 0 as *mut u8);
| ^^^^^^^^^^^^ expected integer, found *-ptr
diff --git a/src/test/ui/asm/type-check-4.rs b/src/test/ui/asm/type-check-4.rs
index c9826662009..666d2c67783 100644
--- a/src/test/ui/asm/type-check-4.rs
+++ b/src/test/ui/asm/type-check-4.rs
@@ -3,7 +3,7 @@
// ignore-spirv
// ignore-wasm32
-#![feature(asm)]
+use std::arch::asm;
fn main() {
unsafe {
diff --git a/src/test/ui/asm/x86_64/bad-clobber-abi.rs b/src/test/ui/asm/x86_64/bad-clobber-abi.rs
index f4ca033048d..ddcd2065bfe 100644
--- a/src/test/ui/asm/x86_64/bad-clobber-abi.rs
+++ b/src/test/ui/asm/x86_64/bad-clobber-abi.rs
@@ -1,9 +1,9 @@
// needs-asm-support
// only-x86_64
-// checks various modes of failure for the `clobber_abi` argument (after parsing)
+use std::arch::asm;
-#![feature(asm)]
+// checks various modes of failure for the `clobber_abi` argument (after parsing)
fn main() {
unsafe {
diff --git a/src/test/ui/asm/x86_64/bad-options.rs b/src/test/ui/asm/x86_64/bad-options.rs
index 3facc876415..f7c2cd6c505 100644
--- a/src/test/ui/asm/x86_64/bad-options.rs
+++ b/src/test/ui/asm/x86_64/bad-options.rs
@@ -1,6 +1,6 @@
// only-x86_64
-#![feature(asm, global_asm)]
+use std::arch::{asm, global_asm};
fn main() {
let mut foo = 0;
diff --git a/src/test/ui/asm/x86_64/bad-options.stderr b/src/test/ui/asm/x86_64/bad-options.stderr
index e2351840eef..a63c42aac27 100644
--- a/src/test/ui/asm/x86_64/bad-options.stderr
+++ b/src/test/ui/asm/x86_64/bad-options.stderr
@@ -45,41 +45,41 @@ LL | asm!("{}", out(reg) foo, clobber_abi("C"), clobber_abi("C"));
| | clobber_abi
| generic outputs
-error: expected one of `)`, `att_syntax`, or `raw`, found `nomem`
+error: expected one of `)`, `att_syntax`, `may_unwind`, or `raw`, found `nomem`
--> $DIR/bad-options.rs:31:25
|
LL | global_asm!("", options(nomem));
- | ^^^^^ expected one of `)`, `att_syntax`, or `raw`
+ | ^^^^^ expected one of `)`, `att_syntax`, `may_unwind`, or `raw`
-error: expected one of `)`, `att_syntax`, or `raw`, found `readonly`
+error: expected one of `)`, `att_syntax`, `may_unwind`, or `raw`, found `readonly`
--> $DIR/bad-options.rs:33:25
|
LL | global_asm!("", options(readonly));
- | ^^^^^^^^ expected one of `)`, `att_syntax`, or `raw`
+ | ^^^^^^^^ expected one of `)`, `att_syntax`, `may_unwind`, or `raw`
-error: expected one of `)`, `att_syntax`, or `raw`, found `noreturn`
+error: expected one of `)`, `att_syntax`, `may_unwind`, or `raw`, found `noreturn`
--> $DIR/bad-options.rs:35:25
|
LL | global_asm!("", options(noreturn));
- | ^^^^^^^^ expected one of `)`, `att_syntax`, or `raw`
+ | ^^^^^^^^ expected one of `)`, `att_syntax`, `may_unwind`, or `raw`
-error: expected one of `)`, `att_syntax`, or `raw`, found `pure`
+error: expected one of `)`, `att_syntax`, `may_unwind`, or `raw`, found `pure`
--> $DIR/bad-options.rs:37:25
|
LL | global_asm!("", options(pure));
- | ^^^^ expected one of `)`, `att_syntax`, or `raw`
+ | ^^^^ expected one of `)`, `att_syntax`, `may_unwind`, or `raw`
-error: expected one of `)`, `att_syntax`, or `raw`, found `nostack`
+error: expected one of `)`, `att_syntax`, `may_unwind`, or `raw`, found `nostack`
--> $DIR/bad-options.rs:39:25
|
LL | global_asm!("", options(nostack));
- | ^^^^^^^ expected one of `)`, `att_syntax`, or `raw`
+ | ^^^^^^^ expected one of `)`, `att_syntax`, `may_unwind`, or `raw`
-error: expected one of `)`, `att_syntax`, or `raw`, found `preserves_flags`
+error: expected one of `)`, `att_syntax`, `may_unwind`, or `raw`, found `preserves_flags`
--> $DIR/bad-options.rs:41:25
|
LL | global_asm!("", options(preserves_flags));
- | ^^^^^^^^^^^^^^^ expected one of `)`, `att_syntax`, or `raw`
+ | ^^^^^^^^^^^^^^^ expected one of `)`, `att_syntax`, `may_unwind`, or `raw`
error: invalid ABI for `clobber_abi`
--> $DIR/bad-options.rs:20:18
diff --git a/src/test/ui/asm/x86_64/bad-reg.rs b/src/test/ui/asm/x86_64/bad-reg.rs
index ba4e95db46a..257274b0bc3 100644
--- a/src/test/ui/asm/x86_64/bad-reg.rs
+++ b/src/test/ui/asm/x86_64/bad-reg.rs
@@ -1,7 +1,9 @@
// only-x86_64
// compile-flags: -C target-feature=+avx2
-#![feature(asm, asm_const, asm_sym)]
+#![feature(asm_const, asm_sym)]
+
+use std::arch::asm;
fn main() {
let mut foo = 0;
diff --git a/src/test/ui/asm/x86_64/bad-reg.stderr b/src/test/ui/asm/x86_64/bad-reg.stderr
index 102a17e9815..3a89b2fdb74 100644
--- a/src/test/ui/asm/x86_64/bad-reg.stderr
+++ b/src/test/ui/asm/x86_64/bad-reg.stderr
@@ -1,17 +1,17 @@
error: invalid register class `foo`: unknown register class
- --> $DIR/bad-reg.rs:12:20
+ --> $DIR/bad-reg.rs:14:20
|
LL | asm!("{}", in(foo) foo);
| ^^^^^^^^^^^
error: invalid register `foo`: unknown register
- --> $DIR/bad-reg.rs:14:18
+ --> $DIR/bad-reg.rs:16:18
|
LL | asm!("", in("foo") foo);
| ^^^^^^^^^^^^^
error: invalid asm template modifier for this register class
- --> $DIR/bad-reg.rs:16:15
+ --> $DIR/bad-reg.rs:18:15
|
LL | asm!("{:z}", in(reg) foo);
| ^^^^ ----------- argument
@@ -21,7 +21,7 @@ LL | asm!("{:z}", in(reg) foo);
= note: the `reg` register class supports the following template modifiers: `l`, `x`, `e`, `r`
error: invalid asm template modifier for this register class
- --> $DIR/bad-reg.rs:18:15
+ --> $DIR/bad-reg.rs:20:15
|
LL | asm!("{:r}", in(xmm_reg) foo);
| ^^^^ --------------- argument
@@ -31,7 +31,7 @@ LL | asm!("{:r}", in(xmm_reg) foo);
= note: the `xmm_reg` register class supports the following template modifiers: `x`, `y`, `z`
error: asm template modifiers are not allowed for `const` arguments
- --> $DIR/bad-reg.rs:20:15
+ --> $DIR/bad-reg.rs:22:15
|
LL | asm!("{:a}", const 0);
| ^^^^ ------- argument
@@ -39,7 +39,7 @@ LL | asm!("{:a}", const 0);
| template modifier
error: asm template modifiers are not allowed for `sym` arguments
- --> $DIR/bad-reg.rs:22:15
+ --> $DIR/bad-reg.rs:24:15
|
LL | asm!("{:a}", sym main);
| ^^^^ -------- argument
@@ -47,73 +47,73 @@ LL | asm!("{:a}", sym main);
| template modifier
error: invalid register `ebp`: the frame pointer cannot be used as an operand for inline asm
- --> $DIR/bad-reg.rs:24:18
+ --> $DIR/bad-reg.rs:26:18
|
LL | asm!("", in("ebp") foo);
| ^^^^^^^^^^^^^
error: invalid register `rsp`: the stack pointer cannot be used as an operand for inline asm
- --> $DIR/bad-reg.rs:26:18
+ --> $DIR/bad-reg.rs:28:18
|
LL | asm!("", in("rsp") foo);
| ^^^^^^^^^^^^^
error: invalid register `ip`: the instruction pointer cannot be used as an operand for inline asm
- --> $DIR/bad-reg.rs:28:18
+ --> $DIR/bad-reg.rs:30:18
|
LL | asm!("", in("ip") foo);
| ^^^^^^^^^^^^
error: invalid register `k0`: the k0 AVX mask register cannot be used as an operand for inline asm
- --> $DIR/bad-reg.rs:30:18
+ --> $DIR/bad-reg.rs:32:18
|
LL | asm!("", in("k0") foo);
| ^^^^^^^^^^^^
error: invalid register `ah`: high byte registers cannot be used as an operand on x86_64
- --> $DIR/bad-reg.rs:32:18
+ --> $DIR/bad-reg.rs:34:18
|
LL | asm!("", in("ah") foo);
| ^^^^^^^^^^^^
error: register class `x87_reg` can only be used as a clobber, not as an input or output
- --> $DIR/bad-reg.rs:35:18
+ --> $DIR/bad-reg.rs:37:18
|
LL | asm!("", in("st(2)") foo);
| ^^^^^^^^^^^^^^^
error: register class `mmx_reg` can only be used as a clobber, not as an input or output
- --> $DIR/bad-reg.rs:37:18
+ --> $DIR/bad-reg.rs:39:18
|
LL | asm!("", in("mm0") foo);
| ^^^^^^^^^^^^^
error: register class `x87_reg` can only be used as a clobber, not as an input or output
- --> $DIR/bad-reg.rs:41:20
+ --> $DIR/bad-reg.rs:43:20
|
LL | asm!("{}", in(x87_reg) foo);
| ^^^^^^^^^^^^^^^
error: register class `mmx_reg` can only be used as a clobber, not as an input or output
- --> $DIR/bad-reg.rs:43:20
+ --> $DIR/bad-reg.rs:45:20
|
LL | asm!("{}", in(mmx_reg) foo);
| ^^^^^^^^^^^^^^^
error: register class `x87_reg` can only be used as a clobber, not as an input or output
- --> $DIR/bad-reg.rs:45:20
+ --> $DIR/bad-reg.rs:47:20
|
LL | asm!("{}", out(x87_reg) _);
| ^^^^^^^^^^^^^^
error: register class `mmx_reg` can only be used as a clobber, not as an input or output
- --> $DIR/bad-reg.rs:47:20
+ --> $DIR/bad-reg.rs:49:20
|
LL | asm!("{}", out(mmx_reg) _);
| ^^^^^^^^^^^^^^
error: register `al` conflicts with register `ax`
- --> $DIR/bad-reg.rs:53:33
+ --> $DIR/bad-reg.rs:55:33
|
LL | asm!("", in("eax") foo, in("al") bar);
| ------------- ^^^^^^^^^^^^ register `al`
@@ -121,7 +121,7 @@ LL | asm!("", in("eax") foo, in("al") bar);
| register `ax`
error: register `ax` conflicts with register `ax`
- --> $DIR/bad-reg.rs:55:33
+ --> $DIR/bad-reg.rs:57:33
|
LL | asm!("", in("rax") foo, out("rax") bar);
| ------------- ^^^^^^^^^^^^^^ register `ax`
@@ -129,13 +129,13 @@ LL | asm!("", in("rax") foo, out("rax") bar);
| register `ax`
|
help: use `lateout` instead of `out` to avoid conflict
- --> $DIR/bad-reg.rs:55:18
+ --> $DIR/bad-reg.rs:57:18
|
LL | asm!("", in("rax") foo, out("rax") bar);
| ^^^^^^^^^^^^^
error: register `ymm0` conflicts with register `xmm0`
- --> $DIR/bad-reg.rs:58:34
+ --> $DIR/bad-reg.rs:60:34
|
LL | asm!("", in("xmm0") foo, in("ymm0") bar);
| -------------- ^^^^^^^^^^^^^^ register `ymm0`
@@ -143,7 +143,7 @@ LL | asm!("", in("xmm0") foo, in("ymm0") bar);
| register `xmm0`
error: register `ymm0` conflicts with register `xmm0`
- --> $DIR/bad-reg.rs:60:34
+ --> $DIR/bad-reg.rs:62:34
|
LL | asm!("", in("xmm0") foo, out("ymm0") bar);
| -------------- ^^^^^^^^^^^^^^^ register `ymm0`
@@ -151,7 +151,7 @@ LL | asm!("", in("xmm0") foo, out("ymm0") bar);
| register `xmm0`
|
help: use `lateout` instead of `out` to avoid conflict
- --> $DIR/bad-reg.rs:60:18
+ --> $DIR/bad-reg.rs:62:18
|
LL | asm!("", in("xmm0") foo, out("ymm0") bar);
| ^^^^^^^^^^^^^^
diff --git a/src/test/ui/asm/x86_64/const.rs b/src/test/ui/asm/x86_64/const.rs
index c1e4cdbb928..aa4cdf99176 100644
--- a/src/test/ui/asm/x86_64/const.rs
+++ b/src/test/ui/asm/x86_64/const.rs
@@ -3,7 +3,9 @@
// revisions: mirunsafeck thirunsafeck
// [thirunsafeck]compile-flags: -Z thir-unsafeck
-#![feature(asm, global_asm, asm_const)]
+#![feature(asm_const)]
+
+use std::arch::{asm, global_asm};
fn const_generic<const X: usize>() -> usize {
unsafe {
diff --git a/src/test/ui/asm/x86_64/duplicate-options.fixed b/src/test/ui/asm/x86_64/duplicate-options.fixed
index d4444e9c6cc..c5f14f5f75c 100644
--- a/src/test/ui/asm/x86_64/duplicate-options.fixed
+++ b/src/test/ui/asm/x86_64/duplicate-options.fixed
@@ -1,7 +1,7 @@
// only-x86_64
// run-rustfix
-#![feature(asm, global_asm)]
+use std::arch::{asm, global_asm};
fn main() {
unsafe {
@@ -19,8 +19,8 @@ fn main() {
"",
options(nomem, noreturn),
options(att_syntax, ), //~ ERROR the `noreturn` option was already provided
- options( nostack), //~ ERROR the `nomem` option was already provided
- options(), //~ ERROR the `noreturn` option was already provided
+ options( nostack), //~ ERROR the `nomem` option was already provided
+ options(), //~ ERROR the `noreturn` option was already provided
);
}
}
diff --git a/src/test/ui/asm/x86_64/duplicate-options.rs b/src/test/ui/asm/x86_64/duplicate-options.rs
index fd28311984b..a8dce1f8d71 100644
--- a/src/test/ui/asm/x86_64/duplicate-options.rs
+++ b/src/test/ui/asm/x86_64/duplicate-options.rs
@@ -1,7 +1,7 @@
// only-x86_64
// run-rustfix
-#![feature(asm, global_asm)]
+use std::arch::{asm, global_asm};
fn main() {
unsafe {
@@ -19,8 +19,8 @@ fn main() {
"",
options(nomem, noreturn),
options(att_syntax, noreturn), //~ ERROR the `noreturn` option was already provided
- options(nomem, nostack), //~ ERROR the `nomem` option was already provided
- options(noreturn), //~ ERROR the `noreturn` option was already provided
+ options(nomem, nostack), //~ ERROR the `nomem` option was already provided
+ options(noreturn), //~ ERROR the `noreturn` option was already provided
);
}
}
diff --git a/src/test/ui/asm/x86_64/interpolated-idents.rs b/src/test/ui/asm/x86_64/interpolated-idents.rs
index f4cb749307d..c05633ae885 100644
--- a/src/test/ui/asm/x86_64/interpolated-idents.rs
+++ b/src/test/ui/asm/x86_64/interpolated-idents.rs
@@ -1,6 +1,6 @@
// only-x86_64
-#![feature(asm)]
+use std::arch::asm;
macro_rules! m {
($in:ident $out:ident $lateout:ident $inout:ident $inlateout:ident $const:ident $sym:ident
diff --git a/src/test/ui/asm/x86_64/issue-82869.rs b/src/test/ui/asm/x86_64/issue-82869.rs
index a8e688cbe1f..3e632eaf88d 100644
--- a/src/test/ui/asm/x86_64/issue-82869.rs
+++ b/src/test/ui/asm/x86_64/issue-82869.rs
@@ -1,9 +1,10 @@
// only-x86_64
// Make sure rustc doesn't ICE on asm! for a foreign architecture.
-#![feature(asm)]
#![crate_type = "rlib"]
+use std::arch::asm;
+
pub unsafe fn aarch64(a: f64, b: f64) -> f64 {
let c;
asm!("add {:d}, {:d}, d0", out(vreg) c, in(vreg) a, in("d0") {
diff --git a/src/test/ui/asm/x86_64/issue-82869.stderr b/src/test/ui/asm/x86_64/issue-82869.stderr
index d05714ea6f2..42be1b6de72 100644
--- a/src/test/ui/asm/x86_64/issue-82869.stderr
+++ b/src/test/ui/asm/x86_64/issue-82869.stderr
@@ -1,17 +1,17 @@
error: invalid register class `vreg`: unknown register class
- --> $DIR/issue-82869.rs:9:32
+ --> $DIR/issue-82869.rs:10:32
|
LL | asm!("add {:d}, {:d}, d0", out(vreg) c, in(vreg) a, in("d0") {
| ^^^^^^^^^^^
error: invalid register class `vreg`: unknown register class
- --> $DIR/issue-82869.rs:9:45
+ --> $DIR/issue-82869.rs:10:45
|
LL | asm!("add {:d}, {:d}, d0", out(vreg) c, in(vreg) a, in("d0") {
| ^^^^^^^^^^
error: invalid register `d0`: unknown register
- --> $DIR/issue-82869.rs:9:57
+ --> $DIR/issue-82869.rs:10:57
|
LL | asm!("add {:d}, {:d}, d0", out(vreg) c, in(vreg) a, in("d0") {
| _________________________________________________________^
diff --git a/src/test/ui/asm/x86_64/issue-89875.rs b/src/test/ui/asm/x86_64/issue-89875.rs
index 9b2b21bbda6..e4b6687e00b 100644
--- a/src/test/ui/asm/x86_64/issue-89875.rs
+++ b/src/test/ui/asm/x86_64/issue-89875.rs
@@ -1,7 +1,9 @@
// build-pass
// only-x86_64
-#![feature(asm, target_feature_11)]
+#![feature(target_feature_11)]
+
+use std::arch::asm;
#[target_feature(enable = "avx")]
fn main() {
diff --git a/src/test/ui/asm/x86_64/may_unwind.rs b/src/test/ui/asm/x86_64/may_unwind.rs
new file mode 100644
index 00000000000..9844d63f0cd
--- /dev/null
+++ b/src/test/ui/asm/x86_64/may_unwind.rs
@@ -0,0 +1,38 @@
+// min-llvm-version: 13.0.0
+// only-x86_64
+// run-pass
+// needs-asm-support
+
+#![feature(asm_sym, asm_unwind)]
+
+use std::arch::asm;
+use std::panic::{catch_unwind, resume_unwind, AssertUnwindSafe};
+
+struct Foo<'a>(&'a mut bool);
+
+impl Drop for Foo<'_> {
+ fn drop(&mut self) {
+ *self.0 = false;
+ }
+}
+
+extern "C" fn panicky() {
+ resume_unwind(Box::new(()));
+}
+
+fn main() {
+ let flag = &mut true;
+ catch_unwind(AssertUnwindSafe(|| {
+ let _foo = Foo(flag);
+ unsafe {
+ asm!(
+ "call {}",
+ sym panicky,
+ clobber_abi("C"),
+ options(may_unwind)
+ );
+ }
+ }))
+ .expect_err("expected a panic");
+ assert_eq!(*flag, false);
+}
diff --git a/src/test/ui/asm/x86_64/multiple-clobber-abi.rs b/src/test/ui/asm/x86_64/multiple-clobber-abi.rs
index a573d672d00..513eb270e4f 100644
--- a/src/test/ui/asm/x86_64/multiple-clobber-abi.rs
+++ b/src/test/ui/asm/x86_64/multiple-clobber-abi.rs
@@ -4,7 +4,9 @@
// Checks that multiple clobber_abi options can be used
-#![feature(asm, asm_sym)]
+#![feature(asm_sym)]
+
+use std::arch::asm;
extern "sysv64" fn foo(x: i32) -> i32 {
x + 16
diff --git a/src/test/ui/asm/x86_64/parse-error.rs b/src/test/ui/asm/x86_64/parse-error.rs
index 1d6545f1b5c..f0629f9f51c 100644
--- a/src/test/ui/asm/x86_64/parse-error.rs
+++ b/src/test/ui/asm/x86_64/parse-error.rs
@@ -1,6 +1,8 @@
// only-x86_64
-#![feature(asm, global_asm, asm_const)]
+#![feature(asm_const)]
+
+use std::arch::{asm, global_asm};
fn main() {
let mut foo = 0;
diff --git a/src/test/ui/asm/x86_64/parse-error.stderr b/src/test/ui/asm/x86_64/parse-error.stderr
index 018df9826c6..2d0a7a94d56 100644
--- a/src/test/ui/asm/x86_64/parse-error.stderr
+++ b/src/test/ui/asm/x86_64/parse-error.stderr
@@ -1,89 +1,89 @@
error: requires at least a template string argument
- --> $DIR/parse-error.rs:9:9
+ --> $DIR/parse-error.rs:11:9
|
LL | asm!();
| ^^^^^^
error: asm template must be a string literal
- --> $DIR/parse-error.rs:11:14
+ --> $DIR/parse-error.rs:13:14
|
LL | asm!(foo);
| ^^^
error: expected token: `,`
- --> $DIR/parse-error.rs:13:19
+ --> $DIR/parse-error.rs:15:19
|
LL | asm!("{}" foo);
| ^^^ expected `,`
error: expected operand, clobber_abi, options, or additional template string
- --> $DIR/parse-error.rs:15:20
+ --> $DIR/parse-error.rs:17:20
|
LL | asm!("{}", foo);
| ^^^ expected operand, clobber_abi, options, or additional template string
error: expected `(`, found `foo`
- --> $DIR/parse-error.rs:17:23
+ --> $DIR/parse-error.rs:19:23
|
LL | asm!("{}", in foo);
| ^^^ expected `(`
error: expected `)`, found `foo`
- --> $DIR/parse-error.rs:19:27
+ --> $DIR/parse-error.rs:21:27
|
LL | asm!("{}", in(reg foo));
| ^^^ expected `)`
error: expected expression, found end of macro arguments
- --> $DIR/parse-error.rs:21:27
+ --> $DIR/parse-error.rs:23:27
|
LL | asm!("{}", in(reg));
| ^ expected expression
error: expected register class or explicit register
- --> $DIR/parse-error.rs:23:26
+ --> $DIR/parse-error.rs:25:26
|
LL | asm!("{}", inout(=) foo => bar);
| ^
error: expected expression, found end of macro arguments
- --> $DIR/parse-error.rs:25:37
+ --> $DIR/parse-error.rs:27:37
|
LL | asm!("{}", inout(reg) foo =>);
| ^ expected expression
error: expected one of `!`, `,`, `.`, `::`, `?`, `{`, or an operator, found `=>`
- --> $DIR/parse-error.rs:27:32
+ --> $DIR/parse-error.rs:29:32
|
LL | asm!("{}", in(reg) foo => bar);
| ^^ expected one of 7 possible tokens
error: argument to `sym` must be a path expression
- --> $DIR/parse-error.rs:29:24
+ --> $DIR/parse-error.rs:31:24
|
LL | asm!("{}", sym foo + bar);
| ^^^^^^^^^
-error: expected one of `)`, `att_syntax`, `nomem`, `noreturn`, `nostack`, `preserves_flags`, `pure`, `raw`, or `readonly`, found `foo`
- --> $DIR/parse-error.rs:31:26
+error: expected one of `)`, `att_syntax`, `may_unwind`, `nomem`, `noreturn`, `nostack`, `preserves_flags`, `pure`, `raw`, or `readonly`, found `foo`
+ --> $DIR/parse-error.rs:33:26
|
LL | asm!("", options(foo));
- | ^^^ expected one of 9 possible tokens
+ | ^^^ expected one of 10 possible tokens
error: expected one of `)` or `,`, found `foo`
- --> $DIR/parse-error.rs:33:32
+ --> $DIR/parse-error.rs:35:32
|
LL | asm!("", options(nomem foo));
| ^^^ expected one of `)` or `,`
-error: expected one of `)`, `att_syntax`, `nomem`, `noreturn`, `nostack`, `preserves_flags`, `pure`, `raw`, or `readonly`, found `foo`
- --> $DIR/parse-error.rs:35:33
+error: expected one of `)`, `att_syntax`, `may_unwind`, `nomem`, `noreturn`, `nostack`, `preserves_flags`, `pure`, `raw`, or `readonly`, found `foo`
+ --> $DIR/parse-error.rs:37:33
|
LL | asm!("", options(nomem, foo));
- | ^^^ expected one of 9 possible tokens
+ | ^^^ expected one of 10 possible tokens
error: arguments are not allowed after options
- --> $DIR/parse-error.rs:37:31
+ --> $DIR/parse-error.rs:39:31
|
LL | asm!("{}", options(), const foo);
| --------- ^^^^^^^^^ argument
@@ -91,31 +91,31 @@ LL | asm!("{}", options(), const foo);
| previous options
error: at least one abi must be provided as an argument to `clobber_abi`
- --> $DIR/parse-error.rs:40:30
+ --> $DIR/parse-error.rs:42:30
|
LL | asm!("", clobber_abi());
| ^
error: expected string literal
- --> $DIR/parse-error.rs:42:30
+ --> $DIR/parse-error.rs:44:30
|
LL | asm!("", clobber_abi(foo));
| ^^^ not a string literal
error: expected one of `)` or `,`, found `foo`
- --> $DIR/parse-error.rs:44:34
+ --> $DIR/parse-error.rs:46:34
|
LL | asm!("", clobber_abi("C" foo));
| ^^^ expected one of `)` or `,`
error: expected string literal
- --> $DIR/parse-error.rs:46:35
+ --> $DIR/parse-error.rs:48:35
|
LL | asm!("", clobber_abi("C", foo));
| ^^^ not a string literal
error: arguments are not allowed after clobber_abi
- --> $DIR/parse-error.rs:48:38
+ --> $DIR/parse-error.rs:50:38
|
LL | asm!("{}", clobber_abi("C"), const foo);
| ---------------- ^^^^^^^^^ argument
@@ -123,7 +123,7 @@ LL | asm!("{}", clobber_abi("C"), const foo);
| clobber_abi
error: clobber_abi is not allowed after options
- --> $DIR/parse-error.rs:51:29
+ --> $DIR/parse-error.rs:53:29
|
LL | asm!("", options(), clobber_abi("C"));
| --------- ^^^^^^^^^^^^^^^^
@@ -131,7 +131,7 @@ LL | asm!("", options(), clobber_abi("C"));
| options
error: clobber_abi is not allowed after options
- --> $DIR/parse-error.rs:53:31
+ --> $DIR/parse-error.rs:55:31
|
LL | asm!("{}", options(), clobber_abi("C"), const foo);
| --------- ^^^^^^^^^^^^^^^^
@@ -139,7 +139,7 @@ LL | asm!("{}", options(), clobber_abi("C"), const foo);
| options
error: duplicate argument named `a`
- --> $DIR/parse-error.rs:55:36
+ --> $DIR/parse-error.rs:57:36
|
LL | asm!("{a}", a = const foo, a = const bar);
| ------------- ^^^^^^^^^^^^^ duplicate argument
@@ -147,7 +147,7 @@ LL | asm!("{a}", a = const foo, a = const bar);
| previously here
error: argument never used
- --> $DIR/parse-error.rs:55:36
+ --> $DIR/parse-error.rs:57:36
|
LL | asm!("{a}", a = const foo, a = const bar);
| ^^^^^^^^^^^^^ argument never used
@@ -155,13 +155,13 @@ LL | asm!("{a}", a = const foo, a = const bar);
= help: if this argument is intentionally unused, consider using it in an asm comment: `"/* {1} */"`
error: explicit register arguments cannot have names
- --> $DIR/parse-error.rs:60:18
+ --> $DIR/parse-error.rs:62:18
|
LL | asm!("", a = in("eax") foo);
| ^^^^^^^^^^^^^^^^^
error: named arguments cannot follow explicit register arguments
- --> $DIR/parse-error.rs:62:36
+ --> $DIR/parse-error.rs:64:36
|
LL | asm!("{a}", in("eax") foo, a = const bar);
| ------------- ^^^^^^^^^^^^^ named argument
@@ -169,7 +169,7 @@ LL | asm!("{a}", in("eax") foo, a = const bar);
| explicit register argument
error: named arguments cannot follow explicit register arguments
- --> $DIR/parse-error.rs:65:36
+ --> $DIR/parse-error.rs:67:36
|
LL | asm!("{a}", in("eax") foo, a = const bar);
| ------------- ^^^^^^^^^^^^^ named argument
@@ -177,7 +177,7 @@ LL | asm!("{a}", in("eax") foo, a = const bar);
| explicit register argument
error: positional arguments cannot follow named arguments or explicit register arguments
- --> $DIR/parse-error.rs:68:36
+ --> $DIR/parse-error.rs:70:36
|
LL | asm!("{1}", in("eax") foo, const bar);
| ------------- ^^^^^^^^^ positional argument
@@ -185,19 +185,19 @@ LL | asm!("{1}", in("eax") foo, const bar);
| explicit register argument
error: expected one of `clobber_abi`, `const`, `in`, `inlateout`, `inout`, `lateout`, `options`, `out`, or `sym`, found `""`
- --> $DIR/parse-error.rs:71:29
+ --> $DIR/parse-error.rs:73:29
|
LL | asm!("", options(), "");
| ^^ expected one of 9 possible tokens
error: expected one of `clobber_abi`, `const`, `in`, `inlateout`, `inout`, `lateout`, `options`, `out`, or `sym`, found `"{}"`
- --> $DIR/parse-error.rs:73:33
+ --> $DIR/parse-error.rs:75:33
|
LL | asm!("{}", in(reg) foo, "{}", out(reg) foo);
| ^^^^ expected one of 9 possible tokens
error: asm template must be a string literal
- --> $DIR/parse-error.rs:75:14
+ --> $DIR/parse-error.rs:77:14
|
LL | asm!(format!("{{{}}}", 0), in(reg) foo);
| ^^^^^^^^^^^^^^^^^^^^
@@ -205,7 +205,7 @@ LL | asm!(format!("{{{}}}", 0), in(reg) foo);
= note: this error originates in the macro `format` (in Nightly builds, run with -Z macro-backtrace for more info)
error: asm template must be a string literal
- --> $DIR/parse-error.rs:77:21
+ --> $DIR/parse-error.rs:79:21
|
LL | asm!("{1}", format!("{{{}}}", 0), in(reg) foo, out(reg) bar);
| ^^^^^^^^^^^^^^^^^^^^
@@ -213,79 +213,79 @@ LL | asm!("{1}", format!("{{{}}}", 0), in(reg) foo, out(reg) bar);
= note: this error originates in the macro `format` (in Nightly builds, run with -Z macro-backtrace for more info)
error: _ cannot be used for input operands
- --> $DIR/parse-error.rs:79:28
+ --> $DIR/parse-error.rs:81:28
|
LL | asm!("{}", in(reg) _);
| ^
error: _ cannot be used for input operands
- --> $DIR/parse-error.rs:81:31
+ --> $DIR/parse-error.rs:83:31
|
LL | asm!("{}", inout(reg) _);
| ^
error: _ cannot be used for input operands
- --> $DIR/parse-error.rs:83:35
+ --> $DIR/parse-error.rs:85:35
|
LL | asm!("{}", inlateout(reg) _);
| ^
error: requires at least a template string argument
- --> $DIR/parse-error.rs:90:1
+ --> $DIR/parse-error.rs:92:1
|
LL | global_asm!();
| ^^^^^^^^^^^^^
error: asm template must be a string literal
- --> $DIR/parse-error.rs:92:13
+ --> $DIR/parse-error.rs:94:13
|
LL | global_asm!(FOO);
| ^^^
error: expected token: `,`
- --> $DIR/parse-error.rs:94:18
+ --> $DIR/parse-error.rs:96:18
|
LL | global_asm!("{}" FOO);
| ^^^ expected `,`
error: expected operand, options, or additional template string
- --> $DIR/parse-error.rs:96:19
+ --> $DIR/parse-error.rs:98:19
|
LL | global_asm!("{}", FOO);
| ^^^ expected operand, options, or additional template string
error: expected expression, found end of macro arguments
- --> $DIR/parse-error.rs:98:24
+ --> $DIR/parse-error.rs:100:24
|
LL | global_asm!("{}", const);
| ^ expected expression
error: expected one of `,`, `.`, `?`, or an operator, found `FOO`
- --> $DIR/parse-error.rs:100:30
+ --> $DIR/parse-error.rs:102:30
|
LL | global_asm!("{}", const(reg) FOO);
| ^^^ expected one of `,`, `.`, `?`, or an operator
-error: expected one of `)`, `att_syntax`, or `raw`, found `FOO`
- --> $DIR/parse-error.rs:102:25
+error: expected one of `)`, `att_syntax`, `may_unwind`, or `raw`, found `FOO`
+ --> $DIR/parse-error.rs:104:25
|
LL | global_asm!("", options(FOO));
- | ^^^ expected one of `)`, `att_syntax`, or `raw`
+ | ^^^ expected one of `)`, `att_syntax`, `may_unwind`, or `raw`
-error: expected one of `)`, `att_syntax`, or `raw`, found `nomem`
- --> $DIR/parse-error.rs:104:25
+error: expected one of `)`, `att_syntax`, `may_unwind`, or `raw`, found `nomem`
+ --> $DIR/parse-error.rs:106:25
|
LL | global_asm!("", options(nomem FOO));
- | ^^^^^ expected one of `)`, `att_syntax`, or `raw`
+ | ^^^^^ expected one of `)`, `att_syntax`, `may_unwind`, or `raw`
-error: expected one of `)`, `att_syntax`, or `raw`, found `nomem`
- --> $DIR/parse-error.rs:106:25
+error: expected one of `)`, `att_syntax`, `may_unwind`, or `raw`, found `nomem`
+ --> $DIR/parse-error.rs:108:25
|
LL | global_asm!("", options(nomem, FOO));
- | ^^^^^ expected one of `)`, `att_syntax`, or `raw`
+ | ^^^^^ expected one of `)`, `att_syntax`, `may_unwind`, or `raw`
error: arguments are not allowed after options
- --> $DIR/parse-error.rs:108:30
+ --> $DIR/parse-error.rs:110:30
|
LL | global_asm!("{}", options(), const FOO);
| --------- ^^^^^^^^^ argument
@@ -293,25 +293,25 @@ LL | global_asm!("{}", options(), const FOO);
| previous options
error: expected string literal
- --> $DIR/parse-error.rs:110:29
+ --> $DIR/parse-error.rs:112:29
|
LL | global_asm!("", clobber_abi(FOO));
| ^^^ not a string literal
error: expected one of `)` or `,`, found `FOO`
- --> $DIR/parse-error.rs:112:33
+ --> $DIR/parse-error.rs:114:33
|
LL | global_asm!("", clobber_abi("C" FOO));
| ^^^ expected one of `)` or `,`
error: expected string literal
- --> $DIR/parse-error.rs:114:34
+ --> $DIR/parse-error.rs:116:34
|
LL | global_asm!("", clobber_abi("C", FOO));
| ^^^ not a string literal
error: arguments are not allowed after clobber_abi
- --> $DIR/parse-error.rs:116:37
+ --> $DIR/parse-error.rs:118:37
|
LL | global_asm!("{}", clobber_abi("C"), const FOO);
| ---------------- ^^^^^^^^^ argument
@@ -319,13 +319,13 @@ LL | global_asm!("{}", clobber_abi("C"), const FOO);
| clobber_abi
error: `clobber_abi` cannot be used with `global_asm!`
- --> $DIR/parse-error.rs:116:19
+ --> $DIR/parse-error.rs:118:19
|
LL | global_asm!("{}", clobber_abi("C"), const FOO);
| ^^^^^^^^^^^^^^^^
error: clobber_abi is not allowed after options
- --> $DIR/parse-error.rs:119:28
+ --> $DIR/parse-error.rs:121:28
|
LL | global_asm!("", options(), clobber_abi("C"));
| --------- ^^^^^^^^^^^^^^^^
@@ -333,7 +333,7 @@ LL | global_asm!("", options(), clobber_abi("C"));
| options
error: clobber_abi is not allowed after options
- --> $DIR/parse-error.rs:121:30
+ --> $DIR/parse-error.rs:123:30
|
LL | global_asm!("{}", options(), clobber_abi("C"), const FOO);
| --------- ^^^^^^^^^^^^^^^^
@@ -341,13 +341,13 @@ LL | global_asm!("{}", options(), clobber_abi("C"), const FOO);
| options
error: `clobber_abi` cannot be used with `global_asm!`
- --> $DIR/parse-error.rs:123:17
+ --> $DIR/parse-error.rs:125:17
|
LL | global_asm!("", clobber_abi("C"), clobber_abi("C"));
| ^^^^^^^^^^^^^^^^ ^^^^^^^^^^^^^^^^
error: duplicate argument named `a`
- --> $DIR/parse-error.rs:125:35
+ --> $DIR/parse-error.rs:127:35
|
LL | global_asm!("{a}", a = const FOO, a = const BAR);
| ------------- ^^^^^^^^^^^^^ duplicate argument
@@ -355,7 +355,7 @@ LL | global_asm!("{a}", a = const FOO, a = const BAR);
| previously here
error: argument never used
- --> $DIR/parse-error.rs:125:35
+ --> $DIR/parse-error.rs:127:35
|
LL | global_asm!("{a}", a = const FOO, a = const BAR);
| ^^^^^^^^^^^^^ argument never used
@@ -363,19 +363,19 @@ LL | global_asm!("{a}", a = const FOO, a = const BAR);
= help: if this argument is intentionally unused, consider using it in an asm comment: `"/* {1} */"`
error: expected one of `clobber_abi`, `const`, or `options`, found `""`
- --> $DIR/parse-error.rs:128:28
+ --> $DIR/parse-error.rs:130:28
|
LL | global_asm!("", options(), "");
| ^^ expected one of `clobber_abi`, `const`, or `options`
error: expected one of `clobber_abi`, `const`, or `options`, found `"{}"`
- --> $DIR/parse-error.rs:130:30
+ --> $DIR/parse-error.rs:132:30
|
LL | global_asm!("{}", const FOO, "{}", const FOO);
| ^^^^ expected one of `clobber_abi`, `const`, or `options`
error: asm template must be a string literal
- --> $DIR/parse-error.rs:132:13
+ --> $DIR/parse-error.rs:134:13
|
LL | global_asm!(format!("{{{}}}", 0), const FOO);
| ^^^^^^^^^^^^^^^^^^^^
@@ -383,7 +383,7 @@ LL | global_asm!(format!("{{{}}}", 0), const FOO);
= note: this error originates in the macro `format` (in Nightly builds, run with -Z macro-backtrace for more info)
error: asm template must be a string literal
- --> $DIR/parse-error.rs:134:20
+ --> $DIR/parse-error.rs:136:20
|
LL | global_asm!("{1}", format!("{{{}}}", 0), const FOO, const BAR);
| ^^^^^^^^^^^^^^^^^^^^
@@ -391,7 +391,7 @@ LL | global_asm!("{1}", format!("{{{}}}", 0), const FOO, const BAR);
= note: this error originates in the macro `format` (in Nightly builds, run with -Z macro-backtrace for more info)
error[E0435]: attempt to use a non-constant value in a constant
- --> $DIR/parse-error.rs:37:37
+ --> $DIR/parse-error.rs:39:37
|
LL | let mut foo = 0;
| ---------- help: consider using `const` instead of `let`: `const foo`
@@ -400,7 +400,7 @@ LL | asm!("{}", options(), const foo);
| ^^^ non-constant value
error[E0435]: attempt to use a non-constant value in a constant
- --> $DIR/parse-error.rs:48:44
+ --> $DIR/parse-error.rs:50:44
|
LL | let mut foo = 0;
| ---------- help: consider using `const` instead of `let`: `const foo`
@@ -409,7 +409,7 @@ LL | asm!("{}", clobber_abi("C"), const foo);
| ^^^ non-constant value
error[E0435]: attempt to use a non-constant value in a constant
- --> $DIR/parse-error.rs:55:31
+ --> $DIR/parse-error.rs:57:31
|
LL | let mut foo = 0;
| ---------- help: consider using `const` instead of `let`: `const foo`
@@ -418,7 +418,7 @@ LL | asm!("{a}", a = const foo, a = const bar);
| ^^^ non-constant value
error[E0435]: attempt to use a non-constant value in a constant
- --> $DIR/parse-error.rs:55:46
+ --> $DIR/parse-error.rs:57:46
|
LL | let mut bar = 0;
| ---------- help: consider using `const` instead of `let`: `const bar`
@@ -427,7 +427,7 @@ LL | asm!("{a}", a = const foo, a = const bar);
| ^^^ non-constant value
error[E0435]: attempt to use a non-constant value in a constant
- --> $DIR/parse-error.rs:62:46
+ --> $DIR/parse-error.rs:64:46
|
LL | let mut bar = 0;
| ---------- help: consider using `const` instead of `let`: `const bar`
@@ -436,7 +436,7 @@ LL | asm!("{a}", in("eax") foo, a = const bar);
| ^^^ non-constant value
error[E0435]: attempt to use a non-constant value in a constant
- --> $DIR/parse-error.rs:65:46
+ --> $DIR/parse-error.rs:67:46
|
LL | let mut bar = 0;
| ---------- help: consider using `const` instead of `let`: `const bar`
@@ -445,7 +445,7 @@ LL | asm!("{a}", in("eax") foo, a = const bar);
| ^^^ non-constant value
error[E0435]: attempt to use a non-constant value in a constant
- --> $DIR/parse-error.rs:68:42
+ --> $DIR/parse-error.rs:70:42
|
LL | let mut bar = 0;
| ---------- help: consider using `const` instead of `let`: `const bar`
diff --git a/src/test/ui/asm/x86_64/srcloc.rs b/src/test/ui/asm/x86_64/srcloc.rs
index c4ccfb8016a..8a21d759772 100644
--- a/src/test/ui/asm/x86_64/srcloc.rs
+++ b/src/test/ui/asm/x86_64/srcloc.rs
@@ -1,7 +1,8 @@
// only-x86_64
// build-fail
// compile-flags: -Ccodegen-units=1
-#![feature(asm)]
+
+use std::arch::asm;
// Checks that inline asm errors are mapped to the correct line in the source code.
diff --git a/src/test/ui/asm/x86_64/srcloc.stderr b/src/test/ui/asm/x86_64/srcloc.stderr
index 77894657292..b62c8948289 100644
--- a/src/test/ui/asm/x86_64/srcloc.stderr
+++ b/src/test/ui/asm/x86_64/srcloc.stderr
@@ -1,5 +1,5 @@
error: invalid instruction mnemonic 'invalid_instruction'
- --> $DIR/srcloc.rs:10:15
+ --> $DIR/srcloc.rs:11:15
|
LL | asm!("invalid_instruction");
| ^
@@ -11,7 +11,7 @@ LL | invalid_instruction
| ^^^^^^^^^^^^^^^^^^^
error: invalid instruction mnemonic 'invalid_instruction'
- --> $DIR/srcloc.rs:14:13
+ --> $DIR/srcloc.rs:15:13
|
LL | invalid_instruction
| ^
@@ -23,7 +23,7 @@ LL | invalid_instruction
| ^^^^^^^^^^^^^^^^^^^
error: invalid instruction mnemonic 'invalid_instruction'
- --> $DIR/srcloc.rs:19:13
+ --> $DIR/srcloc.rs:20:13
|
LL | invalid_instruction
| ^
@@ -35,7 +35,7 @@ LL | invalid_instruction
| ^^^^^^^^^^^^^^^^^^^
error: invalid instruction mnemonic 'invalid_instruction'
- --> $DIR/srcloc.rs:25:13
+ --> $DIR/srcloc.rs:26:13
|
LL | invalid_instruction
| ^
@@ -47,7 +47,7 @@ LL | invalid_instruction
| ^^^^^^^^^^^^^^^^^^^
error: invalid instruction mnemonic 'invalid_instruction'
- --> $DIR/srcloc.rs:32:13
+ --> $DIR/srcloc.rs:33:13
|
LL | invalid_instruction
| ^
@@ -59,7 +59,7 @@ LL | invalid_instruction
| ^^^^^^^^^^^^^^^^^^^
error: invalid instruction mnemonic 'invalid_instruction'
- --> $DIR/srcloc.rs:37:14
+ --> $DIR/srcloc.rs:38:14
|
LL | asm!(concat!("invalid", "_", "instruction"));
| ^
@@ -71,7 +71,7 @@ LL | invalid_instruction
| ^^^^^^^^^^^^^^^^^^^
warning: scale factor without index register is ignored
- --> $DIR/srcloc.rs:40:15
+ --> $DIR/srcloc.rs:41:15
|
LL | asm!("movaps %xmm3, (%esi, 2)", options(att_syntax));
| ^
@@ -83,7 +83,7 @@ LL | movaps %xmm3, (%esi, 2)
| ^
error: invalid instruction mnemonic 'invalid_instruction'
- --> $DIR/srcloc.rs:44:14
+ --> $DIR/srcloc.rs:45:14
|
LL | "invalid_instruction",
| ^
@@ -95,7 +95,7 @@ LL | invalid_instruction
| ^^^^^^^^^^^^^^^^^^^
error: invalid instruction mnemonic 'invalid_instruction'
- --> $DIR/srcloc.rs:50:14
+ --> $DIR/srcloc.rs:51:14
|
LL | "invalid_instruction",
| ^
@@ -107,7 +107,7 @@ LL | invalid_instruction
| ^^^^^^^^^^^^^^^^^^^
error: invalid instruction mnemonic 'invalid_instruction'
- --> $DIR/srcloc.rs:57:14
+ --> $DIR/srcloc.rs:58:14
|
LL | "invalid_instruction",
| ^
@@ -119,7 +119,7 @@ LL | invalid_instruction
| ^^^^^^^^^^^^^^^^^^^
error: invalid instruction mnemonic 'invalid_instruction'
- --> $DIR/srcloc.rs:64:13
+ --> $DIR/srcloc.rs:65:13
|
LL | concat!("invalid", "_", "instruction"),
| ^
@@ -131,7 +131,7 @@ LL | invalid_instruction
| ^^^^^^^^^^^^^^^^^^^
error: invalid instruction mnemonic 'invalid_instruction'
- --> $DIR/srcloc.rs:71:13
+ --> $DIR/srcloc.rs:72:13
|
LL | concat!("invalid", "_", "instruction"),
| ^
@@ -143,7 +143,7 @@ LL | invalid_instruction
| ^^^^^^^^^^^^^^^^^^^
error: invalid instruction mnemonic 'invalid_instruction1'
- --> $DIR/srcloc.rs:78:14
+ --> $DIR/srcloc.rs:79:14
|
LL | "invalid_instruction1",
| ^
@@ -155,7 +155,7 @@ LL | invalid_instruction1
| ^^^^^^^^^^^^^^^^^^^^
error: invalid instruction mnemonic 'invalid_instruction2'
- --> $DIR/srcloc.rs:79:14
+ --> $DIR/srcloc.rs:80:14
|
LL | "invalid_instruction2",
| ^
@@ -167,7 +167,7 @@ LL | invalid_instruction2
| ^^^^^^^^^^^^^^^^^^^^
error: invalid instruction mnemonic 'invalid_instruction1'
- --> $DIR/srcloc.rs:85:13
+ --> $DIR/srcloc.rs:86:13
|
LL | concat!(
| ^
@@ -179,7 +179,7 @@ LL | invalid_instruction1
| ^^^^^^^^^^^^^^^^^^^^
error: invalid instruction mnemonic 'invalid_instruction2'
- --> $DIR/srcloc.rs:85:13
+ --> $DIR/srcloc.rs:86:13
|
LL | concat!(
| ^
@@ -191,7 +191,7 @@ LL | invalid_instruction2
| ^^^^^^^^^^^^^^^^^^^^
error: invalid instruction mnemonic 'invalid_instruction1'
- --> $DIR/srcloc.rs:94:13
+ --> $DIR/srcloc.rs:95:13
|
LL | concat!(
| ^
@@ -203,7 +203,7 @@ LL | invalid_instruction1
| ^^^^^^^^^^^^^^^^^^^^
error: invalid instruction mnemonic 'invalid_instruction2'
- --> $DIR/srcloc.rs:94:13
+ --> $DIR/srcloc.rs:95:13
|
LL | concat!(
| ^
@@ -215,7 +215,7 @@ LL | invalid_instruction2
| ^^^^^^^^^^^^^^^^^^^^
error: invalid instruction mnemonic 'invalid_instruction3'
- --> $DIR/srcloc.rs:98:13
+ --> $DIR/srcloc.rs:99:13
|
LL | concat!(
| ^
@@ -227,7 +227,7 @@ LL | invalid_instruction3
| ^^^^^^^^^^^^^^^^^^^^
error: invalid instruction mnemonic 'invalid_instruction4'
- --> $DIR/srcloc.rs:98:13
+ --> $DIR/srcloc.rs:99:13
|
LL | concat!(
| ^
@@ -239,7 +239,7 @@ LL | invalid_instruction4
| ^^^^^^^^^^^^^^^^^^^^
error: invalid instruction mnemonic 'invalid_instruction1'
- --> $DIR/srcloc.rs:109:13
+ --> $DIR/srcloc.rs:110:13
|
LL | concat!(
| ^
@@ -251,7 +251,7 @@ LL | invalid_instruction1
| ^^^^^^^^^^^^^^^^^^^^
error: invalid instruction mnemonic 'invalid_instruction2'
- --> $DIR/srcloc.rs:109:13
+ --> $DIR/srcloc.rs:110:13
|
LL | concat!(
| ^
@@ -263,7 +263,7 @@ LL | invalid_instruction2
| ^^^^^^^^^^^^^^^^^^^^
error: invalid instruction mnemonic 'invalid_instruction3'
- --> $DIR/srcloc.rs:113:13
+ --> $DIR/srcloc.rs:114:13
|
LL | concat!(
| ^
@@ -275,7 +275,7 @@ LL | invalid_instruction3
| ^^^^^^^^^^^^^^^^^^^^
error: invalid instruction mnemonic 'invalid_instruction4'
- --> $DIR/srcloc.rs:113:13
+ --> $DIR/srcloc.rs:114:13
|
LL | concat!(
| ^
diff --git a/src/test/ui/asm/x86_64/sym.rs b/src/test/ui/asm/x86_64/sym.rs
index 958dbbdd376..fcb6c5fbfaf 100644
--- a/src/test/ui/asm/x86_64/sym.rs
+++ b/src/test/ui/asm/x86_64/sym.rs
@@ -3,7 +3,9 @@
// only-linux
// run-pass
-#![feature(asm, thread_local, asm_sym)]
+#![feature(thread_local, asm_sym)]
+
+use std::arch::asm;
extern "C" fn f1() -> i32 {
111
diff --git a/src/test/ui/asm/x86_64/target-feature-attr.rs b/src/test/ui/asm/x86_64/target-feature-attr.rs
index 4f82cd8aab9..14490c3e0f2 100644
--- a/src/test/ui/asm/x86_64/target-feature-attr.rs
+++ b/src/test/ui/asm/x86_64/target-feature-attr.rs
@@ -1,6 +1,8 @@
// only-x86_64
-#![feature(asm, avx512_target_feature)]
+#![feature(avx512_target_feature)]
+
+use std::arch::asm;
#[target_feature(enable = "avx")]
unsafe fn foo() {
diff --git a/src/test/ui/asm/x86_64/target-feature-attr.stderr b/src/test/ui/asm/x86_64/target-feature-attr.stderr
index 295c8a97ed3..c852726ee7f 100644
--- a/src/test/ui/asm/x86_64/target-feature-attr.stderr
+++ b/src/test/ui/asm/x86_64/target-feature-attr.stderr
@@ -1,23 +1,23 @@
error: register class `ymm_reg` requires the `avx` target feature
- --> $DIR/target-feature-attr.rs:16:40
+ --> $DIR/target-feature-attr.rs:18:40
|
LL | asm!("vaddps {2:y}, {0:y}, {1:y}", in(ymm_reg) x, in(ymm_reg) y, lateout(ymm_reg) x);
| ^^^^^^^^^^^^^
error: register class `ymm_reg` requires the `avx` target feature
- --> $DIR/target-feature-attr.rs:16:55
+ --> $DIR/target-feature-attr.rs:18:55
|
LL | asm!("vaddps {2:y}, {0:y}, {1:y}", in(ymm_reg) x, in(ymm_reg) y, lateout(ymm_reg) x);
| ^^^^^^^^^^^^^
error: register class `ymm_reg` requires the `avx` target feature
- --> $DIR/target-feature-attr.rs:16:70
+ --> $DIR/target-feature-attr.rs:18:70
|
LL | asm!("vaddps {2:y}, {0:y}, {1:y}", in(ymm_reg) x, in(ymm_reg) y, lateout(ymm_reg) x);
| ^^^^^^^^^^^^^^^^^^
error: register class `kreg` requires at least one of the following target features: avx512bw, avx512f
- --> $DIR/target-feature-attr.rs:31:23
+ --> $DIR/target-feature-attr.rs:33:23
|
LL | asm!("/* {0} */", in(kreg) x);
| ^^^^^^^^^^
diff --git a/src/test/ui/asm/x86_64/type-check-2.rs b/src/test/ui/asm/x86_64/type-check-2.rs
index 94aadcf09f4..f95aebb78b5 100644
--- a/src/test/ui/asm/x86_64/type-check-2.rs
+++ b/src/test/ui/asm/x86_64/type-check-2.rs
@@ -1,6 +1,8 @@
// only-x86_64
-#![feature(asm, repr_simd, never_type, asm_sym)]
+#![feature(repr_simd, never_type, asm_sym)]
+
+use std::arch::asm;
#[repr(simd)]
struct SimdNonCopy(f32, f32, f32, f32);
diff --git a/src/test/ui/asm/x86_64/type-check-2.stderr b/src/test/ui/asm/x86_64/type-check-2.stderr
index 9e73c9a8d6a..cec750fdf9a 100644
--- a/src/test/ui/asm/x86_64/type-check-2.stderr
+++ b/src/test/ui/asm/x86_64/type-check-2.stderr
@@ -1,13 +1,13 @@
error: arguments for inline assembly must be copyable
- --> $DIR/type-check-2.rs:42:32
+ --> $DIR/type-check-2.rs:44:32
|
LL | asm!("{}", in(xmm_reg) SimdNonCopy(0.0, 0.0, 0.0, 0.0));
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
= note: `SimdNonCopy` does not implement the Copy trait
-error: cannot use value of type `[closure@$DIR/type-check-2.rs:54:28: 54:38]` for inline assembly
- --> $DIR/type-check-2.rs:54:28
+error: cannot use value of type `[closure@$DIR/type-check-2.rs:56:28: 56:38]` for inline assembly
+ --> $DIR/type-check-2.rs:56:28
|
LL | asm!("{}", in(reg) |x: i32| x);
| ^^^^^^^^^^
@@ -15,7 +15,7 @@ LL | asm!("{}", in(reg) |x: i32| x);
= note: only integers, floats, SIMD vectors, pointers and function pointers can be used as arguments for inline assembly
error: cannot use value of type `Vec<i32>` for inline assembly
- --> $DIR/type-check-2.rs:56:28
+ --> $DIR/type-check-2.rs:58:28
|
LL | asm!("{}", in(reg) vec![0]);
| ^^^^^^^
@@ -24,7 +24,7 @@ LL | asm!("{}", in(reg) vec![0]);
= note: this error originates in the macro `vec` (in Nightly builds, run with -Z macro-backtrace for more info)
error: cannot use value of type `(i32, i32, i32)` for inline assembly
- --> $DIR/type-check-2.rs:58:28
+ --> $DIR/type-check-2.rs:60:28
|
LL | asm!("{}", in(reg) (1, 2, 3));
| ^^^^^^^^^
@@ -32,7 +32,7 @@ LL | asm!("{}", in(reg) (1, 2, 3));
= note: only integers, floats, SIMD vectors, pointers and function pointers can be used as arguments for inline assembly
error: cannot use value of type `[i32; 3]` for inline assembly
- --> $DIR/type-check-2.rs:60:28
+ --> $DIR/type-check-2.rs:62:28
|
LL | asm!("{}", in(reg) [1, 2, 3]);
| ^^^^^^^^^
@@ -40,7 +40,7 @@ LL | asm!("{}", in(reg) [1, 2, 3]);
= note: only integers, floats, SIMD vectors, pointers and function pointers can be used as arguments for inline assembly
error: cannot use value of type `fn() {main}` for inline assembly
- --> $DIR/type-check-2.rs:68:31
+ --> $DIR/type-check-2.rs:70:31
|
LL | asm!("{}", inout(reg) f);
| ^
@@ -48,7 +48,7 @@ LL | asm!("{}", inout(reg) f);
= note: only integers, floats, SIMD vectors, pointers and function pointers can be used as arguments for inline assembly
error: cannot use value of type `&mut i32` for inline assembly
- --> $DIR/type-check-2.rs:71:31
+ --> $DIR/type-check-2.rs:73:31
|
LL | asm!("{}", inout(reg) r);
| ^
@@ -56,31 +56,31 @@ LL | asm!("{}", inout(reg) r);
= note: only integers, floats, SIMD vectors, pointers and function pointers can be used as arguments for inline assembly
error: asm `sym` operand must point to a fn or static
- --> $DIR/type-check-2.rs:35:24
+ --> $DIR/type-check-2.rs:37:24
|
LL | asm!("{}", sym C);
| ^
error: asm `sym` operand must point to a fn or static
- --> $DIR/type-check-2.rs:37:24
+ --> $DIR/type-check-2.rs:39:24
|
LL | asm!("{}", sym x);
| ^
error[E0381]: use of possibly-uninitialized variable: `x`
- --> $DIR/type-check-2.rs:13:28
+ --> $DIR/type-check-2.rs:15:28
|
LL | asm!("{}", in(reg) x);
| ^ use of possibly-uninitialized `x`
error[E0381]: use of possibly-uninitialized variable: `y`
- --> $DIR/type-check-2.rs:16:9
+ --> $DIR/type-check-2.rs:18:9
|
LL | asm!("{}", inout(reg) y);
| ^^^^^^^^^^^^^^^^^^^^^^^^ use of possibly-uninitialized `y`
error[E0596]: cannot borrow `v` as mutable, as it is not declared as mutable
- --> $DIR/type-check-2.rs:24:29
+ --> $DIR/type-check-2.rs:26:29
|
LL | let v: Vec<u64> = vec![0, 1, 2];
| - help: consider changing this to be mutable: `mut v`
@@ -89,7 +89,7 @@ LL | asm!("{}", out(reg) v[0]);
| ^ cannot borrow as mutable
error[E0596]: cannot borrow `v` as mutable, as it is not declared as mutable
- --> $DIR/type-check-2.rs:26:31
+ --> $DIR/type-check-2.rs:28:31
|
LL | let v: Vec<u64> = vec![0, 1, 2];
| - help: consider changing this to be mutable: `mut v`
diff --git a/src/test/ui/asm/x86_64/type-check-3.rs b/src/test/ui/asm/x86_64/type-check-3.rs
index 83674cf8204..595de55fd8b 100644
--- a/src/test/ui/asm/x86_64/type-check-3.rs
+++ b/src/test/ui/asm/x86_64/type-check-3.rs
@@ -1,7 +1,9 @@
// only-x86_64
// compile-flags: -C target-feature=+avx512f
-#![feature(asm, global_asm, asm_const)]
+#![feature(asm_const)]
+
+use std::arch::{asm, global_asm};
use std::arch::x86_64::{_mm256_setzero_ps, _mm_setzero_ps};
diff --git a/src/test/ui/asm/x86_64/type-check-3.stderr b/src/test/ui/asm/x86_64/type-check-3.stderr
index 9f6989ca03d..aeb638d6949 100644
--- a/src/test/ui/asm/x86_64/type-check-3.stderr
+++ b/src/test/ui/asm/x86_64/type-check-3.stderr
@@ -1,5 +1,5 @@
error: type `i128` cannot be used with this register class
- --> $DIR/type-check-3.rs:12:28
+ --> $DIR/type-check-3.rs:14:28
|
LL | asm!("{}", in(reg) 0i128);
| ^^^^^
@@ -7,7 +7,7 @@ LL | asm!("{}", in(reg) 0i128);
= note: register class `reg` supports these types: i16, i32, i64, f32, f64
error: type `__m128` cannot be used with this register class
- --> $DIR/type-check-3.rs:14:28
+ --> $DIR/type-check-3.rs:16:28
|
LL | asm!("{}", in(reg) _mm_setzero_ps());
| ^^^^^^^^^^^^^^^^
@@ -15,7 +15,7 @@ LL | asm!("{}", in(reg) _mm_setzero_ps());
= note: register class `reg` supports these types: i16, i32, i64, f32, f64
error: type `__m256` cannot be used with this register class
- --> $DIR/type-check-3.rs:16:28
+ --> $DIR/type-check-3.rs:18:28
|
LL | asm!("{}", in(reg) _mm256_setzero_ps());
| ^^^^^^^^^^^^^^^^^^^
@@ -23,7 +23,7 @@ LL | asm!("{}", in(reg) _mm256_setzero_ps());
= note: register class `reg` supports these types: i16, i32, i64, f32, f64
error: type `u8` cannot be used with this register class
- --> $DIR/type-check-3.rs:18:32
+ --> $DIR/type-check-3.rs:20:32
|
LL | asm!("{}", in(xmm_reg) 0u8);
| ^^^
@@ -31,7 +31,7 @@ LL | asm!("{}", in(xmm_reg) 0u8);
= note: register class `xmm_reg` supports these types: i32, i64, f32, f64, i8x16, i16x8, i32x4, i64x2, f32x4, f64x2
error: `avx512bw` target feature is not enabled
- --> $DIR/type-check-3.rs:27:29
+ --> $DIR/type-check-3.rs:29:29
|
LL | asm!("{}", in(kreg) 0u64);
| ^^^^
@@ -39,7 +39,7 @@ LL | asm!("{}", in(kreg) 0u64);
= note: this is required to use type `u64` with register class `kreg`
warning: formatting may not be suitable for sub-register argument
- --> $DIR/type-check-3.rs:32:15
+ --> $DIR/type-check-3.rs:34:15
|
LL | asm!("{0} {0}", in(reg) 0i16);
| ^^^ ^^^ ---- for this argument
@@ -49,7 +49,7 @@ LL | asm!("{0} {0}", in(reg) 0i16);
= help: or use the `r` modifier to keep the default formatting of `rax`
warning: formatting may not be suitable for sub-register argument
- --> $DIR/type-check-3.rs:34:15
+ --> $DIR/type-check-3.rs:36:15
|
LL | asm!("{0} {0:x}", in(reg) 0i16);
| ^^^ ---- for this argument
@@ -58,7 +58,7 @@ LL | asm!("{0} {0:x}", in(reg) 0i16);
= help: or use the `r` modifier to keep the default formatting of `rax`
warning: formatting may not be suitable for sub-register argument
- --> $DIR/type-check-3.rs:36:15
+ --> $DIR/type-check-3.rs:38:15
|
LL | asm!("{}", in(reg) 0i32);
| ^^ ---- for this argument
@@ -67,7 +67,7 @@ LL | asm!("{}", in(reg) 0i32);
= help: or use the `r` modifier to keep the default formatting of `rax`
warning: formatting may not be suitable for sub-register argument
- --> $DIR/type-check-3.rs:39:15
+ --> $DIR/type-check-3.rs:41:15
|
LL | asm!("{}", in(ymm_reg) 0i64);
| ^^ ---- for this argument
@@ -76,7 +76,7 @@ LL | asm!("{}", in(ymm_reg) 0i64);
= help: or use the `y` modifier to keep the default formatting of `ymm0`
error: type `i8` cannot be used with this register class
- --> $DIR/type-check-3.rs:50:28
+ --> $DIR/type-check-3.rs:52:28
|
LL | asm!("{}", in(reg) 0i8);
| ^^^
@@ -85,7 +85,7 @@ LL | asm!("{}", in(reg) 0i8);
= help: consider using the `reg_byte` register class instead
error: incompatible types for asm inout argument
- --> $DIR/type-check-3.rs:62:33
+ --> $DIR/type-check-3.rs:64:33
|
LL | asm!("{:r}", inout(reg) 0u32 => val_f32);
| ^^^^ ^^^^^^^ type `f32`
@@ -95,7 +95,7 @@ LL | asm!("{:r}", inout(reg) 0u32 => val_f32);
= note: asm inout arguments must have the same type, unless they are both pointers or integers of the same size
error: incompatible types for asm inout argument
- --> $DIR/type-check-3.rs:64:33
+ --> $DIR/type-check-3.rs:66:33
|
LL | asm!("{:r}", inout(reg) 0u32 => val_ptr);
| ^^^^ ^^^^^^^ type `*mut u8`
@@ -105,7 +105,7 @@ LL | asm!("{:r}", inout(reg) 0u32 => val_ptr);
= note: asm inout arguments must have the same type, unless they are both pointers or integers of the same size
error: incompatible types for asm inout argument
- --> $DIR/type-check-3.rs:66:33
+ --> $DIR/type-check-3.rs:68:33
|
LL | asm!("{:r}", inout(reg) main => val_u32);
| ^^^^ ^^^^^^^ type `u32`
@@ -115,7 +115,7 @@ LL | asm!("{:r}", inout(reg) main => val_u32);
= note: asm inout arguments must have the same type, unless they are both pointers or integers of the same size
error[E0013]: constants cannot refer to statics
- --> $DIR/type-check-3.rs:82:25
+ --> $DIR/type-check-3.rs:84:25
|
LL | global_asm!("{}", const S);
| ^
@@ -123,7 +123,7 @@ LL | global_asm!("{}", const S);
= help: consider extracting the value of the `static` to a `const`, and referring to that
error[E0013]: constants cannot refer to statics
- --> $DIR/type-check-3.rs:85:35
+ --> $DIR/type-check-3.rs:87:35
|
LL | global_asm!("{}", const const_foo(S));
| ^
@@ -131,7 +131,7 @@ LL | global_asm!("{}", const const_foo(S));
= help: consider extracting the value of the `static` to a `const`, and referring to that
error[E0013]: constants cannot refer to statics
- --> $DIR/type-check-3.rs:88:35
+ --> $DIR/type-check-3.rs:90:35
|
LL | global_asm!("{}", const const_bar(S));
| ^
diff --git a/src/test/ui/associated-consts/associated-const-generic-obligations.stderr b/src/test/ui/associated-consts/associated-const-generic-obligations.stderr
index d8bac07e058..f45fa0ad55c 100644
--- a/src/test/ui/associated-consts/associated-const-generic-obligations.stderr
+++ b/src/test/ui/associated-consts/associated-const-generic-obligations.stderr
@@ -1,12 +1,14 @@
error[E0326]: implemented const `FROM` has an incompatible type for trait
--> $DIR/associated-const-generic-obligations.rs:14:17
|
-LL | const FROM: Self::Out;
- | --------- type in trait
-...
LL | const FROM: &'static str = "foo";
| ^^^^^^^^^^^^ expected associated type, found `&str`
|
+note: type in trait
+ --> $DIR/associated-const-generic-obligations.rs:10:17
+ |
+LL | const FROM: Self::Out;
+ | ^^^^^^^^^
= note: expected associated type `<T as Foo>::Out`
found reference `&'static str`
diff --git a/src/test/ui/associated-consts/associated-const-impl-wrong-type.stderr b/src/test/ui/associated-consts/associated-const-impl-wrong-type.stderr
index acdf33b2b83..f3616035fc7 100644
--- a/src/test/ui/associated-consts/associated-const-impl-wrong-type.stderr
+++ b/src/test/ui/associated-consts/associated-const-impl-wrong-type.stderr
@@ -1,11 +1,14 @@
error[E0326]: implemented const `BAR` has an incompatible type for trait
--> $DIR/associated-const-impl-wrong-type.rs:8:16
|
-LL | const BAR: u32;
- | --- type in trait
-...
LL | const BAR: i32 = -1;
| ^^^ expected `u32`, found `i32`
+ |
+note: type in trait
+ --> $DIR/associated-const-impl-wrong-type.rs:2:16
+ |
+LL | const BAR: u32;
+ | ^^^
error: aborting due to previous error
diff --git a/src/test/ui/associated-types/associated-type-destructuring-assignment.rs b/src/test/ui/associated-types/associated-type-destructuring-assignment.rs
index fea7c7a383f..f038c9ce7ba 100644
--- a/src/test/ui/associated-types/associated-type-destructuring-assignment.rs
+++ b/src/test/ui/associated-types/associated-type-destructuring-assignment.rs
@@ -1,6 +1,5 @@
// check-pass
-#![feature(destructuring_assignment)]
#![feature(more_qualified_paths)]
enum E { V() }
diff --git a/src/test/ui/associated-types/associated-types-binding-to-type-defined-in-supertrait.stderr b/src/test/ui/associated-types/associated-types-binding-to-type-defined-in-supertrait.stderr
index 924a09c87f0..0cccc6b38a3 100644
--- a/src/test/ui/associated-types/associated-types-binding-to-type-defined-in-supertrait.stderr
+++ b/src/test/ui/associated-types/associated-types-binding-to-type-defined-in-supertrait.stderr
@@ -2,8 +2,13 @@ error[E0271]: type mismatch resolving `<ModelT as Vehicle>::Color == Blue`
--> $DIR/associated-types-binding-to-type-defined-in-supertrait.rs:31:10
|
LL | fn b() { blue_car(ModelT); }
- | ^^^^^^^^ expected struct `Blue`, found struct `Black`
+ | ^^^^^^^^ type mismatch resolving `<ModelT as Vehicle>::Color == Blue`
|
+note: expected this to be `Blue`
+ --> $DIR/associated-types-binding-to-type-defined-in-supertrait.rs:16:40
+ |
+LL | impl Vehicle for ModelT { type Color = Black; }
+ | ^^^^^
note: required by a bound in `blue_car`
--> $DIR/associated-types-binding-to-type-defined-in-supertrait.rs:27:19
|
@@ -14,8 +19,13 @@ error[E0271]: type mismatch resolving `<ModelU as Vehicle>::Color == Black`
--> $DIR/associated-types-binding-to-type-defined-in-supertrait.rs:32:10
|
LL | fn c() { black_car(ModelU); }
- | ^^^^^^^^^ expected struct `Black`, found struct `Blue`
+ | ^^^^^^^^^ type mismatch resolving `<ModelU as Vehicle>::Color == Black`
+ |
+note: expected this to be `Black`
+ --> $DIR/associated-types-binding-to-type-defined-in-supertrait.rs:21:40
|
+LL | impl Vehicle for ModelU { type Color = Blue; }
+ | ^^^^
note: required by a bound in `black_car`
--> $DIR/associated-types-binding-to-type-defined-in-supertrait.rs:24:20
|
diff --git a/src/test/ui/associated-types/associated-types-eq-3.rs b/src/test/ui/associated-types/associated-types-eq-3.rs
index 3bb03c39e0f..f6988dcf65e 100644
--- a/src/test/ui/associated-types/associated-types-eq-3.rs
+++ b/src/test/ui/associated-types/associated-types-eq-3.rs
@@ -37,8 +37,6 @@ pub fn main() {
let a = 42;
foo1(a);
//~^ ERROR type mismatch resolving
- //~| expected struct `Bar`, found `usize`
baz(&a);
//~^ ERROR type mismatch resolving
- //~| expected struct `Bar`, found `usize`
}
diff --git a/src/test/ui/associated-types/associated-types-eq-3.stderr b/src/test/ui/associated-types/associated-types-eq-3.stderr
index 5f227a3b480..521907a6044 100644
--- a/src/test/ui/associated-types/associated-types-eq-3.stderr
+++ b/src/test/ui/associated-types/associated-types-eq-3.stderr
@@ -17,8 +17,13 @@ error[E0271]: type mismatch resolving `<isize as Foo>::A == Bar`
--> $DIR/associated-types-eq-3.rs:38:5
|
LL | foo1(a);
- | ^^^^ expected struct `Bar`, found `usize`
+ | ^^^^ type mismatch resolving `<isize as Foo>::A == Bar`
|
+note: expected this to be `Bar`
+ --> $DIR/associated-types-eq-3.rs:12:14
+ |
+LL | type A = usize;
+ | ^^^^^
note: required by a bound in `foo1`
--> $DIR/associated-types-eq-3.rs:18:16
|
@@ -26,11 +31,16 @@ LL | fn foo1<I: Foo<A=Bar>>(x: I) {
| ^^^^^ required by this bound in `foo1`
error[E0271]: type mismatch resolving `<isize as Foo>::A == Bar`
- --> $DIR/associated-types-eq-3.rs:41:9
+ --> $DIR/associated-types-eq-3.rs:40:9
|
LL | baz(&a);
- | ^^ expected struct `Bar`, found `usize`
+ | ^^ type mismatch resolving `<isize as Foo>::A == Bar`
+ |
+note: expected this to be `Bar`
+ --> $DIR/associated-types-eq-3.rs:12:14
|
+LL | type A = usize;
+ | ^^^^^
= note: required for the cast to the object type `dyn Foo<A = Bar>`
error: aborting due to 3 previous errors
diff --git a/src/test/ui/associated-types/associated-types-eq-hr.nll.stderr b/src/test/ui/associated-types/associated-types-eq-hr.nll.stderr
index 1da82aba5bc..b306ae273e8 100644
--- a/src/test/ui/associated-types/associated-types-eq-hr.nll.stderr
+++ b/src/test/ui/associated-types/associated-types-eq-hr.nll.stderr
@@ -2,8 +2,13 @@ error[E0271]: type mismatch resolving `for<'x> <UintStruct as TheTrait<&'x isize
--> $DIR/associated-types-eq-hr.rs:87:5
|
LL | foo::<UintStruct>();
- | ^^^^^^^^^^^^^^^^^ expected `isize`, found `usize`
+ | ^^^^^^^^^^^^^^^^^ type mismatch resolving `for<'x> <UintStruct as TheTrait<&'x isize>>::A == &'x isize`
|
+note: expected this to be `&isize`
+ --> $DIR/associated-types-eq-hr.rs:26:14
+ |
+LL | type A = &'a usize;
+ | ^^^^^^^^^
= note: expected reference `&isize`
found reference `&usize`
note: required by a bound in `foo`
@@ -19,8 +24,13 @@ error[E0271]: type mismatch resolving `for<'x> <IntStruct as TheTrait<&'x isize>
--> $DIR/associated-types-eq-hr.rs:91:5
|
LL | bar::<IntStruct>();
- | ^^^^^^^^^^^^^^^^ expected `usize`, found `isize`
+ | ^^^^^^^^^^^^^^^^ type mismatch resolving `for<'x> <IntStruct as TheTrait<&'x isize>>::A == &'x usize`
+ |
+note: expected this to be `&usize`
+ --> $DIR/associated-types-eq-hr.rs:14:14
|
+LL | type A = &'a isize;
+ | ^^^^^^^^^
= note: expected reference `&usize`
found reference `&isize`
note: required by a bound in `bar`
diff --git a/src/test/ui/associated-types/associated-types-eq-hr.stderr b/src/test/ui/associated-types/associated-types-eq-hr.stderr
index e34b4f1c772..1329e1382fd 100644
--- a/src/test/ui/associated-types/associated-types-eq-hr.stderr
+++ b/src/test/ui/associated-types/associated-types-eq-hr.stderr
@@ -2,8 +2,13 @@ error[E0271]: type mismatch resolving `for<'x> <UintStruct as TheTrait<&'x isize
--> $DIR/associated-types-eq-hr.rs:87:5
|
LL | foo::<UintStruct>();
- | ^^^^^^^^^^^^^^^^^ expected `isize`, found `usize`
+ | ^^^^^^^^^^^^^^^^^ type mismatch resolving `for<'x> <UintStruct as TheTrait<&'x isize>>::A == &'x isize`
|
+note: expected this to be `&isize`
+ --> $DIR/associated-types-eq-hr.rs:26:14
+ |
+LL | type A = &'a usize;
+ | ^^^^^^^^^
= note: expected reference `&isize`
found reference `&usize`
note: required by a bound in `foo`
@@ -19,8 +24,13 @@ error[E0271]: type mismatch resolving `for<'x> <IntStruct as TheTrait<&'x isize>
--> $DIR/associated-types-eq-hr.rs:91:5
|
LL | bar::<IntStruct>();
- | ^^^^^^^^^^^^^^^^ expected `usize`, found `isize`
+ | ^^^^^^^^^^^^^^^^ type mismatch resolving `for<'x> <IntStruct as TheTrait<&'x isize>>::A == &'x usize`
+ |
+note: expected this to be `&usize`
+ --> $DIR/associated-types-eq-hr.rs:14:14
|
+LL | type A = &'a isize;
+ | ^^^^^^^^^
= note: expected reference `&usize`
found reference `&isize`
note: required by a bound in `bar`
diff --git a/src/test/ui/associated-types/associated-types-issue-20346.stderr b/src/test/ui/associated-types/associated-types-issue-20346.stderr
index 1c24ce05ef4..516057e53d2 100644
--- a/src/test/ui/associated-types/associated-types-issue-20346.stderr
+++ b/src/test/ui/associated-types/associated-types-issue-20346.stderr
@@ -5,8 +5,13 @@ LL | fn test_adapter<T, I: Iterator<Item=Option<T>>>(it: I) {
| - this type parameter
...
LL | is_iterator_of::<Option<T>, _>(&adapter);
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected enum `Option`, found type parameter `T`
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type mismatch resolving `<Adapter<I> as Iterator>::Item == Option<T>`
|
+note: expected this to be `Option<T>`
+ --> $DIR/associated-types-issue-20346.rs:23:17
+ |
+LL | type Item = T;
+ | ^
= note: expected enum `Option<T>`
found type `T`
note: required by a bound in `is_iterator_of`
diff --git a/src/test/ui/associated-types/cache/project-fn-ret-contravariant.transmute.stderr b/src/test/ui/associated-types/cache/project-fn-ret-contravariant.transmute.stderr
index 0be9b37263a..33f1e0f05b2 100644
--- a/src/test/ui/associated-types/cache/project-fn-ret-contravariant.transmute.stderr
+++ b/src/test/ui/associated-types/cache/project-fn-ret-contravariant.transmute.stderr
@@ -4,7 +4,7 @@ error[E0759]: `x` has lifetime `'a` but it needs to satisfy a `'static` lifetime
LL | fn baz<'a,'b>(x: &'a u32) -> &'static u32 {
| ------- this data with lifetime `'a`...
LL | bar(foo, x)
- | ----^^^---- ...is captured and required to live as long as `'static` here
+ | ^^^ - ...is used and required to live as long as `'static` here
error: aborting due to previous error
diff --git a/src/test/ui/associated-types/cache/project-fn-ret-invariant.transmute.stderr b/src/test/ui/associated-types/cache/project-fn-ret-invariant.transmute.stderr
index 0a44864b249..609627aaa9e 100644
--- a/src/test/ui/associated-types/cache/project-fn-ret-invariant.transmute.stderr
+++ b/src/test/ui/associated-types/cache/project-fn-ret-invariant.transmute.stderr
@@ -5,7 +5,16 @@ LL | fn baz<'a, 'b>(x: Type<'a>) -> Type<'static> {
| -------- this data with lifetime `'a`...
...
LL | bar(foo, x)
- | ----^^^---- ...is captured and required to live as long as `'static` here
+ | ^^^ - ...is used and required to live as long as `'static` here
+ |
+note: `'static` lifetime requirement introduced by the return type
+ --> $DIR/project-fn-ret-invariant.rs:45:37
+ |
+LL | fn baz<'a, 'b>(x: Type<'a>) -> Type<'static> {
+ | ^^^^^^^ `'static` requirement introduced here
+...
+LL | bar(foo, x)
+ | ----------- because of this returned expression
error: aborting due to previous error
diff --git a/src/test/ui/associated-types/defaults-in-other-trait-items.rs b/src/test/ui/associated-types/defaults-in-other-trait-items.rs
index 4014f46285d..505751969b6 100644
--- a/src/test/ui/associated-types/defaults-in-other-trait-items.rs
+++ b/src/test/ui/associated-types/defaults-in-other-trait-items.rs
@@ -10,6 +10,7 @@ trait Tr {
//~^ ERROR mismatched types
//~| NOTE expected associated type, found `()`
//~| NOTE expected associated type `<Self as Tr>::A`
+ //~| NOTE this expression has type `<Self as Tr>::A`
}
}
diff --git a/src/test/ui/associated-types/defaults-in-other-trait-items.stderr b/src/test/ui/associated-types/defaults-in-other-trait-items.stderr
index 493df30a64d..71d421926e7 100644
--- a/src/test/ui/associated-types/defaults-in-other-trait-items.stderr
+++ b/src/test/ui/associated-types/defaults-in-other-trait-items.stderr
@@ -5,13 +5,15 @@ LL | type A = ();
| ------------ associated type defaults can't be assumed inside the trait defining them
...
LL | let () = p;
- | ^^ expected associated type, found `()`
+ | ^^ - this expression has type `<Self as Tr>::A`
+ | |
+ | expected associated type, found `()`
|
= note: expected associated type `<Self as Tr>::A`
found unit type `()`
error[E0308]: mismatched types
- --> $DIR/defaults-in-other-trait-items.rs:35:25
+ --> $DIR/defaults-in-other-trait-items.rs:36:25
|
LL | type Ty = u8;
| ------------- associated type defaults can't be assumed inside the trait defining them
diff --git a/src/test/ui/associated-types/defaults-specialization.stderr b/src/test/ui/associated-types/defaults-specialization.stderr
index 3c7dc1fc3c9..aa8841fbaae 100644
--- a/src/test/ui/associated-types/defaults-specialization.stderr
+++ b/src/test/ui/associated-types/defaults-specialization.stderr
@@ -11,24 +11,23 @@ LL | #![feature(associated_type_defaults, specialization)]
error[E0053]: method `make` has an incompatible type for trait
--> $DIR/defaults-specialization.rs:19:18
|
-LL | fn make() -> Self::Ty {
- | -------- type in trait
-...
LL | fn make() -> u8 { 0 }
| ^^
| |
| expected associated type, found `u8`
| help: change the output type to match the trait: `<A<T> as Tr>::Ty`
|
+note: type in trait
+ --> $DIR/defaults-specialization.rs:9:18
+ |
+LL | fn make() -> Self::Ty {
+ | ^^^^^^^^
= note: expected fn pointer `fn() -> <A<T> as Tr>::Ty`
found fn pointer `fn() -> u8`
error[E0053]: method `make` has an incompatible type for trait
--> $DIR/defaults-specialization.rs:35:18
|
-LL | fn make() -> Self::Ty {
- | -------- type in trait
-...
LL | default type Ty = bool;
| ----------------------- expected this associated type
LL |
@@ -38,6 +37,11 @@ LL | fn make() -> bool { true }
| expected associated type, found `bool`
| help: change the output type to match the trait: `<B<T> as Tr>::Ty`
|
+note: type in trait
+ --> $DIR/defaults-specialization.rs:9:18
+ |
+LL | fn make() -> Self::Ty {
+ | ^^^^^^^^
= note: expected fn pointer `fn() -> <B<T> as Tr>::Ty`
found fn pointer `fn() -> bool`
diff --git a/src/test/ui/associated-types/defaults-suitability.stderr b/src/test/ui/associated-types/defaults-suitability.stderr
index 8a8211ff858..6c63c01e2c2 100644
--- a/src/test/ui/associated-types/defaults-suitability.stderr
+++ b/src/test/ui/associated-types/defaults-suitability.stderr
@@ -1,8 +1,8 @@
error[E0277]: the trait bound `NotClone: Clone` is not satisfied
- --> $DIR/defaults-suitability.rs:13:5
+ --> $DIR/defaults-suitability.rs:13:22
|
LL | type Ty: Clone = NotClone;
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `Clone` is not implemented for `NotClone`
+ | ^^^^^^^^ the trait `Clone` is not implemented for `NotClone`
|
note: required by a bound in `Tr::Ty`
--> $DIR/defaults-suitability.rs:13:14
@@ -11,10 +11,10 @@ LL | type Ty: Clone = NotClone;
| ^^^^^ required by this bound in `Tr::Ty`
error[E0277]: the trait bound `NotClone: Clone` is not satisfied
- --> $DIR/defaults-suitability.rs:22:5
+ --> $DIR/defaults-suitability.rs:22:15
|
LL | type Ty = NotClone;
- | ^^^^^^^^^^^^^^^^^^^ the trait `Clone` is not implemented for `NotClone`
+ | ^^^^^^^^ the trait `Clone` is not implemented for `NotClone`
|
note: required by a bound in `Tr2::Ty`
--> $DIR/defaults-suitability.rs:20:15
@@ -26,10 +26,10 @@ LL | type Ty = NotClone;
| -- required by a bound in this
error[E0277]: the trait bound `T: Clone` is not satisfied
- --> $DIR/defaults-suitability.rs:28:5
+ --> $DIR/defaults-suitability.rs:28:23
|
LL | type Bar: Clone = Vec<T>;
- | ^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `Clone` is not implemented for `T`
+ | ^^^^^^ the trait `Clone` is not implemented for `T`
|
= note: required because of the requirements on the impl of `Clone` for `Vec<T>`
note: required by a bound in `Foo::Bar`
@@ -43,10 +43,10 @@ LL | trait Foo<T: std::clone::Clone> {
| +++++++++++++++++++
error[E0277]: the trait bound `(): Foo<Self>` is not satisfied
- --> $DIR/defaults-suitability.rs:34:5
+ --> $DIR/defaults-suitability.rs:34:29
|
LL | type Assoc: Foo<Self> = ();
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `Foo<Self>` is not implemented for `()`
+ | ^^ the trait `Foo<Self>` is not implemented for `()`
|
note: required by a bound in `Bar::Assoc`
--> $DIR/defaults-suitability.rs:34:17
@@ -55,10 +55,10 @@ LL | type Assoc: Foo<Self> = ();
| ^^^^^^^^^ required by this bound in `Bar::Assoc`
error[E0277]: the trait bound `NotClone: IsU8<NotClone>` is not satisfied
- --> $DIR/defaults-suitability.rs:56:5
+ --> $DIR/defaults-suitability.rs:56:18
|
LL | type Assoc = NotClone;
- | ^^^^^^^^^^^^^^^^^^^^^^ the trait `IsU8<NotClone>` is not implemented for `NotClone`
+ | ^^^^^^^^ the trait `IsU8<NotClone>` is not implemented for `NotClone`
|
note: required by a bound in `D::Assoc`
--> $DIR/defaults-suitability.rs:53:18
@@ -70,10 +70,10 @@ LL | type Assoc = NotClone;
| ----- required by a bound in this
error[E0277]: the trait bound `<Self as Foo2<T>>::Baz: Clone` is not satisfied
- --> $DIR/defaults-suitability.rs:65:5
+ --> $DIR/defaults-suitability.rs:65:23
|
LL | type Bar: Clone = Vec<Self::Baz>;
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `Clone` is not implemented for `<Self as Foo2<T>>::Baz`
+ | ^^^^^^^^^^^^^^ the trait `Clone` is not implemented for `<Self as Foo2<T>>::Baz`
|
= note: required because of the requirements on the impl of `Clone` for `Vec<<Self as Foo2<T>>::Baz>`
note: required by a bound in `Foo2::Bar`
@@ -87,10 +87,10 @@ LL | trait Foo2<T> where <Self as Foo2<T>>::Baz: Clone {
| +++++++++++++++++++++++++++++++++++
error[E0277]: the trait bound `<Self as Foo25<T>>::Baz: Clone` is not satisfied
- --> $DIR/defaults-suitability.rs:74:5
+ --> $DIR/defaults-suitability.rs:74:23
|
LL | type Bar: Clone = Vec<Self::Baz>;
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `Clone` is not implemented for `<Self as Foo25<T>>::Baz`
+ | ^^^^^^^^^^^^^^ the trait `Clone` is not implemented for `<Self as Foo25<T>>::Baz`
|
= note: required because of the requirements on the impl of `Clone` for `Vec<<Self as Foo25<T>>::Baz>`
note: required by a bound in `Foo25::Bar`
@@ -104,10 +104,10 @@ LL | trait Foo25<T: Clone> where <Self as Foo25<T>>::Baz: Clone {
| ++++++++++++++++++++++++++++++++++++
error[E0277]: the trait bound `T: Clone` is not satisfied
- --> $DIR/defaults-suitability.rs:87:5
+ --> $DIR/defaults-suitability.rs:87:16
|
LL | type Baz = T;
- | ^^^^^^^^^^^^^ the trait `Clone` is not implemented for `T`
+ | ^ the trait `Clone` is not implemented for `T`
|
note: required by a bound in `Foo3::Baz`
--> $DIR/defaults-suitability.rs:84:16
diff --git a/src/test/ui/associated-types/defaults-unsound-62211-1.stderr b/src/test/ui/associated-types/defaults-unsound-62211-1.stderr
index b21cae311a0..5cd1cb4a1a7 100644
--- a/src/test/ui/associated-types/defaults-unsound-62211-1.stderr
+++ b/src/test/ui/associated-types/defaults-unsound-62211-1.stderr
@@ -1,8 +1,8 @@
error[E0277]: `Self` doesn't implement `std::fmt::Display`
- --> $DIR/defaults-unsound-62211-1.rs:20:5
+ --> $DIR/defaults-unsound-62211-1.rs:20:96
|
LL | type Output: Copy + Deref<Target = str> + AddAssign<&'static str> + From<Self> + Display = Self;
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `Self` cannot be formatted with the default formatter
+ | ^^^^ `Self` cannot be formatted with the default formatter
|
= note: in format strings you may be able to use `{:?}` (or {:#?} for pretty-print) instead
note: required by a bound in `UncheckedCopy::Output`
@@ -16,10 +16,10 @@ LL | trait UncheckedCopy: Sized + std::fmt::Display {
| +++++++++++++++++++
error[E0277]: cannot add-assign `&'static str` to `Self`
- --> $DIR/defaults-unsound-62211-1.rs:20:5
+ --> $DIR/defaults-unsound-62211-1.rs:20:96
|
LL | type Output: Copy + Deref<Target = str> + AddAssign<&'static str> + From<Self> + Display = Self;
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ no implementation for `Self += &'static str`
+ | ^^^^ no implementation for `Self += &'static str`
|
note: required by a bound in `UncheckedCopy::Output`
--> $DIR/defaults-unsound-62211-1.rs:20:47
@@ -32,10 +32,10 @@ LL | trait UncheckedCopy: Sized + AddAssign<&'static str> {
| +++++++++++++++++++++++++
error[E0277]: the trait bound `Self: Deref` is not satisfied
- --> $DIR/defaults-unsound-62211-1.rs:20:5
+ --> $DIR/defaults-unsound-62211-1.rs:20:96
|
LL | type Output: Copy + Deref<Target = str> + AddAssign<&'static str> + From<Self> + Display = Self;
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `Deref` is not implemented for `Self`
+ | ^^^^ the trait `Deref` is not implemented for `Self`
|
note: required by a bound in `UncheckedCopy::Output`
--> $DIR/defaults-unsound-62211-1.rs:20:25
@@ -48,10 +48,10 @@ LL | trait UncheckedCopy: Sized + Deref {
| +++++++
error[E0277]: the trait bound `Self: Copy` is not satisfied
- --> $DIR/defaults-unsound-62211-1.rs:20:5
+ --> $DIR/defaults-unsound-62211-1.rs:20:96
|
LL | type Output: Copy + Deref<Target = str> + AddAssign<&'static str> + From<Self> + Display = Self;
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `Copy` is not implemented for `Self`
+ | ^^^^ the trait `Copy` is not implemented for `Self`
|
note: required by a bound in `UncheckedCopy::Output`
--> $DIR/defaults-unsound-62211-1.rs:20:18
diff --git a/src/test/ui/associated-types/defaults-unsound-62211-2.stderr b/src/test/ui/associated-types/defaults-unsound-62211-2.stderr
index 2eebfb0a487..89319bb7563 100644
--- a/src/test/ui/associated-types/defaults-unsound-62211-2.stderr
+++ b/src/test/ui/associated-types/defaults-unsound-62211-2.stderr
@@ -1,8 +1,8 @@
error[E0277]: `Self` doesn't implement `std::fmt::Display`
- --> $DIR/defaults-unsound-62211-2.rs:20:5
+ --> $DIR/defaults-unsound-62211-2.rs:20:96
|
LL | type Output: Copy + Deref<Target = str> + AddAssign<&'static str> + From<Self> + Display = Self;
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `Self` cannot be formatted with the default formatter
+ | ^^^^ `Self` cannot be formatted with the default formatter
|
= note: in format strings you may be able to use `{:?}` (or {:#?} for pretty-print) instead
note: required by a bound in `UncheckedCopy::Output`
@@ -16,10 +16,10 @@ LL | trait UncheckedCopy: Sized + std::fmt::Display {
| +++++++++++++++++++
error[E0277]: cannot add-assign `&'static str` to `Self`
- --> $DIR/defaults-unsound-62211-2.rs:20:5
+ --> $DIR/defaults-unsound-62211-2.rs:20:96
|
LL | type Output: Copy + Deref<Target = str> + AddAssign<&'static str> + From<Self> + Display = Self;
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ no implementation for `Self += &'static str`
+ | ^^^^ no implementation for `Self += &'static str`
|
note: required by a bound in `UncheckedCopy::Output`
--> $DIR/defaults-unsound-62211-2.rs:20:47
@@ -32,10 +32,10 @@ LL | trait UncheckedCopy: Sized + AddAssign<&'static str> {
| +++++++++++++++++++++++++
error[E0277]: the trait bound `Self: Deref` is not satisfied
- --> $DIR/defaults-unsound-62211-2.rs:20:5
+ --> $DIR/defaults-unsound-62211-2.rs:20:96
|
LL | type Output: Copy + Deref<Target = str> + AddAssign<&'static str> + From<Self> + Display = Self;
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `Deref` is not implemented for `Self`
+ | ^^^^ the trait `Deref` is not implemented for `Self`
|
note: required by a bound in `UncheckedCopy::Output`
--> $DIR/defaults-unsound-62211-2.rs:20:25
@@ -48,10 +48,10 @@ LL | trait UncheckedCopy: Sized + Deref {
| +++++++
error[E0277]: the trait bound `Self: Copy` is not satisfied
- --> $DIR/defaults-unsound-62211-2.rs:20:5
+ --> $DIR/defaults-unsound-62211-2.rs:20:96
|
LL | type Output: Copy + Deref<Target = str> + AddAssign<&'static str> + From<Self> + Display = Self;
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `Copy` is not implemented for `Self`
+ | ^^^^ the trait `Copy` is not implemented for `Self`
|
note: required by a bound in `UncheckedCopy::Output`
--> $DIR/defaults-unsound-62211-2.rs:20:18
diff --git a/src/test/ui/associated-types/issue-43784-associated-type.stderr b/src/test/ui/associated-types/issue-43784-associated-type.stderr
index a3ed1c1fe74..f1677b822b4 100644
--- a/src/test/ui/associated-types/issue-43784-associated-type.stderr
+++ b/src/test/ui/associated-types/issue-43784-associated-type.stderr
@@ -1,8 +1,8 @@
error[E0277]: the trait bound `T: Copy` is not satisfied
- --> $DIR/issue-43784-associated-type.rs:14:5
+ --> $DIR/issue-43784-associated-type.rs:14:18
|
LL | type Assoc = T;
- | ^^^^^^^^^^^^^^^ the trait `Copy` is not implemented for `T`
+ | ^ the trait `Copy` is not implemented for `T`
|
note: required by a bound in `Complete::Assoc`
--> $DIR/issue-43784-associated-type.rs:5:17
diff --git a/src/test/ui/associated-types/issue-43924.stderr b/src/test/ui/associated-types/issue-43924.stderr
index b7fbf893bb0..526f425b21e 100644
--- a/src/test/ui/associated-types/issue-43924.stderr
+++ b/src/test/ui/associated-types/issue-43924.stderr
@@ -1,8 +1,8 @@
error[E0277]: the trait bound `(dyn ToString + 'static): Default` is not satisfied
- --> $DIR/issue-43924.rs:7:5
+ --> $DIR/issue-43924.rs:7:45
|
LL | type Out: Default + ToString + ?Sized = dyn ToString;
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `Default` is not implemented for `(dyn ToString + 'static)`
+ | ^^^^^^^^^^^^ the trait `Default` is not implemented for `(dyn ToString + 'static)`
|
note: required by a bound in `Foo::Out`
--> $DIR/issue-43924.rs:7:15
diff --git a/src/test/ui/associated-types/issue-44153.stderr b/src/test/ui/associated-types/issue-44153.stderr
index 54f6556c083..200efbe02e6 100644
--- a/src/test/ui/associated-types/issue-44153.stderr
+++ b/src/test/ui/associated-types/issue-44153.stderr
@@ -2,8 +2,13 @@ error[E0271]: type mismatch resolving `<() as Array>::Element == &()`
--> $DIR/issue-44153.rs:18:5
|
LL | <() as Visit>::visit();
- | ^^^^^^^^^^^^^^^^^^^^ expected `&()`, found `()`
+ | ^^^^^^^^^^^^^^^^^^^^ type mismatch resolving `<() as Array>::Element == &()`
|
+note: expected this to be `&()`
+ --> $DIR/issue-44153.rs:10:20
+ |
+LL | type Element = ();
+ | ^^
note: required because of the requirements on the impl of `Visit` for `()`
--> $DIR/issue-44153.rs:13:10
|
diff --git a/src/test/ui/associated-types/issue-54108.stderr b/src/test/ui/associated-types/issue-54108.stderr
index 70e688ba773..6ff5e454234 100644
--- a/src/test/ui/associated-types/issue-54108.stderr
+++ b/src/test/ui/associated-types/issue-54108.stderr
@@ -1,8 +1,8 @@
error[E0277]: cannot add `<T as SubEncoder>::ActualSize` to `<T as SubEncoder>::ActualSize`
- --> $DIR/issue-54108.rs:19:5
+ --> $DIR/issue-54108.rs:19:17
|
LL | type Size = <Self as SubEncoder>::ActualSize;
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ no implementation for `<T as SubEncoder>::ActualSize + <T as SubEncoder>::ActualSize`
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ no implementation for `<T as SubEncoder>::ActualSize + <T as SubEncoder>::ActualSize`
|
= help: the trait `Add` is not implemented for `<T as SubEncoder>::ActualSize`
note: required by a bound in `Encoder::Size`
diff --git a/src/test/ui/associated-types/issue-59324.rs b/src/test/ui/associated-types/issue-59324.rs
new file mode 100644
index 00000000000..9e68e9e7751
--- /dev/null
+++ b/src/test/ui/associated-types/issue-59324.rs
@@ -0,0 +1,26 @@
+trait NotFoo {}
+
+pub trait Foo: NotFoo {
+ type OnlyFoo;
+}
+
+pub trait Service {
+ type AssocType;
+}
+
+pub trait ThriftService<Bug: NotFoo>:
+//~^ ERROR the trait bound `Bug: Foo` is not satisfied
+//~| ERROR the trait bound `Bug: Foo` is not satisfied
+ Service<AssocType = <Bug as Foo>::OnlyFoo>
+{
+ fn get_service(
+ //~^ ERROR the trait bound `Bug: Foo` is not satisfied
+ //~| ERROR the trait bound `Bug: Foo` is not satisfied
+ &self,
+ ) -> Self::AssocType;
+}
+
+fn with_factory<H>(factory: dyn ThriftService<()>) {}
+//~^ ERROR the trait bound `(): Foo` is not satisfied
+
+fn main() {}
diff --git a/src/test/ui/associated-types/issue-59324.stderr b/src/test/ui/associated-types/issue-59324.stderr
new file mode 100644
index 00000000000..2f430d3055e
--- /dev/null
+++ b/src/test/ui/associated-types/issue-59324.stderr
@@ -0,0 +1,69 @@
+error[E0277]: the trait bound `Bug: Foo` is not satisfied
+ --> $DIR/issue-59324.rs:11:1
+ |
+LL | / pub trait ThriftService<Bug: NotFoo>:
+LL | |
+LL | |
+LL | | Service<AssocType = <Bug as Foo>::OnlyFoo>
+... |
+LL | | ) -> Self::AssocType;
+LL | | }
+ | |_^ the trait `Foo` is not implemented for `Bug`
+ |
+help: consider further restricting this bound
+ |
+LL | pub trait ThriftService<Bug: NotFoo + Foo>:
+ | +++++
+
+error[E0277]: the trait bound `Bug: Foo` is not satisfied
+ --> $DIR/issue-59324.rs:11:1
+ |
+LL | / pub trait ThriftService<Bug: NotFoo>:
+LL | |
+LL | |
+LL | | Service<AssocType = <Bug as Foo>::OnlyFoo>
+... |
+LL | | ) -> Self::AssocType;
+LL | | }
+ | |_^ the trait `Foo` is not implemented for `Bug`
+ |
+help: consider further restricting this bound
+ |
+LL | pub trait ThriftService<Bug: NotFoo + Foo>:
+ | +++++
+
+error[E0277]: the trait bound `Bug: Foo` is not satisfied
+ --> $DIR/issue-59324.rs:16:5
+ |
+LL | / fn get_service(
+LL | |
+LL | |
+LL | | &self,
+LL | | ) -> Self::AssocType;
+ | |_________________________^ the trait `Foo` is not implemented for `Bug`
+ |
+help: consider further restricting this bound
+ |
+LL | pub trait ThriftService<Bug: NotFoo + Foo>:
+ | +++++
+
+error[E0277]: the trait bound `Bug: Foo` is not satisfied
+ --> $DIR/issue-59324.rs:16:8
+ |
+LL | fn get_service(
+ | ^^^^^^^^^^^ the trait `Foo` is not implemented for `Bug`
+ |
+help: consider further restricting this bound
+ |
+LL | pub trait ThriftService<Bug: NotFoo + Foo>:
+ | +++++
+
+error[E0277]: the trait bound `(): Foo` is not satisfied
+ --> $DIR/issue-59324.rs:23:29
+ |
+LL | fn with_factory<H>(factory: dyn ThriftService<()>) {}
+ | ^^^^^^^^^^^^^^^^^^^^^ the trait `Foo` is not implemented for `()`
+
+error: aborting due to 5 previous errors
+
+For more information about this error, try `rustc --explain E0277`.
diff --git a/src/test/ui/associated-types/issue-63593.stderr b/src/test/ui/associated-types/issue-63593.stderr
index 70449b0c035..f643ec3ff1f 100644
--- a/src/test/ui/associated-types/issue-63593.stderr
+++ b/src/test/ui/associated-types/issue-63593.stderr
@@ -1,8 +1,8 @@
error[E0277]: the size for values of type `Self` cannot be known at compilation time
- --> $DIR/issue-63593.rs:9:5
+ --> $DIR/issue-63593.rs:9:17
|
LL | type This = Self;
- | ^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time
+ | ^^^^ doesn't have a size known at compile-time
|
note: required by a bound in `MyTrait::This`
--> $DIR/issue-63593.rs:9:5
diff --git a/src/test/ui/associated-types/issue-65774-1.stderr b/src/test/ui/associated-types/issue-65774-1.stderr
index abe1b76116e..82c520b99b1 100644
--- a/src/test/ui/associated-types/issue-65774-1.stderr
+++ b/src/test/ui/associated-types/issue-65774-1.stderr
@@ -1,8 +1,8 @@
error[E0277]: the trait bound `T: MyDisplay` is not satisfied
- --> $DIR/issue-65774-1.rs:10:5
+ --> $DIR/issue-65774-1.rs:10:33
|
LL | type MpuConfig: MyDisplay = T;
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `MyDisplay` is not implemented for `T`
+ | ^ the trait `MyDisplay` is not implemented for `T`
|
note: required by a bound in `MPU::MpuConfig`
--> $DIR/issue-65774-1.rs:10:21
diff --git a/src/test/ui/associated-types/issue-65774-2.stderr b/src/test/ui/associated-types/issue-65774-2.stderr
index 9393cd4c0c3..349cef9df72 100644
--- a/src/test/ui/associated-types/issue-65774-2.stderr
+++ b/src/test/ui/associated-types/issue-65774-2.stderr
@@ -1,8 +1,8 @@
error[E0277]: the trait bound `T: MyDisplay` is not satisfied
- --> $DIR/issue-65774-2.rs:10:5
+ --> $DIR/issue-65774-2.rs:10:33
|
LL | type MpuConfig: MyDisplay = T;
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `MyDisplay` is not implemented for `T`
+ | ^ the trait `MyDisplay` is not implemented for `T`
|
note: required by a bound in `MPU::MpuConfig`
--> $DIR/issue-65774-2.rs:10:21
diff --git a/src/test/ui/associated-types/issue-67684.rs b/src/test/ui/associated-types/issue-67684.rs
new file mode 100644
index 00000000000..49efe8a1bda
--- /dev/null
+++ b/src/test/ui/associated-types/issue-67684.rs
@@ -0,0 +1,62 @@
+// check-pass
+
+#![allow(dead_code)]
+
+trait ParseError {
+ type StreamError;
+}
+
+impl<T> ParseError for T {
+ type StreamError = ();
+}
+
+trait Stream {
+ type Item;
+ type Error: ParseError;
+}
+
+trait Parser
+where
+ <Self as Parser>::PartialState: Default,
+{
+ type PartialState;
+ fn parse_mode(_: &Self, _: Self::PartialState) {
+ loop {}
+ }
+}
+
+impl Stream for () {
+ type Item = ();
+ type Error = ();
+}
+
+impl Parser for () {
+ type PartialState = ();
+}
+
+struct AndThen<A, B>(core::marker::PhantomData<(A, B)>);
+
+impl<A, B> Parser for AndThen<A, B>
+where
+ A: Stream,
+ B: Into<<A::Error as ParseError>::StreamError>,
+{
+ type PartialState = ();
+}
+
+fn expr<A>() -> impl Parser
+where
+ A: Stream<Error = <A as Stream>::Item>,
+{
+ AndThen::<A, ()>(core::marker::PhantomData)
+}
+
+fn parse_mode_impl<A>()
+where
+ <A as Stream>::Error: ParseError,
+ A: Stream<Error = <A as Stream>::Item>,
+{
+ Parser::parse_mode(&expr::<A>(), Default::default())
+}
+
+fn main() {}
diff --git a/src/test/ui/associated-types/issue-69398.rs b/src/test/ui/associated-types/issue-69398.rs
new file mode 100644
index 00000000000..ca3d66b1c8e
--- /dev/null
+++ b/src/test/ui/associated-types/issue-69398.rs
@@ -0,0 +1,21 @@
+// check-pass
+
+pub trait Foo {
+ type Bar;
+}
+
+pub trait Broken {
+ type Assoc;
+ fn broken(&self) where Self::Assoc: Foo;
+}
+
+impl<T> Broken for T {
+ type Assoc = ();
+ fn broken(&self) where Self::Assoc: Foo {
+ let _x: <Self::Assoc as Foo>::Bar;
+ }
+}
+
+fn main() {
+ let _m: &dyn Broken<Assoc=()> = &();
+}
diff --git a/src/test/ui/associated-types/issue-71113.rs b/src/test/ui/associated-types/issue-71113.rs
new file mode 100644
index 00000000000..48de89127f4
--- /dev/null
+++ b/src/test/ui/associated-types/issue-71113.rs
@@ -0,0 +1,16 @@
+// check-pass
+
+use std::borrow::Cow;
+
+enum _Recursive<'a>
+where
+ Self: ToOwned<Owned=Box<Self>>
+{
+ Variant(MyCow<'a, _Recursive<'a>>),
+}
+
+pub struct Wrapper<T>(T);
+
+pub struct MyCow<'a, T: ToOwned<Owned=Box<T>> + 'a>(Wrapper<Cow<'a, T>>);
+
+fn main() {}
diff --git a/src/test/ui/associated-types/issue-72806.stderr b/src/test/ui/associated-types/issue-72806.stderr
index ea98e21d72f..e95943f34d5 100644
--- a/src/test/ui/associated-types/issue-72806.stderr
+++ b/src/test/ui/associated-types/issue-72806.stderr
@@ -1,9 +1,14 @@
error[E0271]: type mismatch resolving `<Foo2 as Bar2>::Ok == char`
- --> $DIR/issue-72806.rs:14:5
+ --> $DIR/issue-72806.rs:14:20
|
LL | type Sibling = Foo2;
- | ^^^^^^^^^^^^^^^^^^^^ expected `char`, found `u32`
+ | ^^^^ type mismatch resolving `<Foo2 as Bar2>::Ok == char`
|
+note: expected this to be `char`
+ --> $DIR/issue-72806.rs:18:15
+ |
+LL | type Ok = u32;
+ | ^^^
note: required by a bound in `Bar::Sibling`
--> $DIR/issue-72806.rs:3:24
|
diff --git a/src/test/ui/associated-types/issue-82079.rs b/src/test/ui/associated-types/issue-82079.rs
new file mode 100644
index 00000000000..590c799c2d7
--- /dev/null
+++ b/src/test/ui/associated-types/issue-82079.rs
@@ -0,0 +1,121 @@
+// check-pass
+
+mod convenience_operators {
+ use crate::{Op, Relation};
+ use std::ops::AddAssign;
+ use std::ops::Mul;
+
+ impl<C: Op> Relation<C> {
+ pub fn map<F: Fn(C::D) -> D2 + 'static, D2: 'static>(
+ self,
+ f: F,
+ ) -> Relation<impl Op<D = D2, R = C::R>> {
+ self.map_dr(move |x, r| (f(x), r))
+ }
+ }
+
+ impl<K: 'static, V: 'static, C: Op<D = (K, V)>> Relation<C> {
+ pub fn semijoin<C2: Op<D = K, R = R2>, R2, R3: AddAssign<R3>>(
+ self,
+ other: Relation<C2>,
+ ) -> Relation<impl Op<D = C::D, R = R3>>
+ where
+ C::R: Mul<R2, Output = R3>,
+ {
+ self.join(other.map(|x| (x, ()))).map(|(k, x, ())| (k, x))
+ }
+ }
+}
+
+mod core {
+ mod operator {
+ mod join {
+ use super::Op;
+ use crate::core::Relation;
+ use std::ops::{AddAssign, Mul};
+ struct Join<LC, RC> {
+ _left: LC,
+ _right: RC,
+ }
+ impl<
+ LC: Op<D = (K, LD), R = LR>,
+ RC: Op<D = (K, RD), R = RR>,
+ K: 'static,
+ LD: 'static,
+ LR: AddAssign<LR> + Mul<RR, Output = OR>,
+ RD: 'static,
+ RR: AddAssign<RR>,
+ OR: AddAssign<OR>,
+ > Op for Join<LC, RC>
+ {
+ type D = (K, LD, RD);
+ type R = OR;
+ }
+ impl<K: 'static, D: 'static, C: Op<D = (K, D)>> Relation<C> {
+ pub fn join<C2: Op<D = (K, D2)>, D2: 'static, OR: AddAssign<OR>>(
+ self,
+ other: Relation<C2>,
+ ) -> Relation<impl Op<D = (K, D, D2), R = OR>>
+ where
+ C::R: Mul<C2::R, Output = OR>,
+ {
+ Relation {
+ inner: Join {
+ _left: self.inner,
+ _right: other.inner,
+ },
+ }
+ }
+ }
+ }
+ mod map {
+ use super::Op;
+ use crate::core::Relation;
+ use std::ops::AddAssign;
+ struct Map<C, MF> {
+ _inner: C,
+ _op: MF,
+ }
+ impl<
+ D1,
+ R1,
+ D2: 'static,
+ R2: AddAssign<R2>,
+ C: Op<D = D1, R = R1>,
+ MF: Fn(D1, R1) -> (D2, R2),
+ > Op for Map<C, MF>
+ {
+ type D = D2;
+ type R = R2;
+ }
+ impl<C: Op> Relation<C> {
+ pub fn map_dr<F: Fn(C::D, C::R) -> (D2, R2), D2: 'static, R2: AddAssign<R2>>(
+ self,
+ f: F,
+ ) -> Relation<impl Op<D = D2, R = R2>> {
+ Relation {
+ inner: Map {
+ _inner: self.inner,
+ _op: f,
+ },
+ }
+ }
+ }
+ }
+ use std::ops::AddAssign;
+ pub trait Op {
+ type D: 'static;
+ type R: AddAssign<Self::R>;
+ }
+ }
+ pub use self::operator::Op;
+ #[derive(Clone)]
+ pub struct Relation<C> {
+ inner: C,
+ }
+}
+
+use self::core::Op;
+pub use self::core::Relation;
+
+fn main() {}
diff --git a/src/test/ui/associated-types/issue-85103.rs b/src/test/ui/associated-types/issue-85103.rs
new file mode 100644
index 00000000000..c5e13856178
--- /dev/null
+++ b/src/test/ui/associated-types/issue-85103.rs
@@ -0,0 +1,9 @@
+#![feature(rustc_attrs)]
+
+use std::borrow::Cow;
+
+#[rustc_layout(debug)]
+type Edges<'a, E> = Cow<'a, [E]>;
+//~^ ERROR layout error: NormalizationFailure
+
+fn main() {}
diff --git a/src/test/ui/associated-types/issue-85103.stderr b/src/test/ui/associated-types/issue-85103.stderr
new file mode 100644
index 00000000000..142f3c411ec
--- /dev/null
+++ b/src/test/ui/associated-types/issue-85103.stderr
@@ -0,0 +1,8 @@
+error: layout error: NormalizationFailure(<[E] as std::borrow::ToOwned>::Owned, Type(<[E] as std::borrow::ToOwned>::Owned))
+ --> $DIR/issue-85103.rs:6:1
+ |
+LL | type Edges<'a, E> = Cow<'a, [E]>;
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: aborting due to previous error
+
diff --git a/src/test/ui/associated-types/issue-87261.rs b/src/test/ui/associated-types/issue-87261.rs
index 384561f8ccd..aae562ae722 100644
--- a/src/test/ui/associated-types/issue-87261.rs
+++ b/src/test/ui/associated-types/issue-87261.rs
@@ -83,17 +83,17 @@ fn main() {
//~^ ERROR type mismatch resolving `<impl DerivedTrait as Trait>::Associated == ()`
accepts_trait(returns_opaque_foo());
- //~^ ERROR type mismatch resolving `<impl Trait + Foo as Trait>::Associated == ()`
+ //~^ ERROR type mismatch resolving `<impl Foo + Trait as Trait>::Associated == ()`
accepts_trait(returns_opaque_derived_foo());
- //~^ ERROR type mismatch resolving `<impl DerivedTrait + Foo as Trait>::Associated == ()`
+ //~^ ERROR type mismatch resolving `<impl Foo + DerivedTrait as Trait>::Associated == ()`
accepts_generic_trait(returns_opaque_generic());
//~^ ERROR type mismatch resolving `<impl GenericTrait<()> as GenericTrait<()>>::Associated == ()`
accepts_generic_trait(returns_opaque_generic_foo());
- //~^ ERROR type mismatch resolving `<impl GenericTrait<()> + Foo as GenericTrait<()>>::Associated == ()`
+ //~^ ERROR type mismatch resolving `<impl Foo + GenericTrait<()> as GenericTrait<()>>::Associated == ()`
accepts_generic_trait(returns_opaque_generic_duplicate());
- //~^ ERROR type mismatch resolving `<impl GenericTrait<()> + GenericTrait<u8> as GenericTrait<()>>::Associated == ()`
+ //~^ ERROR type mismatch resolving `<impl GenericTrait<u8> + GenericTrait<()> as GenericTrait<()>>::Associated == ()`
}
diff --git a/src/test/ui/associated-types/issue-87261.stderr b/src/test/ui/associated-types/issue-87261.stderr
index 8db4a49da3c..c00b48abc1c 100644
--- a/src/test/ui/associated-types/issue-87261.stderr
+++ b/src/test/ui/associated-types/issue-87261.stderr
@@ -160,7 +160,7 @@ help: consider constraining the associated type `<impl DerivedTrait as Trait>::A
LL | fn returns_opaque_derived() -> impl DerivedTrait<Associated = ()> + 'static {
| +++++++++++++++++
-error[E0271]: type mismatch resolving `<impl Trait + Foo as Trait>::Associated == ()`
+error[E0271]: type mismatch resolving `<impl Foo + Trait as Trait>::Associated == ()`
--> $DIR/issue-87261.rs:85:5
|
LL | fn returns_opaque_foo() -> impl Trait + Foo {
@@ -170,18 +170,18 @@ LL | accepts_trait(returns_opaque_foo());
| ^^^^^^^^^^^^^ expected `()`, found associated type
|
= note: expected unit type `()`
- found associated type `<impl Trait + Foo as Trait>::Associated`
+ found associated type `<impl Foo + Trait as Trait>::Associated`
note: required by a bound in `accepts_trait`
--> $DIR/issue-87261.rs:43:27
|
LL | fn accepts_trait<T: Trait<Associated = ()>>(_: T) {}
| ^^^^^^^^^^^^^^^ required by this bound in `accepts_trait`
-help: consider constraining the associated type `<impl Trait + Foo as Trait>::Associated` to `()`
+help: consider constraining the associated type `<impl Foo + Trait as Trait>::Associated` to `()`
|
LL | fn returns_opaque_foo() -> impl Trait<Associated = ()> + Foo {
| +++++++++++++++++
-error[E0271]: type mismatch resolving `<impl DerivedTrait + Foo as Trait>::Associated == ()`
+error[E0271]: type mismatch resolving `<impl Foo + DerivedTrait as Trait>::Associated == ()`
--> $DIR/issue-87261.rs:88:5
|
LL | fn returns_opaque_derived_foo() -> impl DerivedTrait + Foo {
@@ -191,8 +191,8 @@ LL | accepts_trait(returns_opaque_derived_foo());
| ^^^^^^^^^^^^^ expected `()`, found associated type
|
= note: expected unit type `()`
- found associated type `<impl DerivedTrait + Foo as Trait>::Associated`
- = help: consider constraining the associated type `<impl DerivedTrait + Foo as Trait>::Associated` to `()`
+ found associated type `<impl Foo + DerivedTrait as Trait>::Associated`
+ = help: consider constraining the associated type `<impl Foo + DerivedTrait as Trait>::Associated` to `()`
= note: for more information, visit https://doc.rust-lang.org/book/ch19-03-advanced-traits.html
note: required by a bound in `accepts_trait`
--> $DIR/issue-87261.rs:43:27
@@ -221,7 +221,7 @@ help: consider constraining the associated type `<impl GenericTrait<()> as Gener
LL | fn returns_opaque_generic() -> impl GenericTrait<(), Associated = ()> + 'static {
| +++++++++++++++++
-error[E0271]: type mismatch resolving `<impl GenericTrait<()> + Foo as GenericTrait<()>>::Associated == ()`
+error[E0271]: type mismatch resolving `<impl Foo + GenericTrait<()> as GenericTrait<()>>::Associated == ()`
--> $DIR/issue-87261.rs:94:5
|
LL | fn returns_opaque_generic_foo() -> impl GenericTrait<()> + Foo {
@@ -231,18 +231,18 @@ LL | accepts_generic_trait(returns_opaque_generic_foo());
| ^^^^^^^^^^^^^^^^^^^^^ expected `()`, found associated type
|
= note: expected unit type `()`
- found associated type `<impl GenericTrait<()> + Foo as GenericTrait<()>>::Associated`
+ found associated type `<impl Foo + GenericTrait<()> as GenericTrait<()>>::Associated`
note: required by a bound in `accepts_generic_trait`
--> $DIR/issue-87261.rs:44:46
|
LL | fn accepts_generic_trait<T: GenericTrait<(), Associated = ()>>(_: T) {}
| ^^^^^^^^^^^^^^^ required by this bound in `accepts_generic_trait`
-help: consider constraining the associated type `<impl GenericTrait<()> + Foo as GenericTrait<()>>::Associated` to `()`
+help: consider constraining the associated type `<impl Foo + GenericTrait<()> as GenericTrait<()>>::Associated` to `()`
|
LL | fn returns_opaque_generic_foo() -> impl GenericTrait<(), Associated = ()> + Foo {
| +++++++++++++++++
-error[E0271]: type mismatch resolving `<impl GenericTrait<()> + GenericTrait<u8> as GenericTrait<()>>::Associated == ()`
+error[E0271]: type mismatch resolving `<impl GenericTrait<u8> + GenericTrait<()> as GenericTrait<()>>::Associated == ()`
--> $DIR/issue-87261.rs:97:5
|
LL | fn returns_opaque_generic_duplicate() -> impl GenericTrait<()> + GenericTrait<u8> {
@@ -252,8 +252,8 @@ LL | accepts_generic_trait(returns_opaque_generic_duplicate());
| ^^^^^^^^^^^^^^^^^^^^^ expected `()`, found associated type
|
= note: expected unit type `()`
- found associated type `<impl GenericTrait<()> + GenericTrait<u8> as GenericTrait<()>>::Associated`
- = help: consider constraining the associated type `<impl GenericTrait<()> + GenericTrait<u8> as GenericTrait<()>>::Associated` to `()`
+ found associated type `<impl GenericTrait<u8> + GenericTrait<()> as GenericTrait<()>>::Associated`
+ = help: consider constraining the associated type `<impl GenericTrait<u8> + GenericTrait<()> as GenericTrait<()>>::Associated` to `()`
= note: for more information, visit https://doc.rust-lang.org/book/ch19-03-advanced-traits.html
note: required by a bound in `accepts_generic_trait`
--> $DIR/issue-87261.rs:44:46
diff --git a/src/test/ui/associated-types/issue-88856.rs b/src/test/ui/associated-types/issue-88856.rs
new file mode 100644
index 00000000000..7cae7c71cd2
--- /dev/null
+++ b/src/test/ui/associated-types/issue-88856.rs
@@ -0,0 +1,32 @@
+// check-pass
+
+#![feature(generic_const_exprs)]
+#![allow(incomplete_features)]
+
+pub trait Trait{
+ type R;
+ fn func(self)->Self::R;
+}
+
+pub struct TraitImpl<const N:usize>(pub i32);
+
+impl<const N:usize> Trait for TraitImpl<N>
+where [();N/2]:,
+{
+ type R = Self;
+ fn func(self)->Self::R {
+ self
+ }
+}
+
+fn sample<P,Convert>(p:P,f:Convert) -> i32
+where
+ P:Trait,Convert:Fn(P::R)->i32
+{
+ f(p.func())
+}
+
+fn main() {
+ let t = TraitImpl::<10>(4);
+ sample(t,|x|x.0);
+}
diff --git a/src/test/ui/associated-types/issue-91231.rs b/src/test/ui/associated-types/issue-91231.rs
new file mode 100644
index 00000000000..3c1cb81f097
--- /dev/null
+++ b/src/test/ui/associated-types/issue-91231.rs
@@ -0,0 +1,17 @@
+// check-pass
+
+#![feature(extern_types)]
+#![allow(dead_code)]
+
+extern {
+ type Extern;
+}
+
+trait Trait {
+ type Type;
+}
+
+#[inline]
+fn f<'a>(_: <&'a Extern as Trait>::Type) where &'a Extern: Trait {}
+
+fn main() {}
diff --git a/src/test/ui/associated-types/issue-91234.rs b/src/test/ui/associated-types/issue-91234.rs
new file mode 100644
index 00000000000..2f6c2d3aebd
--- /dev/null
+++ b/src/test/ui/associated-types/issue-91234.rs
@@ -0,0 +1,13 @@
+// check-pass
+
+struct Struct;
+
+trait Trait {
+ type Type;
+}
+
+enum Enum<'a> where &'a Struct: Trait {
+ Variant(<&'a Struct as Trait>::Type)
+}
+
+fn main() {}
diff --git a/src/test/ui/associated-types/point-at-type-on-obligation-failure-2.stderr b/src/test/ui/associated-types/point-at-type-on-obligation-failure-2.stderr
index f9406834ad7..2e7a1dd2a31 100644
--- a/src/test/ui/associated-types/point-at-type-on-obligation-failure-2.stderr
+++ b/src/test/ui/associated-types/point-at-type-on-obligation-failure-2.stderr
@@ -1,8 +1,8 @@
error[E0277]: the trait bound `bool: Bar` is not satisfied
- --> $DIR/point-at-type-on-obligation-failure-2.rs:8:5
+ --> $DIR/point-at-type-on-obligation-failure-2.rs:8:18
|
LL | type Assoc = bool;
- | ^^^^^^^^^^^^^^^^^^ the trait `Bar` is not implemented for `bool`
+ | ^^^^ the trait `Bar` is not implemented for `bool`
|
note: required by a bound in `Foo::Assoc`
--> $DIR/point-at-type-on-obligation-failure-2.rs:4:17
@@ -11,10 +11,10 @@ LL | type Assoc: Bar;
| ^^^ required by this bound in `Foo::Assoc`
error[E0277]: the trait bound `bool: Bar` is not satisfied
- --> $DIR/point-at-type-on-obligation-failure-2.rs:19:5
+ --> $DIR/point-at-type-on-obligation-failure-2.rs:19:18
|
LL | type Assoc = bool;
- | ^^^^^^^^^^^^^^^^^^ the trait `Bar` is not implemented for `bool`
+ | ^^^^ the trait `Bar` is not implemented for `bool`
|
note: required by a bound in `Baz::Assoc`
--> $DIR/point-at-type-on-obligation-failure-2.rs:13:18
@@ -26,10 +26,10 @@ LL | type Assoc;
| ----- required by a bound in this
error[E0277]: the trait bound `bool: Bar` is not satisfied
- --> $DIR/point-at-type-on-obligation-failure-2.rs:30:5
+ --> $DIR/point-at-type-on-obligation-failure-2.rs:30:18
|
LL | type Assoc = bool;
- | ^^^^^^^^^^^^^^^^^^ the trait `Bar` is not implemented for `bool`
+ | ^^^^ the trait `Bar` is not implemented for `bool`
|
note: required by a bound in `Bat::Assoc`
--> $DIR/point-at-type-on-obligation-failure-2.rs:24:27
diff --git a/src/test/ui/associated-types/point-at-type-on-obligation-failure.stderr b/src/test/ui/associated-types/point-at-type-on-obligation-failure.stderr
index 85ecba68be9..9afbe82c321 100644
--- a/src/test/ui/associated-types/point-at-type-on-obligation-failure.stderr
+++ b/src/test/ui/associated-types/point-at-type-on-obligation-failure.stderr
@@ -1,9 +1,14 @@
error[E0271]: type mismatch resolving `<Foo2 as Bar2>::Ok == ()`
- --> $DIR/point-at-type-on-obligation-failure.rs:14:5
+ --> $DIR/point-at-type-on-obligation-failure.rs:14:20
|
LL | type Sibling = Foo2;
- | ^^^^^^^^^^^^^^^^^^^^ expected `()`, found `u32`
+ | ^^^^ type mismatch resolving `<Foo2 as Bar2>::Ok == ()`
|
+note: expected this to be `()`
+ --> $DIR/point-at-type-on-obligation-failure.rs:18:15
+ |
+LL | type Ok = u32;
+ | ^^^
note: required by a bound in `Bar::Sibling`
--> $DIR/point-at-type-on-obligation-failure.rs:3:24
|
diff --git a/src/test/ui/ast-json/ast-json-noexpand-output.stdout b/src/test/ui/ast-json/ast-json-noexpand-output.stdout
index 8961655ede3..22484ba6378 100644
--- a/src/test/ui/ast-json/ast-json-noexpand-output.stdout
+++ b/src/test/ui/ast-json/ast-json-noexpand-output.stdout
@@ -1 +1 @@
-{"attrs":[{"kind":{"variant":"Normal","fields":[{"path":{"span":{"lo":0,"hi":0},"segments":[{"ident":{"name":"crate_type","span":{"lo":0,"hi":0}},"id":0,"args":null}],"tokens":null},"args":{"variant":"Eq","fields":[{"lo":0,"hi":0},{"kind":{"variant":"Interpolated","fields":[{"variant":"NtExpr","fields":[{"id":0,"kind":{"variant":"Lit","fields":[{"token":{"kind":"Str","symbol":"lib","suffix":null},"kind":{"variant":"Str","fields":["lib","Cooked"]},"span":{"lo":0,"hi":0}}]},"span":{"lo":0,"hi":0},"attrs":{"0":null},"tokens":{"0":[[{"variant":"Token","fields":[{"kind":{"variant":"Literal","fields":[{"kind":"Str","symbol":"lib","suffix":null}]},"span":{"lo":0,"hi":0}}]},"Alone"]]}}]}]},"span":{"lo":0,"hi":0}}]},"tokens":null},{"0":[[{"variant":"Token","fields":[{"kind":"Pound","span":{"lo":0,"hi":0}}]},"Joint"],[{"variant":"Token","fields":[{"kind":"Not","span":{"lo":0,"hi":0}}]},"Alone"],[{"variant":"Delimited","fields":[{"open":{"lo":0,"hi":0},"close":{"lo":0,"hi":0}},"Bracket",{"0":[[{"variant":"Token","fields":[{"kind":{"variant":"Ident","fields":["crate_type",false]},"span":{"lo":0,"hi":0}}]},"Alone"],[{"variant":"Token","fields":[{"kind":"Eq","span":{"lo":0,"hi":0}}]},"Alone"],[{"variant":"Token","fields":[{"kind":{"variant":"Literal","fields":[{"kind":"Str","symbol":"lib","suffix":null}]},"span":{"lo":0,"hi":0}}]},"Alone"]]}]},"Alone"]]}]},"id":null,"style":"Inner","span":{"lo":0,"hi":0}}],"items":[{"attrs":[],"id":0,"span":{"lo":0,"hi":0},"vis":{"kind":"Inherited","span":{"lo":0,"hi":0},"tokens":null},"ident":{"name":"core","span":{"lo":0,"hi":0}},"kind":{"variant":"ExternCrate","fields":[null]},"tokens":null}],"span":{"lo":0,"hi":0}}
+{"attrs":[{"kind":{"variant":"Normal","fields":[{"path":{"span":{"lo":0,"hi":0},"segments":[{"ident":{"name":"crate_type","span":{"lo":0,"hi":0}},"id":0,"args":null}],"tokens":null},"args":{"variant":"Eq","fields":[{"lo":0,"hi":0},{"kind":{"variant":"Interpolated","fields":[{"variant":"NtExpr","fields":[{"id":0,"kind":{"variant":"Lit","fields":[{"token":{"kind":"Str","symbol":"lib","suffix":null},"kind":{"variant":"Str","fields":["lib","Cooked"]},"span":{"lo":0,"hi":0}}]},"span":{"lo":0,"hi":0},"attrs":{"0":null},"tokens":{"0":[[{"variant":"Token","fields":[{"kind":{"variant":"Literal","fields":[{"kind":"Str","symbol":"lib","suffix":null}]},"span":{"lo":0,"hi":0}}]},"Alone"]]}}]}]},"span":{"lo":0,"hi":0}}]},"tokens":null},{"0":[[{"variant":"Token","fields":[{"kind":"Pound","span":{"lo":0,"hi":0}}]},"Joint"],[{"variant":"Token","fields":[{"kind":"Not","span":{"lo":0,"hi":0}}]},"Alone"],[{"variant":"Delimited","fields":[{"open":{"lo":0,"hi":0},"close":{"lo":0,"hi":0}},"Bracket",{"0":[[{"variant":"Token","fields":[{"kind":{"variant":"Ident","fields":["crate_type",false]},"span":{"lo":0,"hi":0}}]},"Alone"],[{"variant":"Token","fields":[{"kind":"Eq","span":{"lo":0,"hi":0}}]},"Alone"],[{"variant":"Token","fields":[{"kind":{"variant":"Literal","fields":[{"kind":"Str","symbol":"lib","suffix":null}]},"span":{"lo":0,"hi":0}}]},"Alone"]]}]},"Alone"]]}]},"id":null,"style":"Inner","span":{"lo":0,"hi":0}}],"items":[{"attrs":[],"id":0,"span":{"lo":0,"hi":0},"vis":{"kind":"Inherited","span":{"lo":0,"hi":0},"tokens":null},"ident":{"name":"core","span":{"lo":0,"hi":0}},"kind":{"variant":"ExternCrate","fields":[null]},"tokens":null}],"span":{"lo":0,"hi":0},"is_placeholder":null}
diff --git a/src/test/ui/ast-json/ast-json-output.stdout b/src/test/ui/ast-json/ast-json-output.stdout
index 082f04134ce..ae56bef35ff 100644
--- a/src/test/ui/ast-json/ast-json-output.stdout
+++ b/src/test/ui/ast-json/ast-json-output.stdout
@@ -1 +1 @@
-{"attrs":[{"kind":{"variant":"Normal","fields":[{"path":{"span":{"lo":0,"hi":0},"segments":[{"ident":{"name":"crate_type","span":{"lo":0,"hi":0}},"id":0,"args":null}],"tokens":null},"args":{"variant":"Eq","fields":[{"lo":0,"hi":0},{"kind":{"variant":"Interpolated","fields":[{"variant":"NtExpr","fields":[{"id":0,"kind":{"variant":"Lit","fields":[{"token":{"kind":"Str","symbol":"lib","suffix":null},"kind":{"variant":"Str","fields":["lib","Cooked"]},"span":{"lo":0,"hi":0}}]},"span":{"lo":0,"hi":0},"attrs":{"0":null},"tokens":{"0":[[{"variant":"Token","fields":[{"kind":{"variant":"Literal","fields":[{"kind":"Str","symbol":"lib","suffix":null}]},"span":{"lo":0,"hi":0}}]},"Alone"]]}}]}]},"span":{"lo":0,"hi":0}}]},"tokens":null},{"0":[[{"variant":"Token","fields":[{"kind":"Pound","span":{"lo":0,"hi":0}}]},"Joint"],[{"variant":"Token","fields":[{"kind":"Not","span":{"lo":0,"hi":0}}]},"Alone"],[{"variant":"Delimited","fields":[{"open":{"lo":0,"hi":0},"close":{"lo":0,"hi":0}},"Bracket",{"0":[[{"variant":"Token","fields":[{"kind":{"variant":"Ident","fields":["crate_type",false]},"span":{"lo":0,"hi":0}}]},"Alone"],[{"variant":"Token","fields":[{"kind":"Eq","span":{"lo":0,"hi":0}}]},"Alone"],[{"variant":"Token","fields":[{"kind":{"variant":"Literal","fields":[{"kind":"Str","symbol":"lib","suffix":null}]},"span":{"lo":0,"hi":0}}]},"Alone"]]}]},"Alone"]]}]},"id":null,"style":"Inner","span":{"lo":0,"hi":0}}],"items":[{"attrs":[{"kind":{"variant":"Normal","fields":[{"path":{"span":{"lo":0,"hi":0},"segments":[{"ident":{"name":"prelude_import","span":{"lo":0,"hi":0}},"id":0,"args":null}],"tokens":null},"args":"Empty","tokens":null},null]},"id":null,"style":"Outer","span":{"lo":0,"hi":0}}],"id":0,"span":{"lo":0,"hi":0},"vis":{"kind":"Inherited","span":{"lo":0,"hi":0},"tokens":null},"ident":{"name":"","span":{"lo":0,"hi":0}},"kind":{"variant":"Use","fields":[{"prefix":{"span":{"lo":0,"hi":0},"segments":[{"ident":{"name":"{{root}}","span":{"lo":0,"hi":0}},"id":0,"args":null},{"ident":{"name":"std","span":{"lo":0,"hi":0}},"id":0,"args":null},{"ident":{"name":"prelude","span":{"lo":0,"hi":0}},"id":0,"args":null},{"ident":{"name":"rust_2015","span":{"lo":0,"hi":0}},"id":0,"args":null}],"tokens":null},"kind":"Glob","span":{"lo":0,"hi":0}}]},"tokens":null},{"attrs":[{"kind":{"variant":"Normal","fields":[{"path":{"span":{"lo":0,"hi":0},"segments":[{"ident":{"name":"macro_use","span":{"lo":0,"hi":0}},"id":0,"args":null}],"tokens":null},"args":"Empty","tokens":null},null]},"id":null,"style":"Outer","span":{"lo":0,"hi":0}}],"id":0,"span":{"lo":0,"hi":0},"vis":{"kind":"Inherited","span":{"lo":0,"hi":0},"tokens":null},"ident":{"name":"std","span":{"lo":0,"hi":0}},"kind":{"variant":"ExternCrate","fields":[null]},"tokens":null},{"attrs":[],"id":0,"span":{"lo":0,"hi":0},"vis":{"kind":"Inherited","span":{"lo":0,"hi":0},"tokens":null},"ident":{"name":"core","span":{"lo":0,"hi":0}},"kind":{"variant":"ExternCrate","fields":[null]},"tokens":null}],"span":{"lo":0,"hi":0}}
+{"attrs":[{"kind":{"variant":"Normal","fields":[{"path":{"span":{"lo":0,"hi":0},"segments":[{"ident":{"name":"crate_type","span":{"lo":0,"hi":0}},"id":0,"args":null}],"tokens":null},"args":{"variant":"Eq","fields":[{"lo":0,"hi":0},{"kind":{"variant":"Interpolated","fields":[{"variant":"NtExpr","fields":[{"id":0,"kind":{"variant":"Lit","fields":[{"token":{"kind":"Str","symbol":"lib","suffix":null},"kind":{"variant":"Str","fields":["lib","Cooked"]},"span":{"lo":0,"hi":0}}]},"span":{"lo":0,"hi":0},"attrs":{"0":null},"tokens":{"0":[[{"variant":"Token","fields":[{"kind":{"variant":"Literal","fields":[{"kind":"Str","symbol":"lib","suffix":null}]},"span":{"lo":0,"hi":0}}]},"Alone"]]}}]}]},"span":{"lo":0,"hi":0}}]},"tokens":null},{"0":[[{"variant":"Token","fields":[{"kind":"Pound","span":{"lo":0,"hi":0}}]},"Joint"],[{"variant":"Token","fields":[{"kind":"Not","span":{"lo":0,"hi":0}}]},"Alone"],[{"variant":"Delimited","fields":[{"open":{"lo":0,"hi":0},"close":{"lo":0,"hi":0}},"Bracket",{"0":[[{"variant":"Token","fields":[{"kind":{"variant":"Ident","fields":["crate_type",false]},"span":{"lo":0,"hi":0}}]},"Alone"],[{"variant":"Token","fields":[{"kind":"Eq","span":{"lo":0,"hi":0}}]},"Alone"],[{"variant":"Token","fields":[{"kind":{"variant":"Literal","fields":[{"kind":"Str","symbol":"lib","suffix":null}]},"span":{"lo":0,"hi":0}}]},"Alone"]]}]},"Alone"]]}]},"id":null,"style":"Inner","span":{"lo":0,"hi":0}}],"items":[{"attrs":[{"kind":{"variant":"Normal","fields":[{"path":{"span":{"lo":0,"hi":0},"segments":[{"ident":{"name":"prelude_import","span":{"lo":0,"hi":0}},"id":0,"args":null}],"tokens":null},"args":"Empty","tokens":null},null]},"id":null,"style":"Outer","span":{"lo":0,"hi":0}}],"id":0,"span":{"lo":0,"hi":0},"vis":{"kind":"Inherited","span":{"lo":0,"hi":0},"tokens":null},"ident":{"name":"","span":{"lo":0,"hi":0}},"kind":{"variant":"Use","fields":[{"prefix":{"span":{"lo":0,"hi":0},"segments":[{"ident":{"name":"{{root}}","span":{"lo":0,"hi":0}},"id":0,"args":null},{"ident":{"name":"std","span":{"lo":0,"hi":0}},"id":0,"args":null},{"ident":{"name":"prelude","span":{"lo":0,"hi":0}},"id":0,"args":null},{"ident":{"name":"rust_2015","span":{"lo":0,"hi":0}},"id":0,"args":null}],"tokens":null},"kind":"Glob","span":{"lo":0,"hi":0}}]},"tokens":null},{"attrs":[{"kind":{"variant":"Normal","fields":[{"path":{"span":{"lo":0,"hi":0},"segments":[{"ident":{"name":"macro_use","span":{"lo":0,"hi":0}},"id":0,"args":null}],"tokens":null},"args":"Empty","tokens":null},null]},"id":null,"style":"Outer","span":{"lo":0,"hi":0}}],"id":0,"span":{"lo":0,"hi":0},"vis":{"kind":"Inherited","span":{"lo":0,"hi":0},"tokens":null},"ident":{"name":"std","span":{"lo":0,"hi":0}},"kind":{"variant":"ExternCrate","fields":[null]},"tokens":null},{"attrs":[],"id":0,"span":{"lo":0,"hi":0},"vis":{"kind":"Inherited","span":{"lo":0,"hi":0},"tokens":null},"ident":{"name":"core","span":{"lo":0,"hi":0}},"kind":{"variant":"ExternCrate","fields":[null]},"tokens":null}],"span":{"lo":0,"hi":0},"is_placeholder":null}
diff --git a/src/test/ui/async-await/async-block-control-flow-static-semantics.rs b/src/test/ui/async-await/async-block-control-flow-static-semantics.rs
index 5bc7069ff89..e3832767203 100644
--- a/src/test/ui/async-await/async-block-control-flow-static-semantics.rs
+++ b/src/test/ui/async-await/async-block-control-flow-static-semantics.rs
@@ -15,16 +15,16 @@ fn return_targets_async_block_not_fn() -> u8 {
return 0u8;
};
let _: &dyn Future<Output = ()> = &block;
- //~^ ERROR type mismatch resolving `<impl Future as Future>::Output == ()`
+ //~^ ERROR type mismatch
}
async fn return_targets_async_block_not_async_fn() -> u8 {
- //~^ ERROR mismatched types
+ //~^ ERROR mismatched types [E0308]
let block = async {
return 0u8;
};
let _: &dyn Future<Output = ()> = &block;
- //~^ ERROR type mismatch resolving `<impl Future as Future>::Output == ()`
+ //~^ ERROR type mismatch resolving `<impl Future<Output = [async output]> as Future>::Output == ()`
}
fn no_break_in_async_block() {
diff --git a/src/test/ui/async-await/async-block-control-flow-static-semantics.stderr b/src/test/ui/async-await/async-block-control-flow-static-semantics.stderr
index 919904ce3b6..fe864c65b7c 100644
--- a/src/test/ui/async-await/async-block-control-flow-static-semantics.stderr
+++ b/src/test/ui/async-await/async-block-control-flow-static-semantics.stderr
@@ -31,7 +31,7 @@ LL | |
LL | | }
| |_^ expected `u8`, found `()`
-error[E0271]: type mismatch resolving `<impl Future as Future>::Output == ()`
+error[E0271]: type mismatch resolving `<impl Future<Output = [async output]> as Future>::Output == ()`
--> $DIR/async-block-control-flow-static-semantics.rs:26:39
|
LL | let _: &dyn Future<Output = ()> = &block;
@@ -47,7 +47,7 @@ LL | fn return_targets_async_block_not_fn() -> u8 {
| |
| implicitly returns `()` as its body has no tail or `return` expression
-error[E0271]: type mismatch resolving `<impl Future as Future>::Output == ()`
+error[E0271]: type mismatch resolving `<impl Future<Output = [async output]> as Future>::Output == ()`
--> $DIR/async-block-control-flow-static-semantics.rs:17:39
|
LL | let _: &dyn Future<Output = ()> = &block;
diff --git a/src/test/ui/async-await/async-error-span.stderr b/src/test/ui/async-await/async-error-span.stderr
index 994bfd33ba4..7d4447b6d55 100644
--- a/src/test/ui/async-await/async-error-span.stderr
+++ b/src/test/ui/async-await/async-error-span.stderr
@@ -5,6 +5,7 @@ LL | fn get_future() -> impl Future<Output = ()> {
| ^^^^^^^^^^^^^^^^^^^^^^^^ `()` is not a future
|
= help: the trait `Future` is not implemented for `()`
+ = note: () must be a future or must implement `IntoFuture` to be awaited
error[E0698]: type inside `async fn` body must be known in this context
--> $DIR/async-error-span.rs:13:9
@@ -13,10 +14,10 @@ LL | let a;
| ^ cannot infer type
|
note: the type is part of the `async fn` body because of this `await`
- --> $DIR/async-error-span.rs:14:5
+ --> $DIR/async-error-span.rs:14:17
|
LL | get_future().await;
- | ^^^^^^^^^^^^^^^^^^
+ | ^^^^^^
error: aborting due to 2 previous errors
diff --git a/src/test/ui/async-await/async-fn-nonsend.stderr b/src/test/ui/async-await/async-fn-nonsend.stderr
index bf7ab148e23..bff28208573 100644
--- a/src/test/ui/async-await/async-fn-nonsend.stderr
+++ b/src/test/ui/async-await/async-fn-nonsend.stderr
@@ -6,13 +6,13 @@ LL | assert_send(local_dropped_before_await());
|
= help: within `impl Future<Output = ()>`, the trait `Send` is not implemented for `Rc<()>`
note: future is not `Send` as this value is used across an await
- --> $DIR/async-fn-nonsend.rs:24:5
+ --> $DIR/async-fn-nonsend.rs:24:10
|
LL | let x = non_send();
| - has type `impl Debug` which is not `Send`
LL | drop(x);
LL | fut().await;
- | ^^^^^^^^^^^ await occurs here, with `x` maybe used later
+ | ^^^^^^ await occurs here, with `x` maybe used later
LL | }
| - `x` is later dropped here
note: required by a bound in `assert_send`
@@ -29,12 +29,12 @@ LL | assert_send(non_send_temporary_in_match());
|
= help: within `impl Future<Output = ()>`, the trait `Send` is not implemented for `Rc<()>`
note: future is not `Send` as this value is used across an await
- --> $DIR/async-fn-nonsend.rs:33:20
+ --> $DIR/async-fn-nonsend.rs:33:25
|
LL | match Some(non_send()) {
| ---------- has type `impl Debug` which is not `Send`
LL | Some(_) => fut().await,
- | ^^^^^^^^^^^ await occurs here, with `non_send()` maybe used later
+ | ^^^^^^ await occurs here, with `non_send()` maybe used later
...
LL | }
| - `non_send()` is later dropped here
@@ -52,13 +52,13 @@ LL | assert_send(non_sync_with_method_call());
|
= help: the trait `Send` is not implemented for `dyn std::fmt::Write`
note: future is not `Send` as this value is used across an await
- --> $DIR/async-fn-nonsend.rs:42:9
+ --> $DIR/async-fn-nonsend.rs:42:14
|
LL | let f: &mut std::fmt::Formatter = panic!();
| - has type `&mut Formatter<'_>` which is not `Send`
LL | if non_sync().fmt(f).unwrap() == () {
LL | fut().await;
- | ^^^^^^^^^^^ await occurs here, with `f` maybe used later
+ | ^^^^^^ await occurs here, with `f` maybe used later
LL | }
LL | }
| - `f` is later dropped here
diff --git a/src/test/ui/async-await/async-fn-size-moved-locals.rs b/src/test/ui/async-await/async-fn-size-moved-locals.rs
index 636fafc2bc4..a603ebd6e85 100644
--- a/src/test/ui/async-await/async-fn-size-moved-locals.rs
+++ b/src/test/ui/async-await/async-fn-size-moved-locals.rs
@@ -112,7 +112,7 @@ async fn mixed_sizes() {
fn main() {
assert_eq!(1025, std::mem::size_of_val(&single()));
assert_eq!(1026, std::mem::size_of_val(&single_with_noop()));
- assert_eq!(3078, std::mem::size_of_val(&joined()));
- assert_eq!(3079, std::mem::size_of_val(&joined_with_noop()));
- assert_eq!(7181, std::mem::size_of_val(&mixed_sizes()));
+ assert_eq!(3076, std::mem::size_of_val(&joined()));
+ assert_eq!(3076, std::mem::size_of_val(&joined_with_noop()));
+ assert_eq!(6157, std::mem::size_of_val(&mixed_sizes()));
}
diff --git a/src/test/ui/async-await/await-into-future.rs b/src/test/ui/async-await/await-into-future.rs
new file mode 100644
index 00000000000..b74b1684440
--- /dev/null
+++ b/src/test/ui/async-await/await-into-future.rs
@@ -0,0 +1,30 @@
+// run-pass
+// aux-build: issue-72470-lib.rs
+// edition:2021
+#![feature(into_future)]
+
+extern crate issue_72470_lib;
+use std::{future::{Future, IntoFuture}, pin::Pin};
+
+struct AwaitMe;
+
+impl IntoFuture for AwaitMe {
+ type Output = i32;
+ type Future = Pin<Box<dyn Future<Output = i32>>>;
+
+ fn into_future(self) -> Self::Future {
+ Box::pin(me())
+ }
+}
+
+async fn me() -> i32 {
+ 41
+}
+
+async fn run() {
+ assert_eq!(AwaitMe.await, 41);
+}
+
+fn main() {
+ issue_72470_lib::run(run());
+}
diff --git a/src/test/ui/async-await/await-keyword/incorrect-syntax-suggestions.stderr b/src/test/ui/async-await/await-keyword/incorrect-syntax-suggestions.stderr
index 52615df6008..b4323c314ba 100644
--- a/src/test/ui/async-await/await-keyword/incorrect-syntax-suggestions.stderr
+++ b/src/test/ui/async-await/await-keyword/incorrect-syntax-suggestions.stderr
@@ -162,68 +162,68 @@ LL | let _ = (await bar())?;
| ^^^^^^^^^^^ only allowed inside `async` functions and blocks
error[E0728]: `await` is only allowed inside `async` functions and blocks
- --> $DIR/incorrect-syntax-suggestions.rs:71:13
+ --> $DIR/incorrect-syntax-suggestions.rs:71:18
|
LL | fn foo13() -> Result<(), ()> {
| ----- this is not `async`
LL | let _ = bar().await();
- | ^^^^^^^^^^^ only allowed inside `async` functions and blocks
+ | ^^^^^^ only allowed inside `async` functions and blocks
error[E0728]: `await` is only allowed inside `async` functions and blocks
- --> $DIR/incorrect-syntax-suggestions.rs:76:13
+ --> $DIR/incorrect-syntax-suggestions.rs:76:18
|
LL | fn foo14() -> Result<(), ()> {
| ----- this is not `async`
LL | let _ = bar().await()?;
- | ^^^^^^^^^^^ only allowed inside `async` functions and blocks
+ | ^^^^^^ only allowed inside `async` functions and blocks
error[E0728]: `await` is only allowed inside `async` functions and blocks
- --> $DIR/incorrect-syntax-suggestions.rs:81:13
+ --> $DIR/incorrect-syntax-suggestions.rs:81:18
|
LL | fn foo15() -> Result<(), ()> {
| ----- this is not `async`
LL | let _ = bar().await;
- | ^^^^^^^^^^^ only allowed inside `async` functions and blocks
+ | ^^^^^^ only allowed inside `async` functions and blocks
error[E0728]: `await` is only allowed inside `async` functions and blocks
- --> $DIR/incorrect-syntax-suggestions.rs:85:13
+ --> $DIR/incorrect-syntax-suggestions.rs:85:18
|
LL | fn foo16() -> Result<(), ()> {
| ----- this is not `async`
LL | let _ = bar().await?;
- | ^^^^^^^^^^^ only allowed inside `async` functions and blocks
+ | ^^^^^^ only allowed inside `async` functions and blocks
error[E0728]: `await` is only allowed inside `async` functions and blocks
- --> $DIR/incorrect-syntax-suggestions.rs:90:17
+ --> $DIR/incorrect-syntax-suggestions.rs:90:22
|
LL | fn foo() -> Result<(), ()> {
| --- this is not `async`
LL | let _ = bar().await?;
- | ^^^^^^^^^^^ only allowed inside `async` functions and blocks
+ | ^^^^^^ only allowed inside `async` functions and blocks
error[E0728]: `await` is only allowed inside `async` functions and blocks
- --> $DIR/incorrect-syntax-suggestions.rs:97:17
+ --> $DIR/incorrect-syntax-suggestions.rs:97:22
|
LL | let foo = || {
| -- this is not `async`
LL | let _ = bar().await?;
- | ^^^^^^^^^^^ only allowed inside `async` functions and blocks
+ | ^^^^^^ only allowed inside `async` functions and blocks
error[E0728]: `await` is only allowed inside `async` functions and blocks
- --> $DIR/incorrect-syntax-suggestions.rs:113:17
+ --> $DIR/incorrect-syntax-suggestions.rs:113:29
|
LL | fn foo() -> Result<(), ()> {
| --- this is not `async`
LL | let _ = await!(bar())?;
- | ^^^^^^^^^^^^^ only allowed inside `async` functions and blocks
+ | ^ only allowed inside `async` functions and blocks
error[E0728]: `await` is only allowed inside `async` functions and blocks
- --> $DIR/incorrect-syntax-suggestions.rs:121:17
+ --> $DIR/incorrect-syntax-suggestions.rs:121:29
|
LL | let foo = || {
| -- this is not `async`
LL | let _ = await!(bar())?;
- | ^^^^^^^^^^^^^ only allowed inside `async` functions and blocks
+ | ^ only allowed inside `async` functions and blocks
error: aborting due to 33 previous errors
diff --git a/src/test/ui/async-await/generator-desc.stderr b/src/test/ui/async-await/generator-desc.stderr
index 79834ed7ec1..4a45d8d2a94 100644
--- a/src/test/ui/async-await/generator-desc.stderr
+++ b/src/test/ui/async-await/generator-desc.stderr
@@ -46,8 +46,8 @@ LL | pub const fn from_generator<T>(gen: T) -> impl Future<Output = T::Return>
| the expected opaque type
| the found opaque type
|
- = note: expected opaque type `impl Future` (`async` closure body)
- found opaque type `impl Future` (`async` closure body)
+ = note: expected opaque type `impl Future<Output = [async output]>` (`async` closure body)
+ found opaque type `impl Future<Output = [async output]>` (`async` closure body)
error: aborting due to 3 previous errors
diff --git a/src/test/ui/async-await/generics-and-bounds.rs b/src/test/ui/async-await/generics-and-bounds.rs
index 963b19b34a6..90ab0c01f54 100644
--- a/src/test/ui/async-await/generics-and-bounds.rs
+++ b/src/test/ui/async-await/generics-and-bounds.rs
@@ -2,6 +2,8 @@
// edition:2018
// compile-flags: --crate-type lib
+#![feature(in_band_lifetimes)]
+
use std::future::Future;
pub async fn simple_generic<T>() {}
@@ -71,6 +73,10 @@ pub fn call_with_ref_block<'a>(f: &'a (impl Foo + 'a)) -> impl Future<Output = (
async move { f.foo() }
}
+pub fn call_with_ref_block_in_band(f: &'a (impl Foo + 'a)) -> impl Future<Output = ()> + 'a {
+ async move { f.foo() }
+}
+
pub fn async_block_with_same_generic_params_unifies() {
let mut a = call_generic_bound_block(FooType);
a = call_generic_bound_block(FooType);
@@ -85,4 +91,9 @@ pub fn async_block_with_same_generic_params_unifies() {
let f_two = FooType;
let mut d = call_with_ref_block(&f_one);
d = call_with_ref_block(&f_two);
+
+ let f_one = FooType;
+ let f_two = FooType;
+ let mut d = call_with_ref_block_in_band(&f_one);
+ d = call_with_ref_block_in_band(&f_two);
}
diff --git a/src/test/ui/async-await/issue-64130-1-sync.stderr b/src/test/ui/async-await/issue-64130-1-sync.stderr
index 010611fae43..e205de4738f 100644
--- a/src/test/ui/async-await/issue-64130-1-sync.stderr
+++ b/src/test/ui/async-await/issue-64130-1-sync.stderr
@@ -6,12 +6,12 @@ LL | is_sync(bar());
|
= help: within `impl Future<Output = ()>`, the trait `Sync` is not implemented for `Foo`
note: future is not `Sync` as this value is used across an await
- --> $DIR/issue-64130-1-sync.rs:15:5
+ --> $DIR/issue-64130-1-sync.rs:15:10
|
LL | let x = Foo;
| - has type `Foo` which is not `Sync`
LL | baz().await;
- | ^^^^^^^^^^^ await occurs here, with `x` maybe used later
+ | ^^^^^^ await occurs here, with `x` maybe used later
LL | }
| - `x` is later dropped here
note: required by a bound in `is_sync`
diff --git a/src/test/ui/async-await/issue-64130-2-send.stderr b/src/test/ui/async-await/issue-64130-2-send.stderr
index bb598b53594..2225000e2e5 100644
--- a/src/test/ui/async-await/issue-64130-2-send.stderr
+++ b/src/test/ui/async-await/issue-64130-2-send.stderr
@@ -6,12 +6,12 @@ LL | is_send(bar());
|
= help: within `impl Future<Output = ()>`, the trait `Send` is not implemented for `Foo`
note: future is not `Send` as this value is used across an await
- --> $DIR/issue-64130-2-send.rs:15:5
+ --> $DIR/issue-64130-2-send.rs:15:10
|
LL | let x = Foo;
| - has type `Foo` which is not `Send`
LL | baz().await;
- | ^^^^^^^^^^^ await occurs here, with `x` maybe used later
+ | ^^^^^^ await occurs here, with `x` maybe used later
LL | }
| - `x` is later dropped here
note: required by a bound in `is_send`
diff --git a/src/test/ui/async-await/issue-64130-3-other.stderr b/src/test/ui/async-await/issue-64130-3-other.stderr
index 4de7929e181..17867a6a3f6 100644
--- a/src/test/ui/async-await/issue-64130-3-other.stderr
+++ b/src/test/ui/async-await/issue-64130-3-other.stderr
@@ -8,12 +8,12 @@ LL | is_qux(bar());
| ^^^^^ within `impl Future<Output = ()>`, the trait `Qux` is not implemented for `Foo`
|
note: future does not implement `Qux` as this value is used across an await
- --> $DIR/issue-64130-3-other.rs:18:5
+ --> $DIR/issue-64130-3-other.rs:18:10
|
LL | let x = Foo;
| - has type `Foo` which does not implement `Qux`
LL | baz().await;
- | ^^^^^^^^^^^ await occurs here, with `x` maybe used later
+ | ^^^^^^ await occurs here, with `x` maybe used later
LL | }
| - `x` is later dropped here
note: required by a bound in `is_qux`
diff --git a/src/test/ui/async-await/issue-64130-4-async-move.stderr b/src/test/ui/async-await/issue-64130-4-async-move.stderr
index 2d46dfb7269..d631e6dc7f7 100644
--- a/src/test/ui/async-await/issue-64130-4-async-move.stderr
+++ b/src/test/ui/async-await/issue-64130-4-async-move.stderr
@@ -6,13 +6,13 @@ LL | pub fn foo() -> impl Future + Send {
|
= help: the trait `Sync` is not implemented for `(dyn Any + Send + 'static)`
note: future is not `Send` as this value is used across an await
- --> $DIR/issue-64130-4-async-move.rs:21:26
+ --> $DIR/issue-64130-4-async-move.rs:21:31
|
LL | match client.status() {
| ------ has type `&Client` which is not `Send`
LL | 200 => {
LL | let _x = get().await;
- | ^^^^^^^^^^^ await occurs here, with `client` maybe used later
+ | ^^^^^^ await occurs here, with `client` maybe used later
...
LL | }
| - `client` is later dropped here
diff --git a/src/test/ui/async-await/issue-64130-non-send-future-diags.stderr b/src/test/ui/async-await/issue-64130-non-send-future-diags.stderr
index 8eedb359733..1da80d98bf8 100644
--- a/src/test/ui/async-await/issue-64130-non-send-future-diags.stderr
+++ b/src/test/ui/async-await/issue-64130-non-send-future-diags.stderr
@@ -6,12 +6,12 @@ LL | is_send(foo());
|
= help: within `impl Future<Output = ()>`, the trait `Send` is not implemented for `MutexGuard<'_, u32>`
note: future is not `Send` as this value is used across an await
- --> $DIR/issue-64130-non-send-future-diags.rs:17:5
+ --> $DIR/issue-64130-non-send-future-diags.rs:17:10
|
LL | let g = x.lock().unwrap();
| - has type `MutexGuard<'_, u32>` which is not `Send`
LL | baz().await;
- | ^^^^^^^^^^^ await occurs here, with `g` maybe used later
+ | ^^^^^^ await occurs here, with `g` maybe used later
LL | }
| - `g` is later dropped here
note: required by a bound in `is_send`
diff --git a/src/test/ui/async-await/issue-67252-unnamed-future.stderr b/src/test/ui/async-await/issue-67252-unnamed-future.stderr
index d046e2a0561..f32e074d75d 100644
--- a/src/test/ui/async-await/issue-67252-unnamed-future.stderr
+++ b/src/test/ui/async-await/issue-67252-unnamed-future.stderr
@@ -4,14 +4,14 @@ error: future cannot be sent between threads safely
LL | spawn(async {
| ^^^^^ future created by async block is not `Send`
|
- = help: within `impl Future`, the trait `Send` is not implemented for `*mut ()`
+ = help: within `impl Future<Output = [async output]>`, the trait `Send` is not implemented for `*mut ()`
note: future is not `Send` as this value is used across an await
- --> $DIR/issue-67252-unnamed-future.rs:20:9
+ --> $DIR/issue-67252-unnamed-future.rs:20:16
|
LL | let _a = std::ptr::null_mut::<()>(); // `*mut ()` is not `Send`
| -- has type `*mut ()` which is not `Send`
LL | AFuture.await;
- | ^^^^^^^^^^^^^ await occurs here, with `_a` maybe used later
+ | ^^^^^^ await occurs here, with `_a` maybe used later
LL | });
| - `_a` is later dropped here
note: required by a bound in `spawn`
diff --git a/src/test/ui/async-await/issue-68112.stderr b/src/test/ui/async-await/issue-68112.stderr
index 9682a7055e9..a8c2ebe12fa 100644
--- a/src/test/ui/async-await/issue-68112.stderr
+++ b/src/test/ui/async-await/issue-68112.stderr
@@ -44,13 +44,13 @@ LL | require_send(send_fut);
= note: required because of the requirements on the impl of `Send` for `Arc<RefCell<i32>>`
= note: required because it appears within the type `[static generator@$DIR/issue-68112.rs:47:31: 47:36]`
= note: required because it appears within the type `from_generator::GenFuture<[static generator@$DIR/issue-68112.rs:47:31: 47:36]>`
- = note: required because it appears within the type `impl Future`
+ = note: required because it appears within the type `impl Future<Output = [async output]>`
= note: required because it appears within the type `impl Future<Output = Arc<RefCell<i32>>>`
= note: required because it appears within the type `impl Future<Output = Arc<RefCell<i32>>>`
= note: required because it appears within the type `{ResumeTy, impl Future<Output = Arc<RefCell<i32>>>, (), i32, Ready<i32>}`
= note: required because it appears within the type `[static generator@$DIR/issue-68112.rs:55:26: 59:6]`
= note: required because it appears within the type `from_generator::GenFuture<[static generator@$DIR/issue-68112.rs:55:26: 59:6]>`
- = note: required because it appears within the type `impl Future`
+ = note: required because it appears within the type `impl Future<Output = [async output]>`
note: required by a bound in `require_send`
--> $DIR/issue-68112.rs:11:25
|
diff --git a/src/test/ui/async-await/issue-70594.stderr b/src/test/ui/async-await/issue-70594.stderr
index eb24040404b..a159edd5118 100644
--- a/src/test/ui/async-await/issue-70594.stderr
+++ b/src/test/ui/async-await/issue-70594.stderr
@@ -1,10 +1,10 @@
error[E0728]: `await` is only allowed inside `async` functions and blocks
- --> $DIR/issue-70594.rs:4:9
+ --> $DIR/issue-70594.rs:4:11
|
LL | async fn fun() {
| --- this is not `async`
LL | [1; ().await];
- | ^^^^^^^^ only allowed inside `async` functions and blocks
+ | ^^^^^^ only allowed inside `async` functions and blocks
error[E0744]: `.await` is not allowed in a `const`
--> $DIR/issue-70594.rs:4:9
@@ -13,18 +13,25 @@ LL | [1; ().await];
| ^^^^^^^^
error[E0744]: `.await` is not allowed in a `const`
- --> $DIR/issue-70594.rs:4:9
+ --> $DIR/issue-70594.rs:4:11
|
LL | [1; ().await];
- | ^^^^^^^^
+ | ^^^^^^
error[E0277]: `()` is not a future
- --> $DIR/issue-70594.rs:4:9
+ --> $DIR/issue-70594.rs:4:11
|
LL | [1; ().await];
- | ^^^^^^^^ `()` is not a future
+ | ^^^^^^ `()` is not a future
|
= help: the trait `Future` is not implemented for `()`
+ = note: () must be a future or must implement `IntoFuture` to be awaited
+ = note: required because of the requirements on the impl of `IntoFuture` for `()`
+help: remove the `.await`
+ |
+LL - [1; ().await];
+LL + [1; ()];
+ |
error: aborting due to 4 previous errors
diff --git a/src/test/ui/async-await/issue-70935-complex-spans.stderr b/src/test/ui/async-await/issue-70935-complex-spans.stderr
index 8451fb84099..db309938119 100644
--- a/src/test/ui/async-await/issue-70935-complex-spans.stderr
+++ b/src/test/ui/async-await/issue-70935-complex-spans.stderr
@@ -6,25 +6,20 @@ LL | fn foo(tx: std::sync::mpsc::Sender<i32>) -> impl Future + Send {
|
= help: the trait `Sync` is not implemented for `Sender<i32>`
note: future is not `Send` as this value is used across an await
- --> $DIR/issue-70935-complex-spans.rs:13:9
+ --> $DIR/issue-70935-complex-spans.rs:15:11
|
-LL | / baz(|| async{
+LL | baz(|| async{
+ | _____________-
LL | | foo(tx.clone());
LL | | }).await;
- | |________________^ first, await occurs here, with the value maybe used later...
+ | | - ^^^^^^ await occurs here, with the value maybe used later
+ | |_________|
+ | has type `[closure@$DIR/issue-70935-complex-spans.rs:13:13: 15:10]` which is not `Send`
note: the value is later dropped here
--> $DIR/issue-70935-complex-spans.rs:15:17
|
LL | }).await;
| ^
-note: this has type `[closure@$DIR/issue-70935-complex-spans.rs:13:13: 15:10]` which is not `Send`
- --> $DIR/issue-70935-complex-spans.rs:13:13
- |
-LL | baz(|| async{
- | _____________^
-LL | | foo(tx.clone());
-LL | | }).await;
- | |_________^
error: aborting due to previous error
diff --git a/src/test/ui/async-await/issue-71137.stderr b/src/test/ui/async-await/issue-71137.stderr
index dddea12162a..eade6aa2d3d 100644
--- a/src/test/ui/async-await/issue-71137.stderr
+++ b/src/test/ui/async-await/issue-71137.stderr
@@ -6,12 +6,12 @@ LL | fake_spawn(wrong_mutex());
|
= help: within `impl Future<Output = ()>`, the trait `Send` is not implemented for `MutexGuard<'_, i32>`
note: future is not `Send` as this value is used across an await
- --> $DIR/issue-71137.rs:14:5
+ --> $DIR/issue-71137.rs:14:25
|
LL | let mut guard = m.lock().unwrap();
| --------- has type `MutexGuard<'_, i32>` which is not `Send`
LL | (async { "right"; }).await;
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^ await occurs here, with `mut guard` maybe used later
+ | ^^^^^^ await occurs here, with `mut guard` maybe used later
LL | *guard += 1;
LL | }
| - `mut guard` is later dropped here
diff --git a/src/test/ui/async-await/issues/issue-51719.stderr b/src/test/ui/async-await/issues/issue-51719.stderr
index 5b9adb253d9..f3ce5d1c897 100644
--- a/src/test/ui/async-await/issues/issue-51719.stderr
+++ b/src/test/ui/async-await/issues/issue-51719.stderr
@@ -1,8 +1,8 @@
error[E0728]: `await` is only allowed inside `async` functions and blocks
- --> $DIR/issue-51719.rs:8:19
+ --> $DIR/issue-51719.rs:8:24
|
LL | let _gen = || foo().await;
- | -- ^^^^^^^^^^^ only allowed inside `async` functions and blocks
+ | -- ^^^^^^ only allowed inside `async` functions and blocks
| |
| this is not `async`
diff --git a/src/test/ui/async-await/issues/issue-51751.stderr b/src/test/ui/async-await/issues/issue-51751.stderr
index f120bd119c5..8696a5b798b 100644
--- a/src/test/ui/async-await/issues/issue-51751.stderr
+++ b/src/test/ui/async-await/issues/issue-51751.stderr
@@ -1,11 +1,11 @@
error[E0728]: `await` is only allowed inside `async` functions and blocks
- --> $DIR/issue-51751.rs:9:20
+ --> $DIR/issue-51751.rs:9:26
|
LL | fn main() {
| ---- this is not `async`
LL | let result = inc(10000);
LL | let finished = result.await;
- | ^^^^^^^^^^^^ only allowed inside `async` functions and blocks
+ | ^^^^^^ only allowed inside `async` functions and blocks
error: aborting due to previous error
diff --git a/src/test/ui/async-await/issues/issue-54752-async-block.rs b/src/test/ui/async-await/issues/issue-54752-async-block.rs
index c2840d7386f..a8165ae6c32 100644
--- a/src/test/ui/async-await/issues/issue-54752-async-block.rs
+++ b/src/test/ui/async-await/issues/issue-54752-async-block.rs
@@ -3,5 +3,5 @@
// edition:2018
// pp-exact
-fn main() { let _a = (async { }); }
+fn main() { let _a = (async { }); }
//~^ WARNING unnecessary parentheses around assigned value
diff --git a/src/test/ui/async-await/issues/issue-54752-async-block.stderr b/src/test/ui/async-await/issues/issue-54752-async-block.stderr
index 0aea56ddb70..e3ed0b53356 100644
--- a/src/test/ui/async-await/issues/issue-54752-async-block.stderr
+++ b/src/test/ui/async-await/issues/issue-54752-async-block.stderr
@@ -1,14 +1,14 @@
warning: unnecessary parentheses around assigned value
--> $DIR/issue-54752-async-block.rs:6:22
|
-LL | fn main() { let _a = (async { }); }
- | ^ ^
+LL | fn main() { let _a = (async { }); }
+ | ^ ^
|
= note: `#[warn(unused_parens)]` on by default
help: remove these parentheses
|
-LL - fn main() { let _a = (async { }); }
-LL + fn main() { let _a = async { }; }
+LL - fn main() { let _a = (async { }); }
+LL + fn main() { let _a = async { }; }
|
warning: 1 warning emitted
diff --git a/src/test/ui/async-await/issues/issue-60674.stdout b/src/test/ui/async-await/issues/issue-60674.stdout
index 395d9e21b38..6f980e60664 100644
--- a/src/test/ui/async-await/issues/issue-60674.stdout
+++ b/src/test/ui/async-await/issues/issue-60674.stdout
@@ -1,3 +1,3 @@
-async fn f(mut x : u8) { }
-async fn g((mut x, y, mut z) : (u8, u8, u8)) { }
-async fn g(mut x : u8, (a, mut b, c) : (u8, u8, u8), y : u8) { }
+async fn f(mut x : u8) {}
+async fn g((mut x, y, mut z) : (u8, u8, u8)) {}
+async fn g(mut x : u8, (a, mut b, c) : (u8, u8, u8), y : u8) {}
diff --git a/src/test/ui/async-await/issues/issue-62009-1.rs b/src/test/ui/async-await/issues/issue-62009-1.rs
index 3ee7ab2e9d1..40ccf25712e 100644
--- a/src/test/ui/async-await/issues/issue-62009-1.rs
+++ b/src/test/ui/async-await/issues/issue-62009-1.rs
@@ -6,10 +6,10 @@ fn main() {
async { let (); }.await;
//~^ ERROR `await` is only allowed inside `async` functions and blocks
async {
- //~^ ERROR `await` is only allowed inside `async` functions and blocks
let task1 = print_dur().await;
}.await;
+ //~^ ERROR `await` is only allowed inside `async` functions and blocks
(|_| 2333).await;
//~^ ERROR `await` is only allowed inside `async` functions and blocks
- //~^^ ERROR
+ //~| ERROR is not a future
}
diff --git a/src/test/ui/async-await/issues/issue-62009-1.stderr b/src/test/ui/async-await/issues/issue-62009-1.stderr
index e2ea72a1e61..3d80c34942c 100644
--- a/src/test/ui/async-await/issues/issue-62009-1.stderr
+++ b/src/test/ui/async-await/issues/issue-62009-1.stderr
@@ -1,39 +1,43 @@
error[E0728]: `await` is only allowed inside `async` functions and blocks
- --> $DIR/issue-62009-1.rs:6:5
+ --> $DIR/issue-62009-1.rs:6:22
|
LL | fn main() {
| ---- this is not `async`
LL | async { let (); }.await;
- | ^^^^^^^^^^^^^^^^^^^^^^^ only allowed inside `async` functions and blocks
+ | ^^^^^^ only allowed inside `async` functions and blocks
error[E0728]: `await` is only allowed inside `async` functions and blocks
- --> $DIR/issue-62009-1.rs:8:5
+ --> $DIR/issue-62009-1.rs:10:6
|
-LL | fn main() {
- | ---- this is not `async`
+LL | fn main() {
+ | ---- this is not `async`
...
-LL | / async {
-LL | |
-LL | | let task1 = print_dur().await;
-LL | | }.await;
- | |___________^ only allowed inside `async` functions and blocks
+LL | }.await;
+ | ^^^^^^ only allowed inside `async` functions and blocks
error[E0728]: `await` is only allowed inside `async` functions and blocks
- --> $DIR/issue-62009-1.rs:12:5
+ --> $DIR/issue-62009-1.rs:12:15
|
LL | fn main() {
| ---- this is not `async`
...
LL | (|_| 2333).await;
- | ^^^^^^^^^^^^^^^^ only allowed inside `async` functions and blocks
+ | ^^^^^^ only allowed inside `async` functions and blocks
error[E0277]: `[closure@$DIR/issue-62009-1.rs:12:5: 12:15]` is not a future
- --> $DIR/issue-62009-1.rs:12:5
+ --> $DIR/issue-62009-1.rs:12:15
|
LL | (|_| 2333).await;
- | ^^^^^^^^^^^^^^^^ `[closure@$DIR/issue-62009-1.rs:12:5: 12:15]` is not a future
+ | ^^^^^^ `[closure@$DIR/issue-62009-1.rs:12:5: 12:15]` is not a future
|
= help: the trait `Future` is not implemented for `[closure@$DIR/issue-62009-1.rs:12:5: 12:15]`
+ = note: [closure@$DIR/issue-62009-1.rs:12:5: 12:15] must be a future or must implement `IntoFuture` to be awaited
+ = note: required because of the requirements on the impl of `IntoFuture` for `[closure@$DIR/issue-62009-1.rs:12:5: 12:15]`
+help: remove the `.await`
+ |
+LL - (|_| 2333).await;
+LL + (|_| 2333);
+ |
error: aborting due to 4 previous errors
diff --git a/src/test/ui/async-await/issues/issue-62009-2.stderr b/src/test/ui/async-await/issues/issue-62009-2.stderr
index 47b74b5574f..92e9a8a69a8 100644
--- a/src/test/ui/async-await/issues/issue-62009-2.stderr
+++ b/src/test/ui/async-await/issues/issue-62009-2.stderr
@@ -1,10 +1,10 @@
error[E0728]: `await` is only allowed inside `async` functions and blocks
- --> $DIR/issue-62009-2.rs:8:5
+ --> $DIR/issue-62009-2.rs:8:22
|
LL | fn main() {
| ---- this is not `async`
LL | (async || 2333)().await;
- | ^^^^^^^^^^^^^^^^^^^^^^^ only allowed inside `async` functions and blocks
+ | ^^^^^^ only allowed inside `async` functions and blocks
error: aborting due to previous error
diff --git a/src/test/ui/async-await/issues/issue-62097.stderr b/src/test/ui/async-await/issues/issue-62097.stderr
index 56a28d904b9..e23277543c6 100644
--- a/src/test/ui/async-await/issues/issue-62097.stderr
+++ b/src/test/ui/async-await/issues/issue-62097.stderr
@@ -2,12 +2,15 @@ error[E0759]: `self` has an anonymous lifetime `'_` but it needs to satisfy a `'
--> $DIR/issue-62097.rs:12:31
|
LL | pub async fn run_dummy_fn(&self) {
- | ^^^^^
- | |
- | this data with an anonymous lifetime `'_`...
- | ...is captured here...
+ | ^^^^^ this data with an anonymous lifetime `'_`...
LL | foo(|| self.bar()).await;
- | --- ...and is required to live as long as `'static` here
+ | --- ...is used and required to live as long as `'static` here
+ |
+note: `'static` lifetime requirement introduced by this bound
+ --> $DIR/issue-62097.rs:4:19
+ |
+LL | F: FnOnce() + 'static
+ | ^^^^^^^
error: aborting due to previous error
diff --git a/src/test/ui/async-await/issues/issue-65419/issue-65419-async-fn-resume-after-panic.rs b/src/test/ui/async-await/issues/issue-65419/issue-65419-async-fn-resume-after-panic.rs
index f8caebcb876..5e71229beb5 100644
--- a/src/test/ui/async-await/issues/issue-65419/issue-65419-async-fn-resume-after-panic.rs
+++ b/src/test/ui/async-await/issues/issue-65419/issue-65419-async-fn-resume-after-panic.rs
@@ -2,6 +2,7 @@
// be talking about `async fn`s instead. Should also test what happens when it panics.
// run-fail
+// needs-unwind
// error-pattern: thread 'main' panicked at '`async fn` resumed after panicking'
// edition:2018
// ignore-wasm no panic or subprocess support
diff --git a/src/test/ui/async-await/issues/issue-65436-raw-ptr-not-send.stderr b/src/test/ui/async-await/issues/issue-65436-raw-ptr-not-send.stderr
index 666ef851ad6..b4d20064803 100644
--- a/src/test/ui/async-await/issues/issue-65436-raw-ptr-not-send.stderr
+++ b/src/test/ui/async-await/issues/issue-65436-raw-ptr-not-send.stderr
@@ -4,19 +4,19 @@ error: future cannot be sent between threads safely
LL | assert_send(async {
| ^^^^^^^^^^^ future created by async block is not `Send`
|
- = help: within `impl Future`, the trait `Send` is not implemented for `*const u8`
+ = help: within `impl Future<Output = [async output]>`, the trait `Send` is not implemented for `*const u8`
note: future is not `Send` as this value is used across an await
- --> $DIR/issue-65436-raw-ptr-not-send.rs:14:9
+ --> $DIR/issue-65436-raw-ptr-not-send.rs:14:35
|
LL | bar(Foo(std::ptr::null())).await;
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ first, await occurs here, with `std::ptr::null()` maybe used later...
+ | ---------------- ^^^^^^ await occurs here, with `std::ptr::null()` maybe used later
+ | |
+ | has type `*const u8` which is not `Send`
note: `std::ptr::null()` is later dropped here
--> $DIR/issue-65436-raw-ptr-not-send.rs:14:41
|
LL | bar(Foo(std::ptr::null())).await;
- | ---------------- ^
- | |
- | has type `*const u8` which is not `Send`
+ | ^
help: consider moving this into a `let` binding to create a shorter lived borrow
--> $DIR/issue-65436-raw-ptr-not-send.rs:14:13
|
diff --git a/src/test/ui/async-await/issues/issue-72312.nll.stderr b/src/test/ui/async-await/issues/issue-72312.nll.stderr
new file mode 100644
index 00000000000..068d8c64d68
--- /dev/null
+++ b/src/test/ui/async-await/issues/issue-72312.nll.stderr
@@ -0,0 +1,21 @@
+error[E0521]: borrowed data escapes outside of associated function
+ --> $DIR/issue-72312.rs:13:24
+ |
+LL | pub async fn start(&self) {
+ | -----
+ | |
+ | `self` is a reference that is only valid in the associated function body
+ | let's call the lifetime of this reference `'1`
+...
+LL | require_static(async move {
+ | ________________________^
+LL | | &self;
+LL | | });
+ | | ^
+ | | |
+ | |_________`self` escapes the associated function body here
+ | argument requires that `'1` must outlive `'static`
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0521`.
diff --git a/src/test/ui/async-await/issues/issue-72312.rs b/src/test/ui/async-await/issues/issue-72312.rs
new file mode 100644
index 00000000000..eb7d12e290c
--- /dev/null
+++ b/src/test/ui/async-await/issues/issue-72312.rs
@@ -0,0 +1,19 @@
+// edition:2018
+fn require_static<T: 'static>(val: T) -> T {
+ //~^ NOTE 'static` lifetime requirement introduced by this bound
+ val
+}
+
+struct Problem;
+
+impl Problem {
+ pub async fn start(&self) { //~ ERROR E0759
+ //~^ NOTE this data with an anonymous lifetime `'_`
+ //~| NOTE in this expansion of desugaring of `async` block or function
+ require_static(async move { //~ NOTE ...and is required to live as long as `'static` here
+ &self; //~ NOTE ...is used here...
+ });
+ }
+}
+
+fn main() {}
diff --git a/src/test/ui/async-await/issues/issue-72312.stderr b/src/test/ui/async-await/issues/issue-72312.stderr
new file mode 100644
index 00000000000..798f755765c
--- /dev/null
+++ b/src/test/ui/async-await/issues/issue-72312.stderr
@@ -0,0 +1,23 @@
+error[E0759]: `self` has an anonymous lifetime `'_` but it needs to satisfy a `'static` lifetime requirement
+ --> $DIR/issue-72312.rs:10:24
+ |
+LL | pub async fn start(&self) {
+ | ^^^^^ this data with an anonymous lifetime `'_`...
+...
+LL | &self;
+ | ----- ...is used here...
+ |
+note: ...and is required to live as long as `'static` here
+ --> $DIR/issue-72312.rs:13:9
+ |
+LL | require_static(async move {
+ | ^^^^^^^^^^^^^^
+note: `'static` lifetime requirement introduced by this bound
+ --> $DIR/issue-72312.rs:2:22
+ |
+LL | fn require_static<T: 'static>(val: T) -> T {
+ | ^^^^^^^
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0759`.
diff --git a/src/test/ui/async-await/issues/non-async-enclosing-span.stderr b/src/test/ui/async-await/issues/non-async-enclosing-span.stderr
index f826a86f089..20b827479fa 100644
--- a/src/test/ui/async-await/issues/non-async-enclosing-span.stderr
+++ b/src/test/ui/async-await/issues/non-async-enclosing-span.stderr
@@ -1,11 +1,11 @@
error[E0728]: `await` is only allowed inside `async` functions and blocks
- --> $DIR/non-async-enclosing-span.rs:9:13
+ --> $DIR/non-async-enclosing-span.rs:9:27
|
LL | fn main() {
| ---- this is not `async`
LL | let x = move || {};
LL | let y = do_the_thing().await;
- | ^^^^^^^^^^^^^^^^^^^^ only allowed inside `async` functions and blocks
+ | ^^^^^^ only allowed inside `async` functions and blocks
error: aborting due to previous error
diff --git a/src/test/ui/async-await/multiple-lifetimes/ret-impl-trait-one.nll.stderr b/src/test/ui/async-await/multiple-lifetimes/ret-impl-trait-one.nll.stderr
index 9b0018d8904..2722c72c20a 100644
--- a/src/test/ui/async-await/multiple-lifetimes/ret-impl-trait-one.nll.stderr
+++ b/src/test/ui/async-await/multiple-lifetimes/ret-impl-trait-one.nll.stderr
@@ -21,7 +21,7 @@ LL | async fn async_ret_impl_trait1<'a, 'b>(a: &'a u8, b: &'b u8) -> impl Trait<
| |
| hidden type `(&'a u8, &'b u8)` captures the lifetime `'b` as defined here
|
-help: to declare that the `impl Trait` captures 'b, you can add an explicit `'b` lifetime bound
+help: to declare that the `impl Trait` captures `'b`, you can add an explicit `'b` lifetime bound
|
LL | async fn async_ret_impl_trait1<'a, 'b>(a: &'a u8, b: &'b u8) -> impl Trait<'a> + 'b {
| ++++
diff --git a/src/test/ui/async-await/multiple-lifetimes/ret-impl-trait-one.stderr b/src/test/ui/async-await/multiple-lifetimes/ret-impl-trait-one.stderr
index bcd96367e2f..464f283095d 100644
--- a/src/test/ui/async-await/multiple-lifetimes/ret-impl-trait-one.stderr
+++ b/src/test/ui/async-await/multiple-lifetimes/ret-impl-trait-one.stderr
@@ -16,7 +16,7 @@ LL | async fn async_ret_impl_trait1<'a, 'b>(a: &'a u8, b: &'b u8) -> impl Trait<
| |
| hidden type `(&'a u8, &'b u8)` captures the lifetime `'b` as defined here
|
-help: to declare that the `impl Trait` captures 'b, you can add an explicit `'b` lifetime bound
+help: to declare that the `impl Trait` captures `'b`, you can add an explicit `'b` lifetime bound
|
LL | async fn async_ret_impl_trait1<'a, 'b>(a: &'a u8, b: &'b u8) -> impl Trait<'a> + 'b {
| ++++
diff --git a/src/test/ui/async-await/unnecessary-await.rs b/src/test/ui/async-await/unnecessary-await.rs
new file mode 100644
index 00000000000..24673777b80
--- /dev/null
+++ b/src/test/ui/async-await/unnecessary-await.rs
@@ -0,0 +1,14 @@
+// edition:2018
+
+async fn foo () { }
+fn bar() -> impl std::future::Future { async {} }
+fn boo() {}
+
+async fn baz() -> std::io::Result<()> {
+ foo().await;
+ boo().await; //~ ERROR `()` is not a future
+ bar().await;
+ std::io::Result::Ok(())
+}
+
+fn main() {}
diff --git a/src/test/ui/async-await/unnecessary-await.stderr b/src/test/ui/async-await/unnecessary-await.stderr
new file mode 100644
index 00000000000..c3d2a6e7b1e
--- /dev/null
+++ b/src/test/ui/async-await/unnecessary-await.stderr
@@ -0,0 +1,24 @@
+error[E0277]: `()` is not a future
+ --> $DIR/unnecessary-await.rs:9:10
+ |
+LL | boo().await;
+ | -----^^^^^^ `()` is not a future
+ | |
+ | this call returns `()`
+ |
+ = help: the trait `Future` is not implemented for `()`
+ = note: () must be a future or must implement `IntoFuture` to be awaited
+ = note: required because of the requirements on the impl of `IntoFuture` for `()`
+help: remove the `.await`
+ |
+LL - boo().await;
+LL + boo();
+ |
+help: alternatively, consider making `fn boo` asynchronous
+ |
+LL | async fn boo() {}
+ | +++++
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0277`.
diff --git a/src/test/ui/async-await/unresolved_type_param.rs b/src/test/ui/async-await/unresolved_type_param.rs
index d313691b388..85d868c2703 100644
--- a/src/test/ui/async-await/unresolved_type_param.rs
+++ b/src/test/ui/async-await/unresolved_type_param.rs
@@ -10,12 +10,20 @@ async fn foo() {
//~^ ERROR type inside `async fn` body must be known in this context
//~| ERROR type inside `async fn` body must be known in this context
//~| ERROR type inside `async fn` body must be known in this context
+ //~| ERROR type inside `async fn` body must be known in this context
+ //~| ERROR type inside `async fn` body must be known in this context
+ //~| NOTE cannot infer type for type parameter `T`
+ //~| NOTE cannot infer type for type parameter `T`
//~| NOTE cannot infer type for type parameter `T`
//~| NOTE cannot infer type for type parameter `T`
//~| NOTE cannot infer type for type parameter `T`
//~| NOTE the type is part of the `async fn` body because of this `await`
//~| NOTE the type is part of the `async fn` body because of this `await`
//~| NOTE the type is part of the `async fn` body because of this `await`
+ //~| NOTE the type is part of the `async fn` body because of this `await`
+ //~| NOTE the type is part of the `async fn` body because of this `await`
+ //~| NOTE in this expansion of desugaring of `await`
+ //~| NOTE in this expansion of desugaring of `await`
//~| NOTE in this expansion of desugaring of `await`
//~| NOTE in this expansion of desugaring of `await`
//~| NOTE in this expansion of desugaring of `await`
diff --git a/src/test/ui/async-await/unresolved_type_param.stderr b/src/test/ui/async-await/unresolved_type_param.stderr
index 6b9e960ca1a..8c0ecb8785d 100644
--- a/src/test/ui/async-await/unresolved_type_param.stderr
+++ b/src/test/ui/async-await/unresolved_type_param.stderr
@@ -5,10 +5,10 @@ LL | bar().await;
| ^^^ cannot infer type for type parameter `T` declared on the function `bar`
|
note: the type is part of the `async fn` body because of this `await`
- --> $DIR/unresolved_type_param.rs:9:5
+ --> $DIR/unresolved_type_param.rs:9:10
|
LL | bar().await;
- | ^^^^^^^^^^^
+ | ^^^^^^
error[E0698]: type inside `async fn` body must be known in this context
--> $DIR/unresolved_type_param.rs:9:5
@@ -17,10 +17,22 @@ LL | bar().await;
| ^^^ cannot infer type for type parameter `T` declared on the function `bar`
|
note: the type is part of the `async fn` body because of this `await`
+ --> $DIR/unresolved_type_param.rs:9:10
+ |
+LL | bar().await;
+ | ^^^^^^
+
+error[E0698]: type inside `async fn` body must be known in this context
--> $DIR/unresolved_type_param.rs:9:5
|
LL | bar().await;
- | ^^^^^^^^^^^
+ | ^^^ cannot infer type for type parameter `T` declared on the function `bar`
+ |
+note: the type is part of the `async fn` body because of this `await`
+ --> $DIR/unresolved_type_param.rs:9:10
+ |
+LL | bar().await;
+ | ^^^^^^
error[E0698]: type inside `async fn` body must be known in this context
--> $DIR/unresolved_type_param.rs:9:5
@@ -29,11 +41,23 @@ LL | bar().await;
| ^^^ cannot infer type for type parameter `T` declared on the function `bar`
|
note: the type is part of the `async fn` body because of this `await`
+ --> $DIR/unresolved_type_param.rs:9:10
+ |
+LL | bar().await;
+ | ^^^^^^
+
+error[E0698]: type inside `async fn` body must be known in this context
--> $DIR/unresolved_type_param.rs:9:5
|
LL | bar().await;
- | ^^^^^^^^^^^
+ | ^^^ cannot infer type for type parameter `T` declared on the function `bar`
+ |
+note: the type is part of the `async fn` body because of this `await`
+ --> $DIR/unresolved_type_param.rs:9:10
+ |
+LL | bar().await;
+ | ^^^^^^
-error: aborting due to 3 previous errors
+error: aborting due to 5 previous errors
For more information about this error, try `rustc --explain E0698`.
diff --git a/src/test/ui/attributes/duplicated-attributes.rs b/src/test/ui/attributes/duplicated-attributes.rs
new file mode 100644
index 00000000000..84a5abcf8b4
--- /dev/null
+++ b/src/test/ui/attributes/duplicated-attributes.rs
@@ -0,0 +1,41 @@
+// Test that, if an item is annotated with a builtin attribute more than once, a warning is
+// emitted.
+// Tests https://github.com/rust-lang/rust/issues/90979
+
+// check-pass
+// compile-flags: --test
+
+#![feature(test)]
+#![feature(cfg_eval)]
+
+#[test]
+#[test]
+//~^ WARNING duplicated attribute
+fn f() {}
+
+// The following shouldn't trigger an error. The attribute is not duplicated.
+#[test]
+fn f2() {}
+
+// The following shouldn't trigger an error either. The second attribute is not #[test].
+#[test]
+#[inline]
+fn f3() {}
+
+extern crate test;
+use test::Bencher;
+
+#[bench]
+#[bench]
+//~^ WARNING duplicated attribute
+fn f4(_: &mut Bencher) {}
+
+#[cfg_eval]
+#[cfg_eval]
+//~^ WARNING duplicated attribute
+struct S;
+
+#[cfg_eval]
+struct S2;
+
+fn main() {}
diff --git a/src/test/ui/attributes/duplicated-attributes.stderr b/src/test/ui/attributes/duplicated-attributes.stderr
new file mode 100644
index 00000000000..735d950b27c
--- /dev/null
+++ b/src/test/ui/attributes/duplicated-attributes.stderr
@@ -0,0 +1,22 @@
+warning: duplicated attribute
+ --> $DIR/duplicated-attributes.rs:12:1
+ |
+LL | #[test]
+ | ^^^^^^^
+ |
+ = note: `#[warn(duplicate_macro_attributes)]` on by default
+
+warning: duplicated attribute
+ --> $DIR/duplicated-attributes.rs:29:1
+ |
+LL | #[bench]
+ | ^^^^^^^^
+
+warning: duplicated attribute
+ --> $DIR/duplicated-attributes.rs:34:1
+ |
+LL | #[cfg_eval]
+ | ^^^^^^^^^^^
+
+warning: 3 warnings emitted
+
diff --git a/src/test/ui/attributes/issue-90873.rs b/src/test/ui/attributes/issue-90873.rs
new file mode 100644
index 00000000000..76708ea9830
--- /dev/null
+++ b/src/test/ui/attributes/issue-90873.rs
@@ -0,0 +1,9 @@
+#![u=||{static d=||1;}]
+//~^ unexpected token
+//~| cannot find attribute `u` in this scope
+//~| `main` function not found in crate `issue_90873`
+//~| missing type for `static` item
+
+#![a={impl std::ops::Neg for i8 {}}]
+//~^ ERROR unexpected token
+//~| ERROR cannot find attribute `a` in this scope
diff --git a/src/test/ui/attributes/issue-90873.stderr b/src/test/ui/attributes/issue-90873.stderr
new file mode 100644
index 00000000000..2718b65108c
--- /dev/null
+++ b/src/test/ui/attributes/issue-90873.stderr
@@ -0,0 +1,50 @@
+error: unexpected token: `||
+ {
+ static d: _ = || 1;
+ }`
+ --> $DIR/issue-90873.rs:1:6
+ |
+LL | #![u=||{static d=||1;}]
+ | ^^^^^^^^^^^^^^^^^
+
+error: unexpected token: `{
+ impl std::ops::Neg for i8 {}
+ }`
+ --> $DIR/issue-90873.rs:7:6
+ |
+LL | #![a={impl std::ops::Neg for i8 {}}]
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: cannot find attribute `u` in this scope
+ --> $DIR/issue-90873.rs:1:4
+ |
+LL | #![u=||{static d=||1;}]
+ | ^
+
+error: cannot find attribute `a` in this scope
+ --> $DIR/issue-90873.rs:7:4
+ |
+LL | #![a={impl std::ops::Neg for i8 {}}]
+ | ^
+
+error[E0601]: `main` function not found in crate `issue_90873`
+ --> $DIR/issue-90873.rs:1:1
+ |
+LL | / #![u=||{static d=||1;}]
+LL | |
+LL | |
+LL | |
+LL | |
+LL | |
+LL | | #![a={impl std::ops::Neg for i8 {}}]
+ | |____________________________________^ consider adding a `main` function to `$DIR/issue-90873.rs`
+
+error: missing type for `static` item
+ --> $DIR/issue-90873.rs:1:16
+ |
+LL | #![u=||{static d=||1;}]
+ | ^ help: provide a type for the item: `d: <type>`
+
+error: aborting due to 6 previous errors
+
+For more information about this error, try `rustc --explain E0601`.
diff --git a/src/test/ui/auto-traits/typeck-default-trait-impl-precedence.stderr b/src/test/ui/auto-traits/typeck-default-trait-impl-precedence.stderr
index c98925a7b1d..8ce70b1ac06 100644
--- a/src/test/ui/auto-traits/typeck-default-trait-impl-precedence.stderr
+++ b/src/test/ui/auto-traits/typeck-default-trait-impl-precedence.stderr
@@ -4,7 +4,11 @@ error[E0277]: the trait bound `u32: Signed` is not satisfied
LL | is_defaulted::<&'static u32>();
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `Signed` is not implemented for `u32`
|
- = note: required because of the requirements on the impl of `Defaulted` for `&'static u32`
+note: required because of the requirements on the impl of `Defaulted` for `&'static u32`
+ --> $DIR/typeck-default-trait-impl-precedence.rs:10:19
+ |
+LL | impl<'a,T:Signed> Defaulted for &'a T { }
+ | ^^^^^^^^^ ^^^^^
note: required by a bound in `is_defaulted`
--> $DIR/typeck-default-trait-impl-precedence.rs:12:19
|
diff --git a/src/test/ui/binding/fn-arg-incomplete-pattern-drop-order.rs b/src/test/ui/binding/fn-arg-incomplete-pattern-drop-order.rs
index ea4a9e5afa5..684172ca61c 100644
--- a/src/test/ui/binding/fn-arg-incomplete-pattern-drop-order.rs
+++ b/src/test/ui/binding/fn-arg-incomplete-pattern-drop-order.rs
@@ -1,4 +1,5 @@
// run-pass
+// needs-unwind
// Check that partially moved from function parameters are dropped after the
// named bindings that move from them.
diff --git a/src/test/ui/binding/issue-53114-safety-checks.stderr b/src/test/ui/binding/issue-53114-safety-checks.stderr
index 9e7deea4524..84cdb1453f8 100644
--- a/src/test/ui/binding/issue-53114-safety-checks.stderr
+++ b/src/test/ui/binding/issue-53114-safety-checks.stderr
@@ -8,6 +8,7 @@ LL | let _ = &p.b;
= warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
= note: for more information, see issue #82523 <https://github.com/rust-lang/rust/issues/82523>
= note: fields of packed structs are not properly aligned, and creating a misaligned reference is undefined behavior (even if that reference is never dereferenced)
+ = help: copy the field contents to a local variable, or replace the reference with a raw pointer and use `read_unaligned`/`write_unaligned` (loads and stores via `*p` must be properly aligned even when using raw pointers)
warning: reference to packed field is unaligned
--> $DIR/issue-53114-safety-checks.rs:29:17
@@ -18,6 +19,7 @@ LL | let (_,) = (&p.b,);
= warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
= note: for more information, see issue #82523 <https://github.com/rust-lang/rust/issues/82523>
= note: fields of packed structs are not properly aligned, and creating a misaligned reference is undefined behavior (even if that reference is never dereferenced)
+ = help: copy the field contents to a local variable, or replace the reference with a raw pointer and use `read_unaligned`/`write_unaligned` (loads and stores via `*p` must be properly aligned even when using raw pointers)
warning: reference to packed field is unaligned
--> $DIR/issue-53114-safety-checks.rs:39:11
@@ -28,6 +30,7 @@ LL | match &p.b { _ => { } }
= warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
= note: for more information, see issue #82523 <https://github.com/rust-lang/rust/issues/82523>
= note: fields of packed structs are not properly aligned, and creating a misaligned reference is undefined behavior (even if that reference is never dereferenced)
+ = help: copy the field contents to a local variable, or replace the reference with a raw pointer and use `read_unaligned`/`write_unaligned` (loads and stores via `*p` must be properly aligned even when using raw pointers)
warning: reference to packed field is unaligned
--> $DIR/issue-53114-safety-checks.rs:45:12
@@ -38,6 +41,7 @@ LL | match (&p.b,) { (_,) => { } }
= warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
= note: for more information, see issue #82523 <https://github.com/rust-lang/rust/issues/82523>
= note: fields of packed structs are not properly aligned, and creating a misaligned reference is undefined behavior (even if that reference is never dereferenced)
+ = help: copy the field contents to a local variable, or replace the reference with a raw pointer and use `read_unaligned`/`write_unaligned` (loads and stores via `*p` must be properly aligned even when using raw pointers)
error[E0133]: access to union field is unsafe and requires unsafe function or block
--> $DIR/issue-53114-safety-checks.rs:26:13
diff --git a/src/test/ui/binop/binary-op-on-fn-ptr-eq.rs b/src/test/ui/binop/binary-op-on-fn-ptr-eq.rs
new file mode 100644
index 00000000000..8e20640b58d
--- /dev/null
+++ b/src/test/ui/binop/binary-op-on-fn-ptr-eq.rs
@@ -0,0 +1,9 @@
+// run-pass
+// Tests equality between supertype and subtype of a function
+// See the issue #91636
+fn foo(_a: &str) {}
+
+fn main() {
+ let x = foo as fn(&'static str);
+ let _ = x == foo;
+}
diff --git a/src/test/ui/borrowck/borrowck-and-init.stderr b/src/test/ui/borrowck/borrowck-and-init.stderr
index c7e357d4604..d2c7473c036 100644
--- a/src/test/ui/borrowck/borrowck-and-init.stderr
+++ b/src/test/ui/borrowck/borrowck-and-init.stderr
@@ -3,6 +3,8 @@ error[E0381]: borrow of possibly-uninitialized variable: `i`
|
LL | println!("{}", i);
| ^ use of possibly-uninitialized `i`
+ |
+ = note: this error originates in the macro `$crate::format_args_nl` (in Nightly builds, run with -Z macro-backtrace for more info)
error: aborting due to previous error
diff --git a/src/test/ui/borrowck/borrowck-break-uninit-2.stderr b/src/test/ui/borrowck/borrowck-break-uninit-2.stderr
index bc9b25c0221..b134f5cc2d8 100644
--- a/src/test/ui/borrowck/borrowck-break-uninit-2.stderr
+++ b/src/test/ui/borrowck/borrowck-break-uninit-2.stderr
@@ -3,6 +3,8 @@ error[E0381]: borrow of possibly-uninitialized variable: `x`
|
LL | println!("{}", x);
| ^ use of possibly-uninitialized `x`
+ |
+ = note: this error originates in the macro `$crate::format_args_nl` (in Nightly builds, run with -Z macro-backtrace for more info)
error: aborting due to previous error
diff --git a/src/test/ui/borrowck/borrowck-break-uninit.stderr b/src/test/ui/borrowck/borrowck-break-uninit.stderr
index 766d5cfd634..652d7d3076f 100644
--- a/src/test/ui/borrowck/borrowck-break-uninit.stderr
+++ b/src/test/ui/borrowck/borrowck-break-uninit.stderr
@@ -3,6 +3,8 @@ error[E0381]: borrow of possibly-uninitialized variable: `x`
|
LL | println!("{}", x);
| ^ use of possibly-uninitialized `x`
+ |
+ = note: this error originates in the macro `$crate::format_args_nl` (in Nightly builds, run with -Z macro-backtrace for more info)
error: aborting due to previous error
diff --git a/src/test/ui/borrowck/borrowck-or-init.stderr b/src/test/ui/borrowck/borrowck-or-init.stderr
index 3fe8d9eeded..6c757759f71 100644
--- a/src/test/ui/borrowck/borrowck-or-init.stderr
+++ b/src/test/ui/borrowck/borrowck-or-init.stderr
@@ -3,6 +3,8 @@ error[E0381]: borrow of possibly-uninitialized variable: `i`
|
LL | println!("{}", i);
| ^ use of possibly-uninitialized `i`
+ |
+ = note: this error originates in the macro `$crate::format_args_nl` (in Nightly builds, run with -Z macro-backtrace for more info)
error: aborting due to previous error
diff --git a/src/test/ui/borrowck/borrowck-while-break.stderr b/src/test/ui/borrowck/borrowck-while-break.stderr
index 3eaaf8d7df0..fc144a066bb 100644
--- a/src/test/ui/borrowck/borrowck-while-break.stderr
+++ b/src/test/ui/borrowck/borrowck-while-break.stderr
@@ -3,6 +3,8 @@ error[E0381]: borrow of possibly-uninitialized variable: `v`
|
LL | println!("{}", v);
| ^ use of possibly-uninitialized `v`
+ |
+ = note: this error originates in the macro `$crate::format_args_nl` (in Nightly builds, run with -Z macro-backtrace for more info)
error: aborting due to previous error
diff --git a/src/test/ui/borrowck/issue-24267-flow-exit.stderr b/src/test/ui/borrowck/issue-24267-flow-exit.stderr
index 4eb41ca24dd..e29cf7a1a75 100644
--- a/src/test/ui/borrowck/issue-24267-flow-exit.stderr
+++ b/src/test/ui/borrowck/issue-24267-flow-exit.stderr
@@ -3,12 +3,16 @@ error[E0381]: borrow of possibly-uninitialized variable: `x`
|
LL | println!("{}", x);
| ^ use of possibly-uninitialized `x`
+ |
+ = note: this error originates in the macro `$crate::format_args_nl` (in Nightly builds, run with -Z macro-backtrace for more info)
error[E0381]: borrow of possibly-uninitialized variable: `x`
--> $DIR/issue-24267-flow-exit.rs:18:20
|
LL | println!("{}", x);
| ^ use of possibly-uninitialized `x`
+ |
+ = note: this error originates in the macro `$crate::format_args_nl` (in Nightly builds, run with -Z macro-backtrace for more info)
error: aborting due to 2 previous errors
diff --git a/src/test/ui/borrowck/issue-55492-borrowck-migrate-scans-parents.migrate.stderr b/src/test/ui/borrowck/issue-55492-borrowck-migrate-scans-parents.migrate.stderr
index 1cdcc18632c..10400cff5e5 100644
--- a/src/test/ui/borrowck/issue-55492-borrowck-migrate-scans-parents.migrate.stderr
+++ b/src/test/ui/borrowck/issue-55492-borrowck-migrate-scans-parents.migrate.stderr
@@ -1,5 +1,5 @@
error[E0594]: cannot assign to `x`, as it is not declared as mutable
- --> $DIR/issue-55492-borrowck-migrate-scans-parents.rs:19:46
+ --> $DIR/issue-55492-borrowck-migrate-scans-parents.rs:17:46
|
LL | pub fn e(x: &'static mut isize) {
| - help: consider changing this to be mutable: `mut x`
@@ -8,7 +8,7 @@ LL | let mut c1 = |y: &'static mut isize| x = y;
| ^^^^^ cannot assign
error[E0594]: cannot assign to `x`, as it is not declared as mutable
- --> $DIR/issue-55492-borrowck-migrate-scans-parents.rs:30:50
+ --> $DIR/issue-55492-borrowck-migrate-scans-parents.rs:28:50
|
LL | pub fn ee(x: &'static mut isize) {
| - help: consider changing this to be mutable: `mut x`
@@ -17,7 +17,7 @@ LL | let mut c2 = |y: &'static mut isize| x = y;
| ^^^^^ cannot assign
error[E0594]: cannot assign to `x`, as it is not declared as mutable
- --> $DIR/issue-55492-borrowck-migrate-scans-parents.rs:42:14
+ --> $DIR/issue-55492-borrowck-migrate-scans-parents.rs:40:14
|
LL | pub fn capture_assign_whole(x: (i32,)) {
| - help: consider changing this to be mutable: `mut x`
@@ -25,7 +25,7 @@ LL | || { x = (1,); };
| ^^^^^^^^ cannot assign
error[E0594]: cannot assign to `x.0`, as `x` is not declared as mutable
- --> $DIR/issue-55492-borrowck-migrate-scans-parents.rs:47:14
+ --> $DIR/issue-55492-borrowck-migrate-scans-parents.rs:45:14
|
LL | pub fn capture_assign_part(x: (i32,)) {
| - help: consider changing this to be mutable: `mut x`
@@ -33,7 +33,7 @@ LL | || { x.0 = 1; };
| ^^^^^^^ cannot assign
error[E0596]: cannot borrow `x` as mutable, as it is not declared as mutable
- --> $DIR/issue-55492-borrowck-migrate-scans-parents.rs:52:14
+ --> $DIR/issue-55492-borrowck-migrate-scans-parents.rs:50:14
|
LL | pub fn capture_reborrow_whole(x: (i32,)) {
| - help: consider changing this to be mutable: `mut x`
@@ -41,7 +41,7 @@ LL | || { &mut x; };
| ^^^^^^ cannot borrow as mutable
error[E0596]: cannot borrow `x.0` as mutable, as `x` is not declared as mutable
- --> $DIR/issue-55492-borrowck-migrate-scans-parents.rs:57:14
+ --> $DIR/issue-55492-borrowck-migrate-scans-parents.rs:55:14
|
LL | pub fn capture_reborrow_part(x: (i32,)) {
| - help: consider changing this to be mutable: `mut x`
diff --git a/src/test/ui/borrowck/issue-55492-borrowck-migrate-scans-parents.nll.stderr b/src/test/ui/borrowck/issue-55492-borrowck-migrate-scans-parents.nll.stderr
index 1cdcc18632c..10400cff5e5 100644
--- a/src/test/ui/borrowck/issue-55492-borrowck-migrate-scans-parents.nll.stderr
+++ b/src/test/ui/borrowck/issue-55492-borrowck-migrate-scans-parents.nll.stderr
@@ -1,5 +1,5 @@
error[E0594]: cannot assign to `x`, as it is not declared as mutable
- --> $DIR/issue-55492-borrowck-migrate-scans-parents.rs:19:46
+ --> $DIR/issue-55492-borrowck-migrate-scans-parents.rs:17:46
|
LL | pub fn e(x: &'static mut isize) {
| - help: consider changing this to be mutable: `mut x`
@@ -8,7 +8,7 @@ LL | let mut c1 = |y: &'static mut isize| x = y;
| ^^^^^ cannot assign
error[E0594]: cannot assign to `x`, as it is not declared as mutable
- --> $DIR/issue-55492-borrowck-migrate-scans-parents.rs:30:50
+ --> $DIR/issue-55492-borrowck-migrate-scans-parents.rs:28:50
|
LL | pub fn ee(x: &'static mut isize) {
| - help: consider changing this to be mutable: `mut x`
@@ -17,7 +17,7 @@ LL | let mut c2 = |y: &'static mut isize| x = y;
| ^^^^^ cannot assign
error[E0594]: cannot assign to `x`, as it is not declared as mutable
- --> $DIR/issue-55492-borrowck-migrate-scans-parents.rs:42:14
+ --> $DIR/issue-55492-borrowck-migrate-scans-parents.rs:40:14
|
LL | pub fn capture_assign_whole(x: (i32,)) {
| - help: consider changing this to be mutable: `mut x`
@@ -25,7 +25,7 @@ LL | || { x = (1,); };
| ^^^^^^^^ cannot assign
error[E0594]: cannot assign to `x.0`, as `x` is not declared as mutable
- --> $DIR/issue-55492-borrowck-migrate-scans-parents.rs:47:14
+ --> $DIR/issue-55492-borrowck-migrate-scans-parents.rs:45:14
|
LL | pub fn capture_assign_part(x: (i32,)) {
| - help: consider changing this to be mutable: `mut x`
@@ -33,7 +33,7 @@ LL | || { x.0 = 1; };
| ^^^^^^^ cannot assign
error[E0596]: cannot borrow `x` as mutable, as it is not declared as mutable
- --> $DIR/issue-55492-borrowck-migrate-scans-parents.rs:52:14
+ --> $DIR/issue-55492-borrowck-migrate-scans-parents.rs:50:14
|
LL | pub fn capture_reborrow_whole(x: (i32,)) {
| - help: consider changing this to be mutable: `mut x`
@@ -41,7 +41,7 @@ LL | || { &mut x; };
| ^^^^^^ cannot borrow as mutable
error[E0596]: cannot borrow `x.0` as mutable, as `x` is not declared as mutable
- --> $DIR/issue-55492-borrowck-migrate-scans-parents.rs:57:14
+ --> $DIR/issue-55492-borrowck-migrate-scans-parents.rs:55:14
|
LL | pub fn capture_reborrow_part(x: (i32,)) {
| - help: consider changing this to be mutable: `mut x`
diff --git a/src/test/ui/borrowck/issue-55492-borrowck-migrate-scans-parents.rs b/src/test/ui/borrowck/issue-55492-borrowck-migrate-scans-parents.rs
index 751a911a6bb..fe7ed8ed3fa 100644
--- a/src/test/ui/borrowck/issue-55492-borrowck-migrate-scans-parents.rs
+++ b/src/test/ui/borrowck/issue-55492-borrowck-migrate-scans-parents.rs
@@ -3,15 +3,13 @@
// looks at some parent.
// revisions: migrate nll
+//[nll]compile-flags: -Z borrowck=mir
// Since we are testing nll (and migration) explicitly as a separate
// revisions, don't worry about the --compare-mode=nll on this test.
// ignore-compare-mode-nll
-//[nll]compile-flags: -Z borrowck=mir
-
-
// transcribed from borrowck-closures-unique.rs
mod borrowck_closures_unique {
pub fn e(x: &'static mut isize) {
diff --git a/src/test/ui/borrowck/issue-58776-borrowck-scans-children.migrate.stderr b/src/test/ui/borrowck/issue-58776-borrowck-scans-children.migrate.stderr
deleted file mode 100644
index efd4e1a1716..00000000000
--- a/src/test/ui/borrowck/issue-58776-borrowck-scans-children.migrate.stderr
+++ /dev/null
@@ -1,32 +0,0 @@
-error[E0506]: cannot assign to `greeting` because it is borrowed
- --> $DIR/issue-58776-borrowck-scans-children.rs:11:5
- |
-LL | let res = (|| (|| &greeting)())();
- | -- -------- borrow occurs due to use in closure
- | |
- | borrow of `greeting` occurs here
-LL |
-LL | greeting = "DEALLOCATED".to_string();
- | ^^^^^^^^ assignment to borrowed `greeting` occurs here
-...
-LL | println!("thread result: {:?}", res);
- | --- borrow later used here
-
-error[E0505]: cannot move out of `greeting` because it is borrowed
- --> $DIR/issue-58776-borrowck-scans-children.rs:14:10
- |
-LL | let res = (|| (|| &greeting)())();
- | -- -------- borrow occurs due to use in closure
- | |
- | borrow of `greeting` occurs here
-...
-LL | drop(greeting);
- | ^^^^^^^^ move out of `greeting` occurs here
-...
-LL | println!("thread result: {:?}", res);
- | --- borrow later used here
-
-error: aborting due to 2 previous errors
-
-Some errors have detailed explanations: E0505, E0506.
-For more information about an error, try `rustc --explain E0505`.
diff --git a/src/test/ui/borrowck/issue-91206.rs b/src/test/ui/borrowck/issue-91206.rs
new file mode 100644
index 00000000000..3b1fbf4b699
--- /dev/null
+++ b/src/test/ui/borrowck/issue-91206.rs
@@ -0,0 +1,15 @@
+struct TestClient;
+
+impl TestClient {
+ fn get_inner_ref(&self) -> &Vec<usize> {
+ todo!()
+ }
+}
+
+fn main() {
+ let client = TestClient;
+ let inner = client.get_inner_ref();
+ //~^ HELP consider changing this to be a mutable reference
+ inner.clear();
+ //~^ ERROR cannot borrow `*inner` as mutable, as it is behind a `&` reference [E0596]
+}
diff --git a/src/test/ui/borrowck/issue-91206.stderr b/src/test/ui/borrowck/issue-91206.stderr
new file mode 100644
index 00000000000..535d247452a
--- /dev/null
+++ b/src/test/ui/borrowck/issue-91206.stderr
@@ -0,0 +1,12 @@
+error[E0596]: cannot borrow `*inner` as mutable, as it is behind a `&` reference
+ --> $DIR/issue-91206.rs:13:5
+ |
+LL | let inner = client.get_inner_ref();
+ | ----- help: consider changing this to be a mutable reference: `&mut Vec<usize>`
+LL |
+LL | inner.clear();
+ | ^^^^^^^^^^^^^ `inner` is a `&` reference, so the data it refers to cannot be borrowed as mutable
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0596`.
diff --git a/src/test/ui/borrowck/suggest-local-var-double-mut.rs b/src/test/ui/borrowck/suggest-local-var-double-mut.rs
new file mode 100644
index 00000000000..d5996ba68be
--- /dev/null
+++ b/src/test/ui/borrowck/suggest-local-var-double-mut.rs
@@ -0,0 +1,27 @@
+// See issue #77834.
+
+#![crate_type = "lib"]
+
+mod method_syntax {
+ struct Foo;
+
+ impl Foo {
+ fn foo(&mut self, _: f32) -> i32 { todo!() }
+ fn bar(&mut self) -> f32 { todo!() }
+ fn baz(&mut self) {
+ self.foo(self.bar()); //~ ERROR
+ }
+ }
+}
+
+mod fully_qualified_syntax {
+ struct Foo;
+
+ impl Foo {
+ fn foo(&mut self, _: f32) -> i32 { todo!() }
+ fn bar(&mut self) -> f32 { todo!() }
+ fn baz(&mut self) {
+ Self::foo(self, Self::bar(self)); //~ ERROR
+ }
+ }
+}
diff --git a/src/test/ui/borrowck/suggest-local-var-double-mut.stderr b/src/test/ui/borrowck/suggest-local-var-double-mut.stderr
new file mode 100644
index 00000000000..3a43c18a7ed
--- /dev/null
+++ b/src/test/ui/borrowck/suggest-local-var-double-mut.stderr
@@ -0,0 +1,44 @@
+error[E0499]: cannot borrow `*self` as mutable more than once at a time
+ --> $DIR/suggest-local-var-double-mut.rs:12:22
+ |
+LL | self.foo(self.bar());
+ | ---------^^^^^^^^^^-
+ | | | |
+ | | | second mutable borrow occurs here
+ | | first borrow later used by call
+ | first mutable borrow occurs here
+ |
+help: try adding a local storing this argument...
+ --> $DIR/suggest-local-var-double-mut.rs:12:22
+ |
+LL | self.foo(self.bar());
+ | ^^^^^^^^^^
+help: ...and then using that local as the argument to this call
+ --> $DIR/suggest-local-var-double-mut.rs:12:13
+ |
+LL | self.foo(self.bar());
+ | ^^^^^^^^^^^^^^^^^^^^
+
+error[E0499]: cannot borrow `*self` as mutable more than once at a time
+ --> $DIR/suggest-local-var-double-mut.rs:24:39
+ |
+LL | Self::foo(self, Self::bar(self));
+ | --------- ---- ^^^^ second mutable borrow occurs here
+ | | |
+ | | first mutable borrow occurs here
+ | first borrow later used by call
+ |
+help: try adding a local storing this argument...
+ --> $DIR/suggest-local-var-double-mut.rs:24:29
+ |
+LL | Self::foo(self, Self::bar(self));
+ | ^^^^^^^^^^^^^^^
+help: ...and then using that local as the argument to this call
+ --> $DIR/suggest-local-var-double-mut.rs:24:13
+ |
+LL | Self::foo(self, Self::bar(self));
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: aborting due to 2 previous errors
+
+For more information about this error, try `rustc --explain E0499`.
diff --git a/src/test/ui/borrowck/suggest-local-var-imm-and-mut.nll.stderr b/src/test/ui/borrowck/suggest-local-var-imm-and-mut.nll.stderr
new file mode 100644
index 00000000000..2ba0b6b28aa
--- /dev/null
+++ b/src/test/ui/borrowck/suggest-local-var-imm-and-mut.nll.stderr
@@ -0,0 +1,33 @@
+error[E0502]: cannot borrow `*self` as mutable because it is also borrowed as immutable
+ --> $DIR/suggest-local-var-imm-and-mut.rs:12:22
+ |
+LL | self.foo(self.bar());
+ | ---------^^^^^^^^^^-
+ | | | |
+ | | | mutable borrow occurs here
+ | | immutable borrow later used by call
+ | immutable borrow occurs here
+ |
+help: try adding a local storing this argument...
+ --> $DIR/suggest-local-var-imm-and-mut.rs:12:22
+ |
+LL | self.foo(self.bar());
+ | ^^^^^^^^^^
+help: ...and then using that local as the argument to this call
+ --> $DIR/suggest-local-var-imm-and-mut.rs:12:13
+ |
+LL | self.foo(self.bar());
+ | ^^^^^^^^^^^^^^^^^^^^
+
+error[E0502]: cannot borrow `*self` as mutable because it is also borrowed as immutable
+ --> $DIR/suggest-local-var-imm-and-mut.rs:24:39
+ |
+LL | Self::foo(self, Self::bar(self));
+ | --------- ---- ^^^^ mutable borrow occurs here
+ | | |
+ | | immutable borrow occurs here
+ | immutable borrow later used by call
+
+error: aborting due to 2 previous errors
+
+For more information about this error, try `rustc --explain E0502`.
diff --git a/src/test/ui/borrowck/suggest-local-var-imm-and-mut.rs b/src/test/ui/borrowck/suggest-local-var-imm-and-mut.rs
new file mode 100644
index 00000000000..bf167ba79f3
--- /dev/null
+++ b/src/test/ui/borrowck/suggest-local-var-imm-and-mut.rs
@@ -0,0 +1,27 @@
+// See issue #77834.
+
+#![crate_type = "lib"]
+
+mod method_syntax {
+ struct Foo;
+
+ impl Foo {
+ fn foo(&self, _: f32) -> i32 { todo!() }
+ fn bar(&mut self) -> f32 { todo!() }
+ fn baz(&mut self) {
+ self.foo(self.bar()); //~ ERROR
+ }
+ }
+}
+
+mod fully_qualified_syntax {
+ struct Foo;
+
+ impl Foo {
+ fn foo(&self, _: f32) -> i32 { todo!() }
+ fn bar(&mut self) -> f32 { todo!() }
+ fn baz(&mut self) {
+ Self::foo(self, Self::bar(self)); //~ ERROR
+ }
+ }
+}
diff --git a/src/test/ui/borrowck/suggest-local-var-imm-and-mut.stderr b/src/test/ui/borrowck/suggest-local-var-imm-and-mut.stderr
new file mode 100644
index 00000000000..eb934e7b72b
--- /dev/null
+++ b/src/test/ui/borrowck/suggest-local-var-imm-and-mut.stderr
@@ -0,0 +1,22 @@
+error[E0502]: cannot borrow `*self` as mutable because it is also borrowed as immutable
+ --> $DIR/suggest-local-var-imm-and-mut.rs:12:22
+ |
+LL | self.foo(self.bar());
+ | ---------^^^^^^^^^^-
+ | | | |
+ | | | mutable borrow occurs here
+ | | immutable borrow later used by call
+ | immutable borrow occurs here
+
+error[E0502]: cannot borrow `*self` as mutable because it is also borrowed as immutable
+ --> $DIR/suggest-local-var-imm-and-mut.rs:24:29
+ |
+LL | Self::foo(self, Self::bar(self));
+ | --------- ---- ^^^^^^^^^^^^^^^ mutable borrow occurs here
+ | | |
+ | | immutable borrow occurs here
+ | immutable borrow later used by call
+
+error: aborting due to 2 previous errors
+
+For more information about this error, try `rustc --explain E0502`.
diff --git a/src/test/ui/borrowck/two-phase-cannot-nest-mut-self-calls.stderr b/src/test/ui/borrowck/two-phase-cannot-nest-mut-self-calls.stderr
index a89bb941532..85c7159952f 100644
--- a/src/test/ui/borrowck/two-phase-cannot-nest-mut-self-calls.stderr
+++ b/src/test/ui/borrowck/two-phase-cannot-nest-mut-self-calls.stderr
@@ -13,6 +13,23 @@ LL | |
LL | | 0
LL | | });
| |______- immutable borrow occurs here
+ |
+help: try adding a local storing this argument...
+ --> $DIR/two-phase-cannot-nest-mut-self-calls.rs:16:9
+ |
+LL | vec.push(2);
+ | ^^^^^^^^^^^
+help: ...and then using that local as the argument to this call
+ --> $DIR/two-phase-cannot-nest-mut-self-calls.rs:14:5
+ |
+LL | / vec.get({
+LL | |
+LL | | vec.push(2);
+LL | |
+LL | |
+LL | | 0
+LL | | });
+ | |______^
error: aborting due to previous error
diff --git a/src/test/ui/builtin-clone-unwind.rs b/src/test/ui/builtin-clone-unwind.rs
index 2caedb649a3..3623c4a4dd0 100644
--- a/src/test/ui/builtin-clone-unwind.rs
+++ b/src/test/ui/builtin-clone-unwind.rs
@@ -1,4 +1,5 @@
// run-pass
+// needs-unwind
#![allow(unused_variables)]
#![allow(unused_imports)]
diff --git a/src/test/ui/cast/cast-int-to-char.rs b/src/test/ui/cast/cast-int-to-char.rs
new file mode 100644
index 00000000000..379956968bd
--- /dev/null
+++ b/src/test/ui/cast/cast-int-to-char.rs
@@ -0,0 +1,9 @@
+fn foo<T>(_t: T) {}
+
+fn main() {
+ foo::<u32>('0'); //~ ERROR
+ foo::<i32>('0'); //~ ERROR
+ foo::<u64>('0'); //~ ERROR
+ foo::<i64>('0'); //~ ERROR
+ foo::<char>(0u32); //~ ERROR
+}
diff --git a/src/test/ui/cast/cast-int-to-char.stderr b/src/test/ui/cast/cast-int-to-char.stderr
new file mode 100644
index 00000000000..55b9462db8d
--- /dev/null
+++ b/src/test/ui/cast/cast-int-to-char.stderr
@@ -0,0 +1,53 @@
+error[E0308]: mismatched types
+ --> $DIR/cast-int-to-char.rs:4:16
+ |
+LL | foo::<u32>('0');
+ | ^^^ expected `u32`, found `char`
+ |
+help: you can cast a `char` to a `u32`, since a `char` always occupies 4 bytes
+ |
+LL | foo::<u32>('0' as u32);
+ | ++++++
+
+error[E0308]: mismatched types
+ --> $DIR/cast-int-to-char.rs:5:16
+ |
+LL | foo::<i32>('0');
+ | ^^^ expected `i32`, found `char`
+ |
+help: you can cast a `char` to an `i32`, since a `char` always occupies 4 bytes
+ |
+LL | foo::<i32>('0' as i32);
+ | ++++++
+
+error[E0308]: mismatched types
+ --> $DIR/cast-int-to-char.rs:6:16
+ |
+LL | foo::<u64>('0');
+ | ^^^ expected `u64`, found `char`
+ |
+help: you can cast a `char` to a `u64`, since a `char` always occupies 4 bytes
+ |
+LL | foo::<u64>('0' as u64);
+ | ++++++
+
+error[E0308]: mismatched types
+ --> $DIR/cast-int-to-char.rs:7:16
+ |
+LL | foo::<i64>('0');
+ | ^^^ expected `i64`, found `char`
+ |
+help: you can cast a `char` to an `i64`, since a `char` always occupies 4 bytes
+ |
+LL | foo::<i64>('0' as i64);
+ | ++++++
+
+error[E0308]: mismatched types
+ --> $DIR/cast-int-to-char.rs:8:17
+ |
+LL | foo::<char>(0u32);
+ | ^^^^ expected `char`, found `u32`
+
+error: aborting due to 5 previous errors
+
+For more information about this error, try `rustc --explain E0308`.
diff --git a/src/test/ui/cast/issue-88621.rs b/src/test/ui/cast/issue-88621.rs
new file mode 100644
index 00000000000..9242b80e229
--- /dev/null
+++ b/src/test/ui/cast/issue-88621.rs
@@ -0,0 +1,13 @@
+#![feature(arbitrary_enum_discriminant)]
+
+#[repr(u8)]
+enum Kind2 {
+ Foo() = 1,
+ Bar{} = 2,
+ Baz = 3,
+}
+
+fn main() {
+ let _ = Kind2::Foo() as u8;
+ //~^ ERROR non-primitive cast
+}
diff --git a/src/test/ui/cast/issue-88621.stderr b/src/test/ui/cast/issue-88621.stderr
new file mode 100644
index 00000000000..e96d8665152
--- /dev/null
+++ b/src/test/ui/cast/issue-88621.stderr
@@ -0,0 +1,9 @@
+error[E0605]: non-primitive cast: `Kind2` as `u8`
+ --> $DIR/issue-88621.rs:11:13
+ |
+LL | let _ = Kind2::Foo() as u8;
+ | ^^^^^^^^^^^^^^^^^^ an `as` expression can only be used to convert between primitive types or to coerce to a specific trait object
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0605`.
diff --git a/src/test/ui/catch-unwind-bang.rs b/src/test/ui/catch-unwind-bang.rs
index f181991713b..b31b5cab5b7 100644
--- a/src/test/ui/catch-unwind-bang.rs
+++ b/src/test/ui/catch-unwind-bang.rs
@@ -1,4 +1,5 @@
// run-pass
+// needs-unwind
// ignore-wasm32-bare compiled with panic=abort by default
fn worker() -> ! {
diff --git a/src/test/ui/cfg/auxiliary/crate-attributes-using-cfg_attr.rs b/src/test/ui/cfg/auxiliary/crate-attributes-using-cfg_attr.rs
deleted file mode 100644
index 1e0f5d79c0b..00000000000
--- a/src/test/ui/cfg/auxiliary/crate-attributes-using-cfg_attr.rs
+++ /dev/null
@@ -1,6 +0,0 @@
-// no-prefer-dynamic
-// compile-flags: --cfg foo
-
-#![cfg_attr(foo, crate_type="lib")]
-
-pub fn foo() {}
diff --git a/src/test/ui/cfg/crate-attributes-using-cfg_attr.rs b/src/test/ui/cfg/crate-attributes-using-cfg_attr.rs
deleted file mode 100644
index 43b266b778f..00000000000
--- a/src/test/ui/cfg/crate-attributes-using-cfg_attr.rs
+++ /dev/null
@@ -1,6 +0,0 @@
-// run-pass
-// aux-build:crate-attributes-using-cfg_attr.rs
-
-extern crate crate_attributes_using_cfg_attr;
-
-pub fn main() {}
diff --git a/src/test/ui/cfg/future-compat-crate-attributes-using-cfg_attr.rs b/src/test/ui/cfg/future-compat-crate-attributes-using-cfg_attr.rs
new file mode 100644
index 00000000000..ef12b05fab2
--- /dev/null
+++ b/src/test/ui/cfg/future-compat-crate-attributes-using-cfg_attr.rs
@@ -0,0 +1,12 @@
+// check-fail
+// compile-flags:--cfg foo
+
+#![deny(warnings)]
+#![cfg_attr(foo, crate_type="bin")]
+//~^ERROR `crate_type` within
+//~| WARN this was previously accepted
+#![cfg_attr(foo, crate_name="bar")]
+//~^ERROR `crate_name` within
+//~| WARN this was previously accepted
+
+fn main() {}
diff --git a/src/test/ui/cfg/future-compat-crate-attributes-using-cfg_attr.stderr b/src/test/ui/cfg/future-compat-crate-attributes-using-cfg_attr.stderr
new file mode 100644
index 00000000000..5df2eacc96e
--- /dev/null
+++ b/src/test/ui/cfg/future-compat-crate-attributes-using-cfg_attr.stderr
@@ -0,0 +1,26 @@
+error: `crate_type` within an `#![cfg_attr] attribute is deprecated`
+ --> $DIR/future-compat-crate-attributes-using-cfg_attr.rs:5:18
+ |
+LL | #![cfg_attr(foo, crate_type="bin")]
+ | ^^^^^^^^^^^^^^^^
+ |
+note: the lint level is defined here
+ --> $DIR/future-compat-crate-attributes-using-cfg_attr.rs:4:9
+ |
+LL | #![deny(warnings)]
+ | ^^^^^^^^
+ = note: `#[deny(deprecated_cfg_attr_crate_type_name)]` implied by `#[deny(warnings)]`
+ = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
+ = note: for more information, see issue #91632 <https://github.com/rust-lang/rust/issues/91632>
+
+error: `crate_name` within an `#![cfg_attr] attribute is deprecated`
+ --> $DIR/future-compat-crate-attributes-using-cfg_attr.rs:8:18
+ |
+LL | #![cfg_attr(foo, crate_name="bar")]
+ | ^^^^^^^^^^^^^^^^
+ |
+ = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
+ = note: for more information, see issue #91632 <https://github.com/rust-lang/rust/issues/91632>
+
+error: aborting due to 2 previous errors
+
diff --git a/src/test/ui/chalkify/impl_wf_2.stderr b/src/test/ui/chalkify/impl_wf_2.stderr
index 0aac962fdba..80ec03d6221 100644
--- a/src/test/ui/chalkify/impl_wf_2.stderr
+++ b/src/test/ui/chalkify/impl_wf_2.stderr
@@ -1,8 +1,8 @@
error[E0277]: the trait bound `f32: Foo` is not satisfied
- --> $DIR/impl_wf_2.rs:25:5
+ --> $DIR/impl_wf_2.rs:25:17
|
LL | type Item = f32;
- | ^^^^^^^^^^^^^^^^ the trait `Foo` is not implemented for `f32`
+ | ^^^ the trait `Foo` is not implemented for `f32`
|
note: required by a bound in `Bar::Item`
--> $DIR/impl_wf_2.rs:8:16
diff --git a/src/test/ui/cleanup-rvalue-temp-during-incomplete-alloc.rs b/src/test/ui/cleanup-rvalue-temp-during-incomplete-alloc.rs
index eadbe44a8e9..6cd3781b760 100644
--- a/src/test/ui/cleanup-rvalue-temp-during-incomplete-alloc.rs
+++ b/src/test/ui/cleanup-rvalue-temp-during-incomplete-alloc.rs
@@ -1,4 +1,5 @@
// run-pass
+// needs-unwind
#![allow(unused_must_use)]
#![allow(dead_code)]
diff --git a/src/test/ui/closures/2229_closure_analysis/diagnostics/arrays.stderr b/src/test/ui/closures/2229_closure_analysis/diagnostics/arrays.stderr
index a3f2f25e447..f6c21901832 100644
--- a/src/test/ui/closures/2229_closure_analysis/diagnostics/arrays.stderr
+++ b/src/test/ui/closures/2229_closure_analysis/diagnostics/arrays.stderr
@@ -81,6 +81,8 @@ LL | println!("{}", arr[3]);
...
LL | c();
| - mutable borrow later used here
+ |
+ = note: this error originates in the macro `$crate::format_args_nl` (in Nightly builds, run with -Z macro-backtrace for more info)
error[E0502]: cannot borrow `arr` as immutable because it is also borrowed as mutable
--> $DIR/arrays.rs:73:24
diff --git a/src/test/ui/closures/2229_closure_analysis/diagnostics/box.stderr b/src/test/ui/closures/2229_closure_analysis/diagnostics/box.stderr
index 2badf051418..29228d85324 100644
--- a/src/test/ui/closures/2229_closure_analysis/diagnostics/box.stderr
+++ b/src/test/ui/closures/2229_closure_analysis/diagnostics/box.stderr
@@ -25,6 +25,8 @@ LL | println!("{}", e.0.0.m.x);
LL |
LL | c();
| - mutable borrow later used here
+ |
+ = note: this error originates in the macro `$crate::format_args_nl` (in Nightly builds, run with -Z macro-backtrace for more info)
error[E0506]: cannot assign to `e.0.0.m.x` because it is borrowed
--> $DIR/box.rs:55:5
diff --git a/src/test/ui/closures/2229_closure_analysis/diagnostics/repr_packed.stderr b/src/test/ui/closures/2229_closure_analysis/diagnostics/repr_packed.stderr
index d2466681a08..fc0179d2cb4 100644
--- a/src/test/ui/closures/2229_closure_analysis/diagnostics/repr_packed.stderr
+++ b/src/test/ui/closures/2229_closure_analysis/diagnostics/repr_packed.stderr
@@ -8,6 +8,8 @@ LL | println!("{}", foo.x);
= warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
= note: for more information, see issue #82523 <https://github.com/rust-lang/rust/issues/82523>
= note: fields of packed structs are not properly aligned, and creating a misaligned reference is undefined behavior (even if that reference is never dereferenced)
+ = help: copy the field contents to a local variable, or replace the reference with a raw pointer and use `read_unaligned`/`write_unaligned` (loads and stores via `*p` must be properly aligned even when using raw pointers)
+ = note: this warning originates in the macro `$crate::format_args_nl` (in Nightly builds, run with -Z macro-backtrace for more info)
warning: 1 warning emitted
diff --git a/src/test/ui/closures/2229_closure_analysis/diagnostics/simple-struct-min-capture.stderr b/src/test/ui/closures/2229_closure_analysis/diagnostics/simple-struct-min-capture.stderr
index 32705af3d01..4f9fdbd368a 100644
--- a/src/test/ui/closures/2229_closure_analysis/diagnostics/simple-struct-min-capture.stderr
+++ b/src/test/ui/closures/2229_closure_analysis/diagnostics/simple-struct-min-capture.stderr
@@ -13,6 +13,8 @@ LL | println!("{:?}", p);
LL |
LL | c();
| - mutable borrow later used here
+ |
+ = note: this error originates in the macro `$crate::format_args_nl` (in Nightly builds, run with -Z macro-backtrace for more info)
error: aborting due to previous error
diff --git a/src/test/ui/closures/2229_closure_analysis/migrations/mir_calls_to_shims.fixed b/src/test/ui/closures/2229_closure_analysis/migrations/mir_calls_to_shims.fixed
index 7df0dd76b44..89f3931418d 100644
--- a/src/test/ui/closures/2229_closure_analysis/migrations/mir_calls_to_shims.fixed
+++ b/src/test/ui/closures/2229_closure_analysis/migrations/mir_calls_to_shims.fixed
@@ -1,4 +1,5 @@
// run-rustfix
+// needs-unwind
#![deny(rust_2021_incompatible_closure_captures)]
//~^ NOTE: the lint level is defined here
diff --git a/src/test/ui/closures/2229_closure_analysis/migrations/mir_calls_to_shims.rs b/src/test/ui/closures/2229_closure_analysis/migrations/mir_calls_to_shims.rs
index d02fac7c669..6b0b1052174 100644
--- a/src/test/ui/closures/2229_closure_analysis/migrations/mir_calls_to_shims.rs
+++ b/src/test/ui/closures/2229_closure_analysis/migrations/mir_calls_to_shims.rs
@@ -1,4 +1,5 @@
// run-rustfix
+// needs-unwind
#![deny(rust_2021_incompatible_closure_captures)]
//~^ NOTE: the lint level is defined here
diff --git a/src/test/ui/closures/2229_closure_analysis/migrations/mir_calls_to_shims.stderr b/src/test/ui/closures/2229_closure_analysis/migrations/mir_calls_to_shims.stderr
index 74f85b6ebaa..6594ec31653 100644
--- a/src/test/ui/closures/2229_closure_analysis/migrations/mir_calls_to_shims.stderr
+++ b/src/test/ui/closures/2229_closure_analysis/migrations/mir_calls_to_shims.stderr
@@ -1,5 +1,5 @@
error: changes to closure capture in Rust 2021 will affect which traits the closure implements
- --> $DIR/mir_calls_to_shims.rs:20:38
+ --> $DIR/mir_calls_to_shims.rs:21:38
|
LL | let result = panic::catch_unwind(move || {
| ^^^^^^^
@@ -11,7 +11,7 @@ LL | f.0()
| --- in Rust 2018, this closure captures all of `f`, but in Rust 2021, it will only capture `f.0`
|
note: the lint level is defined here
- --> $DIR/mir_calls_to_shims.rs:3:9
+ --> $DIR/mir_calls_to_shims.rs:4:9
|
LL | #![deny(rust_2021_incompatible_closure_captures)]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
diff --git a/src/test/ui/closures/closure-bounds-static-cant-capture-borrowed.stderr b/src/test/ui/closures/closure-bounds-static-cant-capture-borrowed.stderr
index d761abdfc6a..af1f908a808 100644
--- a/src/test/ui/closures/closure-bounds-static-cant-capture-borrowed.stderr
+++ b/src/test/ui/closures/closure-bounds-static-cant-capture-borrowed.stderr
@@ -8,13 +8,18 @@ LL | bar(|| {
LL | |
LL | | let _ = x;
LL | | })
- | |_____^ ...is captured here...
+ | |_____^ ...is used here...
|
note: ...and is required to live as long as `'static` here
--> $DIR/closure-bounds-static-cant-capture-borrowed.rs:5:5
|
LL | bar(|| {
| ^^^
+note: `'static` lifetime requirement introduced by this bound
+ --> $DIR/closure-bounds-static-cant-capture-borrowed.rs:1:39
+ |
+LL | fn bar<F>(blk: F) where F: FnOnce() + 'static {
+ | ^^^^^^^
error: aborting due to previous error
diff --git a/src/test/ui/closures/closure-expected.stderr b/src/test/ui/closures/closure-expected.stderr
index 8b38d5ff459..7ffe3c1ef95 100644
--- a/src/test/ui/closures/closure-expected.stderr
+++ b/src/test/ui/closures/closure-expected.stderr
@@ -11,8 +11,8 @@ LL | let y = x.or_else(4);
note: required by a bound in `Option::<T>::or_else`
--> $SRC_DIR/core/src/option.rs:LL:COL
|
-LL | pub fn or_else<F: FnOnce() -> Option<T>>(self, f: F) -> Option<T> {
- | ^^^^^^^^^^^^^^^^^^^^^ required by this bound in `Option::<T>::or_else`
+LL | F: ~const FnOnce() -> Option<T>,
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `Option::<T>::or_else`
error: aborting due to previous error
diff --git a/src/test/ui/closures/coerce-unsafe-to-closure.stderr b/src/test/ui/closures/coerce-unsafe-to-closure.stderr
index 24db2725347..883348eb98c 100644
--- a/src/test/ui/closures/coerce-unsafe-to-closure.stderr
+++ b/src/test/ui/closures/coerce-unsafe-to-closure.stderr
@@ -10,8 +10,8 @@ LL | let x: Option<&[u8]> = Some("foo").map(std::mem::transmute);
note: required by a bound in `Option::<T>::map`
--> $SRC_DIR/core/src/option.rs:LL:COL
|
-LL | pub fn map<U, F: FnOnce(T) -> U>(self, f: F) -> Option<U> {
- | ^^^^^^^^^^^^^^ required by this bound in `Option::<T>::map`
+LL | F: ~const FnOnce(T) -> U,
+ | ^^^^^^^^^^^^^^^^^^^^^ required by this bound in `Option::<T>::map`
error: aborting due to previous error
diff --git a/src/test/ui/codemap_tests/one_line.stderr b/src/test/ui/codemap_tests/one_line.stderr
index 1ee612184de..6fe6e26135b 100644
--- a/src/test/ui/codemap_tests/one_line.stderr
+++ b/src/test/ui/codemap_tests/one_line.stderr
@@ -7,6 +7,17 @@ LL | v.push(v.pop().unwrap());
| | | second mutable borrow occurs here
| | first borrow later used by call
| first mutable borrow occurs here
+ |
+help: try adding a local storing this argument...
+ --> $DIR/one_line.rs:3:12
+ |
+LL | v.push(v.pop().unwrap());
+ | ^^^^^^^
+help: ...and then using that local as the argument to this call
+ --> $DIR/one_line.rs:3:5
+ |
+LL | v.push(v.pop().unwrap());
+ | ^^^^^^^^^^^^^^^^^^^^^^^^
error: aborting due to previous error
diff --git a/src/test/ui/codemap_tests/tab_3.stderr b/src/test/ui/codemap_tests/tab_3.stderr
index e067dbbf85b..ceb91142ac8 100644
--- a/src/test/ui/codemap_tests/tab_3.stderr
+++ b/src/test/ui/codemap_tests/tab_3.stderr
@@ -14,6 +14,7 @@ note: this function takes ownership of the receiver `self`, which moves `some_ve
|
LL | fn into_iter(self) -> Self::IntoIter;
| ^^^^
+ = note: this error originates in the macro `$crate::format_args_nl` (in Nightly builds, run with -Z macro-backtrace for more info)
error: aborting due to previous error
diff --git a/src/test/ui/coherence/coherence-orphan.stderr b/src/test/ui/coherence/coherence-orphan.stderr
index 051a519ee14..52d2cc88cbe 100644
--- a/src/test/ui/coherence/coherence-orphan.stderr
+++ b/src/test/ui/coherence/coherence-orphan.stderr
@@ -1,15 +1,4 @@
error[E0117]: only traits defined in the current crate can be implemented for arbitrary types
- --> $DIR/coherence-orphan.rs:17:1
- |
-LL | impl !Send for Vec<isize> { }
- | ^^^^^^^^^^^^^^^----------
- | | |
- | | `Vec` is not defined in the current crate
- | impl doesn't use only types from inside the current crate
- |
- = note: define and implement a trait or new type instead
-
-error[E0117]: only traits defined in the current crate can be implemented for arbitrary types
--> $DIR/coherence-orphan.rs:10:1
|
LL | impl TheTrait<usize> for isize { }
@@ -21,6 +10,17 @@ LL | impl TheTrait<usize> for isize { }
|
= note: define and implement a trait or new type instead
+error[E0117]: only traits defined in the current crate can be implemented for arbitrary types
+ --> $DIR/coherence-orphan.rs:17:1
+ |
+LL | impl !Send for Vec<isize> { }
+ | ^^^^^^^^^^^^^^^----------
+ | | |
+ | | `Vec` is not defined in the current crate
+ | impl doesn't use only types from inside the current crate
+ |
+ = note: define and implement a trait or new type instead
+
error: aborting due to 2 previous errors
For more information about this error, try `rustc --explain E0117`.
diff --git a/src/test/ui/compare-method/bad-self-type.stderr b/src/test/ui/compare-method/bad-self-type.stderr
index 737a5ae2656..90e907157a5 100644
--- a/src/test/ui/compare-method/bad-self-type.stderr
+++ b/src/test/ui/compare-method/bad-self-type.stderr
@@ -13,27 +13,31 @@ LL | fn poll(self, _: &mut Context<'_>) -> Poll<()> {
error[E0053]: method `foo` has an incompatible type for trait
--> $DIR/bad-self-type.rs:22:18
|
-LL | fn foo(self);
- | ---- type in trait
-...
LL | fn foo(self: Box<Self>) {}
| ------^^^^^^^^^
| | |
| | expected struct `MyFuture`, found struct `Box`
| help: change the self-receiver type to match the trait: `self`
|
+note: type in trait
+ --> $DIR/bad-self-type.rs:17:12
+ |
+LL | fn foo(self);
+ | ^^^^
= note: expected fn pointer `fn(MyFuture)`
found fn pointer `fn(Box<MyFuture>)`
error[E0053]: method `bar` has an incompatible type for trait
--> $DIR/bad-self-type.rs:24:18
|
-LL | fn bar(self) -> Option<()>;
- | ---------- type in trait
-...
LL | fn bar(self) {}
| ^ expected enum `Option`, found `()`
|
+note: type in trait
+ --> $DIR/bad-self-type.rs:18:21
+ |
+LL | fn bar(self) -> Option<()>;
+ | ^^^^^^^^^^
= note: expected fn pointer `fn(MyFuture) -> Option<()>`
found fn pointer `fn(MyFuture)`
help: change the output type to match the trait
diff --git a/src/test/ui/compare-method/reordered-type-param.stderr b/src/test/ui/compare-method/reordered-type-param.stderr
index d581628ea48..49b5b1b92cd 100644
--- a/src/test/ui/compare-method/reordered-type-param.stderr
+++ b/src/test/ui/compare-method/reordered-type-param.stderr
@@ -1,9 +1,6 @@
error[E0053]: method `b` has an incompatible type for trait
--> $DIR/reordered-type-param.rs:16:30
|
-LL | fn b<C:Clone,D>(&self, x: C) -> C;
- | - type in trait
-...
LL | fn b<F:Clone,G>(&self, _x: G) -> G { panic!() }
| - - ^
| | | |
@@ -12,6 +9,11 @@ LL | fn b<F:Clone,G>(&self, _x: G) -> G { panic!() }
| | found type parameter
| expected type parameter
|
+note: type in trait
+ --> $DIR/reordered-type-param.rs:7:29
+ |
+LL | fn b<C:Clone,D>(&self, x: C) -> C;
+ | ^
= note: expected fn pointer `fn(&E, F) -> F`
found fn pointer `fn(&E, G) -> G`
= note: a type parameter was expected, but a different one was found; you might be missing a type parameter or trait bound
diff --git a/src/test/ui/const-generics/argument_order.min.stderr b/src/test/ui/const-generics/argument_order.min.stderr
deleted file mode 100644
index afd9ed1a723..00000000000
--- a/src/test/ui/const-generics/argument_order.min.stderr
+++ /dev/null
@@ -1,30 +0,0 @@
-error: type parameters must be declared prior to const parameters
- --> $DIR/argument_order.rs:4:28
- |
-LL | struct Bad<const N: usize, T> {
- | -----------------^- help: reorder the parameters: lifetimes, then types, then consts: `<T, const N: usize>`
-
-error: lifetime parameters must be declared prior to const parameters
- --> $DIR/argument_order.rs:10:32
- |
-LL | struct AlsoBad<const N: usize, 'a, T, 'b, const M: usize, U> {
- | -----------------^^-----^^-------------------- help: reorder the parameters: lifetimes, then types, then consts: `<'a, 'b, T, U, const N: usize, const M: usize>`
-
-error: type parameters must be declared prior to const parameters
- --> $DIR/argument_order.rs:10:36
- |
-LL | struct AlsoBad<const N: usize, 'a, T, 'b, const M: usize, U> {
- | ---------------------^----------------------^- help: reorder the parameters: lifetimes, then types, then consts: `<'a, 'b, T, U, const N: usize, const M: usize>`
-
-error[E0747]: lifetime provided when a type was expected
- --> $DIR/argument_order.rs:18:23
- |
-LL | let _: AlsoBad<7, 'static, u32, 'static, 17, u16>;
- | ^^^^^^^
- |
- = note: lifetime arguments must be provided before type arguments
- = help: reorder the arguments: lifetimes, then types, then consts: `<'a, 'b, T, U, N, M>`
-
-error: aborting due to 4 previous errors
-
-For more information about this error, try `rustc --explain E0747`.
diff --git a/src/test/ui/const-generics/argument_order.rs b/src/test/ui/const-generics/argument_order.rs
index 97dd0f14352..196d9b8a1e2 100644
--- a/src/test/ui/const-generics/argument_order.rs
+++ b/src/test/ui/const-generics/argument_order.rs
@@ -1,15 +1,10 @@
-// revisions: full min
-#![cfg_attr(full, feature(const_generics_defaults))]
-
struct Bad<const N: usize, T> {
- //[min]~^ ERROR type parameters must be declared prior to const parameters
arr: [u8; { N }],
another: T,
}
struct AlsoBad<const N: usize, 'a, T, 'b, const M: usize, U> {
//~^ ERROR lifetime parameters must be declared prior
- //[min]~^^ ERROR type parameters must be declared prior to const parameters
a: &'a T,
b: &'b U,
}
diff --git a/src/test/ui/const-generics/argument_order.full.stderr b/src/test/ui/const-generics/argument_order.stderr
index 9762748f441..6b33dffb434 100644
--- a/src/test/ui/const-generics/argument_order.full.stderr
+++ b/src/test/ui/const-generics/argument_order.stderr
@@ -1,11 +1,11 @@
error: lifetime parameters must be declared prior to const parameters
- --> $DIR/argument_order.rs:10:32
+ --> $DIR/argument_order.rs:6:32
|
LL | struct AlsoBad<const N: usize, 'a, T, 'b, const M: usize, U> {
| -----------------^^-----^^-------------------- help: reorder the parameters: lifetimes, then consts and types: `<'a, 'b, const N: usize, T, const M: usize, U>`
error[E0747]: lifetime provided when a type was expected
- --> $DIR/argument_order.rs:18:23
+ --> $DIR/argument_order.rs:13:23
|
LL | let _: AlsoBad<7, 'static, u32, 'static, 17, u16>;
| ^^^^^^^
diff --git a/src/test/ui/const-generics/associated-type-bound-fail.stderr b/src/test/ui/const-generics/associated-type-bound-fail.stderr
index 60e624fc6a8..9dc677ef6ed 100644
--- a/src/test/ui/const-generics/associated-type-bound-fail.stderr
+++ b/src/test/ui/const-generics/associated-type-bound-fail.stderr
@@ -1,8 +1,8 @@
error[E0277]: the trait bound `u16: Bar<N>` is not satisfied
- --> $DIR/associated-type-bound-fail.rs:9:5
+ --> $DIR/associated-type-bound-fail.rs:9:18
|
LL | type Assoc = u16;
- | ^^^^^^^^^^^^^^^^^ the trait `Bar<N>` is not implemented for `u16`
+ | ^^^ the trait `Bar<N>` is not implemented for `u16`
|
= help: the following implementations were found:
<u16 as Bar<3_usize>>
diff --git a/src/test/ui/const-generics/const-arg-type-arg-misordered.stderr b/src/test/ui/const-generics/const-arg-type-arg-misordered.stderr
index 104ee9b48b4..4e12f7a8c6e 100644
--- a/src/test/ui/const-generics/const-arg-type-arg-misordered.stderr
+++ b/src/test/ui/const-generics/const-arg-type-arg-misordered.stderr
@@ -3,9 +3,6 @@ error[E0747]: constant provided when a type was expected
|
LL | fn foo<const N: usize>() -> Array<N, ()> {
| ^
- |
- = note: type arguments must be provided before constant arguments
- = help: reorder the arguments: types, then consts: `<T, N>`
error: aborting due to previous error
diff --git a/src/test/ui/const-generics/const-param-before-other-params.min.stderr b/src/test/ui/const-generics/const-param-before-other-params.min.stderr
deleted file mode 100644
index f439cd9d69f..00000000000
--- a/src/test/ui/const-generics/const-param-before-other-params.min.stderr
+++ /dev/null
@@ -1,14 +0,0 @@
-error: lifetime parameters must be declared prior to const parameters
- --> $DIR/const-param-before-other-params.rs:5:21
- |
-LL | fn bar<const X: u8, 'a>(_: &'a ()) {
- | --------------^^- help: reorder the parameters: lifetimes, then types, then consts: `<'a, const X: u8>`
-
-error: type parameters must be declared prior to const parameters
- --> $DIR/const-param-before-other-params.rs:9:21
- |
-LL | fn foo<const X: u8, T>(_: &T) {}
- | --------------^- help: reorder the parameters: lifetimes, then types, then consts: `<T, const X: u8>`
-
-error: aborting due to 2 previous errors
-
diff --git a/src/test/ui/const-generics/const-param-before-other-params.rs b/src/test/ui/const-generics/const-param-before-other-params.rs
index 0a7b57fe626..da06aca308e 100644
--- a/src/test/ui/const-generics/const-param-before-other-params.rs
+++ b/src/test/ui/const-generics/const-param-before-other-params.rs
@@ -1,12 +1,7 @@
-// revisions: full min
-#![cfg_attr(full, feature(const_generics_defaults))]
-#![cfg_attr(full, allow(incomplete_features))]
-
fn bar<const X: u8, 'a>(_: &'a ()) {
//~^ ERROR lifetime parameters must be declared prior to const parameters
}
fn foo<const X: u8, T>(_: &T) {}
-//[min]~^ ERROR type parameters must be declared prior to const parameters
fn main() {}
diff --git a/src/test/ui/const-generics/const-param-before-other-params.full.stderr b/src/test/ui/const-generics/const-param-before-other-params.stderr
index 982417eb3c6..607d20c4a25 100644
--- a/src/test/ui/const-generics/const-param-before-other-params.full.stderr
+++ b/src/test/ui/const-generics/const-param-before-other-params.stderr
@@ -1,5 +1,5 @@
error: lifetime parameters must be declared prior to const parameters
- --> $DIR/const-param-before-other-params.rs:5:21
+ --> $DIR/const-param-before-other-params.rs:1:21
|
LL | fn bar<const X: u8, 'a>(_: &'a ()) {
| --------------^^- help: reorder the parameters: lifetimes, then consts and types: `<'a, const X: u8>`
diff --git a/src/test/ui/const-generics/defaults/auxiliary/const_defaulty.rs b/src/test/ui/const-generics/defaults/auxiliary/const_defaulty.rs
index 5c548740af2..eed982534c2 100644
--- a/src/test/ui/const-generics/defaults/auxiliary/const_defaulty.rs
+++ b/src/test/ui/const-generics/defaults/auxiliary/const_defaulty.rs
@@ -1,5 +1,3 @@
-#![feature(const_generics_defaults)]
-
pub struct Defaulted<const N: usize=3>;
impl Defaulted {
pub fn new() -> Self {
diff --git a/src/test/ui/const-generics/defaults/auxiliary/trait_object_lt_defaults_lib.rs b/src/test/ui/const-generics/defaults/auxiliary/trait_object_lt_defaults_lib.rs
new file mode 100644
index 00000000000..26a2c47ffb2
--- /dev/null
+++ b/src/test/ui/const-generics/defaults/auxiliary/trait_object_lt_defaults_lib.rs
@@ -0,0 +1 @@
+pub struct Foo<'a, const N: usize, T: 'a + ?Sized>(pub &'a T, [(); N]);
diff --git a/src/test/ui/const-generics/defaults/complex-generic-default-expr.min.stderr b/src/test/ui/const-generics/defaults/complex-generic-default-expr.min.stderr
index aa289ec0778..b836cfeaedb 100644
--- a/src/test/ui/const-generics/defaults/complex-generic-default-expr.min.stderr
+++ b/src/test/ui/const-generics/defaults/complex-generic-default-expr.min.stderr
@@ -1,5 +1,5 @@
error: generic parameters may not be used in const operations
- --> $DIR/complex-generic-default-expr.rs:7:47
+ --> $DIR/complex-generic-default-expr.rs:6:47
|
LL | struct Foo<const N: usize, const M: usize = { N + 1 }>;
| ^ cannot perform const operation using `N`
@@ -8,7 +8,7 @@ LL | struct Foo<const N: usize, const M: usize = { N + 1 }>;
= help: use `#![feature(generic_const_exprs)]` to allow generic const expressions
error: generic parameters may not be used in const operations
- --> $DIR/complex-generic-default-expr.rs:10:62
+ --> $DIR/complex-generic-default-expr.rs:9:62
|
LL | struct Bar<T, const TYPE_SIZE: usize = { std::mem::size_of::<T>() }>(T);
| ^ cannot perform const operation using `T`
diff --git a/src/test/ui/const-generics/defaults/complex-generic-default-expr.rs b/src/test/ui/const-generics/defaults/complex-generic-default-expr.rs
index 814c996fbad..7f50d4c9f29 100644
--- a/src/test/ui/const-generics/defaults/complex-generic-default-expr.rs
+++ b/src/test/ui/const-generics/defaults/complex-generic-default-expr.rs
@@ -1,8 +1,7 @@
// revisions: full min
//[full] check-pass
#![cfg_attr(full, feature(generic_const_exprs))]
-#![feature(const_generics_defaults)]
-#![allow(incomplete_features)]
+#![cfg_attr(full, allow(incomplete_features))]
struct Foo<const N: usize, const M: usize = { N + 1 }>;
//[min]~^ ERROR generic parameters may not be used in const operations
diff --git a/src/test/ui/const-generics/defaults/complex-unord-param.rs b/src/test/ui/const-generics/defaults/complex-unord-param.rs
index c27ed298afd..aebc5975a5a 100644
--- a/src/test/ui/const-generics/defaults/complex-unord-param.rs
+++ b/src/test/ui/const-generics/defaults/complex-unord-param.rs
@@ -1,12 +1,8 @@
-// [full] run-pass
-// revisions: full min
+// run-pass
// Checks a complicated usage of unordered params
-#![cfg_attr(full, feature(const_generics_defaults))]
-#![cfg_attr(full, allow(incomplete_features))]
#![allow(dead_code)]
struct NestedArrays<'a, const N: usize, A: 'a, const M: usize, T:'a =u32> {
- //[min]~^ ERROR type parameters must be declared prior to const parameters
args: &'a [&'a [T; M]; N],
specifier: A,
}
diff --git a/src/test/ui/const-generics/defaults/const-default.rs b/src/test/ui/const-generics/defaults/const-default.rs
index e7cbf01a301..65cb0eb14a3 100644
--- a/src/test/ui/const-generics/defaults/const-default.rs
+++ b/src/test/ui/const-generics/defaults/const-default.rs
@@ -1,6 +1,4 @@
// run-pass
-#![feature(const_generics_defaults)]
-
pub struct ConstDefault<const N: usize = 3>;
impl<const N: usize> ConstDefault<N> {
diff --git a/src/test/ui/const-generics/defaults/const-param-as-default-value.rs b/src/test/ui/const-generics/defaults/const-param-as-default-value.rs
index 9779835d315..c1c955d8758 100644
--- a/src/test/ui/const-generics/defaults/const-param-as-default-value.rs
+++ b/src/test/ui/const-generics/defaults/const-param-as-default-value.rs
@@ -1,5 +1,4 @@
// run-pass
-#![feature(const_generics_defaults)]
struct Foo<const N: usize, const M: usize = N>([u8; N], [u8; M]);
fn foo<const N: usize>() -> Foo<N> {
diff --git a/src/test/ui/const-generics/defaults/const-param-in-ty-defaults.rs b/src/test/ui/const-generics/defaults/const-param-in-ty-defaults.rs
index dbcab77dcd2..5f0cafe2ef1 100644
--- a/src/test/ui/const-generics/defaults/const-param-in-ty-defaults.rs
+++ b/src/test/ui/const-generics/defaults/const-param-in-ty-defaults.rs
@@ -1,5 +1,4 @@
// run-pass
-#![feature(const_generics_defaults)]
struct Foo<const N: usize, T = [u8; N]>(T);
impl<const N: usize> Foo<N> {
diff --git a/src/test/ui/const-generics/defaults/default-annotation.rs b/src/test/ui/const-generics/defaults/default-annotation.rs
index 5517bf8ac5f..7a9f5732f7f 100644
--- a/src/test/ui/const-generics/defaults/default-annotation.rs
+++ b/src/test/ui/const-generics/defaults/default-annotation.rs
@@ -1,6 +1,5 @@
// run-pass
#![feature(staged_api)]
-#![feature(const_generics_defaults)]
#![allow(incomplete_features)]
// FIXME(const_generics_defaults): It seems like we aren't testing the right thing here,
// I would assume that we want the attributes to apply to the const parameter defaults
diff --git a/src/test/ui/const-generics/defaults/default-const-param-cannot-reference-self.rs b/src/test/ui/const-generics/defaults/default-const-param-cannot-reference-self.rs
index 9af84439252..45275e60920 100644
--- a/src/test/ui/const-generics/defaults/default-const-param-cannot-reference-self.rs
+++ b/src/test/ui/const-generics/defaults/default-const-param-cannot-reference-self.rs
@@ -1,5 +1,3 @@
-#![feature(const_generics_defaults)]
-
struct Struct<const N: usize = { Self; 10 }>;
//~^ ERROR generic parameters cannot use `Self` in their defaults [E0735]
diff --git a/src/test/ui/const-generics/defaults/default-const-param-cannot-reference-self.stderr b/src/test/ui/const-generics/defaults/default-const-param-cannot-reference-self.stderr
index 5dfec2fcb73..72d7001fdf1 100644
--- a/src/test/ui/const-generics/defaults/default-const-param-cannot-reference-self.stderr
+++ b/src/test/ui/const-generics/defaults/default-const-param-cannot-reference-self.stderr
@@ -1,17 +1,17 @@
error[E0735]: generic parameters cannot use `Self` in their defaults
- --> $DIR/default-const-param-cannot-reference-self.rs:3:34
+ --> $DIR/default-const-param-cannot-reference-self.rs:1:34
|
LL | struct Struct<const N: usize = { Self; 10 }>;
| ^^^^ `Self` in generic parameter default
error[E0735]: generic parameters cannot use `Self` in their defaults
- --> $DIR/default-const-param-cannot-reference-self.rs:6:30
+ --> $DIR/default-const-param-cannot-reference-self.rs:4:30
|
LL | enum Enum<const N: usize = { Self; 10 }> { }
| ^^^^ `Self` in generic parameter default
error[E0735]: generic parameters cannot use `Self` in their defaults
- --> $DIR/default-const-param-cannot-reference-self.rs:9:32
+ --> $DIR/default-const-param-cannot-reference-self.rs:7:32
|
LL | union Union<const N: usize = { Self; 10 }> { not_empty: () }
| ^^^^ `Self` in generic parameter default
diff --git a/src/test/ui/const-generics/defaults/default-on-impl.rs b/src/test/ui/const-generics/defaults/default-on-impl.rs
index 280d92f839f..9ce46aa09de 100644
--- a/src/test/ui/const-generics/defaults/default-on-impl.rs
+++ b/src/test/ui/const-generics/defaults/default-on-impl.rs
@@ -1,5 +1,3 @@
-#![feature(const_generics_defaults)]
-
struct Foo<const N: usize>;
impl<const N: usize = 1> Foo<N> {}
diff --git a/src/test/ui/const-generics/defaults/default-on-impl.stderr b/src/test/ui/const-generics/defaults/default-on-impl.stderr
index 0f85ceccc8a..ddfc0ead8ad 100644
--- a/src/test/ui/const-generics/defaults/default-on-impl.stderr
+++ b/src/test/ui/const-generics/defaults/default-on-impl.stderr
@@ -1,5 +1,5 @@
error: defaults for const parameters are only allowed in `struct`, `enum`, `type`, or `trait` definitions
- --> $DIR/default-on-impl.rs:5:12
+ --> $DIR/default-on-impl.rs:3:12
|
LL | impl<const N: usize = 1> Foo<N> {}
| ^
diff --git a/src/test/ui/const-generics/defaults/default-param-wf-concrete.rs b/src/test/ui/const-generics/defaults/default-param-wf-concrete.rs
index d4271adefd1..41a52c7eb0d 100644
--- a/src/test/ui/const-generics/defaults/default-param-wf-concrete.rs
+++ b/src/test/ui/const-generics/defaults/default-param-wf-concrete.rs
@@ -1,4 +1,3 @@
-#![feature(const_generics_defaults)]
struct Foo<const N: u8 = { 255 + 1 }>;
//~^ ERROR evaluation of constant value failed
fn main() {}
diff --git a/src/test/ui/const-generics/defaults/default-param-wf-concrete.stderr b/src/test/ui/const-generics/defaults/default-param-wf-concrete.stderr
index 6fca9d31c0a..e8ebddade5c 100644
--- a/src/test/ui/const-generics/defaults/default-param-wf-concrete.stderr
+++ b/src/test/ui/const-generics/defaults/default-param-wf-concrete.stderr
@@ -1,5 +1,5 @@
error[E0080]: evaluation of constant value failed
- --> $DIR/default-param-wf-concrete.rs:2:28
+ --> $DIR/default-param-wf-concrete.rs:1:28
|
LL | struct Foo<const N: u8 = { 255 + 1 }>;
| ^^^^^^^ attempt to compute `u8::MAX + 1_u8`, which would overflow
diff --git a/src/test/ui/const-generics/defaults/doesnt_infer.rs b/src/test/ui/const-generics/defaults/doesnt_infer.rs
index c7f14e47a9d..cd533b57bc3 100644
--- a/src/test/ui/const-generics/defaults/doesnt_infer.rs
+++ b/src/test/ui/const-generics/defaults/doesnt_infer.rs
@@ -1,5 +1,3 @@
-#![feature(const_generics_defaults)]
-
// test that defaulted const params are not used to help type inference
struct Foo<const N: u32 = 2>;
diff --git a/src/test/ui/const-generics/defaults/doesnt_infer.stderr b/src/test/ui/const-generics/defaults/doesnt_infer.stderr
index b57975e26f2..1551e81ea75 100644
--- a/src/test/ui/const-generics/defaults/doesnt_infer.stderr
+++ b/src/test/ui/const-generics/defaults/doesnt_infer.stderr
@@ -1,10 +1,10 @@
error[E0282]: type annotations needed for `Foo<{_: u32}>`
- --> $DIR/doesnt_infer.rs:13:15
+ --> $DIR/doesnt_infer.rs:11:15
|
LL | let foo = Foo::foo();
| --- ^^^^^^^^ cannot infer the value of const parameter `N`
| |
- | consider giving `foo` the explicit type `Foo<{_: u32}>`, where the type parameter `N` is specified
+ | consider giving `foo` the explicit type `Foo<N>`, where the const parameter `N` is specified
error: aborting due to previous error
diff --git a/src/test/ui/const-generics/defaults/external.rs b/src/test/ui/const-generics/defaults/external.rs
index 276e74355c2..25ec523cb54 100644
--- a/src/test/ui/const-generics/defaults/external.rs
+++ b/src/test/ui/const-generics/defaults/external.rs
@@ -1,7 +1,5 @@
// aux-build:const_defaulty.rs
// check-pass
-#![feature(const_generics_defaults)]
-
extern crate const_defaulty;
use const_defaulty::Defaulted;
diff --git a/src/test/ui/const-generics/defaults/forward-declared.rs b/src/test/ui/const-generics/defaults/forward-declared.rs
index 09fc105320e..ede3d873bdc 100644
--- a/src/test/ui/const-generics/defaults/forward-declared.rs
+++ b/src/test/ui/const-generics/defaults/forward-declared.rs
@@ -1,5 +1,3 @@
-#![feature(const_generics_defaults)]
-
struct Foo<const N: usize = M, const M: usize = 10>;
//~^ ERROR generic parameters with a default cannot use forward declared identifiers
diff --git a/src/test/ui/const-generics/defaults/forward-declared.stderr b/src/test/ui/const-generics/defaults/forward-declared.stderr
index a6c4a7ae4ef..4856c7a1fd2 100644
--- a/src/test/ui/const-generics/defaults/forward-declared.stderr
+++ b/src/test/ui/const-generics/defaults/forward-declared.stderr
@@ -1,23 +1,23 @@
error[E0128]: generic parameters with a default cannot use forward declared identifiers
- --> $DIR/forward-declared.rs:3:29
+ --> $DIR/forward-declared.rs:1:29
|
LL | struct Foo<const N: usize = M, const M: usize = 10>;
| ^ defaulted generic parameters cannot be forward declared
error[E0128]: generic parameters with a default cannot use forward declared identifiers
- --> $DIR/forward-declared.rs:6:27
+ --> $DIR/forward-declared.rs:4:27
|
LL | enum Bar<const N: usize = M, const M: usize = 10> {}
| ^ defaulted generic parameters cannot be forward declared
error[E0128]: generic parameters with a default cannot use forward declared identifiers
- --> $DIR/forward-declared.rs:9:30
+ --> $DIR/forward-declared.rs:7:30
|
LL | struct Foo2<const N: usize = N>;
| ^ defaulted generic parameters cannot be forward declared
error[E0128]: generic parameters with a default cannot use forward declared identifiers
- --> $DIR/forward-declared.rs:12:28
+ --> $DIR/forward-declared.rs:10:28
|
LL | enum Bar2<const N: usize = N> {}
| ^ defaulted generic parameters cannot be forward declared
diff --git a/src/test/ui/const-generics/defaults/generic-expr-default-concrete.rs b/src/test/ui/const-generics/defaults/generic-expr-default-concrete.rs
index 52cea51aae1..f082bd8d2e9 100644
--- a/src/test/ui/const-generics/defaults/generic-expr-default-concrete.rs
+++ b/src/test/ui/const-generics/defaults/generic-expr-default-concrete.rs
@@ -1,4 +1,4 @@
-#![feature(generic_const_exprs, const_generics_defaults)]
+#![feature(generic_const_exprs)]
#![allow(incomplete_features)]
struct Foo<const N: usize, const M: usize = { N + 1 }>;
diff --git a/src/test/ui/const-generics/defaults/generic-expr-default-mismatched-types.rs b/src/test/ui/const-generics/defaults/generic-expr-default-mismatched-types.rs
index 3a11631fc47..777865d1cb6 100644
--- a/src/test/ui/const-generics/defaults/generic-expr-default-mismatched-types.rs
+++ b/src/test/ui/const-generics/defaults/generic-expr-default-mismatched-types.rs
@@ -1,4 +1,4 @@
-#![feature(generic_const_exprs, const_generics_defaults)]
+#![feature(generic_const_exprs)]
#![allow(incomplete_features)]
struct Foo<const N: usize, const M: usize = { N + 1 }>;
diff --git a/src/test/ui/const-generics/defaults/generic-expr-default.rs b/src/test/ui/const-generics/defaults/generic-expr-default.rs
index 0adbd5cdf31..8fe43feb78a 100644
--- a/src/test/ui/const-generics/defaults/generic-expr-default.rs
+++ b/src/test/ui/const-generics/defaults/generic-expr-default.rs
@@ -1,4 +1,4 @@
-#![feature(generic_const_exprs, const_generics_defaults)]
+#![feature(generic_const_exprs)]
#![allow(incomplete_features)]
pub struct Foo<const N: usize, const M: usize = { N + 1 }>;
diff --git a/src/test/ui/const-generics/defaults/intermixed-lifetime.min.stderr b/src/test/ui/const-generics/defaults/intermixed-lifetime.min.stderr
deleted file mode 100644
index 725cc36b428..00000000000
--- a/src/test/ui/const-generics/defaults/intermixed-lifetime.min.stderr
+++ /dev/null
@@ -1,14 +0,0 @@
-error: lifetime parameters must be declared prior to const parameters
- --> $DIR/intermixed-lifetime.rs:5:28
- |
-LL | struct Foo<const N: usize, 'a, T = u32>(&'a (), T);
- | -----------------^^---------- help: reorder the parameters: lifetimes, then consts and types: `<'a, const N: usize, T = u32>`
-
-error: lifetime parameters must be declared prior to type parameters
- --> $DIR/intermixed-lifetime.rs:8:37
- |
-LL | struct Bar<const N: usize, T = u32, 'a>(&'a (), T);
- | --------------------------^^- help: reorder the parameters: lifetimes, then consts and types: `<'a, const N: usize, T = u32>`
-
-error: aborting due to 2 previous errors
-
diff --git a/src/test/ui/const-generics/defaults/intermixed-lifetime.rs b/src/test/ui/const-generics/defaults/intermixed-lifetime.rs
index cc215ab0c25..578938db4c4 100644
--- a/src/test/ui/const-generics/defaults/intermixed-lifetime.rs
+++ b/src/test/ui/const-generics/defaults/intermixed-lifetime.rs
@@ -1,6 +1,4 @@
// Checks that lifetimes cannot be interspersed between consts and types.
-// revisions: full min
-#![feature(const_generics_defaults)]
struct Foo<const N: usize, 'a, T = u32>(&'a (), T);
//~^ Error lifetime parameters must be declared prior to const parameters
diff --git a/src/test/ui/const-generics/defaults/intermixed-lifetime.full.stderr b/src/test/ui/const-generics/defaults/intermixed-lifetime.stderr
index 725cc36b428..e27976deb2b 100644
--- a/src/test/ui/const-generics/defaults/intermixed-lifetime.full.stderr
+++ b/src/test/ui/const-generics/defaults/intermixed-lifetime.stderr
@@ -1,11 +1,11 @@
error: lifetime parameters must be declared prior to const parameters
- --> $DIR/intermixed-lifetime.rs:5:28
+ --> $DIR/intermixed-lifetime.rs:3:28
|
LL | struct Foo<const N: usize, 'a, T = u32>(&'a (), T);
| -----------------^^---------- help: reorder the parameters: lifetimes, then consts and types: `<'a, const N: usize, T = u32>`
error: lifetime parameters must be declared prior to type parameters
- --> $DIR/intermixed-lifetime.rs:8:37
+ --> $DIR/intermixed-lifetime.rs:6:37
|
LL | struct Bar<const N: usize, T = u32, 'a>(&'a (), T);
| --------------------------^^- help: reorder the parameters: lifetimes, then consts and types: `<'a, const N: usize, T = u32>`
diff --git a/src/test/ui/const-generics/defaults/mismatch.rs b/src/test/ui/const-generics/defaults/mismatch.rs
index 4ae93a9166d..fce4ec4edda 100644
--- a/src/test/ui/const-generics/defaults/mismatch.rs
+++ b/src/test/ui/const-generics/defaults/mismatch.rs
@@ -1,5 +1,3 @@
-#![feature(const_generics_defaults)]
-
pub struct Example<const N: usize=13>;
pub struct Example2<T=u32, const N: usize=13>(T);
pub struct Example3<const N: usize=13, T=u32>(T);
diff --git a/src/test/ui/const-generics/defaults/mismatch.stderr b/src/test/ui/const-generics/defaults/mismatch.stderr
index 3c7f4fe3b28..36976819195 100644
--- a/src/test/ui/const-generics/defaults/mismatch.stderr
+++ b/src/test/ui/const-generics/defaults/mismatch.stderr
@@ -1,5 +1,5 @@
error[E0308]: mismatched types
- --> $DIR/mismatch.rs:9:28
+ --> $DIR/mismatch.rs:7:28
|
LL | let e: Example::<13> = ();
| ------------- ^^ expected struct `Example`, found `()`
@@ -10,7 +10,7 @@ LL | let e: Example::<13> = ();
found unit type `()`
error[E0308]: mismatched types
- --> $DIR/mismatch.rs:12:34
+ --> $DIR/mismatch.rs:10:34
|
LL | let e: Example2::<u32, 13> = ();
| ------------------- ^^ expected struct `Example2`, found `()`
@@ -21,7 +21,7 @@ LL | let e: Example2::<u32, 13> = ();
found unit type `()`
error[E0308]: mismatched types
- --> $DIR/mismatch.rs:15:34
+ --> $DIR/mismatch.rs:13:34
|
LL | let e: Example3::<13, u32> = ();
| ------------------- ^^ expected struct `Example3`, found `()`
@@ -32,7 +32,7 @@ LL | let e: Example3::<13, u32> = ();
found unit type `()`
error[E0308]: mismatched types
- --> $DIR/mismatch.rs:18:28
+ --> $DIR/mismatch.rs:16:28
|
LL | let e: Example3::<7> = ();
| ------------- ^^ expected struct `Example3`, found `()`
@@ -43,7 +43,7 @@ LL | let e: Example3::<7> = ();
found unit type `()`
error[E0308]: mismatched types
- --> $DIR/mismatch.rs:21:28
+ --> $DIR/mismatch.rs:19:28
|
LL | let e: Example4::<7> = ();
| ------------- ^^ expected struct `Example4`, found `()`
diff --git a/src/test/ui/const-generics/defaults/needs-feature.min.stderr b/src/test/ui/const-generics/defaults/needs-feature.min.stderr
deleted file mode 100644
index 158fa2ec1c8..00000000000
--- a/src/test/ui/const-generics/defaults/needs-feature.min.stderr
+++ /dev/null
@@ -1,8 +0,0 @@
-error: type parameters must be declared prior to const parameters
- --> $DIR/needs-feature.rs:7:26
- |
-LL | struct A<const N: usize, T=u32>(T);
- | -----------------^----- help: reorder the parameters: lifetimes, then types, then consts: `<T = u32, const N: usize>`
-
-error: aborting due to previous error
-
diff --git a/src/test/ui/const-generics/defaults/needs-feature.rs b/src/test/ui/const-generics/defaults/needs-feature.rs
deleted file mode 100644
index 9ba8184e058..00000000000
--- a/src/test/ui/const-generics/defaults/needs-feature.rs
+++ /dev/null
@@ -1,12 +0,0 @@
-//[full] run-pass
-// Verifies that having generic parameters after constants is not permitted without the
-// `const_generics_defaults` feature.
-// revisions: min full
-#![cfg_attr(full, feature(const_generics_defaults))]
-
-struct A<const N: usize, T=u32>(T);
-//[min]~^ ERROR type parameters must be declared prior
-
-fn main() {
- let _: A<3> = A(0);
-}
diff --git a/src/test/ui/const-generics/defaults/param-order-err-pretty-prints-default.rs b/src/test/ui/const-generics/defaults/param-order-err-pretty-prints-default.rs
index 933eacb312d..da087ffc3c4 100644
--- a/src/test/ui/const-generics/defaults/param-order-err-pretty-prints-default.rs
+++ b/src/test/ui/const-generics/defaults/param-order-err-pretty-prints-default.rs
@@ -1,4 +1,3 @@
-#![feature(const_generics_defaults)]
struct Foo<const M: usize = 10, 'a>(&'a u32);
//~^ Error lifetime parameters must be declared prior to const parameters
diff --git a/src/test/ui/const-generics/defaults/param-order-err-pretty-prints-default.stderr b/src/test/ui/const-generics/defaults/param-order-err-pretty-prints-default.stderr
index f50653fe9a1..55f5a535385 100644
--- a/src/test/ui/const-generics/defaults/param-order-err-pretty-prints-default.stderr
+++ b/src/test/ui/const-generics/defaults/param-order-err-pretty-prints-default.stderr
@@ -1,5 +1,5 @@
error: lifetime parameters must be declared prior to const parameters
- --> $DIR/param-order-err-pretty-prints-default.rs:2:33
+ --> $DIR/param-order-err-pretty-prints-default.rs:1:33
|
LL | struct Foo<const M: usize = 10, 'a>(&'a u32);
| ----------------------^^- help: reorder the parameters: lifetimes, then consts and types: `<'a, const M: usize = 10>`
diff --git a/src/test/ui/const-generics/defaults/pretty-printing-ast.rs b/src/test/ui/const-generics/defaults/pretty-printing-ast.rs
index 0487668cd2a..e202d4e86a2 100644
--- a/src/test/ui/const-generics/defaults/pretty-printing-ast.rs
+++ b/src/test/ui/const-generics/defaults/pretty-printing-ast.rs
@@ -3,7 +3,6 @@
// compile-flags: -Z unpretty=expanded
#![crate_type = "lib"]
-#![feature(const_generics_defaults)]
trait Foo<const KIND: bool = true> {}
diff --git a/src/test/ui/const-generics/defaults/pretty-printing-ast.stdout b/src/test/ui/const-generics/defaults/pretty-printing-ast.stdout
index 1bceb8cbb94..99fe9d2e4b3 100644
--- a/src/test/ui/const-generics/defaults/pretty-printing-ast.stdout
+++ b/src/test/ui/const-generics/defaults/pretty-printing-ast.stdout
@@ -5,15 +5,14 @@
// compile-flags: -Z unpretty=expanded
#![crate_type = "lib"]
-#![feature(const_generics_defaults)]
#[prelude_import]
use ::std::prelude::rust_2015::*;
#[macro_use]
extern crate std;
-trait Foo<const KIND : bool = true> { }
+trait Foo<const KIND : bool = true> {}
-fn foo<const SIZE : usize = 5>() { }
+fn foo<const SIZE : usize = 5>() {}
struct Range<const FROM : usize = 0, const LEN : usize = 0, const TO : usize =
FROM>;
diff --git a/src/test/ui/const-generics/defaults/repr-c-issue-82792.rs b/src/test/ui/const-generics/defaults/repr-c-issue-82792.rs
index ca29ee94206..118da2723ac 100644
--- a/src/test/ui/const-generics/defaults/repr-c-issue-82792.rs
+++ b/src/test/ui/const-generics/defaults/repr-c-issue-82792.rs
@@ -2,8 +2,6 @@
// run-pass
-#![feature(const_generics_defaults)]
-
#[repr(C)]
pub struct Loaf<T: Sized, const N: usize = 1> {
head: [T; N],
diff --git a/src/test/ui/const-generics/defaults/rp_impl_trait.rs b/src/test/ui/const-generics/defaults/rp_impl_trait.rs
index 1447ebe5348..dde8eea4525 100644
--- a/src/test/ui/const-generics/defaults/rp_impl_trait.rs
+++ b/src/test/ui/const-generics/defaults/rp_impl_trait.rs
@@ -1,6 +1,4 @@
// run-pass
-#![feature(const_generics_defaults)]
-
struct Uwu<const N: u32 = 1, const M: u32 = N>;
trait Trait {}
diff --git a/src/test/ui/const-generics/defaults/rp_impl_trait_fail.rs b/src/test/ui/const-generics/defaults/rp_impl_trait_fail.rs
index c989fc8338b..308c121a941 100644
--- a/src/test/ui/const-generics/defaults/rp_impl_trait_fail.rs
+++ b/src/test/ui/const-generics/defaults/rp_impl_trait_fail.rs
@@ -1,5 +1,3 @@
-#![feature(const_generics_defaults)]
-
struct Uwu<const N: u32 = 1, const M: u32 = N>;
trait Trait {}
diff --git a/src/test/ui/const-generics/defaults/rp_impl_trait_fail.stderr b/src/test/ui/const-generics/defaults/rp_impl_trait_fail.stderr
index cf28932177a..8c8bfdc0e48 100644
--- a/src/test/ui/const-generics/defaults/rp_impl_trait_fail.stderr
+++ b/src/test/ui/const-generics/defaults/rp_impl_trait_fail.stderr
@@ -1,5 +1,5 @@
error[E0277]: the trait bound `Uwu<10_u32, 12_u32>: Trait` is not satisfied
- --> $DIR/rp_impl_trait_fail.rs:8:14
+ --> $DIR/rp_impl_trait_fail.rs:6:14
|
LL | fn rawr() -> impl Trait {
| ^^^^^^^^^^ the trait `Trait` is not implemented for `Uwu<10_u32, 12_u32>`
@@ -8,7 +8,7 @@ LL | fn rawr() -> impl Trait {
<Uwu<N> as Trait>
error[E0277]: the trait bound `u32: Traitor<N, N>` is not satisfied
- --> $DIR/rp_impl_trait_fail.rs:19:26
+ --> $DIR/rp_impl_trait_fail.rs:17:26
|
LL | fn uwu<const N: u8>() -> impl Traitor<N> {
| ^^^^^^^^^^^^^^^ the trait `Traitor<N, N>` is not implemented for `u32`
@@ -17,7 +17,7 @@ LL | fn uwu<const N: u8>() -> impl Traitor<N> {
<u32 as Traitor<N, 2_u8>>
error[E0277]: the trait bound `u64: Traitor<1_u8, 1_u8>` is not satisfied
- --> $DIR/rp_impl_trait_fail.rs:24:13
+ --> $DIR/rp_impl_trait_fail.rs:22:13
|
LL | fn owo() -> impl Traitor {
| ^^^^^^^^^^^^ the trait `Traitor<1_u8, 1_u8>` is not implemented for `u64`
diff --git a/src/test/ui/const-generics/defaults/simple-defaults.rs b/src/test/ui/const-generics/defaults/simple-defaults.rs
index bc01fe2656c..6a782d2238c 100644
--- a/src/test/ui/const-generics/defaults/simple-defaults.rs
+++ b/src/test/ui/const-generics/defaults/simple-defaults.rs
@@ -1,6 +1,5 @@
// run-pass
// Checks that type param defaults are allowed after const params.
-#![feature(const_generics_defaults)]
#![allow(dead_code)]
struct FixedOutput<'a, const N: usize, T=u32> {
diff --git a/src/test/ui/const-generics/defaults/trait_object_lt_defaults.rs b/src/test/ui/const-generics/defaults/trait_object_lt_defaults.rs
new file mode 100644
index 00000000000..a1828727ecd
--- /dev/null
+++ b/src/test/ui/const-generics/defaults/trait_object_lt_defaults.rs
@@ -0,0 +1,24 @@
+// aux-build:trait_object_lt_defaults_lib.rs
+// run-pass
+#![allow(dead_code)]
+extern crate trait_object_lt_defaults_lib;
+
+// Tests that `A<'a, 3, dyn Test>` is short for `A<'a, 3, dyn Test + 'a>`
+// and `Foo<'a, 3, dyn Test>` is short for `Foo<'a, 3, dyn Test + 'a>`
+// Test is in `const-generics/defaults` because it relies on param ordering
+
+trait Test {}
+
+struct A<'a, const N: usize, T: ?Sized + 'a>(&'a T, [(); N]);
+fn blah<'a>(mut a: A<'a, 3, dyn Test>, arg: &'a (dyn Test + 'a)) {
+ a.0 = arg;
+}
+
+fn other_blah<'a>(
+ mut a: trait_object_lt_defaults_lib::Foo<'a, 3, dyn Test>,
+ arg: &'a (dyn Test + 'a),
+) {
+ a.0 = arg;
+}
+
+fn main() {}
diff --git a/src/test/ui/const-generics/defaults/trait_objects.rs b/src/test/ui/const-generics/defaults/trait_objects.rs
index e36f23fadb2..750e40313fb 100644
--- a/src/test/ui/const-generics/defaults/trait_objects.rs
+++ b/src/test/ui/const-generics/defaults/trait_objects.rs
@@ -1,6 +1,4 @@
// run-pass
-#![feature(const_generics_defaults)]
-
trait Trait<const N: u8 = 12> {
fn uwu(&self) -> u8 {
N
diff --git a/src/test/ui/const-generics/defaults/trait_objects_fail.rs b/src/test/ui/const-generics/defaults/trait_objects_fail.rs
index 09e4265a7a0..7ba12d02b6e 100644
--- a/src/test/ui/const-generics/defaults/trait_objects_fail.rs
+++ b/src/test/ui/const-generics/defaults/trait_objects_fail.rs
@@ -1,5 +1,3 @@
-#![feature(const_generics_defaults)]
-
trait Trait<const N: u8 = 12> {
fn uwu(&self) -> u8 {
N
diff --git a/src/test/ui/const-generics/defaults/trait_objects_fail.stderr b/src/test/ui/const-generics/defaults/trait_objects_fail.stderr
index b097c8cd4ba..13d03c2d42d 100644
--- a/src/test/ui/const-generics/defaults/trait_objects_fail.stderr
+++ b/src/test/ui/const-generics/defaults/trait_objects_fail.stderr
@@ -1,5 +1,5 @@
error[E0277]: the trait bound `u32: Trait` is not satisfied
- --> $DIR/trait_objects_fail.rs:28:9
+ --> $DIR/trait_objects_fail.rs:26:9
|
LL | foo(&10_u32);
| --- ^^^^^^^ the trait `Trait` is not implemented for `u32`
@@ -11,7 +11,7 @@ LL | foo(&10_u32);
= note: required for the cast to the object type `dyn Trait`
error[E0277]: the trait bound `bool: Traitor<{_: u8}, {_: u8}>` is not satisfied
- --> $DIR/trait_objects_fail.rs:30:9
+ --> $DIR/trait_objects_fail.rs:28:9
|
LL | bar(&true);
| --- ^^^^^ the trait `Traitor<{_: u8}, {_: u8}>` is not implemented for `bool`
diff --git a/src/test/ui/const-generics/defaults/type-default-const-param-name.rs b/src/test/ui/const-generics/defaults/type-default-const-param-name.rs
index 8b35c5860d9..405664dedc7 100644
--- a/src/test/ui/const-generics/defaults/type-default-const-param-name.rs
+++ b/src/test/ui/const-generics/defaults/type-default-const-param-name.rs
@@ -1,6 +1,4 @@
// check-pass
-#![feature(const_generics_defaults)]
-
struct N;
struct Foo<const N: usize = 1, T = N>(T);
diff --git a/src/test/ui/const-generics/defaults/wfness.rs b/src/test/ui/const-generics/defaults/wfness.rs
index c171f292fd6..d366040ba3e 100644
--- a/src/test/ui/const-generics/defaults/wfness.rs
+++ b/src/test/ui/const-generics/defaults/wfness.rs
@@ -1,5 +1,3 @@
-#![feature(const_generics_defaults)]
-
struct Ooopsies<const N: u8 = { u8::MAX + 1 }>;
//~^ error: evaluation of constant value failed
diff --git a/src/test/ui/const-generics/defaults/wfness.stderr b/src/test/ui/const-generics/defaults/wfness.stderr
index 2d400f9bbf5..facf0ae19f7 100644
--- a/src/test/ui/const-generics/defaults/wfness.stderr
+++ b/src/test/ui/const-generics/defaults/wfness.stderr
@@ -1,11 +1,11 @@
error[E0080]: evaluation of constant value failed
- --> $DIR/wfness.rs:3:33
+ --> $DIR/wfness.rs:1:33
|
LL | struct Ooopsies<const N: u8 = { u8::MAX + 1 }>;
| ^^^^^^^^^^^ attempt to compute `u8::MAX + 1_u8`, which would overflow
error[E0277]: the trait bound `(): Trait<2_u8>` is not satisfied
- --> $DIR/wfness.rs:8:47
+ --> $DIR/wfness.rs:6:47
|
LL | struct WhereClause<const N: u8 = 2> where (): Trait<N>;
| ^^^^^^^^ the trait `Trait<2_u8>` is not implemented for `()`
@@ -14,7 +14,7 @@ LL | struct WhereClause<const N: u8 = 2> where (): Trait<N>;
<() as Trait<3_u8>>
error[E0277]: the trait bound `(): Trait<1_u8>` is not satisfied
- --> $DIR/wfness.rs:16:13
+ --> $DIR/wfness.rs:14:13
|
LL | fn foo() -> DependentDefaultWfness {
| ^^^^^^^^^^^^^^^^^^^^^^ the trait `Trait<1_u8>` is not implemented for `()`
@@ -22,7 +22,7 @@ LL | fn foo() -> DependentDefaultWfness {
= help: the following implementations were found:
<() as Trait<3_u8>>
note: required by a bound in `WhereClause`
- --> $DIR/wfness.rs:8:47
+ --> $DIR/wfness.rs:6:47
|
LL | struct WhereClause<const N: u8 = 2> where (): Trait<N>;
| ^^^^^^^^ required by this bound in `WhereClause`
diff --git a/src/test/ui/const-generics/defaults/wrong-order.rs b/src/test/ui/const-generics/defaults/wrong-order.rs
index 94e7367b1fb..d53d56f41e6 100644
--- a/src/test/ui/const-generics/defaults/wrong-order.rs
+++ b/src/test/ui/const-generics/defaults/wrong-order.rs
@@ -1,5 +1,3 @@
-#![feature(const_generics_defaults)]
-
struct A<T = u32, const N: usize> {
//~^ ERROR generic parameters with a default must be trailing
arg: T,
diff --git a/src/test/ui/const-generics/defaults/wrong-order.stderr b/src/test/ui/const-generics/defaults/wrong-order.stderr
index 143ce5c4fea..4d2628d034f 100644
--- a/src/test/ui/const-generics/defaults/wrong-order.stderr
+++ b/src/test/ui/const-generics/defaults/wrong-order.stderr
@@ -1,11 +1,11 @@
error: generic parameters with a default must be trailing
- --> $DIR/wrong-order.rs:3:10
+ --> $DIR/wrong-order.rs:1:10
|
LL | struct A<T = u32, const N: usize> {
| ^
error: generic parameters with a default must be trailing
- --> $DIR/wrong-order.rs:8:18
+ --> $DIR/wrong-order.rs:6:18
|
LL | struct Foo<const N: u8 = 3, T>(T);
| ^
diff --git a/src/test/ui/const-generics/generic_arg_infer/dont-use-defaults.rs b/src/test/ui/const-generics/generic_arg_infer/dont-use-defaults.rs
new file mode 100644
index 00000000000..251160a0f5f
--- /dev/null
+++ b/src/test/ui/const-generics/generic_arg_infer/dont-use-defaults.rs
@@ -0,0 +1,15 @@
+// run-pass
+#![feature(generic_arg_infer)]
+
+// test that we dont use defaults to aide in type inference
+
+struct Foo<const N: usize = 2>;
+impl<const N: usize> Foo<N> {
+ fn make_arr() -> [(); N] {
+ [(); N]
+ }
+}
+
+fn main() {
+ let [(), (), ()] = Foo::<_>::make_arr();
+}
diff --git a/src/test/ui/const-generics/generic_arg_infer/issue-91614.rs b/src/test/ui/const-generics/generic_arg_infer/issue-91614.rs
new file mode 100644
index 00000000000..413cc153924
--- /dev/null
+++ b/src/test/ui/const-generics/generic_arg_infer/issue-91614.rs
@@ -0,0 +1,8 @@
+#![feature(portable_simd)]
+#![feature(generic_arg_infer)]
+use std::simd::Mask;
+
+fn main() {
+ let y = Mask::<_, _>::splat(false);
+ //~^ error: type annotations needed for `Mask<_, {_: usize}>`
+}
diff --git a/src/test/ui/const-generics/generic_arg_infer/issue-91614.stderr b/src/test/ui/const-generics/generic_arg_infer/issue-91614.stderr
new file mode 100644
index 00000000000..71a5ff79280
--- /dev/null
+++ b/src/test/ui/const-generics/generic_arg_infer/issue-91614.stderr
@@ -0,0 +1,18 @@
+error[E0283]: type annotations needed for `Mask<_, {_: usize}>`
+ --> $DIR/issue-91614.rs:6:13
+ |
+LL | let y = Mask::<_, _>::splat(false);
+ | - ^^^^^^^^^^^^^^^^^^^ cannot infer type for type parameter `T`
+ | |
+ | consider giving `y` the explicit type `Mask<_, LANES>`, where the type parameter `T` is specified
+ |
+ = note: cannot satisfy `_: MaskElement`
+note: required by a bound in `Mask::<T, LANES>::splat`
+ --> $SRC_DIR/core/src/../../portable-simd/crates/core_simd/src/masks.rs:LL:COL
+ |
+LL | T: MaskElement,
+ | ^^^^^^^^^^^ required by this bound in `Mask::<T, LANES>::splat`
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0283`.
diff --git a/src/test/ui/const-generics/generic_const_exprs/closures.stderr b/src/test/ui/const-generics/generic_const_exprs/closures.stderr
index 0dfd804be41..18010413b93 100644
--- a/src/test/ui/const-generics/generic_const_exprs/closures.stderr
+++ b/src/test/ui/const-generics/generic_const_exprs/closures.stderr
@@ -4,7 +4,7 @@ error: overly complex generic constant
LL | fn test<const N: usize>() -> [u8; N + (|| 42)()] {}
| ^^^^-------^^
| |
- | dereferencing is not supported in generic constants
+ | borrowing is not supported in generic constants
|
= help: consider moving this anonymous constant into a `const` function
= note: this operation may be supported in the future
diff --git a/src/test/ui/const-generics/generic_const_exprs/const_eval_resolve_canonical.rs b/src/test/ui/const-generics/generic_const_exprs/const_eval_resolve_canonical.rs
index b79bc262d2b..18f33acaabb 100644
--- a/src/test/ui/const-generics/generic_const_exprs/const_eval_resolve_canonical.rs
+++ b/src/test/ui/const-generics/generic_const_exprs/const_eval_resolve_canonical.rs
@@ -1,4 +1,3 @@
-// run-pass
#![feature(generic_const_exprs)]
#![allow(incomplete_features)]
@@ -22,8 +21,11 @@ where
}
fn main() {
- // Test that we can correctly infer `T` which requires evaluating
- // `{ N + 1 }` which has substs containing an inference var
+ // FIXME(generic_const_exprs): We can't correctly infer `T` which requires
+ // evaluating `{ N + 1 }` which has substs containing an inference var
let mut _q = Default::default();
+ //~^ ERROR type annotations needed
+
_q = foo::<_, 2>(_q);
+ //~^ ERROR type annotations needed
}
diff --git a/src/test/ui/const-generics/generic_const_exprs/const_eval_resolve_canonical.stderr b/src/test/ui/const-generics/generic_const_exprs/const_eval_resolve_canonical.stderr
new file mode 100644
index 00000000000..e59f1ac8027
--- /dev/null
+++ b/src/test/ui/const-generics/generic_const_exprs/const_eval_resolve_canonical.stderr
@@ -0,0 +1,33 @@
+error[E0282]: type annotations needed
+ --> $DIR/const_eval_resolve_canonical.rs:26:9
+ |
+LL | let mut _q = Default::default();
+ | ^^^^^^ consider giving `_q` a type
+
+error[E0283]: type annotations needed
+ --> $DIR/const_eval_resolve_canonical.rs:29:10
+ |
+LL | _q = foo::<_, 2>(_q);
+ | ^^^^^^^^^^^ cannot infer type
+ |
+note: multiple `impl`s satisfying `(): Foo<{ N + 1 }>` found
+ --> $DIR/const_eval_resolve_canonical.rs:8:1
+ |
+LL | impl Foo<0> for () {
+ | ^^^^^^^^^^^^^^^^^^
+...
+LL | impl Foo<3> for () {
+ | ^^^^^^^^^^^^^^^^^^
+note: required by a bound in `foo`
+ --> $DIR/const_eval_resolve_canonical.rs:18:9
+ |
+LL | fn foo<T, const N: usize>(_: T) -> <() as Foo<{ N + 1 }>>::Assoc
+ | --- required by a bound in this
+LL | where
+LL | (): Foo<{ N + 1 }>,
+ | ^^^^^^^^^^^^^^ required by this bound in `foo`
+
+error: aborting due to 2 previous errors
+
+Some errors have detailed explanations: E0282, E0283.
+For more information about an error, try `rustc --explain E0282`.
diff --git a/src/test/ui/const-generics/generic_const_exprs/unused-complex-default-expr.rs b/src/test/ui/const-generics/generic_const_exprs/unused-complex-default-expr.rs
index 67fefd07ec0..9580f8a7fbc 100644
--- a/src/test/ui/const-generics/generic_const_exprs/unused-complex-default-expr.rs
+++ b/src/test/ui/const-generics/generic_const_exprs/unused-complex-default-expr.rs
@@ -1,5 +1,5 @@
// check-pass
-#![feature(generic_const_exprs, const_generics_defaults)]
+#![feature(generic_const_exprs)]
#![allow(incomplete_features)]
struct Foo<const N: usize, const M: usize = { N + 1 }>;
struct Bar<const N: usize>(Foo<N, 3>);
diff --git a/src/test/ui/const-generics/invalid-enum.rs b/src/test/ui/const-generics/invalid-enum.rs
index bc3c09238f2..cb6d05349db 100644
--- a/src/test/ui/const-generics/invalid-enum.rs
+++ b/src/test/ui/const-generics/invalid-enum.rs
@@ -1,4 +1,4 @@
-#![feature(adt_const_params, const_generics_defaults)]
+#![feature(adt_const_params)]
#![allow(incomplete_features)]
#[derive(PartialEq, Eq)]
diff --git a/src/test/ui/const-generics/issues/issue-72845.rs b/src/test/ui/const-generics/issues/issue-72845.rs
new file mode 100644
index 00000000000..bea5dc8ba21
--- /dev/null
+++ b/src/test/ui/const-generics/issues/issue-72845.rs
@@ -0,0 +1,49 @@
+#![feature(generic_const_exprs)]
+#![feature(specialization)]
+#![allow(incomplete_features)]
+
+//--------------------------------------------------
+
+trait Depth {
+ const C: usize;
+}
+
+trait Type {
+ type AT: Depth;
+}
+
+//--------------------------------------------------
+
+enum Predicate<const B: bool> {}
+
+trait Satisfied {}
+
+impl Satisfied for Predicate<true> {}
+
+//--------------------------------------------------
+
+trait Spec1 {}
+
+impl<T: Type> Spec1 for T where Predicate<{T::AT::C > 0}>: Satisfied {}
+
+trait Spec2 {}
+
+//impl<T: Type > Spec2 for T where Predicate<{T::AT::C > 1}>: Satisfied {}
+impl<T: Type > Spec2 for T where Predicate<true>: Satisfied {}
+
+//--------------------------------------------------
+
+trait Foo {
+ fn Bar();
+}
+
+impl<T: Spec1> Foo for T {
+ default fn Bar() {}
+}
+
+impl<T: Spec2> Foo for T {
+//~^ ERROR conflicting implementations of trait
+ fn Bar() {}
+}
+
+fn main() {}
diff --git a/src/test/ui/const-generics/issues/issue-72845.stderr b/src/test/ui/const-generics/issues/issue-72845.stderr
new file mode 100644
index 00000000000..631c8605fb4
--- /dev/null
+++ b/src/test/ui/const-generics/issues/issue-72845.stderr
@@ -0,0 +1,12 @@
+error[E0119]: conflicting implementations of trait `Foo`
+ --> $DIR/issue-72845.rs:44:1
+ |
+LL | impl<T: Spec1> Foo for T {
+ | ------------------------ first implementation here
+...
+LL | impl<T: Spec2> Foo for T {
+ | ^^^^^^^^^^^^^^^^^^^^^^^^ conflicting implementation
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0119`.
diff --git a/src/test/ui/const-generics/issues/issue-79674.rs b/src/test/ui/const-generics/issues/issue-79674.rs
new file mode 100644
index 00000000000..2f196533dd8
--- /dev/null
+++ b/src/test/ui/const-generics/issues/issue-79674.rs
@@ -0,0 +1,28 @@
+#![feature(const_fn_trait_bound, generic_const_exprs)]
+#![allow(incomplete_features)]
+
+trait MiniTypeId {
+ const TYPE_ID: u64;
+}
+
+impl<T> MiniTypeId for T {
+ const TYPE_ID: u64 = 0;
+}
+
+enum Lift<const V: bool> {}
+
+trait IsFalse {}
+impl IsFalse for Lift<false> {}
+
+const fn is_same_type<T: MiniTypeId, U: MiniTypeId>() -> bool {
+ T::TYPE_ID == U::TYPE_ID
+}
+
+fn requires_distinct<A, B>(_a: A, _b: B) where
+ A: MiniTypeId, B: MiniTypeId,
+ Lift<{is_same_type::<A, B>()}>: IsFalse {}
+
+fn main() {
+ requires_distinct("str", 12);
+ //~^ ERROR mismatched types
+}
diff --git a/src/test/ui/const-generics/issues/issue-79674.stderr b/src/test/ui/const-generics/issues/issue-79674.stderr
new file mode 100644
index 00000000000..8c029289cbb
--- /dev/null
+++ b/src/test/ui/const-generics/issues/issue-79674.stderr
@@ -0,0 +1,12 @@
+error[E0308]: mismatched types
+ --> $DIR/issue-79674.rs:26:5
+ |
+LL | requires_distinct("str", 12);
+ | ^^^^^^^^^^^^^^^^^ expected `true`, found `false`
+ |
+ = note: expected type `true`
+ found type `false`
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0308`.
diff --git a/src/test/ui/const-generics/issues/issue-83249.rs b/src/test/ui/const-generics/issues/issue-83249.rs
new file mode 100644
index 00000000000..65148c55ee5
--- /dev/null
+++ b/src/test/ui/const-generics/issues/issue-83249.rs
@@ -0,0 +1,23 @@
+#![allow(incomplete_features)]
+#![feature(generic_const_exprs)]
+
+trait Foo {
+ const N: usize;
+}
+
+impl Foo for u8 {
+ const N: usize = 1;
+}
+
+fn foo<T: Foo>(_: [u8; T::N]) -> T {
+ todo!()
+}
+
+pub fn bar() {
+ let _: u8 = foo([0; 1]);
+
+ let _ = foo([0; 1]);
+ //~^ ERROR type annotations needed
+}
+
+fn main() {}
diff --git a/src/test/ui/const-generics/issues/issue-83249.stderr b/src/test/ui/const-generics/issues/issue-83249.stderr
new file mode 100644
index 00000000000..402b3aa2d61
--- /dev/null
+++ b/src/test/ui/const-generics/issues/issue-83249.stderr
@@ -0,0 +1,11 @@
+error[E0282]: type annotations needed
+ --> $DIR/issue-83249.rs:19:13
+ |
+LL | let _ = foo([0; 1]);
+ | - ^^^ cannot infer type for type parameter `T` declared on the function `foo`
+ | |
+ | consider giving this pattern a type
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0282`.
diff --git a/src/test/ui/const-generics/issues/issue-83288.rs b/src/test/ui/const-generics/issues/issue-83288.rs
new file mode 100644
index 00000000000..a24596d242e
--- /dev/null
+++ b/src/test/ui/const-generics/issues/issue-83288.rs
@@ -0,0 +1,69 @@
+// build-pass
+
+#![allow(incomplete_features)]
+#![feature(generic_const_exprs)]
+
+use std::{marker::PhantomData, ops::Mul};
+
+pub enum Nil {}
+pub struct Cons<T, L> {
+ _phantom: PhantomData<(T, L)>,
+}
+
+pub trait Indices<const N: usize> {
+ const RANK: usize;
+ const NUM_ELEMS: usize;
+}
+
+impl<const N: usize> Indices<N> for Nil {
+ const RANK: usize = 0;
+ const NUM_ELEMS: usize = 1;
+}
+
+impl<T, I: Indices<N>, const N: usize> Indices<N> for Cons<T, I> {
+ const RANK: usize = I::RANK + 1;
+ const NUM_ELEMS: usize = I::NUM_ELEMS * N;
+}
+
+pub trait Concat<J> {
+ type Output;
+}
+
+impl<J> Concat<J> for Nil {
+ type Output = J;
+}
+
+impl<T, I, J> Concat<J> for Cons<T, I>
+where
+ I: Concat<J>,
+{
+ type Output = Cons<T, <I as Concat<J>>::Output>;
+}
+
+pub struct Tensor<I: Indices<N>, const N: usize>
+where
+ [u8; I::NUM_ELEMS]: Sized,
+{
+ pub data: [u8; I::NUM_ELEMS],
+ _phantom: PhantomData<I>,
+}
+
+impl<I: Indices<N>, J: Indices<N>, const N: usize> Mul<Tensor<J, N>> for Tensor<I, N>
+where
+ I: Concat<J>,
+ <I as Concat<J>>::Output: Indices<N>,
+ [u8; I::NUM_ELEMS]: Sized,
+ [u8; J::NUM_ELEMS]: Sized,
+ [u8; <I as Concat<J>>::Output::NUM_ELEMS]: Sized,
+{
+ type Output = Tensor<<I as Concat<J>>::Output, N>;
+
+ fn mul(self, _rhs: Tensor<J, N>) -> Self::Output {
+ Tensor {
+ data: [0u8; <I as Concat<J>>::Output::NUM_ELEMS],
+ _phantom: PhantomData,
+ }
+ }
+}
+
+fn main() {}
diff --git a/src/test/ui/const-generics/issues/issue-83765.rs b/src/test/ui/const-generics/issues/issue-83765.rs
new file mode 100644
index 00000000000..68536348d38
--- /dev/null
+++ b/src/test/ui/const-generics/issues/issue-83765.rs
@@ -0,0 +1,115 @@
+#![feature(generic_const_exprs)]
+#![allow(incomplete_features)]
+
+trait TensorDimension {
+ const DIM : usize;
+ const ISSCALAR : bool = Self::DIM == 0;
+ fn is_scalar(&self) -> bool {Self::ISSCALAR}
+}
+
+trait TensorSize : TensorDimension {
+ fn size(&self) -> [usize;Self::DIM];
+ fn inbounds(&self,index : [usize;Self::DIM]) -> bool {
+ index.iter().zip(self.size().iter()).all(|(i,s)| i < s)
+ }
+}
+
+
+trait Broadcastable: TensorSize + Sized {
+ type Element;
+ fn bget(&self, index:[usize;Self::DIM]) -> Option<Self::Element>;
+ fn lazy_updim<const NEWDIM : usize>(&self, size : [usize;NEWDIM] ) ->
+ LazyUpdim<Self,{Self::DIM},NEWDIM>
+ {
+ assert!(NEWDIM >= Self::DIM,
+ "Updimmed tensor cannot have fewer indices than the initial one.");
+ LazyUpdim {size,reference:&self}
+ }
+ fn bmap<T,F :Fn(Self::Element) -> T>(&self,foo : F) -> BMap<T,Self,F,{Self::DIM}>{
+ BMap {reference:self,closure : foo}
+ }
+}
+
+
+struct LazyUpdim<'a,T : Broadcastable,const OLDDIM : usize, const DIM : usize> {
+ size : [usize;DIM],
+ reference : &'a T
+}
+
+impl<'a,T : Broadcastable,const DIM : usize> TensorDimension for LazyUpdim<'a,T,{T::DIM},DIM> {
+ const DIM : usize = DIM;
+}
+
+impl<'a,T : Broadcastable,const DIM : usize> TensorSize for LazyUpdim<'a,T,{T::DIM},DIM> {
+ fn size(&self) -> [usize;DIM] {self.size}
+ //~^ ERROR method not compatible with trait
+}
+
+impl<'a,T : Broadcastable,const DIM : usize> Broadcastable for LazyUpdim<'a,T,{T::DIM},DIM>
+{
+ type Element = T::Element;
+ fn bget(&self,index:[usize;DIM]) -> Option<Self::Element> {
+ //~^ ERROR method not compatible with trait
+ assert!(DIM >= T::DIM);
+ if !self.inbounds(index) {return None}
+ //~^ ERROR unconstrained generic constant
+ //~| ERROR mismatched types
+ let size = self.size();
+ //~^ ERROR unconstrained generic constant
+ let newindex : [usize;T::DIM] = Default::default();
+ //~^ ERROR the trait bound `[usize; _]: Default` is not satisfied
+ self.reference.bget(newindex)
+ }
+}
+
+struct BMap<'a,R, T : Broadcastable, F : Fn(T::Element) -> R , const DIM: usize> {
+ reference : &'a T,
+ closure : F
+}
+
+impl<'a,R, T : Broadcastable, F : Fn(T::Element) -> R,
+ const DIM: usize> TensorDimension for BMap<'a,R,T,F,DIM> {
+
+ const DIM : usize = DIM;
+}
+impl<'a,R, T : Broadcastable, F : Fn(T::Element) -> R ,
+ const DIM: usize> TensorSize for BMap<'a,R,T,F,DIM> {
+
+ fn size(&self) -> [usize;DIM] {self.reference.size()}
+ //~^ ERROR unconstrained generic constant
+ //~| ERROR mismatched types
+ //~| ERROR method not compatible with trait
+}
+
+impl<'a,R, T : Broadcastable, F : Fn(T::Element) -> R ,
+ const DIM: usize> Broadcastable for BMap<'a,R,T,F,DIM> {
+
+ type Element = R;
+ fn bget(&self,index:[usize;DIM]) -> Option<Self::Element> {
+ //~^ ERROR method not compatible with trait
+ self.reference.bget(index).map(&self.closure)
+ //~^ ERROR unconstrained generic constant
+ //~| ERROR mismatched types
+ }
+}
+
+impl<T> TensorDimension for Vec<T> {
+ const DIM : usize = 1;
+}
+impl<T> TensorSize for Vec<T> {
+ fn size(&self) -> [usize;1] {[self.len()]}
+}
+impl<T: Clone> Broadcastable for Vec<T> {
+ type Element = T;
+ fn bget(& self,index : [usize;1]) -> Option<T> {
+ self.get(index[0]).cloned()
+ }
+}
+
+fn main() {
+ let v = vec![1,2,3];
+ let bv = v.lazy_updim([3,4]);
+ let bbv = bv.bmap(|x| x*x);
+
+ println!("The size of v is {:?}",bbv.bget([0,2]).expect("Out of bounds."));
+}
diff --git a/src/test/ui/const-generics/issues/issue-83765.stderr b/src/test/ui/const-generics/issues/issue-83765.stderr
new file mode 100644
index 00000000000..a49f850717f
--- /dev/null
+++ b/src/test/ui/const-generics/issues/issue-83765.stderr
@@ -0,0 +1,130 @@
+error[E0308]: method not compatible with trait
+ --> $DIR/issue-83765.rs:44:5
+ |
+LL | fn size(&self) -> [usize;DIM] {self.size}
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected `Self::DIM`, found `DIM`
+ |
+ = note: expected type `Self::DIM`
+ found type `DIM`
+
+error[E0308]: method not compatible with trait
+ --> $DIR/issue-83765.rs:51:5
+ |
+LL | fn bget(&self,index:[usize;DIM]) -> Option<Self::Element> {
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected `Self::DIM`, found `DIM`
+ |
+ = note: expected type `Self::DIM`
+ found type `DIM`
+
+error[E0308]: method not compatible with trait
+ --> $DIR/issue-83765.rs:78:5
+ |
+LL | fn size(&self) -> [usize;DIM] {self.reference.size()}
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected `Self::DIM`, found `DIM`
+ |
+ = note: expected type `Self::DIM`
+ found type `DIM`
+
+error[E0308]: method not compatible with trait
+ --> $DIR/issue-83765.rs:88:5
+ |
+LL | fn bget(&self,index:[usize;DIM]) -> Option<Self::Element> {
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected `Self::DIM`, found `DIM`
+ |
+ = note: expected type `Self::DIM`
+ found type `DIM`
+
+error: unconstrained generic constant
+ --> $DIR/issue-83765.rs:54:18
+ |
+LL | if !self.inbounds(index) {return None}
+ | ^^^^^^^^
+ |
+ = help: try adding a `where` bound using this expression: `where [(); Self::DIM]:`
+note: required by a bound in `TensorSize::inbounds`
+ --> $DIR/issue-83765.rs:12:38
+ |
+LL | fn inbounds(&self,index : [usize;Self::DIM]) -> bool {
+ | ^^^^^^^^^ required by this bound in `TensorSize::inbounds`
+
+error[E0308]: mismatched types
+ --> $DIR/issue-83765.rs:54:27
+ |
+LL | if !self.inbounds(index) {return None}
+ | ^^^^^ expected `Self::DIM`, found `DIM`
+ |
+ = note: expected type `Self::DIM`
+ found type `DIM`
+
+error: unconstrained generic constant
+ --> $DIR/issue-83765.rs:57:25
+ |
+LL | let size = self.size();
+ | ^^^^
+ |
+ = help: try adding a `where` bound using this expression: `where [(); Self::DIM]:`
+note: required by a bound in `TensorSize::size`
+ --> $DIR/issue-83765.rs:11:30
+ |
+LL | fn size(&self) -> [usize;Self::DIM];
+ | ^^^^^^^^^ required by this bound in `TensorSize::size`
+
+error[E0277]: the trait bound `[usize; _]: Default` is not satisfied
+ --> $DIR/issue-83765.rs:59:41
+ |
+LL | let newindex : [usize;T::DIM] = Default::default();
+ | ^^^^^^^^^^^^^^^^ the trait `Default` is not implemented for `[usize; _]`
+ |
+help: consider introducing a `where` bound, but there might be an alternative better way to express this requirement
+ |
+LL | impl<'a,T : Broadcastable,const DIM : usize> Broadcastable for LazyUpdim<'a,T,{T::DIM},DIM> where [usize; _]: Default
+ | +++++++++++++++++++++++++
+
+error: unconstrained generic constant
+ --> $DIR/issue-83765.rs:78:51
+ |
+LL | fn size(&self) -> [usize;DIM] {self.reference.size()}
+ | ^^^^
+ |
+ = help: try adding a `where` bound using this expression: `where [(); Self::DIM]:`
+note: required by a bound in `TensorSize::size`
+ --> $DIR/issue-83765.rs:11:30
+ |
+LL | fn size(&self) -> [usize;Self::DIM];
+ | ^^^^^^^^^ required by this bound in `TensorSize::size`
+
+error[E0308]: mismatched types
+ --> $DIR/issue-83765.rs:78:36
+ |
+LL | fn size(&self) -> [usize;DIM] {self.reference.size()}
+ | ^^^^^^^^^^^^^^^^^^^^^ expected `DIM`, found `Self::DIM`
+ |
+ = note: expected type `DIM`
+ found type `Self::DIM`
+
+error: unconstrained generic constant
+ --> $DIR/issue-83765.rs:90:24
+ |
+LL | self.reference.bget(index).map(&self.closure)
+ | ^^^^
+ |
+ = help: try adding a `where` bound using this expression: `where [(); Self::DIM]:`
+note: required by a bound in `Broadcastable::bget`
+ --> $DIR/issue-83765.rs:20:33
+ |
+LL | fn bget(&self, index:[usize;Self::DIM]) -> Option<Self::Element>;
+ | ^^^^^^^^^ required by this bound in `Broadcastable::bget`
+
+error[E0308]: mismatched types
+ --> $DIR/issue-83765.rs:90:29
+ |
+LL | self.reference.bget(index).map(&self.closure)
+ | ^^^^^ expected `Self::DIM`, found `DIM`
+ |
+ = note: expected type `Self::DIM`
+ found type `DIM`
+
+error: aborting due to 12 previous errors
+
+Some errors have detailed explanations: E0277, E0308.
+For more information about an error, try `rustc --explain E0277`.
diff --git a/src/test/ui/const-generics/issues/issue-86033.rs b/src/test/ui/const-generics/issues/issue-86033.rs
new file mode 100644
index 00000000000..cf08f722fbb
--- /dev/null
+++ b/src/test/ui/const-generics/issues/issue-86033.rs
@@ -0,0 +1,20 @@
+// check-pass
+
+#![feature(generic_const_exprs)]
+#![allow(incomplete_features)]
+
+pub trait IsTrue<const T: bool> {}
+impl IsTrue<true> for () {}
+
+pub trait IsZST {}
+
+impl<T> IsZST for T
+where
+ (): IsTrue<{ std::mem::size_of::<T>() == 0 }>
+{}
+
+fn _func() -> impl IsZST {
+ || {}
+}
+
+fn main() {}
diff --git a/src/test/ui/const-generics/issues/issue-87470.rs b/src/test/ui/const-generics/issues/issue-87470.rs
new file mode 100644
index 00000000000..d60181a418a
--- /dev/null
+++ b/src/test/ui/const-generics/issues/issue-87470.rs
@@ -0,0 +1,24 @@
+// build-pass
+
+#![feature(generic_const_exprs)]
+#![allow(incomplete_features)]
+
+pub trait TraitWithConst {
+ const SOME_CONST: usize;
+}
+
+pub trait OtherTrait: TraitWithConst {
+ fn some_fn(self) -> [u8 ; <Self as TraitWithConst>::SOME_CONST];
+}
+
+impl TraitWithConst for f32 {
+ const SOME_CONST: usize = 32;
+}
+
+impl OtherTrait for f32 {
+ fn some_fn(self) -> [u8 ; <Self as TraitWithConst>::SOME_CONST] {
+ [0; 32]
+ }
+}
+
+fn main() {}
diff --git a/src/test/ui/const-generics/issues/issue-87964.rs b/src/test/ui/const-generics/issues/issue-87964.rs
new file mode 100644
index 00000000000..116686abb9e
--- /dev/null
+++ b/src/test/ui/const-generics/issues/issue-87964.rs
@@ -0,0 +1,29 @@
+// build-pass
+
+#![feature(generic_const_exprs)]
+#![allow(incomplete_features)]
+
+pub trait Target {
+ const LENGTH: usize;
+}
+
+
+pub struct Container<T: Target>
+where
+ [(); T::LENGTH]: Sized,
+{
+ _target: T,
+}
+
+impl<T: Target> Container<T>
+where
+ [(); T::LENGTH]: Sized,
+{
+ pub fn start(
+ _target: T,
+ ) -> Container<T> {
+ Container { _target }
+ }
+}
+
+fn main() {}
diff --git a/src/test/ui/const-generics/issues/issue-88468.rs b/src/test/ui/const-generics/issues/issue-88468.rs
new file mode 100644
index 00000000000..914047236ab
--- /dev/null
+++ b/src/test/ui/const-generics/issues/issue-88468.rs
@@ -0,0 +1,13 @@
+// check-pass
+
+#![allow(incomplete_features)]
+#![feature(generic_const_exprs)]
+
+pub struct Assert<const COND: bool>();
+pub trait IsTrue {}
+impl IsTrue for Assert<true> {}
+
+pub trait IsNotZST {}
+impl<T> IsNotZST for T where Assert<{ std::mem::size_of::<T>() > 0 }>: IsTrue {}
+
+fn main() {}
diff --git a/src/test/ui/const-generics/issues/issue-89146.rs b/src/test/ui/const-generics/issues/issue-89146.rs
new file mode 100644
index 00000000000..e3540f46f1e
--- /dev/null
+++ b/src/test/ui/const-generics/issues/issue-89146.rs
@@ -0,0 +1,26 @@
+// build-pass
+
+#![allow(incomplete_features)]
+#![feature(generic_const_exprs)]
+
+pub trait Foo {
+ const SIZE: usize;
+
+ fn to_bytes(&self) -> [u8; Self::SIZE];
+}
+
+pub fn bar<G: Foo>(a: &G) -> u8
+where
+ [(); G::SIZE]: Sized,
+{
+ deeper_bar(a)
+}
+
+fn deeper_bar<G: Foo>(a: &G) -> u8
+where
+ [(); G::SIZE]: Sized,
+{
+ a.to_bytes()[0]
+}
+
+fn main() {}
diff --git a/src/test/ui/const-generics/issues/issue-89320.rs b/src/test/ui/const-generics/issues/issue-89320.rs
new file mode 100644
index 00000000000..afa5c8fab74
--- /dev/null
+++ b/src/test/ui/const-generics/issues/issue-89320.rs
@@ -0,0 +1,19 @@
+// build-pass
+
+#![feature(generic_const_exprs)]
+#![allow(incomplete_features)]
+
+pub trait Enumerable {
+ const N: usize;
+}
+
+#[derive(Clone)]
+pub struct SymmetricGroup<S>
+where
+ S: Enumerable,
+ [(); S::N]: Sized,
+{
+ _phantom: std::marker::PhantomData<S>,
+}
+
+fn main() {}
diff --git a/src/test/ui/const-generics/issues/issue-90318.rs b/src/test/ui/const-generics/issues/issue-90318.rs
new file mode 100644
index 00000000000..0c640a5ef71
--- /dev/null
+++ b/src/test/ui/const-generics/issues/issue-90318.rs
@@ -0,0 +1,32 @@
+#![feature(const_type_id)]
+#![feature(generic_const_exprs)]
+#![feature(core_intrinsics)]
+#![allow(incomplete_features)]
+
+use std::any::TypeId;
+
+struct If<const B: bool>;
+pub trait True {}
+impl True for If<true> {}
+
+fn consume<T: 'static>(_val: T)
+where
+ If<{ TypeId::of::<T>() != TypeId::of::<()>() }>: True,
+ //~^ ERROR: overly complex generic constant
+ //~| ERROR: calls in constants are limited to constant functions
+{
+}
+
+fn test<T: 'static>()
+where
+ If<{ TypeId::of::<T>() != TypeId::of::<()>() }>: True,
+ //~^ ERROR: overly complex generic constant
+ //~| ERROR: calls in constants are limited to constant functions
+{
+}
+
+fn main() {
+ let a = ();
+ consume(0i32);
+ consume(a);
+}
diff --git a/src/test/ui/const-generics/issues/issue-90318.stderr b/src/test/ui/const-generics/issues/issue-90318.stderr
new file mode 100644
index 00000000000..2b8afe2ef09
--- /dev/null
+++ b/src/test/ui/const-generics/issues/issue-90318.stderr
@@ -0,0 +1,37 @@
+error: overly complex generic constant
+ --> $DIR/issue-90318.rs:14:8
+ |
+LL | If<{ TypeId::of::<T>() != TypeId::of::<()>() }>: True,
+ | ^^-----------------^^^^^^^^^^^^^^^^^^^^^^^^
+ | |
+ | borrowing is not supported in generic constants
+ |
+ = help: consider moving this anonymous constant into a `const` function
+ = note: this operation may be supported in the future
+
+error[E0015]: calls in constants are limited to constant functions, tuple structs and tuple variants
+ --> $DIR/issue-90318.rs:14:10
+ |
+LL | If<{ TypeId::of::<T>() != TypeId::of::<()>() }>: True,
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: overly complex generic constant
+ --> $DIR/issue-90318.rs:22:8
+ |
+LL | If<{ TypeId::of::<T>() != TypeId::of::<()>() }>: True,
+ | ^^-----------------^^^^^^^^^^^^^^^^^^^^^^^^
+ | |
+ | borrowing is not supported in generic constants
+ |
+ = help: consider moving this anonymous constant into a `const` function
+ = note: this operation may be supported in the future
+
+error[E0015]: calls in constants are limited to constant functions, tuple structs and tuple variants
+ --> $DIR/issue-90318.rs:22:10
+ |
+LL | If<{ TypeId::of::<T>() != TypeId::of::<()>() }>: True,
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: aborting due to 4 previous errors
+
+For more information about this error, try `rustc --explain E0015`.
diff --git a/src/test/ui/const-generics/issues/issue-90455.rs b/src/test/ui/const-generics/issues/issue-90455.rs
new file mode 100644
index 00000000000..a580410cf37
--- /dev/null
+++ b/src/test/ui/const-generics/issues/issue-90455.rs
@@ -0,0 +1,12 @@
+#![feature(generic_const_exprs, adt_const_params)]
+#![allow(incomplete_features)]
+
+struct FieldElement<const N: &'static str> {
+ n: [u64; num_limbs(N)],
+ //~^ ERROR unconstrained generic constant
+}
+const fn num_limbs(_: &str) -> usize {
+ 0
+}
+
+fn main() {}
diff --git a/src/test/ui/const-generics/issues/issue-90455.stderr b/src/test/ui/const-generics/issues/issue-90455.stderr
new file mode 100644
index 00000000000..724d7f42e69
--- /dev/null
+++ b/src/test/ui/const-generics/issues/issue-90455.stderr
@@ -0,0 +1,10 @@
+error: unconstrained generic constant
+ --> $DIR/issue-90455.rs:5:8
+ |
+LL | n: [u64; num_limbs(N)],
+ | ^^^^^^^^^^^^^^^^^^^
+ |
+ = help: try adding a `where` bound using this expression: `where [(); num_limbs(N)]:`
+
+error: aborting due to previous error
+
diff --git a/src/test/ui/const-generics/min_const_generics/const-expression-suggest-missing-braces.rs b/src/test/ui/const-generics/min_const_generics/const-expression-suggest-missing-braces.rs
index ae8863c567d..e12e07a28e7 100644
--- a/src/test/ui/const-generics/min_const_generics/const-expression-suggest-missing-braces.rs
+++ b/src/test/ui/const-generics/min_const_generics/const-expression-suggest-missing-braces.rs
@@ -12,8 +12,6 @@ fn b() {
//~^ ERROR expected trait, found constant `BAR`
//~| ERROR expected trait, found constant `BAR`
//~| ERROR type provided when a constant was expected
- //~| WARN trait objects without an explicit `dyn` are deprecated
- //~| WARN this is accepted in the current edition
}
fn c() {
foo::<3 + 3>(); //~ ERROR expressions must be enclosed in braces
diff --git a/src/test/ui/const-generics/min_const_generics/const-expression-suggest-missing-braces.stderr b/src/test/ui/const-generics/min_const_generics/const-expression-suggest-missing-braces.stderr
index 380c17c8e62..d9bcc523b1f 100644
--- a/src/test/ui/const-generics/min_const_generics/const-expression-suggest-missing-braces.stderr
+++ b/src/test/ui/const-generics/min_const_generics/const-expression-suggest-missing-braces.stderr
@@ -10,7 +10,7 @@ LL | foo::<{ BAR + 3 }>();
| + +
error: expressions must be enclosed in braces to be used as const generic arguments
- --> $DIR/const-expression-suggest-missing-braces.rs:19:11
+ --> $DIR/const-expression-suggest-missing-braces.rs:17:11
|
LL | foo::<3 + 3>();
| ^^^^^
@@ -21,7 +21,7 @@ LL | foo::<{ 3 + 3 }>();
| + +
error: expected one of `,` or `>`, found `-`
- --> $DIR/const-expression-suggest-missing-braces.rs:22:15
+ --> $DIR/const-expression-suggest-missing-braces.rs:20:15
|
LL | foo::<BAR - 3>();
| ^ expected one of `,` or `>`
@@ -32,7 +32,7 @@ LL | foo::<{ BAR - 3 }>();
| + +
error: expected one of `,` or `>`, found `-`
- --> $DIR/const-expression-suggest-missing-braces.rs:25:15
+ --> $DIR/const-expression-suggest-missing-braces.rs:23:15
|
LL | foo::<BAR - BAR>();
| ^ expected one of `,` or `>`
@@ -43,7 +43,7 @@ LL | foo::<{ BAR - BAR }>();
| + +
error: expressions must be enclosed in braces to be used as const generic arguments
- --> $DIR/const-expression-suggest-missing-braces.rs:28:11
+ --> $DIR/const-expression-suggest-missing-braces.rs:26:11
|
LL | foo::<100 - BAR>();
| ^^^^^^^^^
@@ -54,7 +54,7 @@ LL | foo::<{ 100 - BAR }>();
| + +
error: expected one of `,` or `>`, found `(`
- --> $DIR/const-expression-suggest-missing-braces.rs:31:19
+ --> $DIR/const-expression-suggest-missing-braces.rs:29:19
|
LL | foo::<bar<i32>()>();
| ^ expected one of `,` or `>`
@@ -65,7 +65,7 @@ LL | foo::<{ bar<i32>() }>();
| + +
error: expected one of `,` or `>`, found `(`
- --> $DIR/const-expression-suggest-missing-braces.rs:34:21
+ --> $DIR/const-expression-suggest-missing-braces.rs:32:21
|
LL | foo::<bar::<i32>()>();
| ^ expected one of `,` or `>`
@@ -76,7 +76,7 @@ LL | foo::<{ bar::<i32>() }>();
| + +
error: expected one of `,` or `>`, found `(`
- --> $DIR/const-expression-suggest-missing-braces.rs:37:21
+ --> $DIR/const-expression-suggest-missing-braces.rs:35:21
|
LL | foo::<bar::<i32>() + BAR>();
| ^ expected one of `,` or `>`
@@ -87,7 +87,7 @@ LL | foo::<{ bar::<i32>() + BAR }>();
| + +
error: expected one of `,` or `>`, found `(`
- --> $DIR/const-expression-suggest-missing-braces.rs:40:21
+ --> $DIR/const-expression-suggest-missing-braces.rs:38:21
|
LL | foo::<bar::<i32>() - BAR>();
| ^ expected one of `,` or `>`
@@ -98,7 +98,7 @@ LL | foo::<{ bar::<i32>() - BAR }>();
| + +
error: expected one of `,` or `>`, found `-`
- --> $DIR/const-expression-suggest-missing-braces.rs:43:15
+ --> $DIR/const-expression-suggest-missing-braces.rs:41:15
|
LL | foo::<BAR - bar::<i32>()>();
| ^ expected one of `,` or `>`
@@ -109,7 +109,7 @@ LL | foo::<{ BAR - bar::<i32>() }>();
| + +
error: expected one of `,` or `>`, found `-`
- --> $DIR/const-expression-suggest-missing-braces.rs:46:15
+ --> $DIR/const-expression-suggest-missing-braces.rs:44:15
|
LL | foo::<BAR - bar::<i32>()>();
| ^ expected one of `,` or `>`
@@ -131,23 +131,13 @@ error[E0404]: expected trait, found constant `BAR`
LL | foo::<BAR + BAR>();
| ^^^ not a trait
-warning: trait objects without an explicit `dyn` are deprecated
- --> $DIR/const-expression-suggest-missing-braces.rs:11:11
- |
-LL | foo::<BAR + BAR>();
- | ^^^^^^^^^ help: use `dyn`: `dyn BAR + BAR`
- |
- = note: `#[warn(bare_trait_objects)]` on by default
- = warning: this is accepted in the current edition (Rust 2015) but is a hard error in Rust 2021!
- = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2021/warnings-promoted-to-error.html>
-
error[E0747]: type provided when a constant was expected
--> $DIR/const-expression-suggest-missing-braces.rs:11:11
|
LL | foo::<BAR + BAR>();
| ^^^^^^^^^
-error: aborting due to 14 previous errors; 1 warning emitted
+error: aborting due to 14 previous errors
Some errors have detailed explanations: E0404, E0747.
For more information about an error, try `rustc --explain E0404`.
diff --git a/src/test/ui/const-generics/min_const_generics/const_default_first.rs b/src/test/ui/const-generics/min_const_generics/const_default_first.rs
index bba4e68d4cc..eafafb8a274 100644
--- a/src/test/ui/const-generics/min_const_generics/const_default_first.rs
+++ b/src/test/ui/const-generics/min_const_generics/const_default_first.rs
@@ -1,6 +1,5 @@
#![crate_type = "lib"]
-#![feature(const_generics_defaults)]
-#![allow(incomplete_features, dead_code)]
+#![allow(dead_code)]
struct Both<const N: usize=3, T> {
//~^ ERROR: generic parameters with a default must be
diff --git a/src/test/ui/const-generics/min_const_generics/const_default_first.stderr b/src/test/ui/const-generics/min_const_generics/const_default_first.stderr
index 1a333642f0c..0d5a393cb7b 100644
--- a/src/test/ui/const-generics/min_const_generics/const_default_first.stderr
+++ b/src/test/ui/const-generics/min_const_generics/const_default_first.stderr
@@ -1,5 +1,5 @@
error: generic parameters with a default must be trailing
- --> $DIR/const_default_first.rs:5:19
+ --> $DIR/const_default_first.rs:4:19
|
LL | struct Both<const N: usize=3, T> {
| ^
diff --git a/src/test/ui/const-generics/min_const_generics/default_function_param.rs b/src/test/ui/const-generics/min_const_generics/default_function_param.rs
index b47dd2f618c..92d495ef665 100644
--- a/src/test/ui/const-generics/min_const_generics/default_function_param.rs
+++ b/src/test/ui/const-generics/min_const_generics/default_function_param.rs
@@ -1,5 +1,4 @@
#![crate_type = "lib"]
-#![feature(const_generics_defaults)]
fn foo<const SIZE: usize = 5usize>() {}
//~^ ERROR defaults for const parameters are
diff --git a/src/test/ui/const-generics/min_const_generics/default_function_param.stderr b/src/test/ui/const-generics/min_const_generics/default_function_param.stderr
index 11df8621faa..07dcd57dab8 100644
--- a/src/test/ui/const-generics/min_const_generics/default_function_param.stderr
+++ b/src/test/ui/const-generics/min_const_generics/default_function_param.stderr
@@ -1,5 +1,5 @@
error: defaults for const parameters are only allowed in `struct`, `enum`, `type`, or `trait` definitions
- --> $DIR/default_function_param.rs:4:14
+ --> $DIR/default_function_param.rs:3:14
|
LL | fn foo<const SIZE: usize = 5usize>() {}
| ^^^^
diff --git a/src/test/ui/const-generics/min_const_generics/default_trait_param.rs b/src/test/ui/const-generics/min_const_generics/default_trait_param.rs
index 14bac473ed9..9cd5e3279ff 100644
--- a/src/test/ui/const-generics/min_const_generics/default_trait_param.rs
+++ b/src/test/ui/const-generics/min_const_generics/default_trait_param.rs
@@ -1,4 +1,4 @@
+// check-pass
trait Foo<const KIND: bool = true> {}
-//~^ ERROR default values for const generic parameters are experimental
fn main() {}
diff --git a/src/test/ui/const-generics/min_const_generics/default_trait_param.stderr b/src/test/ui/const-generics/min_const_generics/default_trait_param.stderr
deleted file mode 100644
index 5617b35ad01..00000000000
--- a/src/test/ui/const-generics/min_const_generics/default_trait_param.stderr
+++ /dev/null
@@ -1,12 +0,0 @@
-error[E0658]: default values for const generic parameters are experimental
- --> $DIR/default_trait_param.rs:1:28
- |
-LL | trait Foo<const KIND: bool = true> {}
- | ^^^^^^
- |
- = note: see issue #44580 <https://github.com/rust-lang/rust/issues/44580> for more information
- = help: add `#![feature(const_generics_defaults)]` to the crate attributes to enable
-
-error: aborting due to previous error
-
-For more information about this error, try `rustc --explain E0658`.
diff --git a/src/test/ui/const-generics/min_const_generics/type_and_const_defaults.rs b/src/test/ui/const-generics/min_const_generics/type_and_const_defaults.rs
index 2adfa9a8c4b..fa119c59f61 100644
--- a/src/test/ui/const-generics/min_const_generics/type_and_const_defaults.rs
+++ b/src/test/ui/const-generics/min_const_generics/type_and_const_defaults.rs
@@ -1,5 +1,4 @@
// run-pass
-#![feature(const_generics_defaults)]
#![allow(dead_code)]
struct Both<T=u32, const N: usize=3> {
diff --git a/src/test/ui/const-generics/params-in-ct-in-ty-param-lazy-norm.min.stderr b/src/test/ui/const-generics/params-in-ct-in-ty-param-lazy-norm.min.stderr
index 17defbe86aa..a5e70f6b9e6 100644
--- a/src/test/ui/const-generics/params-in-ct-in-ty-param-lazy-norm.min.stderr
+++ b/src/test/ui/const-generics/params-in-ct-in-ty-param-lazy-norm.min.stderr
@@ -3,8 +3,6 @@ error: generic parameters with a default must be trailing
|
LL | struct Bar<T = [u8; N], const N: usize>(T);
| ^
- |
- = note: using type defaults and const parameters in the same parameter list is currently not permitted
error: generic parameters may not be used in const operations
--> $DIR/params-in-ct-in-ty-param-lazy-norm.rs:5:44
diff --git a/src/test/ui/const-generics/type-after-const-ok.rs b/src/test/ui/const-generics/type-after-const-ok.rs
index 68d1940160c..f37b0b10233 100644
--- a/src/test/ui/const-generics/type-after-const-ok.rs
+++ b/src/test/ui/const-generics/type-after-const-ok.rs
@@ -1,11 +1,6 @@
-// [full] run-pass
-// revisions: full min
+// run-pass
// Verifies that having generic parameters after constants is permitted
-#![cfg_attr(full, feature(const_generics_defaults))]
-#![cfg_attr(full, allow(incomplete_features))]
-
#[allow(dead_code)]
struct A<const N: usize, T>(T);
-//[min]~^ ERROR type parameters must be declared prior to const parameters
fn main() {}
diff --git a/src/test/ui/consts/assert-type-intrinsics.rs b/src/test/ui/consts/assert-type-intrinsics.rs
new file mode 100644
index 00000000000..31ff6aed03b
--- /dev/null
+++ b/src/test/ui/consts/assert-type-intrinsics.rs
@@ -0,0 +1,22 @@
+// error-pattern: any use of this value will cause an error
+
+#![feature(never_type)]
+#![feature(const_maybe_uninit_assume_init, const_assert_type2)]
+#![feature(core_intrinsics)]
+
+use std::intrinsics;
+
+#[allow(invalid_value)]
+fn main() {
+ use std::mem::MaybeUninit;
+
+ const _BAD1: () = unsafe {
+ MaybeUninit::<!>::uninit().assume_init();
+ };
+ const _BAD2: () = unsafe {
+ intrinsics::assert_uninit_valid::<bool>();
+ };
+ const _BAD3: () = unsafe {
+ intrinsics::assert_zero_valid::<&'static i32>();
+ };
+}
diff --git a/src/test/ui/consts/assert-type-intrinsics.stderr b/src/test/ui/consts/assert-type-intrinsics.stderr
new file mode 100644
index 00000000000..bb57ee82cc1
--- /dev/null
+++ b/src/test/ui/consts/assert-type-intrinsics.stderr
@@ -0,0 +1,39 @@
+error: any use of this value will cause an error
+ --> $DIR/assert-type-intrinsics.rs:14:9
+ |
+LL | / const _BAD1: () = unsafe {
+LL | | MaybeUninit::<!>::uninit().assume_init();
+ | | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ aborted execution: attempted to instantiate uninhabited type `!`
+LL | | };
+ | |______-
+ |
+ = note: `#[deny(const_err)]` on by default
+ = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
+ = note: for more information, see issue #71800 <https://github.com/rust-lang/rust/issues/71800>
+
+error: any use of this value will cause an error
+ --> $DIR/assert-type-intrinsics.rs:17:9
+ |
+LL | / const _BAD2: () = unsafe {
+LL | | intrinsics::assert_uninit_valid::<bool>();
+ | | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ aborted execution: attempted to leave type `bool` uninitialized, which is invalid
+LL | | };
+ | |______-
+ |
+ = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
+ = note: for more information, see issue #71800 <https://github.com/rust-lang/rust/issues/71800>
+
+error: any use of this value will cause an error
+ --> $DIR/assert-type-intrinsics.rs:20:9
+ |
+LL | / const _BAD3: () = unsafe {
+LL | | intrinsics::assert_zero_valid::<&'static i32>();
+ | | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ aborted execution: attempted to zero-initialize type `&i32`, which is invalid
+LL | | };
+ | |______-
+ |
+ = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
+ = note: for more information, see issue #71800 <https://github.com/rust-lang/rust/issues/71800>
+
+error: aborting due to 3 previous errors
+
diff --git a/src/test/ui/consts/assume-type-intrinsics.rs b/src/test/ui/consts/assume-type-intrinsics.rs
deleted file mode 100644
index 77370e1ccc5..00000000000
--- a/src/test/ui/consts/assume-type-intrinsics.rs
+++ /dev/null
@@ -1,13 +0,0 @@
-// error-pattern: any use of this value will cause an error
-
-#![feature(never_type)]
-#![feature(const_maybe_uninit_assume_init)]
-
-#[allow(invalid_value)]
-fn main() {
- use std::mem::MaybeUninit;
-
- const _BAD: () = unsafe {
- MaybeUninit::<!>::uninit().assume_init();
- };
-}
diff --git a/src/test/ui/consts/assume-type-intrinsics.stderr b/src/test/ui/consts/assume-type-intrinsics.stderr
deleted file mode 100644
index e660730396f..00000000000
--- a/src/test/ui/consts/assume-type-intrinsics.stderr
+++ /dev/null
@@ -1,15 +0,0 @@
-error: any use of this value will cause an error
- --> $DIR/assume-type-intrinsics.rs:11:9
- |
-LL | / const _BAD: () = unsafe {
-LL | | MaybeUninit::<!>::uninit().assume_init();
- | | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ aborted execution: attempted to instantiate uninhabited type `!`
-LL | | };
- | |______-
- |
- = note: `#[deny(const_err)]` on by default
- = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
- = note: for more information, see issue #71800 <https://github.com/rust-lang/rust/issues/71800>
-
-error: aborting due to previous error
-
diff --git a/src/test/ui/consts/closure-structural-match-issue-90013.rs b/src/test/ui/consts/closure-structural-match-issue-90013.rs
index 7853ee41a90..1952ddb941e 100644
--- a/src/test/ui/consts/closure-structural-match-issue-90013.rs
+++ b/src/test/ui/consts/closure-structural-match-issue-90013.rs
@@ -1,6 +1,5 @@
// Regression test for issue 90013.
// check-pass
-#![allow(incomplete_features)]
#![feature(inline_const)]
fn main() {
diff --git a/src/test/ui/consts/const-blocks/fn-call-in-const.rs b/src/test/ui/consts/const-blocks/fn-call-in-const.rs
index 7936af75d84..20496f62712 100644
--- a/src/test/ui/consts/const-blocks/fn-call-in-const.rs
+++ b/src/test/ui/consts/const-blocks/fn-call-in-const.rs
@@ -1,7 +1,7 @@
// run-pass
#![feature(inline_const)]
-#![allow(unused, incomplete_features)]
+#![allow(unused)]
// Some type that is not copyable.
struct Bar;
diff --git a/src/test/ui/consts/const-cast-different-types.rs b/src/test/ui/consts/const-cast-different-types.rs
index 3bd5ed8f8c9..5e6d7d899ec 100644
--- a/src/test/ui/consts/const-cast-different-types.rs
+++ b/src/test/ui/consts/const-cast-different-types.rs
@@ -1,6 +1,6 @@
-static a: &'static str = "foo";
-static b: *const u8 = a as *const u8; //~ ERROR casting
-static c: *const u8 = &a as *const u8; //~ ERROR casting
+const a: &str = "foo";
+const b: *const u8 = a as *const u8; //~ ERROR casting
+const c: *const u8 = &a as *const u8; //~ ERROR casting
fn main() {
}
diff --git a/src/test/ui/consts/const-cast-different-types.stderr b/src/test/ui/consts/const-cast-different-types.stderr
index 9960ccb4166..9e622de2eb0 100644
--- a/src/test/ui/consts/const-cast-different-types.stderr
+++ b/src/test/ui/consts/const-cast-different-types.stderr
@@ -1,14 +1,14 @@
error[E0606]: casting `&'static str` as `*const u8` is invalid
- --> $DIR/const-cast-different-types.rs:2:23
+ --> $DIR/const-cast-different-types.rs:2:22
|
-LL | static b: *const u8 = a as *const u8;
- | ^^^^^^^^^^^^^^
+LL | const b: *const u8 = a as *const u8;
+ | ^^^^^^^^^^^^^^
error[E0606]: casting `&&'static str` as `*const u8` is invalid
- --> $DIR/const-cast-different-types.rs:3:23
+ --> $DIR/const-cast-different-types.rs:3:22
|
-LL | static c: *const u8 = &a as *const u8;
- | ^^^^^^^^^^^^^^^
+LL | const c: *const u8 = &a as *const u8;
+ | ^^^^^^^^^^^^^^^
error: aborting due to 2 previous errors
diff --git a/src/test/ui/consts/const-cast-wrong-type.rs b/src/test/ui/consts/const-cast-wrong-type.rs
index c250cc53dbc..6e055a2bcd3 100644
--- a/src/test/ui/consts/const-cast-wrong-type.rs
+++ b/src/test/ui/consts/const-cast-wrong-type.rs
@@ -1,5 +1,5 @@
-static a: [u8; 3] = ['h' as u8, 'i' as u8, 0 as u8];
-static b: *const i8 = &a as *const i8; //~ ERROR mismatched types
+const a: [u8; 3] = ['h' as u8, 'i' as u8, 0 as u8];
+const b: *const i8 = &a as *const i8; //~ ERROR mismatched types
fn main() {
}
diff --git a/src/test/ui/consts/const-cast-wrong-type.stderr b/src/test/ui/consts/const-cast-wrong-type.stderr
index 282f5ccde77..ee186636e4e 100644
--- a/src/test/ui/consts/const-cast-wrong-type.stderr
+++ b/src/test/ui/consts/const-cast-wrong-type.stderr
@@ -1,8 +1,8 @@
error[E0308]: mismatched types
- --> $DIR/const-cast-wrong-type.rs:2:23
+ --> $DIR/const-cast-wrong-type.rs:2:22
|
-LL | static b: *const i8 = &a as *const i8;
- | ^^^^^^^^^^^^^^^ expected `u8`, found `i8`
+LL | const b: *const i8 = &a as *const i8;
+ | ^^^^^^^^^^^^^^^ expected `u8`, found `i8`
error: aborting due to previous error
diff --git a/src/test/ui/consts/const-err.rs b/src/test/ui/consts/const-err.rs
index 031f2121a1e..a8633fd87b5 100644
--- a/src/test/ui/consts/const-err.rs
+++ b/src/test/ui/consts/const-err.rs
@@ -1,5 +1,5 @@
// build-fail
-// compile-flags: -Zforce-overflow-checks=on
+// compile-flags: -C overflow-checks=on
#![allow(arithmetic_overflow)]
#![warn(const_err)]
diff --git a/src/test/ui/consts/const-eval/conditional_array_execution.stderr b/src/test/ui/consts/const-eval/conditional_array_execution.stderr
index 356a7f58d85..9dc40030a6f 100644
--- a/src/test/ui/consts/const-eval/conditional_array_execution.stderr
+++ b/src/test/ui/consts/const-eval/conditional_array_execution.stderr
@@ -28,6 +28,7 @@ LL | println!("{}", FOO);
|
= warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
= note: for more information, see issue #71800 <https://github.com/rust-lang/rust/issues/71800>
+ = note: this warning originates in the macro `$crate::format_args_nl` (in Nightly builds, run with -Z macro-backtrace for more info)
error: aborting due to previous error; 2 warnings emitted
diff --git a/src/test/ui/consts/const-eval/const-eval-query-stack.stderr b/src/test/ui/consts/const-eval/const-eval-query-stack.stderr
index e6fecef9fb3..45a3d901c98 100644
--- a/src/test/ui/consts/const-eval/const-eval-query-stack.stderr
+++ b/src/test/ui/consts/const-eval/const-eval-query-stack.stderr
@@ -20,7 +20,7 @@ error[E0080]: evaluation of constant value failed
LL | let x: &'static i32 = &X;
| ^ referenced constant has errors
query stack during panic:
-#0 [normalize_mir_const_after_erasing_regions] normalizing `main::promoted[1]`
+#0 [try_normalize_mir_const_after_erasing_regions] normalizing `main::promoted[1]`
#1 [optimized_mir] optimizing MIR for `main`
#2 [collect_and_partition_mono_items] collect_and_partition_mono_items
end of query stack
diff --git a/src/test/ui/consts/const-eval/issue-43197.stderr b/src/test/ui/consts/const-eval/issue-43197.stderr
index d4d8cbc669a..32ab7c74b89 100644
--- a/src/test/ui/consts/const-eval/issue-43197.stderr
+++ b/src/test/ui/consts/const-eval/issue-43197.stderr
@@ -39,6 +39,7 @@ LL | println!("{} {}", X, Y);
|
= warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
= note: for more information, see issue #71800 <https://github.com/rust-lang/rust/issues/71800>
+ = note: this warning originates in the macro `$crate::format_args_nl` (in Nightly builds, run with -Z macro-backtrace for more info)
error[E0080]: evaluation of constant value failed
--> $DIR/issue-43197.rs:16:26
@@ -54,6 +55,7 @@ LL | println!("{} {}", X, Y);
|
= warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
= note: for more information, see issue #71800 <https://github.com/rust-lang/rust/issues/71800>
+ = note: this warning originates in the macro `$crate::format_args_nl` (in Nightly builds, run with -Z macro-backtrace for more info)
error: aborting due to 2 previous errors; 4 warnings emitted
diff --git a/src/test/ui/consts/const-eval/issue-91827-extern-types.rs b/src/test/ui/consts/const-eval/issue-91827-extern-types.rs
new file mode 100644
index 00000000000..d5576ebfd02
--- /dev/null
+++ b/src/test/ui/consts/const-eval/issue-91827-extern-types.rs
@@ -0,0 +1,58 @@
+// run-pass
+//
+// Test that we can handle unsized types with an extern type tail part.
+// Regression test for issue #91827.
+
+#![feature(const_ptr_offset_from)]
+#![feature(const_slice_from_raw_parts)]
+#![feature(extern_types)]
+
+use std::ptr::addr_of;
+
+extern "C" {
+ type Opaque;
+}
+
+unsafe impl Sync for Opaque {}
+
+#[repr(C)]
+pub struct List<T> {
+ len: usize,
+ data: [T; 0],
+ tail: Opaque,
+}
+
+#[repr(C)]
+pub struct ListImpl<T, const N: usize> {
+ len: usize,
+ data: [T; N],
+}
+
+impl<T> List<T> {
+ const fn as_slice(&self) -> &[T] {
+ unsafe { std::slice::from_raw_parts(self.data.as_ptr(), self.len) }
+ }
+}
+
+impl<T, const N: usize> ListImpl<T, N> {
+ const fn as_list(&self) -> &List<T> {
+ unsafe { std::mem::transmute(self) }
+ }
+}
+
+pub static A: ListImpl<u128, 3> = ListImpl {
+ len: 3,
+ data: [5, 6, 7],
+};
+pub static A_REF: &'static List<u128> = A.as_list();
+pub static A_TAIL_OFFSET: isize = tail_offset(A.as_list());
+
+const fn tail_offset<T>(list: &List<T>) -> isize {
+ unsafe { (addr_of!(list.tail) as *const u8).offset_from(list as *const List<T> as *const u8) }
+}
+
+fn main() {
+ assert_eq!(A_REF.as_slice(), &[5, 6, 7]);
+ // Check that interpreter and code generation agree about the position of the tail field.
+ assert_eq!(A_TAIL_OFFSET, tail_offset(A_REF));
+}
diff --git a/src/test/ui/consts/drop_zst.rs b/src/test/ui/consts/drop_zst.rs
new file mode 100644
index 00000000000..f7c70d3978b
--- /dev/null
+++ b/src/test/ui/consts/drop_zst.rs
@@ -0,0 +1,17 @@
+// check-fail
+
+#![feature(const_precise_live_drops)]
+
+struct S;
+
+impl Drop for S {
+ fn drop(&mut self) {
+ println!("Hello!");
+ }
+}
+
+const fn foo() {
+ let s = S; //~ destructor
+}
+
+fn main() {}
diff --git a/src/test/ui/consts/drop_zst.stderr b/src/test/ui/consts/drop_zst.stderr
new file mode 100644
index 00000000000..d4be5aa56d9
--- /dev/null
+++ b/src/test/ui/consts/drop_zst.stderr
@@ -0,0 +1,9 @@
+error[E0493]: destructors cannot be evaluated at compile-time
+ --> $DIR/drop_zst.rs:14:9
+ |
+LL | let s = S;
+ | ^ constant functions cannot evaluate destructors
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0493`.
diff --git a/src/test/ui/consts/inline_asm.rs b/src/test/ui/consts/inline_asm.rs
index b46ca6ba6df..4cd7e2717fe 100644
--- a/src/test/ui/consts/inline_asm.rs
+++ b/src/test/ui/consts/inline_asm.rs
@@ -1,6 +1,6 @@
// needs-asm-support
-#![feature(asm)]
+use std::arch::asm;
const _: () = unsafe { asm!("nop") };
//~^ ERROR inline assembly
diff --git a/src/test/ui/consts/issue-70942-trait-vs-impl-mismatch.stderr b/src/test/ui/consts/issue-70942-trait-vs-impl-mismatch.stderr
index 19d9ff71667..1597120fb5c 100644
--- a/src/test/ui/consts/issue-70942-trait-vs-impl-mismatch.stderr
+++ b/src/test/ui/consts/issue-70942-trait-vs-impl-mismatch.stderr
@@ -1,11 +1,14 @@
error[E0326]: implemented const `VALUE` has an incompatible type for trait
--> $DIR/issue-70942-trait-vs-impl-mismatch.rs:8:18
|
-LL | const VALUE: usize;
- | ----- type in trait
-...
LL | const VALUE: i32 = 0;
| ^^^ expected `usize`, found `i32`
+ |
+note: type in trait
+ --> $DIR/issue-70942-trait-vs-impl-mismatch.rs:2:18
+ |
+LL | const VALUE: usize;
+ | ^^^^^
error: aborting due to previous error
diff --git a/src/test/ui/consts/issue-90870.fixed b/src/test/ui/consts/issue-90870.fixed
new file mode 100644
index 00000000000..e767effcdd0
--- /dev/null
+++ b/src/test/ui/consts/issue-90870.fixed
@@ -0,0 +1,34 @@
+// Regression test for issue #90870.
+
+// run-rustfix
+
+#![allow(dead_code)]
+
+const fn f(a: &u8, b: &u8) -> bool {
+ *a == *b
+ //~^ ERROR: calls in constant functions are limited to constant functions, tuple structs and tuple variants [E0015]
+ //~| HELP: consider dereferencing here
+}
+
+const fn g(a: &&&&i64, b: &&&&i64) -> bool {
+ ****a == ****b
+ //~^ ERROR: calls in constant functions are limited to constant functions, tuple structs and tuple variants [E0015]
+ //~| HELP: consider dereferencing here
+}
+
+const fn h(mut a: &[u8], mut b: &[u8]) -> bool {
+ while let ([l, at @ ..], [r, bt @ ..]) = (a, b) {
+ if *l == *r {
+ //~^ ERROR: calls in constant functions are limited to constant functions, tuple structs and tuple variants [E0015]
+ //~| HELP: consider dereferencing here
+ a = at;
+ b = bt;
+ } else {
+ return false;
+ }
+ }
+
+ a.is_empty() && b.is_empty()
+}
+
+fn main() {}
diff --git a/src/test/ui/consts/issue-90870.rs b/src/test/ui/consts/issue-90870.rs
new file mode 100644
index 00000000000..35b3c8242aa
--- /dev/null
+++ b/src/test/ui/consts/issue-90870.rs
@@ -0,0 +1,34 @@
+// Regression test for issue #90870.
+
+// run-rustfix
+
+#![allow(dead_code)]
+
+const fn f(a: &u8, b: &u8) -> bool {
+ a == b
+ //~^ ERROR: calls in constant functions are limited to constant functions, tuple structs and tuple variants [E0015]
+ //~| HELP: consider dereferencing here
+}
+
+const fn g(a: &&&&i64, b: &&&&i64) -> bool {
+ a == b
+ //~^ ERROR: calls in constant functions are limited to constant functions, tuple structs and tuple variants [E0015]
+ //~| HELP: consider dereferencing here
+}
+
+const fn h(mut a: &[u8], mut b: &[u8]) -> bool {
+ while let ([l, at @ ..], [r, bt @ ..]) = (a, b) {
+ if l == r {
+ //~^ ERROR: calls in constant functions are limited to constant functions, tuple structs and tuple variants [E0015]
+ //~| HELP: consider dereferencing here
+ a = at;
+ b = bt;
+ } else {
+ return false;
+ }
+ }
+
+ a.is_empty() && b.is_empty()
+}
+
+fn main() {}
diff --git a/src/test/ui/consts/issue-90870.stderr b/src/test/ui/consts/issue-90870.stderr
new file mode 100644
index 00000000000..0e33e6ebe5a
--- /dev/null
+++ b/src/test/ui/consts/issue-90870.stderr
@@ -0,0 +1,36 @@
+error[E0015]: calls in constant functions are limited to constant functions, tuple structs and tuple variants
+ --> $DIR/issue-90870.rs:8:5
+ |
+LL | a == b
+ | ^^^^^^
+ |
+help: consider dereferencing here
+ |
+LL | *a == *b
+ | + +
+
+error[E0015]: calls in constant functions are limited to constant functions, tuple structs and tuple variants
+ --> $DIR/issue-90870.rs:14:5
+ |
+LL | a == b
+ | ^^^^^^
+ |
+help: consider dereferencing here
+ |
+LL | ****a == ****b
+ | ++++ ++++
+
+error[E0015]: calls in constant functions are limited to constant functions, tuple structs and tuple variants
+ --> $DIR/issue-90870.rs:21:12
+ |
+LL | if l == r {
+ | ^^^^^^
+ |
+help: consider dereferencing here
+ |
+LL | if *l == *r {
+ | + +
+
+error: aborting due to 3 previous errors
+
+For more information about this error, try `rustc --explain E0015`.
diff --git a/src/test/ui/consts/issue-90878-2.rs b/src/test/ui/consts/issue-90878-2.rs
index 7e3f18cc9d5..ac5640646a8 100644
--- a/src/test/ui/consts/issue-90878-2.rs
+++ b/src/test/ui/consts/issue-90878-2.rs
@@ -1,7 +1,5 @@
#![l=|x|[b;x ]] //~ ERROR unexpected token: `|x| [b; x]`
//~^ ERROR cannot find attribute `l` in this scope
-//~^^ ERROR attempt to use a non-constant value in a constant [E0435]
-//~^^^ ERROR cannot find value `b` in this scope [E0425]
// notice the space at the start,
// we can't attach any attributes to this file because it needs to be at the start
diff --git a/src/test/ui/consts/issue-90878-2.stderr b/src/test/ui/consts/issue-90878-2.stderr
index 9e167424995..4ccce36eedf 100644
--- a/src/test/ui/consts/issue-90878-2.stderr
+++ b/src/test/ui/consts/issue-90878-2.stderr
@@ -10,21 +10,5 @@ error: cannot find attribute `l` in this scope
LL | #![l=|x|[b;x ]]
| ^
-error[E0435]: attempt to use a non-constant value in a constant
- --> $DIR/issue-90878-2.rs:1:13
- |
-LL | #![l=|x|[b;x ]]
- | - ^
- | |
- | this would need to be a `const`
-
-error[E0425]: cannot find value `b` in this scope
- --> $DIR/issue-90878-2.rs:1:11
- |
-LL | #![l=|x|[b;x ]]
- | ^ help: a local variable with a similar name exists: `x`
-
-error: aborting due to 4 previous errors
+error: aborting due to 2 previous errors
-Some errors have detailed explanations: E0425, E0435.
-For more information about an error, try `rustc --explain E0425`.
diff --git a/src/test/ui/consts/miri_unleashed/inline_asm.rs b/src/test/ui/consts/miri_unleashed/inline_asm.rs
index b9421330d05..1bb22a1301a 100644
--- a/src/test/ui/consts/miri_unleashed/inline_asm.rs
+++ b/src/test/ui/consts/miri_unleashed/inline_asm.rs
@@ -1,9 +1,11 @@
// compile-flags: -Zunleash-the-miri-inside-of-you
// only-x86_64
-#![feature(asm,llvm_asm)]
+#![feature(llvm_asm)]
#![allow(const_err)]
#![allow(deprecated)] // llvm_asm!
+use std::arch::asm;
+
fn main() {}
// Make sure we catch executing inline assembly.
diff --git a/src/test/ui/consts/miri_unleashed/inline_asm.stderr b/src/test/ui/consts/miri_unleashed/inline_asm.stderr
index ac9191a340c..34ac808ed17 100644
--- a/src/test/ui/consts/miri_unleashed/inline_asm.stderr
+++ b/src/test/ui/consts/miri_unleashed/inline_asm.stderr
@@ -1,5 +1,5 @@
error[E0080]: could not evaluate static initializer
- --> $DIR/inline_asm.rs:11:14
+ --> $DIR/inline_asm.rs:13:14
|
LL | unsafe { llvm_asm!("xor %eax, %eax" ::: "eax"); }
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ inline assembly is not supported
@@ -7,7 +7,7 @@ LL | unsafe { llvm_asm!("xor %eax, %eax" ::: "eax"); }
= note: this error originates in the macro `llvm_asm` (in Nightly builds, run with -Z macro-backtrace for more info)
error[E0080]: could not evaluate static initializer
- --> $DIR/inline_asm.rs:20:14
+ --> $DIR/inline_asm.rs:22:14
|
LL | unsafe { asm!("nop"); }
| ^^^^^^^^^^^ inline assembly is not supported
@@ -15,12 +15,12 @@ LL | unsafe { asm!("nop"); }
warning: skipping const checks
|
help: skipping check that does not even have a feature gate
- --> $DIR/inline_asm.rs:11:14
+ --> $DIR/inline_asm.rs:13:14
|
LL | unsafe { llvm_asm!("xor %eax, %eax" ::: "eax"); }
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
help: skipping check that does not even have a feature gate
- --> $DIR/inline_asm.rs:20:14
+ --> $DIR/inline_asm.rs:22:14
|
LL | unsafe { asm!("nop"); }
| ^^^^^^^^^^^
diff --git a/src/test/ui/consts/miri_unleashed/tls.stderr b/src/test/ui/consts/miri_unleashed/tls.stderr
index 30309da499f..ebe20348830 100644
--- a/src/test/ui/consts/miri_unleashed/tls.stderr
+++ b/src/test/ui/consts/miri_unleashed/tls.stderr
@@ -2,13 +2,13 @@ error[E0080]: could not evaluate static initializer
--> $DIR/tls.rs:12:25
|
LL | unsafe { let _val = A; }
- | ^ cannot access thread local static (DefId(0:6 ~ tls[f423]::A))
+ | ^ cannot access thread local static (DefId(0:6 ~ tls[HASH]::A))
error[E0080]: could not evaluate static initializer
--> $DIR/tls.rs:19:26
|
LL | unsafe { let _val = &A; }
- | ^ cannot access thread local static (DefId(0:6 ~ tls[f423]::A))
+ | ^ cannot access thread local static (DefId(0:6 ~ tls[HASH]::A))
warning: skipping const checks
|
diff --git a/src/test/ui/consts/not_const_clusure_in_const.rs b/src/test/ui/consts/not_const_clusure_in_const.rs
deleted file mode 100644
index fd2cfa442d3..00000000000
--- a/src/test/ui/consts/not_const_clusure_in_const.rs
+++ /dev/null
@@ -1,9 +0,0 @@
-// run-pass
-
-const _FOO: fn() -> String = || "foo".into();
-
-pub fn bar() -> fn() -> String {
- || "bar".into()
-}
-
-fn main(){}
diff --git a/src/test/ui/consts/try-operator.rs b/src/test/ui/consts/try-operator.rs
new file mode 100644
index 00000000000..fe43b132cbd
--- /dev/null
+++ b/src/test/ui/consts/try-operator.rs
@@ -0,0 +1,23 @@
+// run-pass
+
+#![feature(try_trait_v2)]
+#![feature(const_trait_impl)]
+#![feature(const_try)]
+#![feature(const_convert)]
+
+fn main() {
+ const fn result() -> Result<bool, ()> {
+ Err(())?;
+ Ok(true)
+ }
+
+ const FOO: Result<bool, ()> = result();
+ assert_eq!(Err(()), FOO);
+
+ const fn option() -> Option<()> {
+ None?;
+ Some(())
+ }
+ const BAR: Option<()> = option();
+ assert_eq!(None, BAR);
+}
diff --git a/src/test/ui/crate-loading/invalid-rlib.rs b/src/test/ui/crate-loading/invalid-rlib.rs
index 77c29090a3e..aea861e3261 100644
--- a/src/test/ui/crate-loading/invalid-rlib.rs
+++ b/src/test/ui/crate-loading/invalid-rlib.rs
@@ -6,3 +6,5 @@
#![no_std]
use ::foo; //~ ERROR invalid metadata files for crate `foo`
//~| NOTE failed to mmap file
+//~^^ ERROR invalid metadata files for crate `foo`
+//~| NOTE failed to mmap file
diff --git a/src/test/ui/crate-loading/invalid-rlib.stderr b/src/test/ui/crate-loading/invalid-rlib.stderr
index b2c79f742fb..3c0d23bf7b4 100644
--- a/src/test/ui/crate-loading/invalid-rlib.stderr
+++ b/src/test/ui/crate-loading/invalid-rlib.stderr
@@ -6,6 +6,14 @@ LL | use ::foo;
|
= note: failed to mmap file 'auxiliary/libfoo.rlib'
-error: aborting due to previous error
+error[E0786]: found invalid metadata files for crate `foo`
+ --> $DIR/invalid-rlib.rs:7:7
+ |
+LL | use ::foo;
+ | ^^^
+ |
+ = note: failed to mmap file 'auxiliary/libfoo.rlib'
+
+error: aborting due to 2 previous errors
For more information about this error, try `rustc --explain E0786`.
diff --git a/src/test/ui/crate-loading/missing-std.rs b/src/test/ui/crate-loading/missing-std.rs
index 1a34c21ba54..400d9f6e0ba 100644
--- a/src/test/ui/crate-loading/missing-std.rs
+++ b/src/test/ui/crate-loading/missing-std.rs
@@ -1,6 +1,7 @@
// compile-flags: --target x86_64-unknown-uefi
// needs-llvm-components: x86
// rustc-env:CARGO=/usr/bin/cargo
+#![feature(no_core)]
#![no_core]
extern crate core;
//~^ ERROR can't find crate for `core`
diff --git a/src/test/ui/crate-loading/missing-std.stderr b/src/test/ui/crate-loading/missing-std.stderr
index 25808efdfa6..70bcae1e0ed 100644
--- a/src/test/ui/crate-loading/missing-std.stderr
+++ b/src/test/ui/crate-loading/missing-std.stderr
@@ -1,5 +1,5 @@
error[E0463]: can't find crate for `core`
- --> $DIR/missing-std.rs:5:1
+ --> $DIR/missing-std.rs:6:1
|
LL | extern crate core;
| ^^^^^^^^^^^^^^^^^^ can't find crate
@@ -8,6 +8,8 @@ LL | extern crate core;
= help: consider downloading the target with `rustup target add x86_64-unknown-uefi`
= help: consider building the standard library from source with `cargo build -Zbuild-std`
-error: aborting due to previous error
+error: requires `sized` lang_item
+
+error: aborting due to 2 previous errors
For more information about this error, try `rustc --explain E0463`.
diff --git a/src/test/ui/cross/cross-file-errors/main.rs b/src/test/ui/cross/cross-file-errors/main.rs
index 1902ab94d4c..4219f892deb 100644
--- a/src/test/ui/cross/cross-file-errors/main.rs
+++ b/src/test/ui/cross/cross-file-errors/main.rs
@@ -4,5 +4,4 @@ mod underscore;
fn main() {
underscore!();
//~^ ERROR `_` can only be used on the left-hand side of an assignment
- //~| ERROR destructuring assignments are unstable
}
diff --git a/src/test/ui/cross/cross-file-errors/main.stderr b/src/test/ui/cross/cross-file-errors/main.stderr
index 829535f9212..293a300ed61 100644
--- a/src/test/ui/cross/cross-file-errors/main.stderr
+++ b/src/test/ui/cross/cross-file-errors/main.stderr
@@ -1,18 +1,3 @@
-error[E0658]: destructuring assignments are unstable
- --> $DIR/underscore.rs:8:9
- |
-LL | _
- | ^
- |
- ::: $DIR/main.rs:5:5
- |
-LL | underscore!();
- | ------------- in this macro invocation
- |
- = note: see issue #71126 <https://github.com/rust-lang/rust/issues/71126> for more information
- = help: add `#![feature(destructuring_assignment)]` to the crate attributes to enable
- = note: this error originates in the macro `underscore` (in Nightly builds, run with -Z macro-backtrace for more info)
-
error: in expressions, `_` can only be used on the left-hand side of an assignment
--> $DIR/underscore.rs:8:9
|
@@ -26,6 +11,5 @@ LL | underscore!();
|
= note: this error originates in the macro `underscore` (in Nightly builds, run with -Z macro-backtrace for more info)
-error: aborting due to 2 previous errors
+error: aborting due to previous error
-For more information about this error, try `rustc --explain E0658`.
diff --git a/src/test/ui/derives/derive-macro-const-default.rs b/src/test/ui/derives/derive-macro-const-default.rs
index 7c4ebca8746..ce80271d274 100644
--- a/src/test/ui/derives/derive-macro-const-default.rs
+++ b/src/test/ui/derives/derive-macro-const-default.rs
@@ -1,6 +1,4 @@
// check-pass
-#![feature(const_generics_defaults)]
-
#[derive(Clone, PartialEq, Debug)]
struct Example<T, const N: usize = 1usize>([T; N]);
diff --git a/src/test/ui/derives/issue-36617.rs b/src/test/ui/derives/issue-36617.rs
index 08fc82e91f6..08f293d2ebb 100644
--- a/src/test/ui/derives/issue-36617.rs
+++ b/src/test/ui/derives/issue-36617.rs
@@ -1,3 +1,16 @@
#![derive(Copy)] //~ ERROR cannot determine resolution for the attribute macro `derive`
+//~^ ERROR `derive` attribute cannot be used at crate level
+
+#![test]//~ ERROR cannot determine resolution for the attribute macro `test`
+//~^ ERROR `test` attribute cannot be used at crate level
+
+#![test_case]//~ ERROR cannot determine resolution for the attribute macro `test_case`
+//~^ ERROR `test_case` attribute cannot be used at crate level
+
+#![bench]//~ ERROR cannot determine resolution for the attribute macro `bench`
+//~^ ERROR `bench` attribute cannot be used at crate level
+
+#![global_allocator]//~ ERROR cannot determine resolution for the attribute macro `global_allocator`
+//~^ ERROR `global_allocator` attribute cannot be used at crate level
fn main() {}
diff --git a/src/test/ui/derives/issue-36617.stderr b/src/test/ui/derives/issue-36617.stderr
index 0716764b427..9cc0a29b065 100644
--- a/src/test/ui/derives/issue-36617.stderr
+++ b/src/test/ui/derives/issue-36617.stderr
@@ -6,5 +6,92 @@ LL | #![derive(Copy)]
|
= note: import resolution is stuck, try simplifying macro imports
-error: aborting due to previous error
+error: cannot determine resolution for the attribute macro `test`
+ --> $DIR/issue-36617.rs:4:4
+ |
+LL | #![test]
+ | ^^^^
+ |
+ = note: import resolution is stuck, try simplifying macro imports
+
+error: cannot determine resolution for the attribute macro `test_case`
+ --> $DIR/issue-36617.rs:7:4
+ |
+LL | #![test_case]
+ | ^^^^^^^^^
+ |
+ = note: import resolution is stuck, try simplifying macro imports
+
+error: cannot determine resolution for the attribute macro `bench`
+ --> $DIR/issue-36617.rs:10:4
+ |
+LL | #![bench]
+ | ^^^^^
+ |
+ = note: import resolution is stuck, try simplifying macro imports
+
+error: cannot determine resolution for the attribute macro `global_allocator`
+ --> $DIR/issue-36617.rs:13:4
+ |
+LL | #![global_allocator]
+ | ^^^^^^^^^^^^^^^^
+ |
+ = note: import resolution is stuck, try simplifying macro imports
+
+error: `derive` attribute cannot be used at crate level
+ --> $DIR/issue-36617.rs:1:1
+ |
+LL | #![derive(Copy)]
+ | ^^^^^^^^^^^^^^^^
+ |
+help: perhaps you meant to use an outer attribute
+ |
+LL | #[derive(Copy)]
+ | ~~~~~~~~~~~~~~~
+
+error: `test` attribute cannot be used at crate level
+ --> $DIR/issue-36617.rs:4:1
+ |
+LL | #![test]
+ | ^^^^^^^^
+ |
+help: perhaps you meant to use an outer attribute
+ |
+LL | #[test]
+ | ~~~~~~~
+
+error: `test_case` attribute cannot be used at crate level
+ --> $DIR/issue-36617.rs:7:1
+ |
+LL | #![test_case]
+ | ^^^^^^^^^^^^^
+ |
+help: perhaps you meant to use an outer attribute
+ |
+LL | #[test_case]
+ | ~~~~~~~~~~~~
+
+error: `bench` attribute cannot be used at crate level
+ --> $DIR/issue-36617.rs:10:1
+ |
+LL | #![bench]
+ | ^^^^^^^^^
+ |
+help: perhaps you meant to use an outer attribute
+ |
+LL | #[bench]
+ | ~~~~~~~~
+
+error: `global_allocator` attribute cannot be used at crate level
+ --> $DIR/issue-36617.rs:13:1
+ |
+LL | #![global_allocator]
+ | ^^^^^^^^^^^^^^^^^^^^
+ |
+help: perhaps you meant to use an outer attribute
+ |
+LL | #[global_allocator]
+ | ~~~~~~~~~~~~~~~~~~~
+
+error: aborting due to 10 previous errors
diff --git a/src/test/ui/destructuring-assignment/bad-expr-lhs.rs b/src/test/ui/destructuring-assignment/bad-expr-lhs.rs
index 39536f12e3b..53794783a3c 100644
--- a/src/test/ui/destructuring-assignment/bad-expr-lhs.rs
+++ b/src/test/ui/destructuring-assignment/bad-expr-lhs.rs
@@ -1,12 +1,9 @@
fn main() {
1 = 2; //~ ERROR invalid left-hand side of assignment
1 += 2; //~ ERROR invalid left-hand side of assignment
- (1, 2) = (3, 4); //~ ERROR destructuring assignments are unstable
+ (1, 2) = (3, 4);
+ //~^ ERROR invalid left-hand side of assignment
//~| ERROR invalid left-hand side of assignment
- //~| ERROR invalid left-hand side of assignment
-
- let (a, b) = (1, 2);
- (a, b) = (3, 4); //~ ERROR destructuring assignments are unstable
None = Some(3); //~ ERROR invalid left-hand side of assignment
}
diff --git a/src/test/ui/destructuring-assignment/bad-expr-lhs.stderr b/src/test/ui/destructuring-assignment/bad-expr-lhs.stderr
index d4b2193d09f..d2986747480 100644
--- a/src/test/ui/destructuring-assignment/bad-expr-lhs.stderr
+++ b/src/test/ui/destructuring-assignment/bad-expr-lhs.stderr
@@ -1,25 +1,3 @@
-error[E0658]: destructuring assignments are unstable
- --> $DIR/bad-expr-lhs.rs:4:12
- |
-LL | (1, 2) = (3, 4);
- | ------ ^
- | |
- | cannot assign to this expression
- |
- = note: see issue #71126 <https://github.com/rust-lang/rust/issues/71126> for more information
- = help: add `#![feature(destructuring_assignment)]` to the crate attributes to enable
-
-error[E0658]: destructuring assignments are unstable
- --> $DIR/bad-expr-lhs.rs:9:12
- |
-LL | (a, b) = (3, 4);
- | ------ ^
- | |
- | cannot assign to this expression
- |
- = note: see issue #71126 <https://github.com/rust-lang/rust/issues/71126> for more information
- = help: add `#![feature(destructuring_assignment)]` to the crate attributes to enable
-
error[E0070]: invalid left-hand side of assignment
--> $DIR/bad-expr-lhs.rs:2:7
|
@@ -53,14 +31,14 @@ LL | (1, 2) = (3, 4);
| cannot assign to this expression
error[E0070]: invalid left-hand side of assignment
- --> $DIR/bad-expr-lhs.rs:11:10
+ --> $DIR/bad-expr-lhs.rs:8:10
|
LL | None = Some(3);
| ---- ^
| |
| cannot assign to this expression
-error: aborting due to 7 previous errors
+error: aborting due to 5 previous errors
-Some errors have detailed explanations: E0067, E0070, E0658.
+Some errors have detailed explanations: E0067, E0070.
For more information about an error, try `rustc --explain E0067`.
diff --git a/src/test/ui/destructuring-assignment/default-match-bindings-forbidden.rs b/src/test/ui/destructuring-assignment/default-match-bindings-forbidden.rs
index adecd0ff291..ff867c00071 100644
--- a/src/test/ui/destructuring-assignment/default-match-bindings-forbidden.rs
+++ b/src/test/ui/destructuring-assignment/default-match-bindings-forbidden.rs
@@ -1,5 +1,3 @@
-#![feature(destructuring_assignment)]
-
fn main() {
let mut x = &0;
let mut y = &0;
diff --git a/src/test/ui/destructuring-assignment/default-match-bindings-forbidden.stderr b/src/test/ui/destructuring-assignment/default-match-bindings-forbidden.stderr
index e6161fdfa24..2250f561b54 100644
--- a/src/test/ui/destructuring-assignment/default-match-bindings-forbidden.stderr
+++ b/src/test/ui/destructuring-assignment/default-match-bindings-forbidden.stderr
@@ -1,10 +1,8 @@
error[E0308]: mismatched types
- --> $DIR/default-match-bindings-forbidden.rs:6:5
+ --> $DIR/default-match-bindings-forbidden.rs:4:5
|
LL | (x, y) = &(1, 2);
- | ^^^^^^ ------- this expression has type `&({integer}, {integer})`
- | |
- | expected reference, found tuple
+ | ^^^^^^ expected reference, found tuple
|
= note: expected type `&({integer}, {integer})`
found tuple `(_, _)`
diff --git a/src/test/ui/destructuring-assignment/drop-order.rs b/src/test/ui/destructuring-assignment/drop-order.rs
index d06b31c7f27..79671054ca7 100644
--- a/src/test/ui/destructuring-assignment/drop-order.rs
+++ b/src/test/ui/destructuring-assignment/drop-order.rs
@@ -2,7 +2,6 @@
//! Test that let bindings and destructuring assignments have consistent drop orders
-#![feature(destructuring_assignment)]
#![allow(unused_variables, unused_assignments)]
use std::cell::RefCell;
diff --git a/src/test/ui/destructuring-assignment/nested_destructure.rs b/src/test/ui/destructuring-assignment/nested_destructure.rs
index 0d45ff7da72..94b3a5ff9a7 100644
--- a/src/test/ui/destructuring-assignment/nested_destructure.rs
+++ b/src/test/ui/destructuring-assignment/nested_destructure.rs
@@ -1,7 +1,5 @@
// run-pass
-#![feature(destructuring_assignment)]
-
struct Struct<S, T> {
a: S,
b: T,
diff --git a/src/test/ui/destructuring-assignment/note-unsupported.rs b/src/test/ui/destructuring-assignment/note-unsupported.rs
index 249fba7f920..c69edd42170 100644
--- a/src/test/ui/destructuring-assignment/note-unsupported.rs
+++ b/src/test/ui/destructuring-assignment/note-unsupported.rs
@@ -3,25 +3,20 @@ struct S { x: u8, y: u8 }
fn main() {
let (a, b) = (1, 2);
- (a, b) = (3, 4); //~ ERROR destructuring assignments are unstable
+ (a, b) = (3, 4);
(a, b) += (3, 4); //~ ERROR invalid left-hand side of assignment
//~| ERROR binary assignment operation `+=` cannot be applied
- [a, b] = [3, 4]; //~ ERROR destructuring assignments are unstable
+ [a, b] = [3, 4];
[a, b] += [3, 4]; //~ ERROR invalid left-hand side of assignment
//~| ERROR binary assignment operation `+=` cannot be applied
let s = S { x: 3, y: 4 };
- S { x: a, y: b } = s; //~ ERROR destructuring assignments are unstable
+ S { x: a, y: b } = s;
S { x: a, y: b } += s; //~ ERROR invalid left-hand side of assignment
//~| ERROR binary assignment operation `+=` cannot be applied
S { x: a, ..s } = S { x: 3, y: 4 };
//~^ ERROR functional record updates are not allowed in destructuring assignments
- //~| ERROR destructuring assignments are unstable
-
- let c = 3;
-
- ((a, b), c) = ((3, 4), 5); //~ ERROR destructuring assignments are unstable
}
diff --git a/src/test/ui/destructuring-assignment/note-unsupported.stderr b/src/test/ui/destructuring-assignment/note-unsupported.stderr
index 7b9788ca0fe..3e2282743bf 100644
--- a/src/test/ui/destructuring-assignment/note-unsupported.stderr
+++ b/src/test/ui/destructuring-assignment/note-unsupported.stderr
@@ -1,64 +1,9 @@
-error[E0658]: destructuring assignments are unstable
- --> $DIR/note-unsupported.rs:6:12
- |
-LL | (a, b) = (3, 4);
- | ------ ^
- | |
- | cannot assign to this expression
- |
- = note: see issue #71126 <https://github.com/rust-lang/rust/issues/71126> for more information
- = help: add `#![feature(destructuring_assignment)]` to the crate attributes to enable
-
-error[E0658]: destructuring assignments are unstable
- --> $DIR/note-unsupported.rs:10:12
- |
-LL | [a, b] = [3, 4];
- | ------ ^
- | |
- | cannot assign to this expression
- |
- = note: see issue #71126 <https://github.com/rust-lang/rust/issues/71126> for more information
- = help: add `#![feature(destructuring_assignment)]` to the crate attributes to enable
-
-error[E0658]: destructuring assignments are unstable
- --> $DIR/note-unsupported.rs:16:22
- |
-LL | S { x: a, y: b } = s;
- | ---------------- ^
- | |
- | cannot assign to this expression
- |
- = note: see issue #71126 <https://github.com/rust-lang/rust/issues/71126> for more information
- = help: add `#![feature(destructuring_assignment)]` to the crate attributes to enable
-
-error[E0658]: destructuring assignments are unstable
- --> $DIR/note-unsupported.rs:20:21
- |
-LL | S { x: a, ..s } = S { x: 3, y: 4 };
- | --------------- ^
- | |
- | cannot assign to this expression
- |
- = note: see issue #71126 <https://github.com/rust-lang/rust/issues/71126> for more information
- = help: add `#![feature(destructuring_assignment)]` to the crate attributes to enable
-
error: functional record updates are not allowed in destructuring assignments
--> $DIR/note-unsupported.rs:20:17
|
LL | S { x: a, ..s } = S { x: 3, y: 4 };
| ^ help: consider removing the trailing pattern
-error[E0658]: destructuring assignments are unstable
- --> $DIR/note-unsupported.rs:26:17
- |
-LL | ((a, b), c) = ((3, 4), 5);
- | ----------- ^
- | |
- | cannot assign to this expression
- |
- = note: see issue #71126 <https://github.com/rust-lang/rust/issues/71126> for more information
- = help: add `#![feature(destructuring_assignment)]` to the crate attributes to enable
-
error[E0368]: binary assignment operation `+=` cannot be applied to type `({integer}, {integer})`
--> $DIR/note-unsupported.rs:7:5
|
@@ -124,7 +69,7 @@ LL | S { x: a, y: b } += s;
| |
| cannot assign to this expression
-error: aborting due to 12 previous errors
+error: aborting due to 7 previous errors
-Some errors have detailed explanations: E0067, E0368, E0658.
+Some errors have detailed explanations: E0067, E0368.
For more information about an error, try `rustc --explain E0067`.
diff --git a/src/test/ui/destructuring-assignment/slice_destructure.rs b/src/test/ui/destructuring-assignment/slice_destructure.rs
index 76cdc1260fc..762c4b5e8ea 100644
--- a/src/test/ui/destructuring-assignment/slice_destructure.rs
+++ b/src/test/ui/destructuring-assignment/slice_destructure.rs
@@ -1,7 +1,5 @@
// run-pass
-#![feature(destructuring_assignment)]
-
fn main() {
let (mut a, mut b);
[a, b] = [0, 1];
diff --git a/src/test/ui/destructuring-assignment/slice_destructure_fail.rs b/src/test/ui/destructuring-assignment/slice_destructure_fail.rs
index 90d93892f7f..33b09eb349d 100644
--- a/src/test/ui/destructuring-assignment/slice_destructure_fail.rs
+++ b/src/test/ui/destructuring-assignment/slice_destructure_fail.rs
@@ -1,5 +1,3 @@
-#![feature(destructuring_assignment)]
-
fn main() {
let (mut a, mut b);
[a, .., b, ..] = [0, 1]; //~ ERROR `..` can only be used once per slice pattern
diff --git a/src/test/ui/destructuring-assignment/slice_destructure_fail.stderr b/src/test/ui/destructuring-assignment/slice_destructure_fail.stderr
index cc412c72df5..92c86febac4 100644
--- a/src/test/ui/destructuring-assignment/slice_destructure_fail.stderr
+++ b/src/test/ui/destructuring-assignment/slice_destructure_fail.stderr
@@ -1,5 +1,5 @@
error: `..` can only be used once per slice pattern
- --> $DIR/slice_destructure_fail.rs:5:14
+ --> $DIR/slice_destructure_fail.rs:3:14
|
LL | [a, .., b, ..] = [0, 1];
| -- ^^ can only be used once per slice pattern
@@ -7,13 +7,13 @@ LL | [a, .., b, ..] = [0, 1];
| previously used here
error[E0527]: pattern requires 3 elements but array has 2
- --> $DIR/slice_destructure_fail.rs:6:3
+ --> $DIR/slice_destructure_fail.rs:4:3
|
LL | [a, a, b] = [1, 2];
| ^^^^^^^^^ expected 2 elements
error[E0527]: pattern requires 1 element but array has 2
- --> $DIR/slice_destructure_fail.rs:7:3
+ --> $DIR/slice_destructure_fail.rs:5:3
|
LL | [_] = [1, 2];
| ^^^ expected 2 elements
diff --git a/src/test/ui/destructuring-assignment/struct_destructure.rs b/src/test/ui/destructuring-assignment/struct_destructure.rs
index 2bcbd9d0d74..8cceaadd7b9 100644
--- a/src/test/ui/destructuring-assignment/struct_destructure.rs
+++ b/src/test/ui/destructuring-assignment/struct_destructure.rs
@@ -1,6 +1,5 @@
// run-pass
-#![feature(destructuring_assignment)]
struct Struct<S, T> {
a: S,
b: T,
diff --git a/src/test/ui/destructuring-assignment/struct_destructure_fail.rs b/src/test/ui/destructuring-assignment/struct_destructure_fail.rs
index 4aa327b61f4..c001fccd4cb 100644
--- a/src/test/ui/destructuring-assignment/struct_destructure_fail.rs
+++ b/src/test/ui/destructuring-assignment/struct_destructure_fail.rs
@@ -1,4 +1,3 @@
-#![feature(destructuring_assignment)]
struct Struct<S, T> {
a: S,
b: T,
diff --git a/src/test/ui/destructuring-assignment/struct_destructure_fail.stderr b/src/test/ui/destructuring-assignment/struct_destructure_fail.stderr
index 635bd5e7edf..ae7b3d1e5a9 100644
--- a/src/test/ui/destructuring-assignment/struct_destructure_fail.stderr
+++ b/src/test/ui/destructuring-assignment/struct_destructure_fail.stderr
@@ -1,5 +1,5 @@
error: expected identifier, found reserved identifier `_`
- --> $DIR/struct_destructure_fail.rs:12:17
+ --> $DIR/struct_destructure_fail.rs:11:17
|
LL | Struct { a, _ } = Struct { a: 1, b: 2 };
| ------ ^ expected identifier, found reserved identifier
@@ -7,25 +7,25 @@ LL | Struct { a, _ } = Struct { a: 1, b: 2 };
| while parsing this struct
error: functional record updates are not allowed in destructuring assignments
- --> $DIR/struct_destructure_fail.rs:14:19
+ --> $DIR/struct_destructure_fail.rs:13:19
|
LL | Struct { a, ..d } = Struct { a: 1, b: 2 };
| ^ help: consider removing the trailing pattern
error: base expression required after `..`
- --> $DIR/struct_destructure_fail.rs:16:19
+ --> $DIR/struct_destructure_fail.rs:15:19
|
LL | Struct { a, .. };
| ^ add a base expression here
error[E0026]: struct `Struct` does not have a field named `c`
- --> $DIR/struct_destructure_fail.rs:11:20
+ --> $DIR/struct_destructure_fail.rs:10:20
|
LL | Struct { a, b, c } = Struct { a: 0, b: 1 };
| ^ struct `Struct` does not have this field
error[E0027]: pattern does not mention field `b`
- --> $DIR/struct_destructure_fail.rs:12:5
+ --> $DIR/struct_destructure_fail.rs:11:5
|
LL | Struct { a, _ } = Struct { a: 1, b: 2 };
| ^^^^^^^^^^^^^^^ missing field `b`
diff --git a/src/test/ui/destructuring-assignment/tuple_destructure.rs b/src/test/ui/destructuring-assignment/tuple_destructure.rs
index 2096182d421..2a8584029d0 100644
--- a/src/test/ui/destructuring-assignment/tuple_destructure.rs
+++ b/src/test/ui/destructuring-assignment/tuple_destructure.rs
@@ -1,7 +1,5 @@
// run-pass
-#![feature(destructuring_assignment)]
-
fn main() {
let (mut a, mut b);
(a, b) = (0, 1);
diff --git a/src/test/ui/destructuring-assignment/tuple_destructure_fail.rs b/src/test/ui/destructuring-assignment/tuple_destructure_fail.rs
index 5524e91dc40..4e3172d1973 100644
--- a/src/test/ui/destructuring-assignment/tuple_destructure_fail.rs
+++ b/src/test/ui/destructuring-assignment/tuple_destructure_fail.rs
@@ -1,5 +1,3 @@
-#![feature(destructuring_assignment)]
-
const C: i32 = 1;
fn main() {
diff --git a/src/test/ui/destructuring-assignment/tuple_destructure_fail.stderr b/src/test/ui/destructuring-assignment/tuple_destructure_fail.stderr
index 1146b88278d..184b3ea6da8 100644
--- a/src/test/ui/destructuring-assignment/tuple_destructure_fail.stderr
+++ b/src/test/ui/destructuring-assignment/tuple_destructure_fail.stderr
@@ -1,5 +1,5 @@
error: `..` can only be used once per tuple pattern
- --> $DIR/tuple_destructure_fail.rs:7:16
+ --> $DIR/tuple_destructure_fail.rs:5:16
|
LL | (a, .., b, ..) = (0, 1);
| -- ^^ can only be used once per tuple pattern
@@ -7,18 +7,16 @@ LL | (a, .., b, ..) = (0, 1);
| previously used here
error[E0308]: mismatched types
- --> $DIR/tuple_destructure_fail.rs:8:5
+ --> $DIR/tuple_destructure_fail.rs:6:5
|
LL | (a, a, b) = (1, 2);
- | ^^^^^^^^^ ------ this expression has type `({integer}, {integer})`
- | |
- | expected a tuple with 2 elements, found one with 3 elements
+ | ^^^^^^^^^ expected a tuple with 2 elements, found one with 3 elements
|
= note: expected type `({integer}, {integer})`
found tuple `(_, _, _)`
error[E0070]: invalid left-hand side of assignment
- --> $DIR/tuple_destructure_fail.rs:9:13
+ --> $DIR/tuple_destructure_fail.rs:7:13
|
LL | (C, ..) = (0,1);
| - ^
@@ -26,12 +24,10 @@ LL | (C, ..) = (0,1);
| cannot assign to this expression
error[E0308]: mismatched types
- --> $DIR/tuple_destructure_fail.rs:10:5
+ --> $DIR/tuple_destructure_fail.rs:8:5
|
LL | (_,) = (1, 2);
- | ^^^^ ------ this expression has type `({integer}, {integer})`
- | |
- | expected a tuple with 2 elements, found one with 1 element
+ | ^^^^ expected a tuple with 2 elements, found one with 1 element
|
= note: expected type `({integer}, {integer})`
found tuple `(_,)`
diff --git a/src/test/ui/destructuring-assignment/tuple_struct_destructure.rs b/src/test/ui/destructuring-assignment/tuple_struct_destructure.rs
index 7b5c5ad2bae..07b5f7a314e 100644
--- a/src/test/ui/destructuring-assignment/tuple_struct_destructure.rs
+++ b/src/test/ui/destructuring-assignment/tuple_struct_destructure.rs
@@ -1,7 +1,5 @@
// run-pass
-#![feature(destructuring_assignment)]
-
struct TupleStruct<S, T>(S, T);
impl<S, T> TupleStruct<S, T> {
diff --git a/src/test/ui/destructuring-assignment/tuple_struct_destructure_fail.rs b/src/test/ui/destructuring-assignment/tuple_struct_destructure_fail.rs
index c39db061177..845f867d7b8 100644
--- a/src/test/ui/destructuring-assignment/tuple_struct_destructure_fail.rs
+++ b/src/test/ui/destructuring-assignment/tuple_struct_destructure_fail.rs
@@ -1,5 +1,3 @@
-#![feature(destructuring_assignment)]
-
struct TupleStruct<S, T>(S, T);
enum Enum<S, T> {
diff --git a/src/test/ui/destructuring-assignment/tuple_struct_destructure_fail.stderr b/src/test/ui/destructuring-assignment/tuple_struct_destructure_fail.stderr
index 9aae4b0a3fa..5cc7acba3f3 100644
--- a/src/test/ui/destructuring-assignment/tuple_struct_destructure_fail.stderr
+++ b/src/test/ui/destructuring-assignment/tuple_struct_destructure_fail.stderr
@@ -1,5 +1,5 @@
error: `..` can only be used once per tuple struct or variant pattern
- --> $DIR/tuple_struct_destructure_fail.rs:25:27
+ --> $DIR/tuple_struct_destructure_fail.rs:23:27
|
LL | TupleStruct(a, .., b, ..) = TupleStruct(0, 1);
| -- ^^ can only be used once per tuple struct or variant pattern
@@ -7,7 +7,7 @@ LL | TupleStruct(a, .., b, ..) = TupleStruct(0, 1);
| previously used here
error: `..` can only be used once per tuple struct or variant pattern
- --> $DIR/tuple_struct_destructure_fail.rs:27:35
+ --> $DIR/tuple_struct_destructure_fail.rs:25:35
|
LL | Enum::SingleVariant(a, .., b, ..) = Enum::SingleVariant(0, 1);
| -- ^^ can only be used once per tuple struct or variant pattern
@@ -15,7 +15,7 @@ LL | Enum::SingleVariant(a, .., b, ..) = Enum::SingleVariant(0, 1);
| previously used here
error[E0023]: this pattern has 3 fields, but the corresponding tuple struct has 2 fields
- --> $DIR/tuple_struct_destructure_fail.rs:30:17
+ --> $DIR/tuple_struct_destructure_fail.rs:28:17
|
LL | struct TupleStruct<S, T>(S, T);
| - - tuple struct has 2 fields
@@ -24,7 +24,7 @@ LL | TupleStruct(a, a, b) = TupleStruct(1, 2);
| ^ ^ ^ expected 2 fields, found 3
error[E0023]: this pattern has 1 field, but the corresponding tuple struct has 2 fields
- --> $DIR/tuple_struct_destructure_fail.rs:32:17
+ --> $DIR/tuple_struct_destructure_fail.rs:30:17
|
LL | struct TupleStruct<S, T>(S, T);
| - - tuple struct has 2 fields
@@ -42,7 +42,7 @@ LL | TupleStruct(..) = TupleStruct(1, 2);
| ~~
error[E0023]: this pattern has 3 fields, but the corresponding tuple variant has 2 fields
- --> $DIR/tuple_struct_destructure_fail.rs:34:25
+ --> $DIR/tuple_struct_destructure_fail.rs:32:25
|
LL | SingleVariant(S, T)
| - - tuple variant has 2 fields
@@ -51,7 +51,7 @@ LL | Enum::SingleVariant(a, a, b) = Enum::SingleVariant(1, 2);
| ^ ^ ^ expected 2 fields, found 3
error[E0023]: this pattern has 1 field, but the corresponding tuple variant has 2 fields
- --> $DIR/tuple_struct_destructure_fail.rs:36:25
+ --> $DIR/tuple_struct_destructure_fail.rs:34:25
|
LL | SingleVariant(S, T)
| - - tuple variant has 2 fields
@@ -69,7 +69,7 @@ LL | Enum::SingleVariant(..) = Enum::SingleVariant(1, 2);
| ~~
error[E0070]: invalid left-hand side of assignment
- --> $DIR/tuple_struct_destructure_fail.rs:40:12
+ --> $DIR/tuple_struct_destructure_fail.rs:38:12
|
LL | test() = TupleStruct(0, 0);
| ------ ^
@@ -77,7 +77,7 @@ LL | test() = TupleStruct(0, 0);
| cannot assign to this expression
error[E0070]: invalid left-hand side of assignment
- --> $DIR/tuple_struct_destructure_fail.rs:42:14
+ --> $DIR/tuple_struct_destructure_fail.rs:40:14
|
LL | (test)() = TupleStruct(0, 0);
| -------- ^
@@ -85,7 +85,7 @@ LL | (test)() = TupleStruct(0, 0);
| cannot assign to this expression
error[E0070]: invalid left-hand side of assignment
- --> $DIR/tuple_struct_destructure_fail.rs:44:38
+ --> $DIR/tuple_struct_destructure_fail.rs:42:38
|
LL | <Alias::<isize> as Test>::test() = TupleStruct(0, 0);
| -------------------------------- ^
diff --git a/src/test/ui/destructuring-assignment/underscore-range-expr-gating.rs b/src/test/ui/destructuring-assignment/underscore-range-expr-gating.rs
deleted file mode 100644
index 4ed4f56702c..00000000000
--- a/src/test/ui/destructuring-assignment/underscore-range-expr-gating.rs
+++ /dev/null
@@ -1,10 +0,0 @@
-fn main() {}
-
-struct S { x : u32 }
-
-#[cfg(FALSE)]
-fn foo() {
- _; //~ ERROR destructuring assignments are unstable
-
- S { x: 5, .. }; //~ ERROR destructuring assignments are unstable
-}
diff --git a/src/test/ui/destructuring-assignment/underscore-range-expr-gating.stderr b/src/test/ui/destructuring-assignment/underscore-range-expr-gating.stderr
deleted file mode 100644
index a5ed761a01c..00000000000
--- a/src/test/ui/destructuring-assignment/underscore-range-expr-gating.stderr
+++ /dev/null
@@ -1,21 +0,0 @@
-error[E0658]: destructuring assignments are unstable
- --> $DIR/underscore-range-expr-gating.rs:7:5
- |
-LL | _;
- | ^
- |
- = note: see issue #71126 <https://github.com/rust-lang/rust/issues/71126> for more information
- = help: add `#![feature(destructuring_assignment)]` to the crate attributes to enable
-
-error[E0658]: destructuring assignments are unstable
- --> $DIR/underscore-range-expr-gating.rs:9:15
- |
-LL | S { x: 5, .. };
- | ^^
- |
- = note: see issue #71126 <https://github.com/rust-lang/rust/issues/71126> for more information
- = help: add `#![feature(destructuring_assignment)]` to the crate attributes to enable
-
-error: aborting due to 2 previous errors
-
-For more information about this error, try `rustc --explain E0658`.
diff --git a/src/test/ui/destructuring-assignment/warn-unused-duplication.rs b/src/test/ui/destructuring-assignment/warn-unused-duplication.rs
index c1c5c2cd3ce..390f44b8aa5 100644
--- a/src/test/ui/destructuring-assignment/warn-unused-duplication.rs
+++ b/src/test/ui/destructuring-assignment/warn-unused-duplication.rs
@@ -1,7 +1,5 @@
// run-pass
-#![feature(destructuring_assignment)]
-
#![warn(unused_assignments)]
fn main() {
diff --git a/src/test/ui/destructuring-assignment/warn-unused-duplication.stderr b/src/test/ui/destructuring-assignment/warn-unused-duplication.stderr
index b87ef6f1571..1df7a5f224f 100644
--- a/src/test/ui/destructuring-assignment/warn-unused-duplication.stderr
+++ b/src/test/ui/destructuring-assignment/warn-unused-duplication.stderr
@@ -1,11 +1,11 @@
warning: value assigned to `a` is never read
- --> $DIR/warn-unused-duplication.rs:11:6
+ --> $DIR/warn-unused-duplication.rs:9:6
|
LL | (a, a) = (0, 1);
| ^
|
note: the lint level is defined here
- --> $DIR/warn-unused-duplication.rs:5:9
+ --> $DIR/warn-unused-duplication.rs:3:9
|
LL | #![warn(unused_assignments)]
| ^^^^^^^^^^^^^^^^^^
diff --git a/src/test/ui/did_you_mean/bad-assoc-ty.rs b/src/test/ui/did_you_mean/bad-assoc-ty.rs
index 1b6bcfbb9fc..609a5b0de6b 100644
--- a/src/test/ui/did_you_mean/bad-assoc-ty.rs
+++ b/src/test/ui/did_you_mean/bad-assoc-ty.rs
@@ -32,6 +32,8 @@ type G = dyn 'static + (Send)::AssocTy;
// Recovery should not apply in this context.
type H = Fn(u8) -> (u8)::Output;
//~^ ERROR ambiguous associated type
+//~| WARN trait objects without an explicit `dyn` are deprecated
+//~| WARN this is accepted in the current edition
macro_rules! ty {
($ty: ty) => ($ty::AssocTy);
diff --git a/src/test/ui/did_you_mean/bad-assoc-ty.stderr b/src/test/ui/did_you_mean/bad-assoc-ty.stderr
index 0e2fdf9f6c2..11514a28b2c 100644
--- a/src/test/ui/did_you_mean/bad-assoc-ty.stderr
+++ b/src/test/ui/did_you_mean/bad-assoc-ty.stderr
@@ -41,13 +41,13 @@ LL | type G = dyn 'static + (Send)::AssocTy;
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `<dyn 'static + (Send)>::AssocTy`
error: missing angle brackets in associated item path
- --> $DIR/bad-assoc-ty.rs:44:10
+ --> $DIR/bad-assoc-ty.rs:46:10
|
LL | type I = ty!()::AssocTy;
| ^^^^^^^^^^^^^^ help: try: `<ty!()>::AssocTy`
error: missing angle brackets in associated item path
- --> $DIR/bad-assoc-ty.rs:37:19
+ --> $DIR/bad-assoc-ty.rs:39:19
|
LL | ($ty: ty) => ($ty::AssocTy);
| ^^^^^^^^^^^^ help: try: `<$ty>::AssocTy`
@@ -99,6 +99,20 @@ error[E0223]: ambiguous associated type
LL | type G = dyn 'static + (Send)::AssocTy;
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use fully-qualified syntax: `<(dyn Send + 'static) as Trait>::AssocTy`
+warning: trait objects without an explicit `dyn` are deprecated
+ --> $DIR/bad-assoc-ty.rs:33:10
+ |
+LL | type H = Fn(u8) -> (u8)::Output;
+ | ^^^^^^^^^^^^^^
+ |
+ = note: `#[warn(bare_trait_objects)]` on by default
+ = warning: this is accepted in the current edition (Rust 2015) but is a hard error in Rust 2021!
+ = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2021/warnings-promoted-to-error.html>
+help: use `dyn`
+ |
+LL | type H = <dyn Fn(u8) -> (u8)>::Output;
+ | ++++ +
+
error[E0223]: ambiguous associated type
--> $DIR/bad-assoc-ty.rs:33:10
|
@@ -106,7 +120,7 @@ LL | type H = Fn(u8) -> (u8)::Output;
| ^^^^^^^^^^^^^^^^^^^^^^ help: use fully-qualified syntax: `<(dyn Fn(u8) -> u8 + 'static) as Trait>::Output`
error[E0223]: ambiguous associated type
- --> $DIR/bad-assoc-ty.rs:37:19
+ --> $DIR/bad-assoc-ty.rs:39:19
|
LL | ($ty: ty) => ($ty::AssocTy);
| ^^^^^^^^^^^^ help: use fully-qualified syntax: `<u8 as Trait>::AssocTy`
@@ -117,13 +131,13 @@ LL | type J = ty!(u8);
= note: this error originates in the macro `ty` (in Nightly builds, run with -Z macro-backtrace for more info)
error[E0223]: ambiguous associated type
- --> $DIR/bad-assoc-ty.rs:44:10
+ --> $DIR/bad-assoc-ty.rs:46:10
|
LL | type I = ty!()::AssocTy;
| ^^^^^^^^^^^^^^ help: use fully-qualified syntax: `<u8 as Trait>::AssocTy`
error[E0121]: the type placeholder `_` is not allowed within types on item signatures for functions
- --> $DIR/bad-assoc-ty.rs:49:13
+ --> $DIR/bad-assoc-ty.rs:51:13
|
LL | fn foo<X: K<_, _>>(x: X) {}
| ^ ^ not allowed in type signatures
@@ -136,7 +150,7 @@ LL | fn foo<X: K<T, T>, T>(x: X) {}
| ~ ~ +++
error[E0121]: the type placeholder `_` is not allowed within types on item signatures for functions
- --> $DIR/bad-assoc-ty.rs:52:34
+ --> $DIR/bad-assoc-ty.rs:54:34
|
LL | fn bar<F>(_: F) where F: Fn() -> _ {}
| ^ not allowed in type signatures
@@ -147,7 +161,7 @@ LL | fn bar<F, T>(_: F) where F: Fn() -> T {}
| +++ ~
error[E0121]: the type placeholder `_` is not allowed within types on item signatures for functions
- --> $DIR/bad-assoc-ty.rs:55:19
+ --> $DIR/bad-assoc-ty.rs:57:19
|
LL | fn baz<F: Fn() -> _>(_: F) {}
| ^ not allowed in type signatures
@@ -158,7 +172,7 @@ LL | fn baz<F: Fn() -> T, T>(_: F) {}
| ~+++
error[E0121]: the type placeholder `_` is not allowed within types on item signatures for structs
- --> $DIR/bad-assoc-ty.rs:58:33
+ --> $DIR/bad-assoc-ty.rs:60:33
|
LL | struct L<F>(F) where F: Fn() -> _;
| ^ not allowed in type signatures
@@ -169,7 +183,7 @@ LL | struct L<F, T>(F) where F: Fn() -> T;
| +++ ~
error[E0121]: the type placeholder `_` is not allowed within types on item signatures for structs
- --> $DIR/bad-assoc-ty.rs:60:30
+ --> $DIR/bad-assoc-ty.rs:62:30
|
LL | struct M<F> where F: Fn() -> _ {
| ^ not allowed in type signatures
@@ -180,7 +194,7 @@ LL | struct M<F, T> where F: Fn() -> T {
| +++ ~
error[E0121]: the type placeholder `_` is not allowed within types on item signatures for enums
- --> $DIR/bad-assoc-ty.rs:64:28
+ --> $DIR/bad-assoc-ty.rs:66:28
|
LL | enum N<F> where F: Fn() -> _ {
| ^ not allowed in type signatures
@@ -191,7 +205,7 @@ LL | enum N<F, T> where F: Fn() -> T {
| +++ ~
error[E0121]: the type placeholder `_` is not allowed within types on item signatures for unions
- --> $DIR/bad-assoc-ty.rs:69:29
+ --> $DIR/bad-assoc-ty.rs:71:29
|
LL | union O<F> where F: Fn() -> _ {
| ^ not allowed in type signatures
@@ -202,7 +216,7 @@ LL | union O<F, T> where F: Fn() -> T {
| +++ ~
error[E0121]: the type placeholder `_` is not allowed within types on item signatures for traits
- --> $DIR/bad-assoc-ty.rs:74:29
+ --> $DIR/bad-assoc-ty.rs:76:29
|
LL | trait P<F> where F: Fn() -> _ {
| ^ not allowed in type signatures
@@ -213,7 +227,7 @@ LL | trait P<F, T> where F: Fn() -> T {
| +++ ~
error[E0121]: the type placeholder `_` is not allowed within types on item signatures for functions
- --> $DIR/bad-assoc-ty.rs:79:38
+ --> $DIR/bad-assoc-ty.rs:81:38
|
LL | fn foo<F>(_: F) where F: Fn() -> _ {}
| ^ not allowed in type signatures
@@ -223,7 +237,7 @@ help: use type parameters instead
LL | fn foo<F, T>(_: F) where F: Fn() -> T {}
| +++ ~
-error: aborting due to 28 previous errors
+error: aborting due to 28 previous errors; 1 warning emitted
Some errors have detailed explanations: E0121, E0223.
For more information about an error, try `rustc --explain E0121`.
diff --git a/src/test/ui/did_you_mean/issue-38147-2.rs b/src/test/ui/did_you_mean/issue-38147-2.rs
index fe2634d88ab..154b149b720 100644
--- a/src/test/ui/did_you_mean/issue-38147-2.rs
+++ b/src/test/ui/did_you_mean/issue-38147-2.rs
@@ -1,11 +1,16 @@
struct Bar<'a> {
- s: &'a String
+ s: &'a String,
+ // use wonky spaces to ensure we are creating the span correctly
+ longer_name: & 'a Vec<u8>
}
impl<'a> Bar<'a> {
fn f(&mut self) {
self.s.push('x');
//~^ ERROR cannot borrow `*self.s` as mutable, as it is behind a `&` reference
+
+ self.longer_name.push(13);
+ //~^ ERROR cannot borrow `*self.longer_name` as mutable, as it is behind a `&` reference
}
}
diff --git a/src/test/ui/did_you_mean/issue-38147-2.stderr b/src/test/ui/did_you_mean/issue-38147-2.stderr
index 8bf5c76977d..7c287a7dbfa 100644
--- a/src/test/ui/did_you_mean/issue-38147-2.stderr
+++ b/src/test/ui/did_you_mean/issue-38147-2.stderr
@@ -1,12 +1,25 @@
error[E0596]: cannot borrow `*self.s` as mutable, as it is behind a `&` reference
- --> $DIR/issue-38147-2.rs:7:9
+ --> $DIR/issue-38147-2.rs:9:9
|
-LL | s: &'a String
- | ---------- help: consider changing this to be mutable: `&'a mut String`
-...
LL | self.s.push('x');
| ^^^^^^^^^^^^^^^^ cannot borrow as mutable
+ |
+help: consider changing this to be mutable
+ |
+LL | s: &'a mut String,
+ | +++
+
+error[E0596]: cannot borrow `*self.longer_name` as mutable, as it is behind a `&` reference
+ --> $DIR/issue-38147-2.rs:12:9
+ |
+LL | self.longer_name.push(13);
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^ cannot borrow as mutable
+ |
+help: consider changing this to be mutable
+ |
+LL | longer_name: & 'a mut Vec<u8>
+ | +++
-error: aborting due to previous error
+error: aborting due to 2 previous errors
For more information about this error, try `rustc --explain E0596`.
diff --git a/src/test/ui/did_you_mean/issue-38147-3.stderr b/src/test/ui/did_you_mean/issue-38147-3.stderr
index 0e1e42261c4..94ffe17f101 100644
--- a/src/test/ui/did_you_mean/issue-38147-3.stderr
+++ b/src/test/ui/did_you_mean/issue-38147-3.stderr
@@ -1,11 +1,13 @@
error[E0596]: cannot borrow `*self.s` as mutable, as it is behind a `&` reference
--> $DIR/issue-38147-3.rs:7:9
|
-LL | s: &'a String
- | ---------- help: consider changing this to be mutable: `&'a mut String`
-...
LL | self.s.push('x');
| ^^^^^^^^^^^^^^^^ cannot borrow as mutable
+ |
+help: consider changing this to be mutable
+ |
+LL | s: &'a mut String
+ | +++
error: aborting due to previous error
diff --git a/src/test/ui/drop/drop-trait-enum.rs b/src/test/ui/drop/drop-trait-enum.rs
index 4ab8f733ad7..d2b77650a9d 100644
--- a/src/test/ui/drop/drop-trait-enum.rs
+++ b/src/test/ui/drop/drop-trait-enum.rs
@@ -3,6 +3,7 @@
#![allow(unused_assignments)]
#![allow(unused_variables)]
// ignore-emscripten no threads support
+// needs-unwind
use std::thread;
use std::sync::mpsc::{channel, Sender};
diff --git a/src/test/ui/drop/dynamic-drop-async.rs b/src/test/ui/drop/dynamic-drop-async.rs
index c0bf0bdf731..13bd71ecb33 100644
--- a/src/test/ui/drop/dynamic-drop-async.rs
+++ b/src/test/ui/drop/dynamic-drop-async.rs
@@ -4,6 +4,7 @@
// * Dropping one of the values panics while dropping the future.
// run-pass
+// needs-unwind
// edition:2018
// ignore-wasm32-bare compiled with panic=abort by default
diff --git a/src/test/ui/drop/dynamic-drop.rs b/src/test/ui/drop/dynamic-drop.rs
index 7bb43d5b503..736123ed119 100644
--- a/src/test/ui/drop/dynamic-drop.rs
+++ b/src/test/ui/drop/dynamic-drop.rs
@@ -1,4 +1,5 @@
// run-pass
+// needs-unwind
// ignore-wasm32-bare compiled with panic=abort by default
#![feature(generators, generator_trait)]
diff --git a/src/test/ui/drop/issue-90752-raw-ptr-shenanigans.rs b/src/test/ui/drop/issue-90752-raw-ptr-shenanigans.rs
new file mode 100644
index 00000000000..4e67b35949e
--- /dev/null
+++ b/src/test/ui/drop/issue-90752-raw-ptr-shenanigans.rs
@@ -0,0 +1,41 @@
+// run-pass
+
+use std::cell::RefCell;
+
+struct S<'a>(i32, &'a RefCell<Vec<i32>>);
+
+impl<'a> Drop for S<'a> {
+ fn drop(&mut self) {
+ self.1.borrow_mut().push(self.0);
+ }
+}
+
+fn test(drops: &RefCell<Vec<i32>>) {
+ let mut foo = None;
+ let pfoo: *mut _ = &mut foo;
+
+ match foo {
+ None => (),
+ _ => return,
+ }
+
+ // Both S(0) and S(1) should be dropped, but aren't.
+ unsafe { *pfoo = Some((S(0, drops), S(1, drops))); }
+
+ match foo {
+ Some((_x, _)) => {}
+ _ => {}
+ }
+}
+
+fn main() {
+ let drops = RefCell::new(Vec::new());
+ test(&drops);
+
+ // Ideally, we want this...
+ //assert_eq!(*drops.borrow(), &[0, 1]);
+
+ // But the delayed access through the raw pointer confuses drop elaboration,
+ // causing S(1) to be leaked.
+ assert_eq!(*drops.borrow(), &[0]);
+}
diff --git a/src/test/ui/drop/issue-90752.rs b/src/test/ui/drop/issue-90752.rs
new file mode 100644
index 00000000000..4395e45e773
--- /dev/null
+++ b/src/test/ui/drop/issue-90752.rs
@@ -0,0 +1,32 @@
+// run-pass
+
+use std::cell::RefCell;
+
+struct S<'a>(i32, &'a RefCell<Vec<i32>>);
+
+impl<'a> Drop for S<'a> {
+ fn drop(&mut self) {
+ self.1.borrow_mut().push(self.0);
+ }
+}
+
+fn test(drops: &RefCell<Vec<i32>>) {
+ let mut foo = None;
+ match foo {
+ None => (),
+ _ => return,
+ }
+
+ *(&mut foo) = Some((S(0, drops), S(1, drops))); // Both S(0) and S(1) should be dropped
+
+ match foo {
+ Some((_x, _)) => {}
+ _ => {}
+ }
+}
+
+fn main() {
+ let drops = RefCell::new(Vec::new());
+ test(&drops);
+ assert_eq!(*drops.borrow(), &[0, 1]);
+}
diff --git a/src/test/ui/drop/terminate-in-initializer.rs b/src/test/ui/drop/terminate-in-initializer.rs
index c9cb932e62a..66f267aa7c7 100644
--- a/src/test/ui/drop/terminate-in-initializer.rs
+++ b/src/test/ui/drop/terminate-in-initializer.rs
@@ -1,4 +1,5 @@
// run-pass
+// needs-unwind
// ignore-emscripten no threads support
// Issue #787
diff --git a/src/test/ui/dst/dst-bad-assign-3.stderr b/src/test/ui/dst/dst-bad-assign-3.stderr
index 04e46233532..b326dbbbc14 100644
--- a/src/test/ui/dst/dst-bad-assign-3.stderr
+++ b/src/test/ui/dst/dst-bad-assign-3.stderr
@@ -2,7 +2,9 @@ error[E0308]: mismatched types
--> $DIR/dst-bad-assign-3.rs:33:12
|
LL | f5.2 = Bar1 {f: 36};
- | ^^^^^^^^^^^^ expected trait object `dyn ToBar`, found struct `Bar1`
+ | ---- ^^^^^^^^^^^^ expected trait object `dyn ToBar`, found struct `Bar1`
+ | |
+ | expected due to the type of this binding
|
= note: expected trait object `dyn ToBar`
found struct `Bar1`
diff --git a/src/test/ui/dst/dst-bad-assign.stderr b/src/test/ui/dst/dst-bad-assign.stderr
index f87a34c6d37..614f2138751 100644
--- a/src/test/ui/dst/dst-bad-assign.stderr
+++ b/src/test/ui/dst/dst-bad-assign.stderr
@@ -2,7 +2,9 @@ error[E0308]: mismatched types
--> $DIR/dst-bad-assign.rs:35:14
|
LL | f5.ptr = Bar1 {f: 36};
- | ^^^^^^^^^^^^ expected trait object `dyn ToBar`, found struct `Bar1`
+ | ------ ^^^^^^^^^^^^ expected trait object `dyn ToBar`, found struct `Bar1`
+ | |
+ | expected due to the type of this binding
|
= note: expected trait object `dyn ToBar`
found struct `Bar1`
diff --git a/src/test/ui/dst/dst-bad-deep.stderr b/src/test/ui/dst/dst-bad-deep.stderr
index 71e57b3e062..98db7959115 100644
--- a/src/test/ui/dst/dst-bad-deep.stderr
+++ b/src/test/ui/dst/dst-bad-deep.stderr
@@ -10,11 +10,6 @@ note: required because it appears within the type `Fat<[isize]>`
|
LL | struct Fat<T: ?Sized> {
| ^^^
-note: required because it appears within the type `Fat<Fat<[isize]>>`
- --> $DIR/dst-bad-deep.rs:6:8
- |
-LL | struct Fat<T: ?Sized> {
- | ^^^
= note: structs must have a statically known size to be initialized
error: aborting due to previous error
diff --git a/src/test/ui/dyn-keyword/dyn-2018-edition-lint.rs b/src/test/ui/dyn-keyword/dyn-2018-edition-lint.rs
index 23ca36b71e0..a074b5fa5f7 100644
--- a/src/test/ui/dyn-keyword/dyn-2018-edition-lint.rs
+++ b/src/test/ui/dyn-keyword/dyn-2018-edition-lint.rs
@@ -6,6 +6,14 @@ fn function(x: &SomeTrait, y: Box<SomeTrait>) {
//~| WARN this is accepted in the current edition
//~| ERROR trait objects without an explicit `dyn` are deprecated
//~| WARN this is accepted in the current edition
+ //~| ERROR trait objects without an explicit `dyn` are deprecated
+ //~| WARN this is accepted in the current edition
+ //~| ERROR trait objects without an explicit `dyn` are deprecated
+ //~| WARN this is accepted in the current edition
+ //~| ERROR trait objects without an explicit `dyn` are deprecated
+ //~| WARN this is accepted in the current edition
+ //~| ERROR trait objects without an explicit `dyn` are deprecated
+ //~| WARN this is accepted in the current edition
let _x: &SomeTrait = todo!();
//~^ ERROR trait objects without an explicit `dyn` are deprecated
//~| WARN this is accepted in the current edition
diff --git a/src/test/ui/dyn-keyword/dyn-2018-edition-lint.stderr b/src/test/ui/dyn-keyword/dyn-2018-edition-lint.stderr
index c9bb08cf35c..b8e4942dfef 100644
--- a/src/test/ui/dyn-keyword/dyn-2018-edition-lint.stderr
+++ b/src/test/ui/dyn-keyword/dyn-2018-edition-lint.stderr
@@ -2,7 +2,7 @@ error: trait objects without an explicit `dyn` are deprecated
--> $DIR/dyn-2018-edition-lint.rs:4:17
|
LL | fn function(x: &SomeTrait, y: Box<SomeTrait>) {
- | ^^^^^^^^^ help: use `dyn`: `dyn SomeTrait`
+ | ^^^^^^^^^
|
note: the lint level is defined here
--> $DIR/dyn-2018-edition-lint.rs:2:8
@@ -11,24 +11,95 @@ LL | #[deny(bare_trait_objects)]
| ^^^^^^^^^^^^^^^^^^
= warning: this is accepted in the current edition (Rust 2018) but is a hard error in Rust 2021!
= note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2021/warnings-promoted-to-error.html>
+help: use `dyn`
+ |
+LL - fn function(x: &SomeTrait, y: Box<SomeTrait>) {
+LL + fn function(x: &dyn SomeTrait, y: Box<SomeTrait>) {
+ |
error: trait objects without an explicit `dyn` are deprecated
--> $DIR/dyn-2018-edition-lint.rs:4:35
|
LL | fn function(x: &SomeTrait, y: Box<SomeTrait>) {
- | ^^^^^^^^^ help: use `dyn`: `dyn SomeTrait`
+ | ^^^^^^^^^
|
= warning: this is accepted in the current edition (Rust 2018) but is a hard error in Rust 2021!
= note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2021/warnings-promoted-to-error.html>
+help: use `dyn`
+ |
+LL - fn function(x: &SomeTrait, y: Box<SomeTrait>) {
+LL + fn function(x: &SomeTrait, y: Box<dyn SomeTrait>) {
+ |
error: trait objects without an explicit `dyn` are deprecated
- --> $DIR/dyn-2018-edition-lint.rs:9:14
+ --> $DIR/dyn-2018-edition-lint.rs:17:14
|
LL | let _x: &SomeTrait = todo!();
- | ^^^^^^^^^ help: use `dyn`: `dyn SomeTrait`
+ | ^^^^^^^^^
+ |
+ = warning: this is accepted in the current edition (Rust 2018) but is a hard error in Rust 2021!
+ = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2021/warnings-promoted-to-error.html>
+help: use `dyn`
+ |
+LL - let _x: &SomeTrait = todo!();
+LL + let _x: &dyn SomeTrait = todo!();
+ |
+
+error: trait objects without an explicit `dyn` are deprecated
+ --> $DIR/dyn-2018-edition-lint.rs:4:17
+ |
+LL | fn function(x: &SomeTrait, y: Box<SomeTrait>) {
+ | ^^^^^^^^^
+ |
+ = warning: this is accepted in the current edition (Rust 2018) but is a hard error in Rust 2021!
+ = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2021/warnings-promoted-to-error.html>
+help: use `dyn`
+ |
+LL - fn function(x: &SomeTrait, y: Box<SomeTrait>) {
+LL + fn function(x: &dyn SomeTrait, y: Box<SomeTrait>) {
+ |
+
+error: trait objects without an explicit `dyn` are deprecated
+ --> $DIR/dyn-2018-edition-lint.rs:4:17
+ |
+LL | fn function(x: &SomeTrait, y: Box<SomeTrait>) {
+ | ^^^^^^^^^
|
= warning: this is accepted in the current edition (Rust 2018) but is a hard error in Rust 2021!
= note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2021/warnings-promoted-to-error.html>
+help: use `dyn`
+ |
+LL - fn function(x: &SomeTrait, y: Box<SomeTrait>) {
+LL + fn function(x: &dyn SomeTrait, y: Box<SomeTrait>) {
+ |
+
+error: trait objects without an explicit `dyn` are deprecated
+ --> $DIR/dyn-2018-edition-lint.rs:4:35
+ |
+LL | fn function(x: &SomeTrait, y: Box<SomeTrait>) {
+ | ^^^^^^^^^
+ |
+ = warning: this is accepted in the current edition (Rust 2018) but is a hard error in Rust 2021!
+ = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2021/warnings-promoted-to-error.html>
+help: use `dyn`
+ |
+LL - fn function(x: &SomeTrait, y: Box<SomeTrait>) {
+LL + fn function(x: &SomeTrait, y: Box<dyn SomeTrait>) {
+ |
+
+error: trait objects without an explicit `dyn` are deprecated
+ --> $DIR/dyn-2018-edition-lint.rs:4:35
+ |
+LL | fn function(x: &SomeTrait, y: Box<SomeTrait>) {
+ | ^^^^^^^^^
+ |
+ = warning: this is accepted in the current edition (Rust 2018) but is a hard error in Rust 2021!
+ = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2021/warnings-promoted-to-error.html>
+help: use `dyn`
+ |
+LL - fn function(x: &SomeTrait, y: Box<SomeTrait>) {
+LL + fn function(x: &SomeTrait, y: Box<dyn SomeTrait>) {
+ |
-error: aborting due to 3 previous errors
+error: aborting due to 7 previous errors
diff --git a/src/test/ui/dyn-keyword/dyn-2021-edition-error.rs b/src/test/ui/dyn-keyword/dyn-2021-edition-error.rs
index bc1bed8a9a4..0f05d8753ea 100644
--- a/src/test/ui/dyn-keyword/dyn-2021-edition-error.rs
+++ b/src/test/ui/dyn-keyword/dyn-2021-edition-error.rs
@@ -4,7 +4,6 @@ fn function(x: &SomeTrait, y: Box<SomeTrait>) {
//~^ ERROR trait objects must include the `dyn` keyword
//~| ERROR trait objects must include the `dyn` keyword
let _x: &SomeTrait = todo!();
- //~^ ERROR trait objects must include the `dyn` keyword
}
trait SomeTrait {}
diff --git a/src/test/ui/dyn-keyword/dyn-2021-edition-error.stderr b/src/test/ui/dyn-keyword/dyn-2021-edition-error.stderr
index 730bc691bf8..b5bc359d716 100644
--- a/src/test/ui/dyn-keyword/dyn-2021-edition-error.stderr
+++ b/src/test/ui/dyn-keyword/dyn-2021-edition-error.stderr
@@ -1,15 +1,4 @@
error[E0782]: trait objects must include the `dyn` keyword
- --> $DIR/dyn-2021-edition-error.rs:6:14
- |
-LL | let _x: &SomeTrait = todo!();
- | ^^^^^^^^^
- |
-help: add `dyn` keyword before this trait
- |
-LL | let _x: &dyn SomeTrait = todo!();
- | +++
-
-error[E0782]: trait objects must include the `dyn` keyword
--> $DIR/dyn-2021-edition-error.rs:3:17
|
LL | fn function(x: &SomeTrait, y: Box<SomeTrait>) {
@@ -17,8 +6,9 @@ LL | fn function(x: &SomeTrait, y: Box<SomeTrait>) {
|
help: add `dyn` keyword before this trait
|
-LL | fn function(x: &dyn SomeTrait, y: Box<SomeTrait>) {
- | +++
+LL - fn function(x: &SomeTrait, y: Box<SomeTrait>) {
+LL + fn function(x: &dyn SomeTrait, y: Box<SomeTrait>) {
+ |
error[E0782]: trait objects must include the `dyn` keyword
--> $DIR/dyn-2021-edition-error.rs:3:35
@@ -28,9 +18,10 @@ LL | fn function(x: &SomeTrait, y: Box<SomeTrait>) {
|
help: add `dyn` keyword before this trait
|
-LL | fn function(x: &SomeTrait, y: Box<dyn SomeTrait>) {
- | +++
+LL - fn function(x: &SomeTrait, y: Box<SomeTrait>) {
+LL + fn function(x: &SomeTrait, y: Box<dyn SomeTrait>) {
+ |
-error: aborting due to 3 previous errors
+error: aborting due to 2 previous errors
For more information about this error, try `rustc --explain E0782`.
diff --git a/src/test/ui/dyn-keyword/dyn-angle-brackets.fixed b/src/test/ui/dyn-keyword/dyn-angle-brackets.fixed
index 25caa6a8030..00069a3e7ad 100644
--- a/src/test/ui/dyn-keyword/dyn-angle-brackets.fixed
+++ b/src/test/ui/dyn-keyword/dyn-angle-brackets.fixed
@@ -15,8 +15,6 @@ impl fmt::Display for Foo {
<dyn fmt::Debug>::fmt(self, f)
//~^ ERROR trait objects without an explicit `dyn` are deprecated
//~| WARNING this is accepted in the current edition
- //~| ERROR trait objects without an explicit `dyn` are deprecated
- //~| WARNING this is accepted in the current edition
}
}
diff --git a/src/test/ui/dyn-keyword/dyn-angle-brackets.rs b/src/test/ui/dyn-keyword/dyn-angle-brackets.rs
index cf72da2b61e..ee5fee4cfb8 100644
--- a/src/test/ui/dyn-keyword/dyn-angle-brackets.rs
+++ b/src/test/ui/dyn-keyword/dyn-angle-brackets.rs
@@ -15,8 +15,6 @@ impl fmt::Display for Foo {
<fmt::Debug>::fmt(self, f)
//~^ ERROR trait objects without an explicit `dyn` are deprecated
//~| WARNING this is accepted in the current edition
- //~| ERROR trait objects without an explicit `dyn` are deprecated
- //~| WARNING this is accepted in the current edition
}
}
diff --git a/src/test/ui/dyn-keyword/dyn-angle-brackets.stderr b/src/test/ui/dyn-keyword/dyn-angle-brackets.stderr
index ef0f5b7f59d..fd4030e9622 100644
--- a/src/test/ui/dyn-keyword/dyn-angle-brackets.stderr
+++ b/src/test/ui/dyn-keyword/dyn-angle-brackets.stderr
@@ -2,7 +2,7 @@ error: trait objects without an explicit `dyn` are deprecated
--> $DIR/dyn-angle-brackets.rs:15:10
|
LL | <fmt::Debug>::fmt(self, f)
- | ^^^^^^^^^^ help: use `dyn`: `dyn fmt::Debug`
+ | ^^^^^^^^^^
|
note: the lint level is defined here
--> $DIR/dyn-angle-brackets.rs:4:9
@@ -11,15 +11,11 @@ LL | #![deny(bare_trait_objects)]
| ^^^^^^^^^^^^^^^^^^
= warning: this is accepted in the current edition (Rust 2018) but is a hard error in Rust 2021!
= note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2021/warnings-promoted-to-error.html>
-
-error: trait objects without an explicit `dyn` are deprecated
- --> $DIR/dyn-angle-brackets.rs:15:10
+help: use `dyn`
|
-LL | <fmt::Debug>::fmt(self, f)
- | ^^^^^^^^^^ help: use `dyn`: `dyn fmt::Debug`
- |
- = warning: this is accepted in the current edition (Rust 2018) but is a hard error in Rust 2021!
- = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2021/warnings-promoted-to-error.html>
+LL - <fmt::Debug>::fmt(self, f)
+LL + <dyn fmt::Debug>::fmt(self, f)
+ |
-error: aborting due to 2 previous errors
+error: aborting due to previous error
diff --git a/src/test/ui/editions/dyn-trait-sugg-2021.rs b/src/test/ui/editions/dyn-trait-sugg-2021.rs
index 47c48e7ec9e..de0444b63e2 100644
--- a/src/test/ui/editions/dyn-trait-sugg-2021.rs
+++ b/src/test/ui/editions/dyn-trait-sugg-2021.rs
@@ -3,10 +3,10 @@
trait Foo<T> {}
impl<T> dyn Foo<T> {
- fn hi(_x: T) {}
+ fn hi(_x: T) {}
}
fn main() {
Foo::hi(123);
- //~^ ERROR trait objects without an explicit `dyn` are deprecated
+ //~^ ERROR trait objects must include the `dyn` keyword
}
diff --git a/src/test/ui/editions/dyn-trait-sugg-2021.stderr b/src/test/ui/editions/dyn-trait-sugg-2021.stderr
index a7119b073ab..8c68dec1df7 100644
--- a/src/test/ui/editions/dyn-trait-sugg-2021.stderr
+++ b/src/test/ui/editions/dyn-trait-sugg-2021.stderr
@@ -1,8 +1,13 @@
-error[E0782]: trait objects without an explicit `dyn` are deprecated
+error[E0782]: trait objects must include the `dyn` keyword
--> $DIR/dyn-trait-sugg-2021.rs:10:5
|
LL | Foo::hi(123);
- | ^^^ help: use `dyn`: `<dyn Foo>`
+ | ^^^
+ |
+help: add `dyn` keyword before this trait
+ |
+LL | <dyn Foo>::hi(123);
+ | ++++ +
error: aborting due to previous error
diff --git a/src/test/ui/empty_global_asm.rs b/src/test/ui/empty_global_asm.rs
index efbe2b2eb67..dbcc7be0578 100644
--- a/src/test/ui/empty_global_asm.rs
+++ b/src/test/ui/empty_global_asm.rs
@@ -1,6 +1,7 @@
// run-pass
-#![feature(global_asm)]
+#[allow(unused_imports)]
+use std::arch::global_asm;
#[cfg(target_arch = "x86")]
global_asm!("");
diff --git a/src/test/ui/entry-point/imported_main_const_fn_item_type_forbidden.stderr b/src/test/ui/entry-point/imported_main_const_fn_item_type_forbidden.stderr
index 6aa170fdfd2..c731c328322 100644
--- a/src/test/ui/entry-point/imported_main_const_fn_item_type_forbidden.stderr
+++ b/src/test/ui/entry-point/imported_main_const_fn_item_type_forbidden.stderr
@@ -21,7 +21,7 @@ LL | type MainFn = impl Fn();
LL | pub const BAR: MainFn = bar;
| ^^^ expected opaque type, found fn item
|
- = note: expected opaque type `impl Fn<()>`
+ = note: expected opaque type `impl Fn()`
found fn item `fn() {bar}`
error: could not find defining uses
diff --git a/src/test/ui/enum-discriminant/arbitrary_enum_discriminant.rs b/src/test/ui/enum-discriminant/arbitrary_enum_discriminant.rs
index 22c5332c925..ccc423e4a19 100644
--- a/src/test/ui/enum-discriminant/arbitrary_enum_discriminant.rs
+++ b/src/test/ui/enum-discriminant/arbitrary_enum_discriminant.rs
@@ -22,14 +22,6 @@ impl Enum {
}
}
-#[allow(dead_code)]
-#[repr(u8)]
-enum FieldlessEnum {
- Unit = 3,
- Tuple() = 2,
- Struct {} = 1,
-}
-
fn main() {
const UNIT: Enum = Enum::Unit;
const TUPLE: Enum = Enum::Tuple(5);
@@ -48,9 +40,4 @@ fn main() {
assert_eq!(3, UNIT_TAG);
assert_eq!(2, TUPLE_TAG);
assert_eq!(1, STRUCT_TAG);
-
- // Ensure `as` conversions are correct
- assert_eq!(3, FieldlessEnum::Unit as u8);
- assert_eq!(2, FieldlessEnum::Tuple() as u8);
- assert_eq!(1, FieldlessEnum::Struct{} as u8);
}
diff --git a/src/test/ui/error-codes/E0070.rs b/src/test/ui/error-codes/E0070.rs
index ab956d81098..3aae0c9ff6e 100644
--- a/src/test/ui/error-codes/E0070.rs
+++ b/src/test/ui/error-codes/E0070.rs
@@ -6,7 +6,6 @@ fn some_function() {
SOME_CONST = 14; //~ ERROR E0070
1 = 3; //~ ERROR E0070
some_other_func() = 4; //~ ERROR E0070
- //~^ ERROR E0308
}
fn main() {
diff --git a/src/test/ui/error-codes/E0070.stderr b/src/test/ui/error-codes/E0070.stderr
index e24d498e352..8868bc257a7 100644
--- a/src/test/ui/error-codes/E0070.stderr
+++ b/src/test/ui/error-codes/E0070.stderr
@@ -22,13 +22,6 @@ LL | some_other_func() = 4;
| |
| cannot assign to this expression
-error[E0308]: mismatched types
- --> $DIR/E0070.rs:8:25
- |
-LL | some_other_func() = 4;
- | ^ expected `()`, found integer
-
-error: aborting due to 4 previous errors
+error: aborting due to 3 previous errors
-Some errors have detailed explanations: E0070, E0308.
-For more information about an error, try `rustc --explain E0070`.
+For more information about this error, try `rustc --explain E0070`.
diff --git a/src/test/ui/error-codes/E0161.edition.stderr b/src/test/ui/error-codes/E0161.edition.stderr
index 1060675cd45..fb082bc1eab 100644
--- a/src/test/ui/error-codes/E0161.edition.stderr
+++ b/src/test/ui/error-codes/E0161.edition.stderr
@@ -1,5 +1,5 @@
error[E0161]: cannot move a value of type dyn Bar: the size of dyn Bar cannot be statically determined
- --> $DIR/E0161.rs:29:5
+ --> $DIR/E0161.rs:32:5
|
LL | x.f();
| ^^^^^
diff --git a/src/test/ui/error-codes/E0161.migrate.stderr b/src/test/ui/error-codes/E0161.migrate.stderr
index 1060675cd45..fb082bc1eab 100644
--- a/src/test/ui/error-codes/E0161.migrate.stderr
+++ b/src/test/ui/error-codes/E0161.migrate.stderr
@@ -1,5 +1,5 @@
error[E0161]: cannot move a value of type dyn Bar: the size of dyn Bar cannot be statically determined
- --> $DIR/E0161.rs:29:5
+ --> $DIR/E0161.rs:32:5
|
LL | x.f();
| ^^^^^
diff --git a/src/test/ui/error-codes/E0161.nll.stderr b/src/test/ui/error-codes/E0161.nll.stderr
index 1060675cd45..fb082bc1eab 100644
--- a/src/test/ui/error-codes/E0161.nll.stderr
+++ b/src/test/ui/error-codes/E0161.nll.stderr
@@ -1,5 +1,5 @@
error[E0161]: cannot move a value of type dyn Bar: the size of dyn Bar cannot be statically determined
- --> $DIR/E0161.rs:29:5
+ --> $DIR/E0161.rs:32:5
|
LL | x.f();
| ^^^^^
diff --git a/src/test/ui/error-codes/E0161.rs b/src/test/ui/error-codes/E0161.rs
index ba74529e4b6..f3a7b68c7cf 100644
--- a/src/test/ui/error-codes/E0161.rs
+++ b/src/test/ui/error-codes/E0161.rs
@@ -1,5 +1,3 @@
-// ignore-compare-mode-nll
-
// Check that E0161 is a hard error in all possible configurations that might
// affect it.
@@ -13,6 +11,11 @@
//[zflagsul] check-pass
//[editionul] check-pass
+// Since we are testing nll (and migration) explicitly as a separate
+// revisions, don't worry about the --compare-mode=nll on this test.
+
+// ignore-compare-mode-nll
+
#![allow(incomplete_features)]
#![cfg_attr(nll, feature(nll))]
#![cfg_attr(nllul, feature(nll))]
diff --git a/src/test/ui/error-codes/E0161.zflags.stderr b/src/test/ui/error-codes/E0161.zflags.stderr
index 1060675cd45..fb082bc1eab 100644
--- a/src/test/ui/error-codes/E0161.zflags.stderr
+++ b/src/test/ui/error-codes/E0161.zflags.stderr
@@ -1,5 +1,5 @@
error[E0161]: cannot move a value of type dyn Bar: the size of dyn Bar cannot be statically determined
- --> $DIR/E0161.rs:29:5
+ --> $DIR/E0161.rs:32:5
|
LL | x.f();
| ^^^^^
diff --git a/src/test/ui/error-codes/E0271.stderr b/src/test/ui/error-codes/E0271.stderr
index 284eaafc6cc..9c9c7237d71 100644
--- a/src/test/ui/error-codes/E0271.stderr
+++ b/src/test/ui/error-codes/E0271.stderr
@@ -2,8 +2,13 @@ error[E0271]: type mismatch resolving `<i8 as Trait>::AssociatedType == u32`
--> $DIR/E0271.rs:10:5
|
LL | foo(3_i8);
- | ^^^ expected `u32`, found `&str`
+ | ^^^ type mismatch resolving `<i8 as Trait>::AssociatedType == u32`
|
+note: expected this to be `u32`
+ --> $DIR/E0271.rs:7:43
+ |
+LL | impl Trait for i8 { type AssociatedType = &'static str; }
+ | ^^^^^^^^^^^^
note: required by a bound in `foo`
--> $DIR/E0271.rs:3:32
|
diff --git a/src/test/ui/expr/if/if-without-block.stderr b/src/test/ui/expr/if/if-without-block.stderr
index ee2bb62e2bb..d3f6ca07617 100644
--- a/src/test/ui/expr/if/if-without-block.stderr
+++ b/src/test/ui/expr/if/if-without-block.stderr
@@ -7,7 +7,11 @@ LL | if 5 == {
LL | }
| ^ expected `{`
|
- = help: maybe you forgot the right operand of the condition?
+help: maybe you forgot the right operand of the condition?
+ --> $DIR/if-without-block.rs:3:10
+ |
+LL | if 5 == {
+ | ^^
error: aborting due to previous error
diff --git a/src/test/ui/expr/malformed_closure/ruby_style_closure.stderr b/src/test/ui/expr/malformed_closure/ruby_style_closure.stderr
index 53924e24e46..9db9cfc7ff0 100644
--- a/src/test/ui/expr/malformed_closure/ruby_style_closure.stderr
+++ b/src/test/ui/expr/malformed_closure/ruby_style_closure.stderr
@@ -23,8 +23,8 @@ LL | | });
note: required by a bound in `Option::<T>::and_then`
--> $SRC_DIR/core/src/option.rs:LL:COL
|
-LL | pub fn and_then<U, F: FnOnce(T) -> Option<U>>(self, f: F) -> Option<U> {
- | ^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `Option::<T>::and_then`
+LL | F: ~const FnOnce(T) -> Option<U>,
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `Option::<T>::and_then`
error: aborting due to 2 previous errors
diff --git a/src/test/ui/extern-flag/empty-extern-arg.rs b/src/test/ui/extern-flag/empty-extern-arg.rs
index d3cb5aaaeba..3170537b0e0 100644
--- a/src/test/ui/extern-flag/empty-extern-arg.rs
+++ b/src/test/ui/extern-flag/empty-extern-arg.rs
@@ -1,4 +1,6 @@
// compile-flags: --extern std=
// error-pattern: extern location for std does not exist
+// needs-unwind since it affects the error output
+// ignore-emscripten compiled with panic=abort, personality not required
fn main() {}
diff --git a/src/test/ui/extern-flag/empty-extern-arg.stderr b/src/test/ui/extern-flag/empty-extern-arg.stderr
index 199c4fb616b..39a66c08de0 100644
--- a/src/test/ui/extern-flag/empty-extern-arg.stderr
+++ b/src/test/ui/extern-flag/empty-extern-arg.stderr
@@ -1,4 +1,11 @@
error: extern location for std does not exist:
-error: aborting due to previous error
+error: language item required, but not found: `eh_personality`
+ |
+ = note: this can occur when a binary crate with `#![no_std]` is compiled for a target where `eh_personality` is defined in the standard library
+ = help: you may be able to compile for a target that doesn't need `eh_personality`, specify a target with `--target` or in `.cargo/config`
+
+error: `#[panic_handler]` function required, but not found
+
+error: aborting due to 3 previous errors
diff --git a/src/test/ui/extern/extern-crate-multiple-missing.rs b/src/test/ui/extern/extern-crate-multiple-missing.rs
new file mode 100644
index 00000000000..a6560ca7862
--- /dev/null
+++ b/src/test/ui/extern/extern-crate-multiple-missing.rs
@@ -0,0 +1,10 @@
+// If multiple `extern crate` resolutions fail each of them should produce an error
+extern crate bar; //~ ERROR can't find crate for `bar`
+extern crate foo; //~ ERROR can't find crate for `foo`
+
+fn main() {
+ // If the crate name introduced by `extern crate` failed to resolve then subsequent
+ // derived paths do not emit additional errors
+ foo::something();
+ bar::something();
+}
diff --git a/src/test/ui/extern/extern-crate-multiple-missing.stderr b/src/test/ui/extern/extern-crate-multiple-missing.stderr
new file mode 100644
index 00000000000..893bb4fb26d
--- /dev/null
+++ b/src/test/ui/extern/extern-crate-multiple-missing.stderr
@@ -0,0 +1,15 @@
+error[E0463]: can't find crate for `bar`
+ --> $DIR/extern-crate-multiple-missing.rs:2:1
+ |
+LL | extern crate bar;
+ | ^^^^^^^^^^^^^^^^^ can't find crate
+
+error[E0463]: can't find crate for `foo`
+ --> $DIR/extern-crate-multiple-missing.rs:3:1
+ |
+LL | extern crate foo;
+ | ^^^^^^^^^^^^^^^^^ can't find crate
+
+error: aborting due to 2 previous errors
+
+For more information about this error, try `rustc --explain E0463`.
diff --git a/src/test/ui/extern/extern-types-unsized.stderr b/src/test/ui/extern/extern-types-unsized.stderr
index e21077159b2..8d6713261d5 100644
--- a/src/test/ui/extern/extern-types-unsized.stderr
+++ b/src/test/ui/extern/extern-types-unsized.stderr
@@ -71,11 +71,6 @@ note: required because it appears within the type `Bar<A>`
|
LL | struct Bar<T: ?Sized> {
| ^^^
-note: required because it appears within the type `Bar<Bar<A>>`
- --> $DIR/extern-types-unsized.rs:14:8
- |
-LL | struct Bar<T: ?Sized> {
- | ^^^
note: required by a bound in `assert_sized`
--> $DIR/extern-types-unsized.rs:19:17
|
diff --git a/src/test/ui/extern/issue-64655-allow-unwind-when-calling-panic-directly.rs b/src/test/ui/extern/issue-64655-allow-unwind-when-calling-panic-directly.rs
index 74c6e501c91..7a91cbdc2f5 100644
--- a/src/test/ui/extern/issue-64655-allow-unwind-when-calling-panic-directly.rs
+++ b/src/test/ui/extern/issue-64655-allow-unwind-when-calling-panic-directly.rs
@@ -1,4 +1,5 @@
// run-pass
+// needs-unwind
// ignore-wasm32-bare compiled with panic=abort by default
// ignore-emscripten no threads support
diff --git a/src/test/ui/extern/issue-64655-extern-rust-must-allow-unwind.rs b/src/test/ui/extern/issue-64655-extern-rust-must-allow-unwind.rs
index bc15fcb0e39..e84ff41b344 100644
--- a/src/test/ui/extern/issue-64655-extern-rust-must-allow-unwind.rs
+++ b/src/test/ui/extern/issue-64655-extern-rust-must-allow-unwind.rs
@@ -1,4 +1,5 @@
// run-pass
+// needs-unwind
// ignore-wasm32-bare compiled with panic=abort by default
// ignore-emscripten no threads support
diff --git a/src/test/ui/feature-gates/feature-gate-asm.rs b/src/test/ui/feature-gates/feature-gate-asm.rs
index b4dca7216b1..556219b98a9 100644
--- a/src/test/ui/feature-gates/feature-gate-asm.rs
+++ b/src/test/ui/feature-gates/feature-gate-asm.rs
@@ -4,8 +4,6 @@
fn main() {
unsafe {
- asm!("");
- //~^ ERROR inline assembly is not stable enough
llvm_asm!("");
//~^ ERROR prefer using the new asm! syntax instead
}
diff --git a/src/test/ui/feature-gates/feature-gate-asm.stderr b/src/test/ui/feature-gates/feature-gate-asm.stderr
index 144a4258184..72ba70d0d91 100644
--- a/src/test/ui/feature-gates/feature-gate-asm.stderr
+++ b/src/test/ui/feature-gates/feature-gate-asm.stderr
@@ -1,14 +1,5 @@
-error[E0658]: use of unstable library feature 'asm': inline assembly is not stable enough for use and is subject to change
- --> $DIR/feature-gate-asm.rs:7:9
- |
-LL | asm!("");
- | ^^^
- |
- = note: see issue #72016 <https://github.com/rust-lang/rust/issues/72016> for more information
- = help: add `#![feature(asm)]` to the crate attributes to enable
-
error[E0658]: use of unstable library feature 'llvm_asm': prefer using the new asm! syntax instead
- --> $DIR/feature-gate-asm.rs:9:9
+ --> $DIR/feature-gate-asm.rs:7:9
|
LL | llvm_asm!("");
| ^^^^^^^^
@@ -16,6 +7,6 @@ LL | llvm_asm!("");
= note: see issue #70173 <https://github.com/rust-lang/rust/issues/70173> for more information
= help: add `#![feature(llvm_asm)]` to the crate attributes to enable
-error: aborting due to 2 previous errors
+error: aborting due to previous error
For more information about this error, try `rustc --explain E0658`.
diff --git a/src/test/ui/feature-gates/feature-gate-asm2.rs b/src/test/ui/feature-gates/feature-gate-asm2.rs
index 9044f2cb6af..712e3a56fd8 100644
--- a/src/test/ui/feature-gates/feature-gate-asm2.rs
+++ b/src/test/ui/feature-gates/feature-gate-asm2.rs
@@ -4,8 +4,6 @@
fn main() {
unsafe {
- println!("{:?}", asm!(""));
- //~^ ERROR inline assembly is not stable enough
println!("{:?}", llvm_asm!(""));
//~^ ERROR prefer using the new asm! syntax instead
}
diff --git a/src/test/ui/feature-gates/feature-gate-asm2.stderr b/src/test/ui/feature-gates/feature-gate-asm2.stderr
index 0b0c8a64d22..0297fec16dd 100644
--- a/src/test/ui/feature-gates/feature-gate-asm2.stderr
+++ b/src/test/ui/feature-gates/feature-gate-asm2.stderr
@@ -1,14 +1,5 @@
-error[E0658]: use of unstable library feature 'asm': inline assembly is not stable enough for use and is subject to change
- --> $DIR/feature-gate-asm2.rs:7:26
- |
-LL | println!("{:?}", asm!(""));
- | ^^^
- |
- = note: see issue #72016 <https://github.com/rust-lang/rust/issues/72016> for more information
- = help: add `#![feature(asm)]` to the crate attributes to enable
-
error[E0658]: use of unstable library feature 'llvm_asm': prefer using the new asm! syntax instead
- --> $DIR/feature-gate-asm2.rs:9:26
+ --> $DIR/feature-gate-asm2.rs:7:26
|
LL | println!("{:?}", llvm_asm!(""));
| ^^^^^^^^
@@ -16,6 +7,6 @@ LL | println!("{:?}", llvm_asm!(""));
= note: see issue #70173 <https://github.com/rust-lang/rust/issues/70173> for more information
= help: add `#![feature(llvm_asm)]` to the crate attributes to enable
-error: aborting due to 2 previous errors
+error: aborting due to previous error
For more information about this error, try `rustc --explain E0658`.
diff --git a/src/test/ui/feature-gates/feature-gate-asm_const.rs b/src/test/ui/feature-gates/feature-gate-asm_const.rs
index c152b54c669..d41d7b258aa 100644
--- a/src/test/ui/feature-gates/feature-gate-asm_const.rs
+++ b/src/test/ui/feature-gates/feature-gate-asm_const.rs
@@ -1,6 +1,6 @@
// only-x86_64
-#![feature(asm)]
+use std::arch::asm;
fn main() {
unsafe {
diff --git a/src/test/ui/feature-gates/feature-gate-asm_sym.rs b/src/test/ui/feature-gates/feature-gate-asm_sym.rs
index d89c7dd0ef4..e4d781c6859 100644
--- a/src/test/ui/feature-gates/feature-gate-asm_sym.rs
+++ b/src/test/ui/feature-gates/feature-gate-asm_sym.rs
@@ -1,6 +1,6 @@
// only-x86_64
-#![feature(asm)]
+use std::arch::asm;
fn main() {
unsafe {
diff --git a/src/test/ui/feature-gates/feature-gate-asm_unwind.rs b/src/test/ui/feature-gates/feature-gate-asm_unwind.rs
new file mode 100644
index 00000000000..df161b60081
--- /dev/null
+++ b/src/test/ui/feature-gates/feature-gate-asm_unwind.rs
@@ -0,0 +1,10 @@
+// only-x86_64
+
+use std::arch::asm;
+
+fn main() {
+ unsafe {
+ asm!("", options(may_unwind));
+ //~^ ERROR the `may_unwind` option is unstable
+ }
+}
diff --git a/src/test/ui/feature-gates/feature-gate-asm_unwind.stderr b/src/test/ui/feature-gates/feature-gate-asm_unwind.stderr
new file mode 100644
index 00000000000..6b5bf286e7b
--- /dev/null
+++ b/src/test/ui/feature-gates/feature-gate-asm_unwind.stderr
@@ -0,0 +1,12 @@
+error[E0658]: the `may_unwind` option is unstable
+ --> $DIR/feature-gate-asm_unwind.rs:7:9
+ |
+LL | asm!("", options(may_unwind));
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ |
+ = note: see issue #72016 <https://github.com/rust-lang/rust/issues/72016> for more information
+ = help: add `#![feature(asm_unwind)]` to the crate attributes to enable
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0658`.
diff --git a/src/test/ui/feature-gates/feature-gate-concat_bytes.rs b/src/test/ui/feature-gates/feature-gate-concat_bytes.rs
new file mode 100644
index 00000000000..07d63cb11e0
--- /dev/null
+++ b/src/test/ui/feature-gates/feature-gate-concat_bytes.rs
@@ -0,0 +1,4 @@
+fn main() {
+ let a = concat_bytes!(b'A', b"BC"); //~ ERROR use of unstable library feature 'concat_bytes'
+ assert_eq!(a, &[65, 66, 67]);
+}
diff --git a/src/test/ui/feature-gates/feature-gate-concat_bytes.stderr b/src/test/ui/feature-gates/feature-gate-concat_bytes.stderr
new file mode 100644
index 00000000000..4b3ee4c19ce
--- /dev/null
+++ b/src/test/ui/feature-gates/feature-gate-concat_bytes.stderr
@@ -0,0 +1,12 @@
+error[E0658]: use of unstable library feature 'concat_bytes'
+ --> $DIR/feature-gate-concat_bytes.rs:2:13
+ |
+LL | let a = concat_bytes!(b'A', b"BC");
+ | ^^^^^^^^^^^^
+ |
+ = note: see issue #87555 <https://github.com/rust-lang/rust/issues/87555> for more information
+ = help: add `#![feature(concat_bytes)]` to the crate attributes to enable
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0658`.
diff --git a/src/test/ui/feature-gates/feature-gate-const_generics_defaults.rs b/src/test/ui/feature-gates/feature-gate-const_generics_defaults.rs
deleted file mode 100644
index 5b5ccc88873..00000000000
--- a/src/test/ui/feature-gates/feature-gate-const_generics_defaults.rs
+++ /dev/null
@@ -1,9 +0,0 @@
-#[cfg(FALSE)]
-struct A<const N: usize = 3>;
-//~^ ERROR default values for const generic parameters are experimental
-
-#[cfg(FALSE)]
-fn foo<const B: bool = false>() {}
-//~^ ERROR default values for const generic parameters are experimental
-
-fn main() {}
diff --git a/src/test/ui/feature-gates/feature-gate-const_generics_defaults.stderr b/src/test/ui/feature-gates/feature-gate-const_generics_defaults.stderr
deleted file mode 100644
index e2b48d793fd..00000000000
--- a/src/test/ui/feature-gates/feature-gate-const_generics_defaults.stderr
+++ /dev/null
@@ -1,21 +0,0 @@
-error[E0658]: default values for const generic parameters are experimental
- --> $DIR/feature-gate-const_generics_defaults.rs:2:25
- |
-LL | struct A<const N: usize = 3>;
- | ^^^
- |
- = note: see issue #44580 <https://github.com/rust-lang/rust/issues/44580> for more information
- = help: add `#![feature(const_generics_defaults)]` to the crate attributes to enable
-
-error[E0658]: default values for const generic parameters are experimental
- --> $DIR/feature-gate-const_generics_defaults.rs:6:22
- |
-LL | fn foo<const B: bool = false>() {}
- | ^^^^^^^
- |
- = note: see issue #44580 <https://github.com/rust-lang/rust/issues/44580> for more information
- = help: add `#![feature(const_generics_defaults)]` to the crate attributes to enable
-
-error: aborting due to 2 previous errors
-
-For more information about this error, try `rustc --explain E0658`.
diff --git a/src/test/ui/feature-gates/feature-gate-destructuring_assignment.rs b/src/test/ui/feature-gates/feature-gate-destructuring_assignment.rs
deleted file mode 100644
index e7801f0e8ec..00000000000
--- a/src/test/ui/feature-gates/feature-gate-destructuring_assignment.rs
+++ /dev/null
@@ -1,4 +0,0 @@
-fn main() {
- let (a, b) = (0, 1);
- (a, b) = (2, 3); //~ ERROR destructuring assignments are unstable
-}
diff --git a/src/test/ui/feature-gates/feature-gate-destructuring_assignment.stderr b/src/test/ui/feature-gates/feature-gate-destructuring_assignment.stderr
deleted file mode 100644
index 62e71decb32..00000000000
--- a/src/test/ui/feature-gates/feature-gate-destructuring_assignment.stderr
+++ /dev/null
@@ -1,14 +0,0 @@
-error[E0658]: destructuring assignments are unstable
- --> $DIR/feature-gate-destructuring_assignment.rs:3:12
- |
-LL | (a, b) = (2, 3);
- | ------ ^
- | |
- | cannot assign to this expression
- |
- = note: see issue #71126 <https://github.com/rust-lang/rust/issues/71126> for more information
- = help: add `#![feature(destructuring_assignment)]` to the crate attributes to enable
-
-error: aborting due to previous error
-
-For more information about this error, try `rustc --explain E0658`.
diff --git a/src/test/ui/feature-gates/feature-gate-doc_keyword.rs b/src/test/ui/feature-gates/feature-gate-doc_keyword.rs
deleted file mode 100644
index 4bb9a40deb0..00000000000
--- a/src/test/ui/feature-gates/feature-gate-doc_keyword.rs
+++ /dev/null
@@ -1,5 +0,0 @@
-#[doc(keyword = "match")] //~ ERROR: `#[doc(keyword)]` is experimental
-/// wonderful
-mod foo{}
-
-fn main() {}
diff --git a/src/test/ui/feature-gates/feature-gate-doc_keyword.stderr b/src/test/ui/feature-gates/feature-gate-doc_keyword.stderr
deleted file mode 100644
index c5dc7d537fd..00000000000
--- a/src/test/ui/feature-gates/feature-gate-doc_keyword.stderr
+++ /dev/null
@@ -1,12 +0,0 @@
-error[E0658]: `#[doc(keyword)]` is experimental
- --> $DIR/feature-gate-doc_keyword.rs:1:1
- |
-LL | #[doc(keyword = "match")]
- | ^^^^^^^^^^^^^^^^^^^^^^^^^
- |
- = note: see issue #51315 <https://github.com/rust-lang/rust/issues/51315> for more information
- = help: add `#![feature(doc_keyword)]` to the crate attributes to enable
-
-error: aborting due to previous error
-
-For more information about this error, try `rustc --explain E0658`.
diff --git a/src/test/ui/feature-gates/feature-gate-generic_associated_types.stderr b/src/test/ui/feature-gates/feature-gate-generic_associated_types.stderr
index 318fb63d382..6c2c3ed9c36 100644
--- a/src/test/ui/feature-gates/feature-gate-generic_associated_types.stderr
+++ b/src/test/ui/feature-gates/feature-gate-generic_associated_types.stderr
@@ -62,10 +62,10 @@ LL | type Assoc where Self: Sized = Foo;
= help: add `#![feature(generic_associated_types)]` to the crate attributes to enable
error[E0277]: the trait bound `U32: Clone` is not satisfied
- --> $DIR/feature-gate-generic_associated_types.rs:16:5
+ --> $DIR/feature-gate-generic_associated_types.rs:16:26
|
LL | type Pointer2<U32> = Box<U32>;
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `Clone` is not implemented for `U32`
+ | ^^^^^^^^ the trait `Clone` is not implemented for `U32`
|
help: consider restricting type parameter `U32`
|
diff --git a/src/test/ui/feature-gates/feature-gate-global_asm.rs b/src/test/ui/feature-gates/feature-gate-global_asm.rs
deleted file mode 100644
index 1420eef299b..00000000000
--- a/src/test/ui/feature-gates/feature-gate-global_asm.rs
+++ /dev/null
@@ -1,5 +0,0 @@
-// needs-asm-support
-
-global_asm!(""); //~ ERROR `global_asm!` is not stable
-
-fn main() {}
diff --git a/src/test/ui/feature-gates/feature-gate-global_asm.stderr b/src/test/ui/feature-gates/feature-gate-global_asm.stderr
deleted file mode 100644
index 7c4d3e3e6e5..00000000000
--- a/src/test/ui/feature-gates/feature-gate-global_asm.stderr
+++ /dev/null
@@ -1,12 +0,0 @@
-error[E0658]: use of unstable library feature 'global_asm': `global_asm!` is not stable enough for use and is subject to change
- --> $DIR/feature-gate-global_asm.rs:3:1
- |
-LL | global_asm!("");
- | ^^^^^^^^^^
- |
- = note: see issue #35119 <https://github.com/rust-lang/rust/issues/35119> for more information
- = help: add `#![feature(global_asm)]` to the crate attributes to enable
-
-error: aborting due to previous error
-
-For more information about this error, try `rustc --explain E0658`.
diff --git a/src/test/ui/feature-gates/feature-gate-inline_const_pat.rs b/src/test/ui/feature-gates/feature-gate-inline_const_pat.rs
new file mode 100644
index 00000000000..3d0df289fb7
--- /dev/null
+++ b/src/test/ui/feature-gates/feature-gate-inline_const_pat.rs
@@ -0,0 +1,4 @@
+fn main() {
+ let const { () } = ();
+ //~^ ERROR inline-const in pattern position is experimental [E0658]
+}
diff --git a/src/test/ui/feature-gates/feature-gate-inline_const_pat.stderr b/src/test/ui/feature-gates/feature-gate-inline_const_pat.stderr
new file mode 100644
index 00000000000..ca533d8505c
--- /dev/null
+++ b/src/test/ui/feature-gates/feature-gate-inline_const_pat.stderr
@@ -0,0 +1,12 @@
+error[E0658]: inline-const in pattern position is experimental
+ --> $DIR/feature-gate-inline_const_pat.rs:2:9
+ |
+LL | let const { () } = ();
+ | ^^^^^
+ |
+ = note: see issue #76001 <https://github.com/rust-lang/rust/issues/76001> for more information
+ = help: add `#![feature(inline_const_pat)]` to the crate attributes to enable
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0658`.
diff --git a/src/test/ui/feature-gates/feature-gate-naked_functions.rs b/src/test/ui/feature-gates/feature-gate-naked_functions.rs
index 71ca5b9373a..8e93b194174 100644
--- a/src/test/ui/feature-gates/feature-gate-naked_functions.rs
+++ b/src/test/ui/feature-gates/feature-gate-naked_functions.rs
@@ -1,5 +1,6 @@
// needs-asm-support
-#![feature(asm)]
+
+use std::arch::asm;
#[naked]
//~^ the `#[naked]` attribute is an experimental feature
diff --git a/src/test/ui/feature-gates/feature-gate-naked_functions.stderr b/src/test/ui/feature-gates/feature-gate-naked_functions.stderr
index 653d7b738da..4378fb36367 100644
--- a/src/test/ui/feature-gates/feature-gate-naked_functions.stderr
+++ b/src/test/ui/feature-gates/feature-gate-naked_functions.stderr
@@ -1,5 +1,5 @@
error[E0658]: the `#[naked]` attribute is an experimental feature
- --> $DIR/feature-gate-naked_functions.rs:4:1
+ --> $DIR/feature-gate-naked_functions.rs:5:1
|
LL | #[naked]
| ^^^^^^^^
@@ -8,7 +8,7 @@ LL | #[naked]
= help: add `#![feature(naked_functions)]` to the crate attributes to enable
error[E0658]: the `#[naked]` attribute is an experimental feature
- --> $DIR/feature-gate-naked_functions.rs:10:1
+ --> $DIR/feature-gate-naked_functions.rs:11:1
|
LL | #[naked]
| ^^^^^^^^
diff --git a/src/test/ui/feature-gates/feature-gate-rustdoc_internals.rs b/src/test/ui/feature-gates/feature-gate-rustdoc_internals.rs
new file mode 100644
index 00000000000..d2ff4f62009
--- /dev/null
+++ b/src/test/ui/feature-gates/feature-gate-rustdoc_internals.rs
@@ -0,0 +1,5 @@
+#[doc(keyword = "match")] //~ ERROR: `#[doc(keyword)]` is meant for internal use only
+/// wonderful
+mod foo {}
+
+fn main() {}
diff --git a/src/test/ui/feature-gates/feature-gate-rustdoc_internals.stderr b/src/test/ui/feature-gates/feature-gate-rustdoc_internals.stderr
new file mode 100644
index 00000000000..e96461ac38a
--- /dev/null
+++ b/src/test/ui/feature-gates/feature-gate-rustdoc_internals.stderr
@@ -0,0 +1,12 @@
+error[E0658]: `#[doc(keyword)]` is meant for internal use only
+ --> $DIR/feature-gate-rustdoc_internals.rs:1:1
+ |
+LL | #[doc(keyword = "match")]
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^
+ |
+ = note: see issue #90418 <https://github.com/rust-lang/rust/issues/90418> for more information
+ = help: add `#![feature(rustdoc_internals)]` to the crate attributes to enable
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0658`.
diff --git a/src/test/ui/feature-gates/issue-43106-gating-of-bench.rs b/src/test/ui/feature-gates/issue-43106-gating-of-bench.rs
index 31eee88d1fa..796325b79af 100644
--- a/src/test/ui/feature-gates/issue-43106-gating-of-bench.rs
+++ b/src/test/ui/feature-gates/issue-43106-gating-of-bench.rs
@@ -6,5 +6,5 @@
#![bench = "4100"]
//~^ ERROR cannot determine resolution for the attribute macro `bench`
-
+//~^^ ERROR `bench` attribute cannot be used at crate level
fn main() {}
diff --git a/src/test/ui/feature-gates/issue-43106-gating-of-bench.stderr b/src/test/ui/feature-gates/issue-43106-gating-of-bench.stderr
index d0305c5160f..6b332211942 100644
--- a/src/test/ui/feature-gates/issue-43106-gating-of-bench.stderr
+++ b/src/test/ui/feature-gates/issue-43106-gating-of-bench.stderr
@@ -6,5 +6,16 @@ LL | #![bench = "4100"]
|
= note: import resolution is stuck, try simplifying macro imports
-error: aborting due to previous error
+error: `bench` attribute cannot be used at crate level
+ --> $DIR/issue-43106-gating-of-bench.rs:7:1
+ |
+LL | #![bench = "4100"]
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ |
+help: perhaps you meant to use an outer attribute
+ |
+LL | #[bench = "4100"]
+ |
+
+error: aborting due to 2 previous errors
diff --git a/src/test/ui/feature-gates/issue-43106-gating-of-builtin-attrs-error.stderr b/src/test/ui/feature-gates/issue-43106-gating-of-builtin-attrs-error.stderr
index 9e2e2d4137d..f94ec7d4704 100644
--- a/src/test/ui/feature-gates/issue-43106-gating-of-builtin-attrs-error.stderr
+++ b/src/test/ui/feature-gates/issue-43106-gating-of-builtin-attrs-error.stderr
@@ -129,36 +129,66 @@ error: `macro_export` attribute cannot be used at crate level
|
LL | #![macro_export]
| ^^^^^^^^^^^^^^^^
+ |
+help: perhaps you meant to use an outer attribute
+ |
+LL | #[macro_export]
+ |
error: `rustc_main` attribute cannot be used at crate level
--> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:14:1
|
LL | #![rustc_main]
| ^^^^^^^^^^^^^^
+ |
+help: perhaps you meant to use an outer attribute
+ |
+LL | #[rustc_main]
+ | ~~~~~~~~~~~~~
error: `start` attribute cannot be used at crate level
--> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:16:1
|
LL | #![start]
| ^^^^^^^^^
+ |
+help: perhaps you meant to use an outer attribute
+ |
+LL | #[start]
+ |
error: `repr` attribute cannot be used at crate level
--> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:18:1
|
LL | #![repr()]
| ^^^^^^^^^^
+ |
+help: perhaps you meant to use an outer attribute
+ |
+LL | #[repr()]
+ |
error: `path` attribute cannot be used at crate level
--> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:20:1
|
LL | #![path = "3800"]
| ^^^^^^^^^^^^^^^^^
+ |
+help: perhaps you meant to use an outer attribute
+ |
+LL | #[path = "3800"]
+ |
error: `automatically_derived` attribute cannot be used at crate level
--> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:22:1
|
LL | #![automatically_derived]
| ^^^^^^^^^^^^^^^^^^^^^^^^^
+ |
+help: perhaps you meant to use an outer attribute
+ |
+LL | #[automatically_derived]
+ |
error[E0518]: attribute should be applied to function or closure
--> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:36:17
diff --git a/src/test/ui/feature-gates/issue-43106-gating-of-test.rs b/src/test/ui/feature-gates/issue-43106-gating-of-test.rs
index ee3fe712e36..39835c9268e 100644
--- a/src/test/ui/feature-gates/issue-43106-gating-of-test.rs
+++ b/src/test/ui/feature-gates/issue-43106-gating-of-test.rs
@@ -3,5 +3,5 @@
#![allow(soft_unstable)]
#![test = "4200"]
//~^ ERROR cannot determine resolution for the attribute macro `test`
-
+//~^^ ERROR `test` attribute cannot be used at crate level
fn main() {}
diff --git a/src/test/ui/feature-gates/issue-43106-gating-of-test.stderr b/src/test/ui/feature-gates/issue-43106-gating-of-test.stderr
index 335af5e7905..300a9966dd8 100644
--- a/src/test/ui/feature-gates/issue-43106-gating-of-test.stderr
+++ b/src/test/ui/feature-gates/issue-43106-gating-of-test.stderr
@@ -6,5 +6,16 @@ LL | #![test = "4200"]
|
= note: import resolution is stuck, try simplifying macro imports
-error: aborting due to previous error
+error: `test` attribute cannot be used at crate level
+ --> $DIR/issue-43106-gating-of-test.rs:4:1
+ |
+LL | #![test = "4200"]
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ |
+help: perhaps you meant to use an outer attribute
+ |
+LL | #[test = "4200"]
+ |
+
+error: aborting due to 2 previous errors
diff --git a/src/test/ui/feature-gates/thread-local-const-init.rs b/src/test/ui/feature-gates/thread-local-const-init.rs
deleted file mode 100644
index 6584ffa7cf9..00000000000
--- a/src/test/ui/feature-gates/thread-local-const-init.rs
+++ /dev/null
@@ -1,4 +0,0 @@
-thread_local!(static X: u32 = const { 0 });
-//~^ ERROR: use of unstable library feature 'thread_local_const_init'
-
-fn main() {}
diff --git a/src/test/ui/feature-gates/thread-local-const-init.stderr b/src/test/ui/feature-gates/thread-local-const-init.stderr
deleted file mode 100644
index f80506831b4..00000000000
--- a/src/test/ui/feature-gates/thread-local-const-init.stderr
+++ /dev/null
@@ -1,13 +0,0 @@
-error[E0658]: use of unstable library feature 'thread_local_const_init'
- --> $DIR/thread-local-const-init.rs:1:1
- |
-LL | thread_local!(static X: u32 = const { 0 });
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
- |
- = note: see issue #84223 <https://github.com/rust-lang/rust/issues/84223> for more information
- = help: add `#![feature(thread_local_const_init)]` to the crate attributes to enable
- = note: this error originates in the macro `$crate::__thread_local_inner` (in Nightly builds, run with -Z macro-backtrace for more info)
-
-error: aborting due to previous error
-
-For more information about this error, try `rustc --explain E0658`.
diff --git a/src/test/ui/fmt/issue-91556.rs b/src/test/ui/fmt/issue-91556.rs
new file mode 100644
index 00000000000..e782e6f9076
--- /dev/null
+++ b/src/test/ui/fmt/issue-91556.rs
@@ -0,0 +1,8 @@
+fn main() {
+ let _ = format!(concat!("{0}𝖳𝖾𝗌𝗍{"), i);
+ //~^ ERROR: invalid format string: expected `'}'` but string was terminated
+ //~| NOTE: if you intended to print `{`, you can escape it using `{{`
+ //~| NOTE: in this expansion of concat!
+ //~| NOTE: in this expansion of concat!
+ //~| NOTE: expected `'}'` in format string
+}
diff --git a/src/test/ui/fmt/issue-91556.stderr b/src/test/ui/fmt/issue-91556.stderr
new file mode 100644
index 00000000000..dbd5aef458b
--- /dev/null
+++ b/src/test/ui/fmt/issue-91556.stderr
@@ -0,0 +1,11 @@
+error: invalid format string: expected `'}'` but string was terminated
+ --> $DIR/issue-91556.rs:2:19
+ |
+LL | let _ = format!(concat!("{0}𝖳𝖾𝗌𝗍{"), i);
+ | ^^^^^^^^^^^^^^^^^^^ expected `'}'` in format string
+ |
+ = note: if you intended to print `{`, you can escape it using `{{`
+ = note: this error originates in the macro `concat` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error: aborting due to previous error
+
diff --git a/src/test/ui/fn/fn-compare-mismatch.stderr b/src/test/ui/fn/fn-compare-mismatch.stderr
index 585f556abc8..096440225b9 100644
--- a/src/test/ui/fn/fn-compare-mismatch.stderr
+++ b/src/test/ui/fn/fn-compare-mismatch.stderr
@@ -9,11 +9,11 @@ LL | let x = f == g;
help: you might have forgotten to call this function
|
LL | let x = f() == g;
- | ~~~
+ | ++
help: you might have forgotten to call this function
|
LL | let x = f == g();
- | ~~~
+ | ++
error[E0308]: mismatched types
--> $DIR/fn-compare-mismatch.rs:4:18
diff --git a/src/test/ui/fn/fn-recover-return-sign2.rs b/src/test/ui/fn/fn-recover-return-sign2.rs
index b6a6a1ec2a6..31f56565c49 100644
--- a/src/test/ui/fn/fn-recover-return-sign2.rs
+++ b/src/test/ui/fn/fn-recover-return-sign2.rs
@@ -3,6 +3,6 @@
fn foo() => impl Fn() => bool {
//~^ ERROR return types are denoted using `->`
- //~| ERROR expected one of `+`, `->`, `::`, `;`, `where`, or `{`, found `=>`
+ //~| ERROR expected one of `+`, `->`, `::`, `where`, or `{`, found `=>`
unimplemented!()
}
diff --git a/src/test/ui/fn/fn-recover-return-sign2.stderr b/src/test/ui/fn/fn-recover-return-sign2.stderr
index d62cacd4bf5..25ee8dd0c5d 100644
--- a/src/test/ui/fn/fn-recover-return-sign2.stderr
+++ b/src/test/ui/fn/fn-recover-return-sign2.stderr
@@ -4,11 +4,11 @@ error: return types are denoted using `->`
LL | fn foo() => impl Fn() => bool {
| ^^ help: use `->` instead
-error: expected one of `+`, `->`, `::`, `;`, `where`, or `{`, found `=>`
+error: expected one of `+`, `->`, `::`, `where`, or `{`, found `=>`
--> $DIR/fn-recover-return-sign2.rs:4:23
|
LL | fn foo() => impl Fn() => bool {
- | ^^ expected one of `+`, `->`, `::`, `;`, `where`, or `{`
+ | ^^ expected one of `+`, `->`, `::`, `where`, or `{`
error: aborting due to 2 previous errors
diff --git a/src/test/ui/fn/implied-bounds-unnorm-associated-type-2.rs b/src/test/ui/fn/implied-bounds-unnorm-associated-type-2.rs
new file mode 100644
index 00000000000..5a92bcd37b6
--- /dev/null
+++ b/src/test/ui/fn/implied-bounds-unnorm-associated-type-2.rs
@@ -0,0 +1,22 @@
+// check-pass
+
+trait Trait {
+ type Type;
+}
+
+impl<T> Trait for T {
+ type Type = ();
+}
+
+fn f<'a, 'b>(_: <&'a &'b () as Trait>::Type)
+where
+ 'a: 'a,
+ 'b: 'b,
+{
+}
+
+fn g<'a, 'b>() {
+ f::<'a, 'b>(());
+}
+
+fn main() {}
diff --git a/src/test/ui/fn/implied-bounds-unnorm-associated-type-3.rs b/src/test/ui/fn/implied-bounds-unnorm-associated-type-3.rs
new file mode 100644
index 00000000000..dc25ac08613
--- /dev/null
+++ b/src/test/ui/fn/implied-bounds-unnorm-associated-type-3.rs
@@ -0,0 +1,25 @@
+// check-fail
+// See issue #91899. If we treat unnormalized args as WF, `Self` can also be a
+// source of unsoundness.
+
+pub trait Yokeable<'a>: 'static {
+ type Output: 'a;
+}
+
+impl<'a, T: 'static + ?Sized> Yokeable<'a> for &'static T {
+ type Output = &'a T;
+}
+
+pub trait ZeroCopyFrom<C: ?Sized>: for<'a> Yokeable<'a> {
+ /// Clone the cart `C` into a [`Yokeable`] struct, which may retain references into `C`.
+ fn zero_copy_from<'b>(cart: &'b C) -> <Self as Yokeable<'b>>::Output;
+}
+
+impl<T> ZeroCopyFrom<[T]> for &'static [T] {
+ fn zero_copy_from<'b>(cart: &'b [T]) -> &'b [T] {
+ //~^ the parameter
+ cart
+ }
+}
+
+fn main() {}
diff --git a/src/test/ui/fn/implied-bounds-unnorm-associated-type-3.stderr b/src/test/ui/fn/implied-bounds-unnorm-associated-type-3.stderr
new file mode 100644
index 00000000000..26eecf6a21d
--- /dev/null
+++ b/src/test/ui/fn/implied-bounds-unnorm-associated-type-3.stderr
@@ -0,0 +1,12 @@
+error[E0310]: the parameter type `T` may not live long enough
+ --> $DIR/implied-bounds-unnorm-associated-type-3.rs:19:5
+ |
+LL | fn zero_copy_from<'b>(cart: &'b [T]) -> &'b [T] {
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ |
+ = help: consider adding an explicit lifetime bound `T: 'static`...
+ = note: ...so that the type `[T]` will meet its required lifetime bounds
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0310`.
diff --git a/src/test/ui/fn/implied-bounds-unnorm-associated-type.nll.stderr b/src/test/ui/fn/implied-bounds-unnorm-associated-type.nll.stderr
new file mode 100644
index 00000000000..e37ec7f2665
--- /dev/null
+++ b/src/test/ui/fn/implied-bounds-unnorm-associated-type.nll.stderr
@@ -0,0 +1,14 @@
+error: lifetime may not live long enough
+ --> $DIR/implied-bounds-unnorm-associated-type.rs:14:5
+ |
+LL | fn f<'a, 'b>(s: &'b str, _: <&'a &'b () as Trait>::Type) -> &'a str {
+ | -- -- lifetime `'b` defined here
+ | |
+ | lifetime `'a` defined here
+LL | s
+ | ^ returning this value requires that `'b` must outlive `'a`
+ |
+ = help: consider adding the following bound: `'b: 'a`
+
+error: aborting due to previous error
+
diff --git a/src/test/ui/fn/implied-bounds-unnorm-associated-type.rs b/src/test/ui/fn/implied-bounds-unnorm-associated-type.rs
new file mode 100644
index 00000000000..2e5ac7d7398
--- /dev/null
+++ b/src/test/ui/fn/implied-bounds-unnorm-associated-type.rs
@@ -0,0 +1,22 @@
+// check-fail
+// See issue #91068. Types in the substs of an associated type can't be implied
+// to be WF, since they don't actually have to be constructed.
+
+trait Trait {
+ type Type;
+}
+
+impl<T> Trait for T {
+ type Type = ();
+}
+
+fn f<'a, 'b>(s: &'b str, _: <&'a &'b () as Trait>::Type) -> &'a str {
+ s //~ ERROR lifetime mismatch [E0623]
+}
+
+fn main() {
+ let x = String::from("Hello World!");
+ let y = f(&x, ());
+ drop(x);
+ println!("{}", y);
+}
diff --git a/src/test/ui/fn/implied-bounds-unnorm-associated-type.stderr b/src/test/ui/fn/implied-bounds-unnorm-associated-type.stderr
new file mode 100644
index 00000000000..93ab5dceee9
--- /dev/null
+++ b/src/test/ui/fn/implied-bounds-unnorm-associated-type.stderr
@@ -0,0 +1,13 @@
+error[E0623]: lifetime mismatch
+ --> $DIR/implied-bounds-unnorm-associated-type.rs:14:5
+ |
+LL | fn f<'a, 'b>(s: &'b str, _: <&'a &'b () as Trait>::Type) -> &'a str {
+ | ------- ----------
+ | |
+ | these two types are declared with different lifetimes...
+LL | s
+ | ^ ...but data from `s` flows here
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0623`.
diff --git a/src/test/ui/fully-qualified-type/fully-qualified-type-name1.rs b/src/test/ui/fully-qualified-type/fully-qualified-type-name1.rs
index 1c6b9805b51..229c174daa8 100644
--- a/src/test/ui/fully-qualified-type/fully-qualified-type-name1.rs
+++ b/src/test/ui/fully-qualified-type/fully-qualified-type-name1.rs
@@ -1,10 +1,10 @@
// Test that we use fully-qualified type names in error messages.
fn main() {
- let x: Option<usize>;
+ let x: //~ NOTE expected due to the type of this binding
+ Option<usize>; //~ NOTE expected due to this type
x = 5;
//~^ ERROR mismatched types
- //~| expected enum `Option<usize>`
- //~| found type `{integer}`
- //~| expected enum `Option`, found integer
+ //~| NOTE expected enum `Option<usize>`
+ //~| NOTE expected enum `Option`, found integer
}
diff --git a/src/test/ui/fully-qualified-type/fully-qualified-type-name1.stderr b/src/test/ui/fully-qualified-type/fully-qualified-type-name1.stderr
index 03fb299b39c..4750c5ccdf7 100644
--- a/src/test/ui/fully-qualified-type/fully-qualified-type-name1.stderr
+++ b/src/test/ui/fully-qualified-type/fully-qualified-type-name1.stderr
@@ -1,6 +1,10 @@
error[E0308]: mismatched types
- --> $DIR/fully-qualified-type-name1.rs:5:9
+ --> $DIR/fully-qualified-type-name1.rs:6:9
|
+LL | let x:
+ | - expected due to the type of this binding
+LL | Option<usize>;
+ | ------------- expected due to this type
LL | x = 5;
| ^ expected enum `Option`, found integer
|
diff --git a/src/test/ui/generator/generator-region-requirements.stderr b/src/test/ui/generator/generator-region-requirements.stderr
index b6b9db22426..30d67050b90 100644
--- a/src/test/ui/generator/generator-region-requirements.stderr
+++ b/src/test/ui/generator/generator-region-requirements.stderr
@@ -5,7 +5,7 @@ LL | fn dangle(x: &mut i32) -> &'static mut i32 {
| -------- this data with an anonymous lifetime `'_`...
...
LL | x
- | ^ ...is captured here...
+ | ^ ...is used here...
...
LL | GeneratorState::Complete(c) => return c,
| - ...and is required to live as long as `'static` here
diff --git a/src/test/ui/generator/generator-resume-after-panic.rs b/src/test/ui/generator/generator-resume-after-panic.rs
index 55704f40e9f..f2e67f1f750 100644
--- a/src/test/ui/generator/generator-resume-after-panic.rs
+++ b/src/test/ui/generator/generator-resume-after-panic.rs
@@ -1,4 +1,5 @@
// run-fail
+// needs-unwind
// error-pattern:generator resumed after panicking
// ignore-emscripten no processes
diff --git a/src/test/ui/generator/issue-68112.stderr b/src/test/ui/generator/issue-68112.stderr
index c3fc8dd8f92..a7d7a732548 100644
--- a/src/test/ui/generator/issue-68112.stderr
+++ b/src/test/ui/generator/issue-68112.stderr
@@ -9,7 +9,7 @@ note: generator is not `Send` as this value is used across a yield
--> $DIR/issue-68112.rs:31:9
|
LL | let _non_send_gen = make_non_send_generator();
- | ------------- has type `impl Generator` which is not `Send`
+ | ------------- has type `impl Generator<Return = Arc<RefCell<i32>>>` which is not `Send`
LL | yield;
| ^^^^^ yield occurs here, with `_non_send_gen` maybe used later
LL | };
@@ -29,9 +29,9 @@ LL | require_send(send_gen);
= help: the trait `Sync` is not implemented for `RefCell<i32>`
= note: required because of the requirements on the impl of `Send` for `Arc<RefCell<i32>>`
= note: required because it appears within the type `[generator@$DIR/issue-68112.rs:38:5: 41:6]`
- = note: required because it appears within the type `impl Generator`
- = note: required because it appears within the type `impl Generator`
- = note: required because it appears within the type `{impl Generator, ()}`
+ = note: required because it appears within the type `impl Generator<Return = Arc<RefCell<i32>>>`
+ = note: required because it appears within the type `impl Generator<Return = Arc<RefCell<i32>>>`
+ = note: required because it appears within the type `{impl Generator<Return = Arc<RefCell<i32>>>, ()}`
= note: required because it appears within the type `[generator@$DIR/issue-68112.rs:48:20: 51:6]`
note: required by a bound in `require_send`
--> $DIR/issue-68112.rs:22:25
diff --git a/src/test/ui/generator/issue-91477.rs b/src/test/ui/generator/issue-91477.rs
new file mode 100644
index 00000000000..6c027feb422
--- /dev/null
+++ b/src/test/ui/generator/issue-91477.rs
@@ -0,0 +1,7 @@
+#![feature(generators)]
+
+fn foo() -> impl Sized {
+ yield 1; //~ ERROR E0627
+}
+
+fn main() {}
diff --git a/src/test/ui/generator/issue-91477.stderr b/src/test/ui/generator/issue-91477.stderr
new file mode 100644
index 00000000000..4597dc1bcdf
--- /dev/null
+++ b/src/test/ui/generator/issue-91477.stderr
@@ -0,0 +1,9 @@
+error[E0627]: yield expression outside of generator literal
+ --> $DIR/issue-91477.rs:4:5
+ |
+LL | yield 1;
+ | ^^^^^^^
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0627`.
diff --git a/src/test/ui/generator/panic-drops-resume.rs b/src/test/ui/generator/panic-drops-resume.rs
index 29f4788b275..8d8eb6a97b1 100644
--- a/src/test/ui/generator/panic-drops-resume.rs
+++ b/src/test/ui/generator/panic-drops-resume.rs
@@ -1,6 +1,7 @@
//! Tests that panics inside a generator will correctly drop the initial resume argument.
// run-pass
+// needs-unwind
// ignore-wasm no unwind support
// ignore-emscripten no unwind support
diff --git a/src/test/ui/generator/panic-drops.rs b/src/test/ui/generator/panic-drops.rs
index c9a201725ae..a9de4e7fc7d 100644
--- a/src/test/ui/generator/panic-drops.rs
+++ b/src/test/ui/generator/panic-drops.rs
@@ -1,4 +1,5 @@
// run-pass
+// needs-unwind
// ignore-wasm32-bare compiled with panic=abort by default
diff --git a/src/test/ui/generator/panic-safe.rs b/src/test/ui/generator/panic-safe.rs
index 500a3c9c295..14a0c8dbaf1 100644
--- a/src/test/ui/generator/panic-safe.rs
+++ b/src/test/ui/generator/panic-safe.rs
@@ -1,4 +1,5 @@
// run-pass
+// needs-unwind
// ignore-wasm32-bare compiled with panic=abort by default
diff --git a/src/test/ui/generator/print/generator-print-verbose-1.stderr b/src/test/ui/generator/print/generator-print-verbose-1.stderr
index 53f0936632a..2b9bcb1bf8a 100644
--- a/src/test/ui/generator/print/generator-print-verbose-1.stderr
+++ b/src/test/ui/generator/print/generator-print-verbose-1.stderr
@@ -9,7 +9,7 @@ note: generator is not `Send` as this value is used across a yield
--> $DIR/generator-print-verbose-1.rs:35:9
|
LL | let _non_send_gen = make_non_send_generator();
- | ------------- has type `Opaque(DefId(0:34 ~ generator_print_verbose_1[70c9]::make_non_send_generator::{opaque#0}), [])` which is not `Send`
+ | ------------- has type `Opaque(DefId(0:34 ~ generator_print_verbose_1[HASH]::make_non_send_generator::{opaque#0}), [])` which is not `Send`
LL | yield;
| ^^^^^ yield occurs here, with `_non_send_gen` maybe used later
LL | };
@@ -29,10 +29,10 @@ LL | require_send(send_gen);
= help: the trait `Sync` is not implemented for `RefCell<i32>`
= note: required because of the requirements on the impl of `Send` for `Arc<RefCell<i32>>`
= note: required because it appears within the type `[make_gen2<Arc<RefCell<i32>>>::{closure#0} upvar_tys=(Arc<RefCell<i32>>) {()}]`
- = note: required because it appears within the type `Opaque(DefId(0:39 ~ generator_print_verbose_1[70c9]::make_gen2::{opaque#0}), [std::sync::Arc<std::cell::RefCell<i32>>])`
- = note: required because it appears within the type `Opaque(DefId(0:42 ~ generator_print_verbose_1[70c9]::make_non_send_generator2::{opaque#0}), [])`
- = note: required because it appears within the type `{Opaque(DefId(0:42 ~ generator_print_verbose_1[70c9]::make_non_send_generator2::{opaque#0}), []), ()}`
- = note: required because it appears within the type `[test2::{closure#0} upvar_tys=() {Opaque(DefId(0:42 ~ generator_print_verbose_1[70c9]::make_non_send_generator2::{opaque#0}), []), ()}]`
+ = note: required because it appears within the type `Opaque(DefId(0:39 ~ generator_print_verbose_1[HASH]::make_gen2::{opaque#0}), [std::sync::Arc<std::cell::RefCell<i32>>])`
+ = note: required because it appears within the type `Opaque(DefId(0:42 ~ generator_print_verbose_1[HASH]::make_non_send_generator2::{opaque#0}), [])`
+ = note: required because it appears within the type `{Opaque(DefId(0:42 ~ generator_print_verbose_1[HASH]::make_non_send_generator2::{opaque#0}), []), ()}`
+ = note: required because it appears within the type `[test2::{closure#0} upvar_tys=() {Opaque(DefId(0:42 ~ generator_print_verbose_1[HASH]::make_non_send_generator2::{opaque#0}), []), ()}]`
note: required by a bound in `require_send`
--> $DIR/generator-print-verbose-1.rs:26:25
|
diff --git a/src/test/ui/generator/resume-after-return.rs b/src/test/ui/generator/resume-after-return.rs
index efed08bd470..538609b981a 100644
--- a/src/test/ui/generator/resume-after-return.rs
+++ b/src/test/ui/generator/resume-after-return.rs
@@ -1,4 +1,5 @@
// run-pass
+// needs-unwind
// ignore-wasm32-bare compiled with panic=abort by default
diff --git a/src/test/ui/generator/yield-while-ref-reborrowed.stderr b/src/test/ui/generator/yield-while-ref-reborrowed.stderr
index 68d785efcfe..67cd1f64d94 100644
--- a/src/test/ui/generator/yield-while-ref-reborrowed.stderr
+++ b/src/test/ui/generator/yield-while-ref-reborrowed.stderr
@@ -10,6 +10,8 @@ LL | println!("{}", x);
| ^ second borrow occurs here
LL | Pin::new(&mut b).resume(());
| ------ first borrow later used here
+ |
+ = note: this error originates in the macro `$crate::format_args_nl` (in Nightly builds, run with -Z macro-backtrace for more info)
error: aborting due to previous error
diff --git a/src/test/ui/generic-associated-types/cross-crate-bounds.stderr b/src/test/ui/generic-associated-types/cross-crate-bounds.stderr
index d6716cac06e..c4009dd9625 100644
--- a/src/test/ui/generic-associated-types/cross-crate-bounds.stderr
+++ b/src/test/ui/generic-associated-types/cross-crate-bounds.stderr
@@ -1,8 +1,8 @@
error[E0277]: the trait bound `(): AsRef<()>` is not satisfied
- --> $DIR/cross-crate-bounds.rs:15:5
+ --> $DIR/cross-crate-bounds.rs:15:16
|
LL | type Bar = ();
- | ^^^^^^^^^^^^^^ the trait `AsRef<()>` is not implemented for `()`
+ | ^^ the trait `AsRef<()>` is not implemented for `()`
|
note: required by a bound in `foo_defn::Foo::Bar`
--> $DIR/auxiliary/foo_defn.rs:6:15
diff --git a/src/test/ui/generic-associated-types/equality-bound.rs b/src/test/ui/generic-associated-types/equality-bound.rs
new file mode 100644
index 00000000000..fcc2da8014f
--- /dev/null
+++ b/src/test/ui/generic-associated-types/equality-bound.rs
@@ -0,0 +1,15 @@
+fn sum<I: Iterator<Item = ()>>(i: I) -> i32 where I::Item = i32 {
+//~^ ERROR equality constraints are not yet supported in `where` clauses
+ panic!()
+}
+fn sum2<I: Iterator>(i: I) -> i32 where I::Item = i32 {
+//~^ ERROR equality constraints are not yet supported in `where` clauses
+ panic!()
+}
+fn sum3<J: Iterator>(i: J) -> i32 where I::Item = i32 {
+//~^ ERROR equality constraints are not yet supported in `where` clauses
+//~| ERROR failed to resolve: use of undeclared type `I`
+ panic!()
+}
+
+fn main() {}
diff --git a/src/test/ui/generic-associated-types/equality-bound.stderr b/src/test/ui/generic-associated-types/equality-bound.stderr
new file mode 100644
index 00000000000..27432641958
--- /dev/null
+++ b/src/test/ui/generic-associated-types/equality-bound.stderr
@@ -0,0 +1,43 @@
+error: equality constraints are not yet supported in `where` clauses
+ --> $DIR/equality-bound.rs:1:51
+ |
+LL | fn sum<I: Iterator<Item = ()>>(i: I) -> i32 where I::Item = i32 {
+ | ^^^^^^^^^^^^^ not supported
+ |
+ = note: see issue #20041 <https://github.com/rust-lang/rust/issues/20041> for more information
+help: if `Iterator::Item` is an associated type you're trying to set, use the associated type binding syntax
+ |
+LL - fn sum<I: Iterator<Item = ()>>(i: I) -> i32 where I::Item = i32 {
+LL + fn sum<I: Iterator<Item = (), Item = i32>>(i: I) -> i32 where {
+ |
+
+error: equality constraints are not yet supported in `where` clauses
+ --> $DIR/equality-bound.rs:5:41
+ |
+LL | fn sum2<I: Iterator>(i: I) -> i32 where I::Item = i32 {
+ | ^^^^^^^^^^^^^ not supported
+ |
+ = note: see issue #20041 <https://github.com/rust-lang/rust/issues/20041> for more information
+help: if `Iterator::Item` is an associated type you're trying to set, use the associated type binding syntax
+ |
+LL - fn sum2<I: Iterator>(i: I) -> i32 where I::Item = i32 {
+LL + fn sum2<I: Iterator<Item = i32>>(i: I) -> i32 where {
+ |
+
+error: equality constraints are not yet supported in `where` clauses
+ --> $DIR/equality-bound.rs:9:41
+ |
+LL | fn sum3<J: Iterator>(i: J) -> i32 where I::Item = i32 {
+ | ^^^^^^^^^^^^^ not supported
+ |
+ = note: see issue #20041 <https://github.com/rust-lang/rust/issues/20041> for more information
+
+error[E0433]: failed to resolve: use of undeclared type `I`
+ --> $DIR/equality-bound.rs:9:41
+ |
+LL | fn sum3<J: Iterator>(i: J) -> i32 where I::Item = i32 {
+ | ^ use of undeclared type `I`
+
+error: aborting due to 4 previous errors
+
+For more information about this error, try `rustc --explain E0433`.
diff --git a/src/test/ui/generic-associated-types/gat-trait-path-parenthesised-args.rs b/src/test/ui/generic-associated-types/gat-trait-path-parenthesised-args.rs
index 48b4a4fc393..f01da8c61ed 100644
--- a/src/test/ui/generic-associated-types/gat-trait-path-parenthesised-args.rs
+++ b/src/test/ui/generic-associated-types/gat-trait-path-parenthesised-args.rs
@@ -9,7 +9,5 @@ fn foo<'a>(arg: Box<dyn X<Y('a) = &'a ()>>) {}
//~| ERROR: parenthesized generic arguments cannot be used
//~| ERROR this associated type takes 0 generic arguments but 1 generic argument
//~| ERROR this associated type takes 1 lifetime argument but 0 lifetime arguments
- //~| WARNING: trait objects without an explicit `dyn` are deprecated
- //~| WARNING: this is accepted in the current edition
fn main() {}
diff --git a/src/test/ui/generic-associated-types/gat-trait-path-parenthesised-args.stderr b/src/test/ui/generic-associated-types/gat-trait-path-parenthesised-args.stderr
index 5e0f98c0bbf..6014a02c4d9 100644
--- a/src/test/ui/generic-associated-types/gat-trait-path-parenthesised-args.stderr
+++ b/src/test/ui/generic-associated-types/gat-trait-path-parenthesised-args.stderr
@@ -10,16 +10,6 @@ error: parenthesized generic arguments cannot be used in associated type constra
LL | fn foo<'a>(arg: Box<dyn X<Y('a) = &'a ()>>) {}
| ^^^^^
-warning: trait objects without an explicit `dyn` are deprecated
- --> $DIR/gat-trait-path-parenthesised-args.rs:7:29
- |
-LL | fn foo<'a>(arg: Box<dyn X<Y('a) = &'a ()>>) {}
- | ^^ help: use `dyn`: `dyn 'a`
- |
- = note: `#[warn(bare_trait_objects)]` on by default
- = warning: this is accepted in the current edition (Rust 2015) but is a hard error in Rust 2021!
- = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2021/warnings-promoted-to-error.html>
-
error[E0107]: this associated type takes 1 lifetime argument but 0 lifetime arguments were supplied
--> $DIR/gat-trait-path-parenthesised-args.rs:7:27
|
@@ -50,6 +40,6 @@ note: associated type defined here, with 0 generic parameters
LL | type Y<'a>;
| ^
-error: aborting due to 4 previous errors; 1 warning emitted
+error: aborting due to 4 previous errors
For more information about this error, try `rustc --explain E0107`.
diff --git a/src/test/ui/generic-associated-types/generic-associated-types-where.stderr b/src/test/ui/generic-associated-types/generic-associated-types-where.stderr
index 99a601003c1..544f2bcbbd7 100644
--- a/src/test/ui/generic-associated-types/generic-associated-types-where.stderr
+++ b/src/test/ui/generic-associated-types/generic-associated-types-where.stderr
@@ -1,8 +1,8 @@
error[E0277]: `T` doesn't implement `std::fmt::Display`
- --> $DIR/generic-associated-types-where.rs:20:5
+ --> $DIR/generic-associated-types-where.rs:20:22
|
LL | type Assoc2<T> = Vec<T>;
- | ^^^^^^^^^^^^^^^^^^^^^^^^ `T` cannot be formatted with the default formatter
+ | ^^^^^^ `T` cannot be formatted with the default formatter
|
= note: in format strings you may be able to use `{:?}` (or {:#?} for pretty-print) instead
help: consider restricting type parameter `T`
diff --git a/src/test/ui/generic-associated-types/impl_bounds.stderr b/src/test/ui/generic-associated-types/impl_bounds.stderr
index 1c8a1f09af5..5be431f2933 100644
--- a/src/test/ui/generic-associated-types/impl_bounds.stderr
+++ b/src/test/ui/generic-associated-types/impl_bounds.stderr
@@ -17,10 +17,10 @@ LL | type B<'a, 'b> where 'b: 'a = (&'a(), &'b ());
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ found
error[E0478]: lifetime bound not satisfied
- --> $DIR/impl_bounds.rs:17:5
+ --> $DIR/impl_bounds.rs:17:35
|
LL | type B<'a, 'b> where 'b: 'a = (&'a(), &'b ());
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ | ^^^^^^^^^^^^^^^
|
note: lifetime parameter instantiated with the lifetime `'a` as defined here
--> $DIR/impl_bounds.rs:17:12
diff --git a/src/test/ui/generic-associated-types/issue-68641-check-gat-bounds.stderr b/src/test/ui/generic-associated-types/issue-68641-check-gat-bounds.stderr
index 1d3aeaefca0..2e21b38cb0e 100644
--- a/src/test/ui/generic-associated-types/issue-68641-check-gat-bounds.stderr
+++ b/src/test/ui/generic-associated-types/issue-68641-check-gat-bounds.stderr
@@ -1,8 +1,8 @@
error[E0277]: the trait bound `T: Copy` is not satisfied
- --> $DIR/issue-68641-check-gat-bounds.rs:14:5
+ --> $DIR/issue-68641-check-gat-bounds.rs:14:21
|
LL | type Item<'a> = T;
- | ^^^^^^^^^^^^^^^^^^ the trait `Copy` is not implemented for `T`
+ | ^ the trait `Copy` is not implemented for `T`
|
note: required by a bound in `UnsafeCopy::Item`
--> $DIR/issue-68641-check-gat-bounds.rs:6:20
diff --git a/src/test/ui/generic-associated-types/issue-68642-broken-llvm-ir.stderr b/src/test/ui/generic-associated-types/issue-68642-broken-llvm-ir.stderr
index 574b81556e7..713cc744f5a 100644
--- a/src/test/ui/generic-associated-types/issue-68642-broken-llvm-ir.stderr
+++ b/src/test/ui/generic-associated-types/issue-68642-broken-llvm-ir.stderr
@@ -1,8 +1,8 @@
error[E0277]: expected a `Fn<()>` closure, found `T`
- --> $DIR/issue-68642-broken-llvm-ir.rs:14:5
+ --> $DIR/issue-68642-broken-llvm-ir.rs:14:18
|
LL | type F<'a> = Self;
- | ^^^^^^^^^^^^^^^^^^ expected an `Fn<()>` closure, found `T`
+ | ^^^^ expected an `Fn<()>` closure, found `T`
|
= note: wrap the `T` in a closure with no arguments: `|| { /* code */ }`
note: required by a bound in `Fun::F`
diff --git a/src/test/ui/generic-associated-types/issue-68643-broken-mir.stderr b/src/test/ui/generic-associated-types/issue-68643-broken-mir.stderr
index 9c4cbc5eb56..a7b7f64cdb1 100644
--- a/src/test/ui/generic-associated-types/issue-68643-broken-mir.stderr
+++ b/src/test/ui/generic-associated-types/issue-68643-broken-mir.stderr
@@ -1,8 +1,8 @@
error[E0277]: expected a `Fn<()>` closure, found `T`
- --> $DIR/issue-68643-broken-mir.rs:14:5
+ --> $DIR/issue-68643-broken-mir.rs:14:18
|
LL | type F<'a> = Self;
- | ^^^^^^^^^^^^^^^^^^ expected an `Fn<()>` closure, found `T`
+ | ^^^^ expected an `Fn<()>` closure, found `T`
|
= note: wrap the `T` in a closure with no arguments: `|| { /* code */ }`
note: required by a bound in `Fun::F`
diff --git a/src/test/ui/generic-associated-types/issue-68644-codegen-selection.stderr b/src/test/ui/generic-associated-types/issue-68644-codegen-selection.stderr
index 0df5c0f8c79..5e921e053bb 100644
--- a/src/test/ui/generic-associated-types/issue-68644-codegen-selection.stderr
+++ b/src/test/ui/generic-associated-types/issue-68644-codegen-selection.stderr
@@ -1,8 +1,8 @@
error[E0277]: expected a `Fn<()>` closure, found `T`
- --> $DIR/issue-68644-codegen-selection.rs:14:5
+ --> $DIR/issue-68644-codegen-selection.rs:14:18
|
LL | type F<'a> = Self;
- | ^^^^^^^^^^^^^^^^^^ expected an `Fn<()>` closure, found `T`
+ | ^^^^ expected an `Fn<()>` closure, found `T`
|
= note: wrap the `T` in a closure with no arguments: `|| { /* code */ }`
note: required by a bound in `Fun::F`
diff --git a/src/test/ui/generic-associated-types/issue-68645-codegen-fulfillment.stderr b/src/test/ui/generic-associated-types/issue-68645-codegen-fulfillment.stderr
index 35a4350804e..7edcdce628e 100644
--- a/src/test/ui/generic-associated-types/issue-68645-codegen-fulfillment.stderr
+++ b/src/test/ui/generic-associated-types/issue-68645-codegen-fulfillment.stderr
@@ -1,8 +1,8 @@
error[E0277]: expected a `Fn<()>` closure, found `T`
- --> $DIR/issue-68645-codegen-fulfillment.rs:14:5
+ --> $DIR/issue-68645-codegen-fulfillment.rs:14:18
|
LL | type F<'a> = Self;
- | ^^^^^^^^^^^^^^^^^^ expected an `Fn<()>` closure, found `T`
+ | ^^^^ expected an `Fn<()>` closure, found `T`
|
= note: wrap the `T` in a closure with no arguments: `|| { /* code */ }`
note: required by a bound in `Fun::F`
diff --git a/src/test/ui/generic-associated-types/issue-68656-unsized-values.stderr b/src/test/ui/generic-associated-types/issue-68656-unsized-values.stderr
index d69ac8e580a..8e0f2371601 100644
--- a/src/test/ui/generic-associated-types/issue-68656-unsized-values.stderr
+++ b/src/test/ui/generic-associated-types/issue-68656-unsized-values.stderr
@@ -1,10 +1,10 @@
error[E0271]: type mismatch resolving `<T as Deref>::Target == T`
- --> $DIR/issue-68656-unsized-values.rs:15:5
+ --> $DIR/issue-68656-unsized-values.rs:15:21
|
LL | impl<T: Copy + std::ops::Deref> UnsafeCopy<T> for T {
| - this type parameter
LL | type Item<'a> = T;
- | ^^^^^^^^^^^^^^^^^^ expected type parameter `T`, found associated type
+ | ^ expected type parameter `T`, found associated type
|
= note: expected type parameter `T`
found associated type `<T as Deref>::Target`
diff --git a/src/test/ui/generic-associated-types/issue-74684-2.stderr b/src/test/ui/generic-associated-types/issue-74684-2.stderr
index 86e9450904b..f0e03e73f0b 100644
--- a/src/test/ui/generic-associated-types/issue-74684-2.stderr
+++ b/src/test/ui/generic-associated-types/issue-74684-2.stderr
@@ -2,8 +2,13 @@ error[E0271]: type mismatch resolving `<{integer} as Fun>::F<'_> == [u8]`
--> $DIR/issue-74684-2.rs:23:5
|
LL | bug(Box::new(x));
- | ^^^ expected slice `[u8]`, found `i32`
+ | ^^^ type mismatch resolving `<{integer} as Fun>::F<'_> == [u8]`
|
+note: expected this to be `[u8]`
+ --> $DIR/issue-74684-2.rs:10:18
+ |
+LL | type F<'a> = i32;
+ | ^^^
note: required by a bound in `bug`
--> $DIR/issue-74684-2.rs:13:28
|
diff --git a/src/test/ui/generic-associated-types/issue-74816.stderr b/src/test/ui/generic-associated-types/issue-74816.stderr
index 49ae87cbfe9..9eaa74e343e 100644
--- a/src/test/ui/generic-associated-types/issue-74816.stderr
+++ b/src/test/ui/generic-associated-types/issue-74816.stderr
@@ -1,8 +1,8 @@
error[E0277]: the trait bound `Self: Trait1` is not satisfied
- --> $DIR/issue-74816.rs:9:5
+ --> $DIR/issue-74816.rs:9:31
|
LL | type Associated: Trait1 = Self;
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `Trait1` is not implemented for `Self`
+ | ^^^^ the trait `Trait1` is not implemented for `Self`
|
note: required by a bound in `Trait2::Associated`
--> $DIR/issue-74816.rs:9:22
@@ -15,10 +15,10 @@ LL | trait Trait2: Trait1 {
| ++++++++
error[E0277]: the size for values of type `Self` cannot be known at compilation time
- --> $DIR/issue-74816.rs:9:5
+ --> $DIR/issue-74816.rs:9:31
|
LL | type Associated: Trait1 = Self;
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time
+ | ^^^^ doesn't have a size known at compile-time
|
note: required by a bound in `Trait2::Associated`
--> $DIR/issue-74816.rs:9:5
diff --git a/src/test/ui/generic-associated-types/issue-74824.stderr b/src/test/ui/generic-associated-types/issue-74824.stderr
index bd51e5a447b..8517eb9fa21 100644
--- a/src/test/ui/generic-associated-types/issue-74824.stderr
+++ b/src/test/ui/generic-associated-types/issue-74824.stderr
@@ -1,8 +1,8 @@
error[E0277]: the trait bound `Box<T>: Copy` is not satisfied
- --> $DIR/issue-74824.rs:7:5
+ --> $DIR/issue-74824.rs:7:26
|
LL | type Copy<T>: Copy = Box<T>;
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `Copy` is not implemented for `Box<T>`
+ | ^^^^^^ the trait `Copy` is not implemented for `Box<T>`
|
note: required by a bound in `UnsafeCopy::Copy`
--> $DIR/issue-74824.rs:7:19
@@ -11,10 +11,10 @@ LL | type Copy<T>: Copy = Box<T>;
| ^^^^ required by this bound in `UnsafeCopy::Copy`
error[E0277]: the trait bound `T: Clone` is not satisfied
- --> $DIR/issue-74824.rs:7:5
+ --> $DIR/issue-74824.rs:7:26
|
LL | type Copy<T>: Copy = Box<T>;
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `Clone` is not implemented for `T`
+ | ^^^^^^ the trait `Clone` is not implemented for `T`
|
= note: required because of the requirements on the impl of `Clone` for `Box<T>`
note: required by a bound in `UnsafeCopy::Copy`
diff --git a/src/test/ui/generic-associated-types/issue-78113-lifetime-mismatch-dyn-trait-box.stderr b/src/test/ui/generic-associated-types/issue-78113-lifetime-mismatch-dyn-trait-box.stderr
index 24be83024b4..c4a7d8faa41 100644
--- a/src/test/ui/generic-associated-types/issue-78113-lifetime-mismatch-dyn-trait-box.stderr
+++ b/src/test/ui/generic-associated-types/issue-78113-lifetime-mismatch-dyn-trait-box.stderr
@@ -1,8 +1,8 @@
error: incompatible lifetime on type
- --> $DIR/issue-78113-lifetime-mismatch-dyn-trait-box.rs:17:5
+ --> $DIR/issue-78113-lifetime-mismatch-dyn-trait-box.rs:17:18
|
LL | type T<'a> = Box<dyn A + 'a>;
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ | ^^^^^^^^^^^^^^^
|
note: because this has an unmet lifetime requirement
--> $DIR/issue-78113-lifetime-mismatch-dyn-trait-box.rs:12:17
@@ -26,10 +26,10 @@ LL | impl A for Box<dyn A + '_> {}
| ++++
error: incompatible lifetime on type
- --> $DIR/issue-78113-lifetime-mismatch-dyn-trait-box.rs:27:5
+ --> $DIR/issue-78113-lifetime-mismatch-dyn-trait-box.rs:27:18
|
LL | type T<'a> = Box<dyn A + 'a>;
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ | ^^^^^^^^^^^^^^^
|
note: because this has an unmet lifetime requirement
--> $DIR/issue-78113-lifetime-mismatch-dyn-trait-box.rs:23:17
@@ -48,10 +48,10 @@ LL | impl C for Box<dyn A + 'static> {}
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
error: incompatible lifetime on type
- --> $DIR/issue-78113-lifetime-mismatch-dyn-trait-box.rs:37:5
+ --> $DIR/issue-78113-lifetime-mismatch-dyn-trait-box.rs:37:18
|
LL | type T<'a> = (Box<dyn A + 'a>, Box<dyn A + 'a>);
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
note: because this has an unmet lifetime requirement
--> $DIR/issue-78113-lifetime-mismatch-dyn-trait-box.rs:33:17
diff --git a/src/test/ui/generic-associated-types/issue-86787.rs b/src/test/ui/generic-associated-types/issue-86787.rs
index 0f62f83e256..5863bac2f9d 100644
--- a/src/test/ui/generic-associated-types/issue-86787.rs
+++ b/src/test/ui/generic-associated-types/issue-86787.rs
@@ -9,7 +9,7 @@ enum Either<L, R> {
pub trait HasChildrenOf {
type T;
type TRef<'a>;
- //~^ Missing required bounds
+ //~^ missing required
fn ref_children<'a>(&'a self) -> Vec<Self::TRef<'a>>;
fn take_children(self) -> Vec<Self::T>;
diff --git a/src/test/ui/generic-associated-types/issue-86787.stderr b/src/test/ui/generic-associated-types/issue-86787.stderr
index 87dcd875de7..d4b2267d3dd 100644
--- a/src/test/ui/generic-associated-types/issue-86787.stderr
+++ b/src/test/ui/generic-associated-types/issue-86787.stderr
@@ -1,10 +1,13 @@
-error: Missing required bounds on TRef
+error: missing required bound on `TRef`
--> $DIR/issue-86787.rs:11:5
|
LL | type TRef<'a>;
| ^^^^^^^^^^^^^-
| |
- | help: add the required where clauses: `where Self: 'a`
+ | help: add the required where clause: `where Self: 'a`
+ |
+ = note: this bound is currently required to ensure that impls have maximum flexibility
+ = note: we are soliciting feedback, see issue #87479 <https://github.com/rust-lang/rust/issues/87479> for more information
error: aborting due to previous error
diff --git a/src/test/ui/generic-associated-types/issue-87429-associated-type-default.stderr b/src/test/ui/generic-associated-types/issue-87429-associated-type-default.stderr
index 01cb0bfc72c..e5db2f1b7c3 100644
--- a/src/test/ui/generic-associated-types/issue-87429-associated-type-default.stderr
+++ b/src/test/ui/generic-associated-types/issue-87429-associated-type-default.stderr
@@ -1,8 +1,8 @@
error[E0277]: can't compare `Foo` with `Foo`
- --> $DIR/issue-87429-associated-type-default.rs:14:5
+ --> $DIR/issue-87429-associated-type-default.rs:14:60
|
LL | type Member<'a>: for<'b> PartialEq<Self::Member<'b>> = Foo;
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ no implementation for `Foo == Foo`
+ | ^^^ no implementation for `Foo == Foo`
|
= help: the trait `PartialEq` is not implemented for `Foo`
note: required by a bound in `Family2::Member`
diff --git a/src/test/ui/generic-associated-types/issue-87429-specialization.stderr b/src/test/ui/generic-associated-types/issue-87429-specialization.stderr
index 87bd35f5878..ca44ecfdb53 100644
--- a/src/test/ui/generic-associated-types/issue-87429-specialization.stderr
+++ b/src/test/ui/generic-associated-types/issue-87429-specialization.stderr
@@ -9,10 +9,10 @@ LL | #![feature(specialization)]
= help: consider using `min_specialization` instead, which is more stable and complete
error[E0277]: can't compare `Foo` with `Foo`
- --> $DIR/issue-87429-specialization.rs:21:5
+ --> $DIR/issue-87429-specialization.rs:21:31
|
LL | default type Member<'a> = Foo;
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ no implementation for `Foo == Foo`
+ | ^^^ no implementation for `Foo == Foo`
|
= help: the trait `PartialEq` is not implemented for `Foo`
note: required by a bound in `Family::Member`
diff --git a/src/test/ui/generic-associated-types/issue-87748.rs b/src/test/ui/generic-associated-types/issue-87748.rs
deleted file mode 100644
index 93c3b3937cb..00000000000
--- a/src/test/ui/generic-associated-types/issue-87748.rs
+++ /dev/null
@@ -1,30 +0,0 @@
-// Checks that we properly add implied bounds from unnormalized projections in
-// inputs when typechecking functions.
-
-// check-pass
-
-#![feature(generic_associated_types)]
-
-trait MyTrait {
- type Assoc<'a, 'b> where 'b: 'a;
- fn do_sth(arg: Self::Assoc<'_, '_>);
-}
-
-struct A;
-struct B;
-struct C;
-
-impl MyTrait for A {
- type Assoc<'a, 'b> where 'b: 'a = u32;
- fn do_sth(_: u32) {}
-}
-impl MyTrait for B {
- type Assoc<'a, 'b> where 'b: 'a = u32;
- fn do_sth(_: Self::Assoc<'_, '_>) {}
-}
-impl MyTrait for C {
- type Assoc<'a, 'b> where 'b: 'a = u32;
- fn do_sth(_: Self::Assoc<'static, 'static>) {}
-}
-
-fn main () {}
diff --git a/src/test/ui/generic-associated-types/issue-88595.stderr b/src/test/ui/generic-associated-types/issue-88595.stderr
index 1948f82d0c9..cb462871ccd 100644
--- a/src/test/ui/generic-associated-types/issue-88595.stderr
+++ b/src/test/ui/generic-associated-types/issue-88595.stderr
@@ -1,8 +1,8 @@
error[E0478]: lifetime bound not satisfied
- --> $DIR/issue-88595.rs:19:5
+ --> $DIR/issue-88595.rs:19:18
|
LL | type B<'b> = impl Clone;
- | ^^^^^^^^^^^^^^^^^^^^^^^^
+ | ^^^^^^^^^^
|
note: lifetime parameter instantiated with the lifetime `'a` as defined here
--> $DIR/issue-88595.rs:18:6
diff --git a/src/test/ui/generic-associated-types/issue-90014.stderr b/src/test/ui/generic-associated-types/issue-90014.stderr
index 125d817e351..23e8d08af34 100644
--- a/src/test/ui/generic-associated-types/issue-90014.stderr
+++ b/src/test/ui/generic-associated-types/issue-90014.stderr
@@ -1,8 +1,8 @@
error[E0477]: the type `&mut ()` does not fulfill the required lifetime
- --> $DIR/issue-90014.rs:14:5
+ --> $DIR/issue-90014.rs:14:20
|
LL | type Fut<'a> = impl Future<Output = ()>;
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ | ^^^^^^^^^^^^^^^^^^^^^^^^
|
note: type must outlive the lifetime `'a` as defined here
--> $DIR/issue-90014.rs:14:14
diff --git a/src/test/ui/generic-associated-types/missing-bounds.fixed b/src/test/ui/generic-associated-types/missing-bounds.fixed
index 54478d16282..0e234120a51 100644
--- a/src/test/ui/generic-associated-types/missing-bounds.fixed
+++ b/src/test/ui/generic-associated-types/missing-bounds.fixed
@@ -34,11 +34,12 @@ impl<B: std::ops::Add<Output = B>> Add for D<B> {
struct E<B>(B);
-impl<B: Add> Add for E<B> where B: Add<Output = B> {
+impl<B: Add> Add for E<B> where B: Add<Output = B>, B: Add<Output = B> {
+ //~^ ERROR equality constraints are not yet supported in `where` clauses
type Output = Self;
fn add(self, rhs: Self) -> Self {
- Self(self.0 + rhs.0)
+ Self(self.0 + rhs.0) //~ ERROR mismatched types
}
}
diff --git a/src/test/ui/generic-associated-types/missing-bounds.rs b/src/test/ui/generic-associated-types/missing-bounds.rs
index 962d2db9476..ffafff5e9f5 100644
--- a/src/test/ui/generic-associated-types/missing-bounds.rs
+++ b/src/test/ui/generic-associated-types/missing-bounds.rs
@@ -34,11 +34,12 @@ impl<B> Add for D<B> {
struct E<B>(B);
-impl<B: Add> Add for E<B> where B: Add<Output = B> {
+impl<B: Add> Add for E<B> where <B as Add>::Output = B {
+ //~^ ERROR equality constraints are not yet supported in `where` clauses
type Output = Self;
fn add(self, rhs: Self) -> Self {
- Self(self.0 + rhs.0)
+ Self(self.0 + rhs.0) //~ ERROR mismatched types
}
}
diff --git a/src/test/ui/generic-associated-types/missing-bounds.stderr b/src/test/ui/generic-associated-types/missing-bounds.stderr
index 4d33fe84829..c9603b8d1ea 100644
--- a/src/test/ui/generic-associated-types/missing-bounds.stderr
+++ b/src/test/ui/generic-associated-types/missing-bounds.stderr
@@ -1,3 +1,15 @@
+error: equality constraints are not yet supported in `where` clauses
+ --> $DIR/missing-bounds.rs:37:33
+ |
+LL | impl<B: Add> Add for E<B> where <B as Add>::Output = B {
+ | ^^^^^^^^^^^^^^^^^^^^^^ not supported
+ |
+ = note: see issue #20041 <https://github.com/rust-lang/rust/issues/20041> for more information
+help: if `Output` is an associated type you're trying to set, use the associated type binding syntax
+ |
+LL | impl<B: Add> Add for E<B> where B: Add<Output = B> {
+ | ~~~~~~~~~~~~~~~~~~
+
error[E0308]: mismatched types
--> $DIR/missing-bounds.rs:11:11
|
@@ -43,7 +55,23 @@ help: consider restricting type parameter `B`
LL | impl<B: std::ops::Add<Output = B>> Add for D<B> {
| +++++++++++++++++++++++++++
-error: aborting due to 3 previous errors
+error[E0308]: mismatched types
+ --> $DIR/missing-bounds.rs:42:14
+ |
+LL | impl<B: Add> Add for E<B> where <B as Add>::Output = B {
+ | - this type parameter
+...
+LL | Self(self.0 + rhs.0)
+ | ^^^^^^^^^^^^^^ expected type parameter `B`, found associated type
+ |
+ = note: expected type parameter `B`
+ found associated type `<B as Add>::Output`
+help: consider further restricting type parameter `B`
+ |
+LL | impl<B: Add> Add for E<B> where <B as Add>::Output = B, B: Add<Output = B> {
+ | ++++++++++++++++++++
+
+error: aborting due to 5 previous errors
Some errors have detailed explanations: E0308, E0369.
For more information about an error, try `rustc --explain E0308`.
diff --git a/src/test/ui/generic-associated-types/projection-type-lifetime-mismatch.stderr b/src/test/ui/generic-associated-types/projection-type-lifetime-mismatch.stderr
index 1ffd205652f..32c5ccf1648 100644
--- a/src/test/ui/generic-associated-types/projection-type-lifetime-mismatch.stderr
+++ b/src/test/ui/generic-associated-types/projection-type-lifetime-mismatch.stderr
@@ -4,7 +4,9 @@ error[E0759]: `x` has an anonymous lifetime `'_` but it needs to satisfy a `'sta
LL | fn f(x: &impl for<'a> X<Y<'a> = &'a ()>) -> &'static () {
| ------------------------------- this data with an anonymous lifetime `'_`...
LL | x.m()
- | --^-- ...is captured and required to live as long as `'static` here
+ | - ^
+ | |
+ | ...is used and required to live as long as `'static` here
error[E0759]: `x` has an anonymous lifetime `'_` but it needs to satisfy a `'static` lifetime requirement
--> $DIR/projection-type-lifetime-mismatch.rs:22:7
@@ -12,7 +14,9 @@ error[E0759]: `x` has an anonymous lifetime `'_` but it needs to satisfy a `'sta
LL | fn g<T: for<'a> X<Y<'a> = &'a ()>>(x: &T) -> &'static () {
| -- this data with an anonymous lifetime `'_`...
LL | x.m()
- | --^-- ...is captured and required to live as long as `'static` here
+ | - ^
+ | |
+ | ...is used and required to live as long as `'static` here
error[E0759]: `x` has an anonymous lifetime `'_` but it needs to satisfy a `'static` lifetime requirement
--> $DIR/projection-type-lifetime-mismatch.rs:27:7
@@ -20,7 +24,9 @@ error[E0759]: `x` has an anonymous lifetime `'_` but it needs to satisfy a `'sta
LL | fn h(x: &()) -> &'static () {
| --- this data with an anonymous lifetime `'_`...
LL | x.m()
- | --^-- ...is captured and required to live as long as `'static` here
+ | - ^
+ | |
+ | ...is used and required to live as long as `'static` here
error: aborting due to 3 previous errors
diff --git a/src/test/ui/generic-associated-types/self-outlives-lint.rs b/src/test/ui/generic-associated-types/self-outlives-lint.rs
index af90d158855..37b3a6155d5 100644
--- a/src/test/ui/generic-associated-types/self-outlives-lint.rs
+++ b/src/test/ui/generic-associated-types/self-outlives-lint.rs
@@ -7,7 +7,7 @@ use std::fmt::Debug;
// We have a `&'a self`, so we need a `Self: 'a`
trait Iterable {
type Item<'x>;
- //~^ Missing required bounds
+ //~^ missing required
fn iter<'a>(&'a self) -> Self::Item<'a>;
}
@@ -23,7 +23,7 @@ impl<T> Iterable for T {
// We have a `&'a T`, so we need a `T: 'x`
trait Deserializer<T> {
type Out<'x>;
- //~^ Missing required bounds
+ //~^ missing required
fn deserialize<'a>(&self, input: &'a T) -> Self::Out<'a>;
}
@@ -37,14 +37,14 @@ impl<T> Deserializer<T> for () {
// We have a `&'b T` and a `'b: 'a`, so it is implied that `T: 'a`. Therefore, we need a `T: 'x`
trait Deserializer2<T> {
type Out<'x>;
- //~^ Missing required bounds
+ //~^ missing required
fn deserialize2<'a, 'b: 'a>(&self, input1: &'b T) -> Self::Out<'a>;
}
// We have a `&'a T` and a `&'b U`, so we need a `T: 'x` and a `U: 'y`
trait Deserializer3<T, U> {
type Out<'x, 'y>;
- //~^ Missing required bounds
+ //~^ missing required
fn deserialize2<'a, 'b>(&self, input: &'a T, input2: &'b U) -> Self::Out<'a, 'b>;
}
@@ -59,7 +59,7 @@ struct Wrap<T>(T);
// We pass `Wrap<T>` and we see `&'z Wrap<T>`, so we require `D: 'x`
trait Des {
type Out<'x, D>;
- //~^ Missing required bounds
+ //~^ missing required
fn des<'z, T>(&self, data: &'z Wrap<T>) -> Self::Out<'z, Wrap<T>>;
}
/*
@@ -75,7 +75,7 @@ impl Des for () {
// implied bound that `T: 'z`, so we require `D: 'x`
trait Des2 {
type Out<'x, D>;
- //~^ Missing required bounds
+ //~^ missing required
fn des<'z, T>(&self, data: &'z Wrap<T>) -> Self::Out<'z, T>;
}
/*
@@ -90,7 +90,7 @@ impl Des2 for () {
// We see `&'z T`, so we require `D: 'x`
trait Des3 {
type Out<'x, D>;
- //~^ Missing required bounds
+ //~^ missing required
fn des<'z, T>(&self, data: &'z T) -> Self::Out<'z, T>;
}
/*
@@ -112,7 +112,7 @@ trait NoGat<'a> {
// FIXME: we require two bounds (`where Self: 'a, Self: 'b`) when we should only require one
trait TraitLifetime<'a> {
type Bar<'b>;
- //~^ Missing required bounds
+ //~^ missing required
fn method(&'a self) -> Self::Bar<'a>;
}
@@ -120,14 +120,14 @@ trait TraitLifetime<'a> {
// FIXME: we require two bounds (`where Self: 'a, Self: 'b`) when we should only require one
trait TraitLifetimeWhere<'a> where Self: 'a {
type Bar<'b>;
- //~^ Missing required bounds
+ //~^ missing required
fn method(&'a self) -> Self::Bar<'a>;
}
// Explicit bound instead of implicit; we want to still error
trait ExplicitBound {
type Bar<'b>;
- //~^ Missing required bounds
+ //~^ missing required
fn method<'b>(&self, token: &'b ()) -> Self::Bar<'b> where Self: 'b;
}
@@ -141,14 +141,15 @@ trait NotInReturn {
trait IterableTwo {
type Item<'a>;
type Iterator<'a>: Iterator<Item = Self::Item<'a>>;
- //~^ Missing required bounds
+ //~^ missing required
fn iter<'a>(&'a self) -> Self::Iterator<'a>;
}
-// We also should report region outlives clauses
+// We also should report region outlives clauses. Here, we know that `'y: 'x`,
+// because of `&'x &'y`, so we require that `'b: 'a`.
trait RegionOutlives {
type Bar<'a, 'b>;
- //~^ Missing required bounds
+ //~^ missing required
fn foo<'x, 'y>(&self, input: &'x &'y ()) -> Self::Bar<'x, 'y>;
}
@@ -161,6 +162,17 @@ impl Foo for () {
}
*/
+// Similar to the above, except with explicit bounds
+trait ExplicitRegionOutlives<'ctx> {
+ type Fut<'out>;
+ //~^ missing required
+
+ fn test<'out>(ctx: &'ctx i32) -> Self::Fut<'out>
+ where
+ 'ctx: 'out;
+}
+
+
// If there are multiple methods that return the GAT, require a set of clauses
// that can be satisfied by *all* methods
trait MultipleMethods {
@@ -170,4 +182,11 @@ trait MultipleMethods {
fn gimme_default(&self) -> Self::Bar<'static>;
}
+// We would normally require `Self: 'a`, but we can prove that `Self: 'static`
+// because of the the bounds on the trait, so the bound is proven
+trait Trait: 'static {
+ type Assoc<'a>;
+ fn make_assoc(_: &u32) -> Self::Assoc<'_>;
+}
+
fn main() {}
diff --git a/src/test/ui/generic-associated-types/self-outlives-lint.stderr b/src/test/ui/generic-associated-types/self-outlives-lint.stderr
index bf85780f69f..3b9146ad875 100644
--- a/src/test/ui/generic-associated-types/self-outlives-lint.stderr
+++ b/src/test/ui/generic-associated-types/self-outlives-lint.stderr
@@ -1,98 +1,145 @@
-error: Missing required bounds on Item
+error: missing required bound on `Item`
--> $DIR/self-outlives-lint.rs:9:5
|
LL | type Item<'x>;
| ^^^^^^^^^^^^^-
| |
- | help: add the required where clauses: `where Self: 'x`
+ | help: add the required where clause: `where Self: 'x`
+ |
+ = note: this bound is currently required to ensure that impls have maximum flexibility
+ = note: we are soliciting feedback, see issue #87479 <https://github.com/rust-lang/rust/issues/87479> for more information
-error: Missing required bounds on Out
+error: missing required bound on `Out`
--> $DIR/self-outlives-lint.rs:25:5
|
LL | type Out<'x>;
| ^^^^^^^^^^^^-
| |
- | help: add the required where clauses: `where T: 'x`
+ | help: add the required where clause: `where T: 'x`
+ |
+ = note: this bound is currently required to ensure that impls have maximum flexibility
+ = note: we are soliciting feedback, see issue #87479 <https://github.com/rust-lang/rust/issues/87479> for more information
-error: Missing required bounds on Out
+error: missing required bound on `Out`
--> $DIR/self-outlives-lint.rs:39:5
|
LL | type Out<'x>;
| ^^^^^^^^^^^^-
| |
- | help: add the required where clauses: `where T: 'x`
+ | help: add the required where clause: `where T: 'x`
+ |
+ = note: this bound is currently required to ensure that impls have maximum flexibility
+ = note: we are soliciting feedback, see issue #87479 <https://github.com/rust-lang/rust/issues/87479> for more information
-error: Missing required bounds on Out
+error: missing required bounds on `Out`
--> $DIR/self-outlives-lint.rs:46:5
|
LL | type Out<'x, 'y>;
| ^^^^^^^^^^^^^^^^-
| |
| help: add the required where clauses: `where T: 'x, U: 'y`
+ |
+ = note: these bounds are currently required to ensure that impls have maximum flexibility
+ = note: we are soliciting feedback, see issue #87479 <https://github.com/rust-lang/rust/issues/87479> for more information
-error: Missing required bounds on Out
+error: missing required bound on `Out`
--> $DIR/self-outlives-lint.rs:61:5
|
LL | type Out<'x, D>;
| ^^^^^^^^^^^^^^^-
| |
- | help: add the required where clauses: `where D: 'x`
+ | help: add the required where clause: `where D: 'x`
+ |
+ = note: this bound is currently required to ensure that impls have maximum flexibility
+ = note: we are soliciting feedback, see issue #87479 <https://github.com/rust-lang/rust/issues/87479> for more information
-error: Missing required bounds on Out
+error: missing required bound on `Out`
--> $DIR/self-outlives-lint.rs:77:5
|
LL | type Out<'x, D>;
| ^^^^^^^^^^^^^^^-
| |
- | help: add the required where clauses: `where D: 'x`
+ | help: add the required where clause: `where D: 'x`
+ |
+ = note: this bound is currently required to ensure that impls have maximum flexibility
+ = note: we are soliciting feedback, see issue #87479 <https://github.com/rust-lang/rust/issues/87479> for more information
-error: Missing required bounds on Out
+error: missing required bound on `Out`
--> $DIR/self-outlives-lint.rs:92:5
|
LL | type Out<'x, D>;
| ^^^^^^^^^^^^^^^-
| |
- | help: add the required where clauses: `where D: 'x`
+ | help: add the required where clause: `where D: 'x`
+ |
+ = note: this bound is currently required to ensure that impls have maximum flexibility
+ = note: we are soliciting feedback, see issue #87479 <https://github.com/rust-lang/rust/issues/87479> for more information
-error: Missing required bounds on Bar
+error: missing required bounds on `Bar`
--> $DIR/self-outlives-lint.rs:114:5
|
LL | type Bar<'b>;
| ^^^^^^^^^^^^-
| |
| help: add the required where clauses: `where Self: 'a, Self: 'b`
+ |
+ = note: these bounds are currently required to ensure that impls have maximum flexibility
+ = note: we are soliciting feedback, see issue #87479 <https://github.com/rust-lang/rust/issues/87479> for more information
-error: Missing required bounds on Bar
+error: missing required bound on `Bar`
--> $DIR/self-outlives-lint.rs:122:5
|
LL | type Bar<'b>;
| ^^^^^^^^^^^^-
| |
- | help: add the required where clauses: `where Self: 'a, Self: 'b`
+ | help: add the required where clause: `where Self: 'b`
+ |
+ = note: this bound is currently required to ensure that impls have maximum flexibility
+ = note: we are soliciting feedback, see issue #87479 <https://github.com/rust-lang/rust/issues/87479> for more information
-error: Missing required bounds on Bar
+error: missing required bound on `Bar`
--> $DIR/self-outlives-lint.rs:129:5
|
LL | type Bar<'b>;
| ^^^^^^^^^^^^-
| |
- | help: add the required where clauses: `where Self: 'b`
+ | help: add the required where clause: `where Self: 'b`
+ |
+ = note: this bound is currently required to ensure that impls have maximum flexibility
+ = note: we are soliciting feedback, see issue #87479 <https://github.com/rust-lang/rust/issues/87479> for more information
-error: Missing required bounds on Iterator
+error: missing required bound on `Iterator`
--> $DIR/self-outlives-lint.rs:143:5
|
LL | type Iterator<'a>: Iterator<Item = Self::Item<'a>>;
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^-
| |
- | help: add the required where clauses: `where Self: 'a`
+ | help: add the required where clause: `where Self: 'a`
+ |
+ = note: this bound is currently required to ensure that impls have maximum flexibility
+ = note: we are soliciting feedback, see issue #87479 <https://github.com/rust-lang/rust/issues/87479> for more information
-error: Missing required bounds on Bar
- --> $DIR/self-outlives-lint.rs:150:5
+error: missing required bound on `Bar`
+ --> $DIR/self-outlives-lint.rs:151:5
|
LL | type Bar<'a, 'b>;
| ^^^^^^^^^^^^^^^^-
| |
- | help: add the required where clauses: `where 'a: 'b`
+ | help: add the required where clause: `where 'b: 'a`
+ |
+ = note: this bound is currently required to ensure that impls have maximum flexibility
+ = note: we are soliciting feedback, see issue #87479 <https://github.com/rust-lang/rust/issues/87479> for more information
+
+error: missing required bound on `Fut`
+ --> $DIR/self-outlives-lint.rs:167:5
+ |
+LL | type Fut<'out>;
+ | ^^^^^^^^^^^^^^-
+ | |
+ | help: add the required where clause: `where 'ctx: 'out`
+ |
+ = note: this bound is currently required to ensure that impls have maximum flexibility
+ = note: we are soliciting feedback, see issue #87479 <https://github.com/rust-lang/rust/issues/87479> for more information
-error: aborting due to 12 previous errors
+error: aborting due to 13 previous errors
diff --git a/src/test/ui/generic-associated-types/unsatisfied-outlives-bound.stderr b/src/test/ui/generic-associated-types/unsatisfied-outlives-bound.stderr
index ebb47893457..7ec9386cabe 100644
--- a/src/test/ui/generic-associated-types/unsatisfied-outlives-bound.stderr
+++ b/src/test/ui/generic-associated-types/unsatisfied-outlives-bound.stderr
@@ -1,8 +1,8 @@
error[E0477]: the type `&'b ()` does not fulfill the required lifetime
- --> $DIR/unsatisfied-outlives-bound.rs:8:5
+ --> $DIR/unsatisfied-outlives-bound.rs:8:21
|
LL | type Item<'a> = &'b ();
- | ^^^^^^^^^^^^^^^^^^^^^^^
+ | ^^^^^^
|
note: type must outlive the lifetime `'a` as defined here as required by this binding
--> $DIR/unsatisfied-outlives-bound.rs:8:15
@@ -11,10 +11,10 @@ LL | type Item<'a> = &'b ();
| ^^
error[E0477]: the type `&'a ()` does not fulfill the required lifetime
- --> $DIR/unsatisfied-outlives-bound.rs:17:5
+ --> $DIR/unsatisfied-outlives-bound.rs:17:21
|
LL | type Item<'a> = &'a ();
- | ^^^^^^^^^^^^^^^^^^^^^^^
+ | ^^^^^^
|
note: type must satisfy the static lifetime as required by this binding
--> $DIR/unsatisfied-outlives-bound.rs:13:20
diff --git a/src/test/ui/generics/issue-59508-1.rs b/src/test/ui/generics/issue-59508-1.rs
index 6376c429b28..7e1dd770704 100644
--- a/src/test/ui/generics/issue-59508-1.rs
+++ b/src/test/ui/generics/issue-59508-1.rs
@@ -1,8 +1,7 @@
#![allow(dead_code)]
-#![feature(const_generics_defaults)]
// This test checks that generic parameter re-ordering diagnostic suggestions mention that
-// consts come after types and lifetimes when the `const_generics_defaults` feature is enabled.
+// consts come after types and lifetimes.
// We cannot run rustfix on this test because of the above const generics warning.
struct A;
diff --git a/src/test/ui/generics/issue-59508-1.stderr b/src/test/ui/generics/issue-59508-1.stderr
index df244f02dce..d162365ea4b 100644
--- a/src/test/ui/generics/issue-59508-1.stderr
+++ b/src/test/ui/generics/issue-59508-1.stderr
@@ -1,5 +1,5 @@
error: lifetime parameters must be declared prior to type parameters
- --> $DIR/issue-59508-1.rs:11:25
+ --> $DIR/issue-59508-1.rs:10:25
|
LL | pub fn do_things<T, 'a, 'b: 'a>() {
| ----^^--^^----- help: reorder the parameters: lifetimes, then consts and types: `<'a, 'b: 'a, T>`
diff --git a/src/test/ui/generics/issue-59508.stderr b/src/test/ui/generics/issue-59508.stderr
index 33e967cebff..c52ae4182b8 100644
--- a/src/test/ui/generics/issue-59508.stderr
+++ b/src/test/ui/generics/issue-59508.stderr
@@ -2,7 +2,7 @@ error: lifetime parameters must be declared prior to type parameters
--> $DIR/issue-59508.rs:10:25
|
LL | pub fn do_things<T, 'a, 'b: 'a>() {
- | ----^^--^^----- help: reorder the parameters: lifetimes, then types, then consts: `<'a, 'b: 'a, T>`
+ | ----^^--^^----- help: reorder the parameters: lifetimes, then consts and types: `<'a, 'b: 'a, T>`
error: aborting due to previous error
diff --git a/src/test/ui/generics/lifetime-before-type-params.stderr b/src/test/ui/generics/lifetime-before-type-params.stderr
index 047bc7f6d90..62d95e45329 100644
--- a/src/test/ui/generics/lifetime-before-type-params.stderr
+++ b/src/test/ui/generics/lifetime-before-type-params.stderr
@@ -2,25 +2,25 @@ error: lifetime parameters must be declared prior to type parameters
--> $DIR/lifetime-before-type-params.rs:2:13
|
LL | fn first<T, 'a, 'b>() {}
- | ----^^--^^- help: reorder the parameters: lifetimes, then types, then consts: `<'a, 'b, T>`
+ | ----^^--^^- help: reorder the parameters: lifetimes, then consts and types: `<'a, 'b, T>`
error: lifetime parameters must be declared prior to type parameters
--> $DIR/lifetime-before-type-params.rs:4:18
|
LL | fn second<'a, T, 'b>() {}
- | --------^^- help: reorder the parameters: lifetimes, then types, then consts: `<'a, 'b, T>`
+ | --------^^- help: reorder the parameters: lifetimes, then consts and types: `<'a, 'b, T>`
error: lifetime parameters must be declared prior to type parameters
--> $DIR/lifetime-before-type-params.rs:6:16
|
LL | fn third<T, U, 'a>() {}
- | -------^^- help: reorder the parameters: lifetimes, then types, then consts: `<'a, T, U>`
+ | -------^^- help: reorder the parameters: lifetimes, then consts and types: `<'a, T, U>`
error: lifetime parameters must be declared prior to type parameters
--> $DIR/lifetime-before-type-params.rs:8:18
|
LL | fn fourth<'a, T, 'b, U, 'c, V>() {}
- | --------^^-----^^---- help: reorder the parameters: lifetimes, then types, then consts: `<'a, 'b, 'c, T, U, V>`
+ | --------^^-----^^---- help: reorder the parameters: lifetimes, then consts and types: `<'a, 'b, 'c, T, U, V>`
error: aborting due to 4 previous errors
diff --git a/src/test/ui/half-open-range-patterns/exclusive_range_pattern_syntax_collision.stderr b/src/test/ui/half-open-range-patterns/exclusive_range_pattern_syntax_collision.stderr
index a6f8563a047..241485db49b 100644
--- a/src/test/ui/half-open-range-patterns/exclusive_range_pattern_syntax_collision.stderr
+++ b/src/test/ui/half-open-range-patterns/exclusive_range_pattern_syntax_collision.stderr
@@ -1,8 +1,6 @@
error[E0308]: mismatched types
--> $DIR/exclusive_range_pattern_syntax_collision.rs:6:13
|
-LL | match [5..4, 99..105, 43..44] {
- | ----------------------- this expression has type `[std::ops::Range<{integer}>; 3]`
LL | [_, 99.., _] => {},
| ^^ expected struct `std::ops::Range`, found integer
|
diff --git a/src/test/ui/half-open-range-patterns/exclusive_range_pattern_syntax_collision2.stderr b/src/test/ui/half-open-range-patterns/exclusive_range_pattern_syntax_collision2.stderr
index 4e0102c930d..777d029d7dd 100644
--- a/src/test/ui/half-open-range-patterns/exclusive_range_pattern_syntax_collision2.stderr
+++ b/src/test/ui/half-open-range-patterns/exclusive_range_pattern_syntax_collision2.stderr
@@ -7,8 +7,6 @@ LL | [_, 99..] => {},
error[E0308]: mismatched types
--> $DIR/exclusive_range_pattern_syntax_collision2.rs:6:13
|
-LL | match [5..4, 99..105, 43..44] {
- | ----------------------- this expression has type `[std::ops::Range<{integer}>; 3]`
LL | [_, 99..] => {},
| ^^ expected struct `std::ops::Range`, found integer
|
diff --git a/src/test/ui/half-open-range-patterns/exclusive_range_pattern_syntax_collision3.stderr b/src/test/ui/half-open-range-patterns/exclusive_range_pattern_syntax_collision3.stderr
index 665eef2fcb9..6119733a7d8 100644
--- a/src/test/ui/half-open-range-patterns/exclusive_range_pattern_syntax_collision3.stderr
+++ b/src/test/ui/half-open-range-patterns/exclusive_range_pattern_syntax_collision3.stderr
@@ -1,8 +1,6 @@
error[E0308]: mismatched types
--> $DIR/exclusive_range_pattern_syntax_collision3.rs:6:12
|
-LL | match [5..4, 99..105, 43..44] {
- | ----------------------- this expression has type `[std::ops::Range<{integer}>; 3]`
LL | [..9, 99..100, _] => {},
| ^ expected struct `std::ops::Range`, found integer
|
@@ -12,8 +10,6 @@ LL | [..9, 99..100, _] => {},
error[E0308]: mismatched types
--> $DIR/exclusive_range_pattern_syntax_collision3.rs:6:15
|
-LL | match [5..4, 99..105, 43..44] {
- | ----------------------- this expression has type `[std::ops::Range<{integer}>; 3]`
LL | [..9, 99..100, _] => {},
| ^^ --- this is of type `{integer}`
| |
@@ -25,8 +21,6 @@ LL | [..9, 99..100, _] => {},
error[E0308]: mismatched types
--> $DIR/exclusive_range_pattern_syntax_collision3.rs:6:19
|
-LL | match [5..4, 99..105, 43..44] {
- | ----------------------- this expression has type `[std::ops::Range<{integer}>; 3]`
LL | [..9, 99..100, _] => {},
| -- ^^^ expected struct `std::ops::Range`, found integer
| |
diff --git a/src/test/ui/half-open-range-patterns/pat-tuple-5.stderr b/src/test/ui/half-open-range-patterns/pat-tuple-5.stderr
index 307ad711b74..31ea3a17871 100644
--- a/src/test/ui/half-open-range-patterns/pat-tuple-5.stderr
+++ b/src/test/ui/half-open-range-patterns/pat-tuple-5.stderr
@@ -1,8 +1,6 @@
error[E0308]: mismatched types
--> $DIR/pat-tuple-5.rs:8:10
|
-LL | match (0, 1) {
- | ------ this expression has type `({integer}, {integer})`
LL | (PAT ..) => {}
| ^^^ expected tuple, found `u8`
|
diff --git a/src/test/ui/half-open-range-patterns/range_pat_interactions0.rs b/src/test/ui/half-open-range-patterns/range_pat_interactions0.rs
index 4f478a69881..8f745e8104f 100644
--- a/src/test/ui/half-open-range-patterns/range_pat_interactions0.rs
+++ b/src/test/ui/half-open-range-patterns/range_pat_interactions0.rs
@@ -2,7 +2,7 @@
#![allow(incomplete_features)]
#![feature(exclusive_range_pattern)]
#![feature(half_open_range_patterns)]
-#![feature(inline_const)]
+#![feature(inline_const_pat)]
fn main() {
let mut if_lettable = vec![];
diff --git a/src/test/ui/half-open-range-patterns/range_pat_interactions3.rs b/src/test/ui/half-open-range-patterns/range_pat_interactions3.rs
index 0afb5126059..41c7e46dfc1 100644
--- a/src/test/ui/half-open-range-patterns/range_pat_interactions3.rs
+++ b/src/test/ui/half-open-range-patterns/range_pat_interactions3.rs
@@ -12,7 +12,7 @@ fn main() {
y @ (0..5 | 6) => or_two.push(y),
//~^ exclusive range pattern syntax is experimental
y @ 0..const { 5 + 1 } => assert_eq!(y, 5),
- //~^ inline-const is experimental
+ //~^ inline-const in pattern position is experimental
//~| exclusive range pattern syntax is experimental
y @ -5.. => range_from.push(y),
y @ ..-7 => assert_eq!(y, -8),
diff --git a/src/test/ui/half-open-range-patterns/range_pat_interactions3.stderr b/src/test/ui/half-open-range-patterns/range_pat_interactions3.stderr
index 8278e7cc6cf..5e36996a462 100644
--- a/src/test/ui/half-open-range-patterns/range_pat_interactions3.stderr
+++ b/src/test/ui/half-open-range-patterns/range_pat_interactions3.stderr
@@ -7,14 +7,14 @@ LL | y @ ..-7 => assert_eq!(y, -8),
= note: see issue #67264 <https://github.com/rust-lang/rust/issues/67264> for more information
= help: add `#![feature(half_open_range_patterns)]` to the crate attributes to enable
-error[E0658]: inline-const is experimental
+error[E0658]: inline-const in pattern position is experimental
--> $DIR/range_pat_interactions3.rs:14:20
|
LL | y @ 0..const { 5 + 1 } => assert_eq!(y, 5),
| ^^^^^
|
= note: see issue #76001 <https://github.com/rust-lang/rust/issues/76001> for more information
- = help: add `#![feature(inline_const)]` to the crate attributes to enable
+ = help: add `#![feature(inline_const_pat)]` to the crate attributes to enable
error[E0658]: exclusive range pattern syntax is experimental
--> $DIR/range_pat_interactions3.rs:10:17
diff --git a/src/test/ui/higher-rank-trait-bounds/issue-88586-hr-self-outlives-in-trait-def.rs b/src/test/ui/higher-rank-trait-bounds/issue-88586-hr-self-outlives-in-trait-def.rs
new file mode 100644
index 00000000000..b50f56b03d9
--- /dev/null
+++ b/src/test/ui/higher-rank-trait-bounds/issue-88586-hr-self-outlives-in-trait-def.rs
@@ -0,0 +1,11 @@
+// Regression test for #88586: a higher-ranked outlives bound on Self in a trait
+// definition caused an ICE when debug_assertions were enabled.
+//
+// FIXME: The error output in the absence of the ICE is unhelpful; this should be improved.
+
+trait A where for<'a> Self: 'a
+//~^ ERROR the parameter type `Self` may not live long enough
+{
+}
+
+fn main() {}
diff --git a/src/test/ui/higher-rank-trait-bounds/issue-88586-hr-self-outlives-in-trait-def.stderr b/src/test/ui/higher-rank-trait-bounds/issue-88586-hr-self-outlives-in-trait-def.stderr
new file mode 100644
index 00000000000..18618ffcc86
--- /dev/null
+++ b/src/test/ui/higher-rank-trait-bounds/issue-88586-hr-self-outlives-in-trait-def.stderr
@@ -0,0 +1,19 @@
+error[E0311]: the parameter type `Self` may not live long enough
+ --> $DIR/issue-88586-hr-self-outlives-in-trait-def.rs:6:1
+ |
+LL | / trait A where for<'a> Self: 'a
+LL | |
+LL | | {
+LL | | }
+ | |_^
+ |
+ = help: consider adding an explicit lifetime bound `Self: 'a`...
+ = note: ...so that the type `Self` will meet its required lifetime bounds...
+note: ...that is required by this bound
+ --> $DIR/issue-88586-hr-self-outlives-in-trait-def.rs:6:29
+ |
+LL | trait A where for<'a> Self: 'a
+ | ^^
+
+error: aborting due to previous error
+
diff --git a/src/test/ui/higher-rank-trait-bounds/normalize-under-binder/issue-71955.migrate.stderr b/src/test/ui/higher-rank-trait-bounds/normalize-under-binder/issue-71955.migrate.stderr
index 119cec1fa95..7da6b029c26 100644
--- a/src/test/ui/higher-rank-trait-bounds/normalize-under-binder/issue-71955.migrate.stderr
+++ b/src/test/ui/higher-rank-trait-bounds/normalize-under-binder/issue-71955.migrate.stderr
@@ -1,5 +1,5 @@
error: implementation of `Parser` is not general enough
- --> $DIR/issue-71955.rs:52:5
+ --> $DIR/issue-71955.rs:57:5
|
LL | foo(bar, "string", |s| s.len() == 5);
| ^^^ implementation of `Parser` is not general enough
@@ -8,7 +8,7 @@ LL | foo(bar, "string", |s| s.len() == 5);
= note: ...but it actually implements `Parser<'1>`, for some specific lifetime `'1`
error: implementation of `Parser` is not general enough
- --> $DIR/issue-71955.rs:52:5
+ --> $DIR/issue-71955.rs:57:5
|
LL | foo(bar, "string", |s| s.len() == 5);
| ^^^ implementation of `Parser` is not general enough
@@ -17,7 +17,7 @@ LL | foo(bar, "string", |s| s.len() == 5);
= note: ...but it actually implements `Parser<'1>`, for some specific lifetime `'1`
error: implementation of `Parser` is not general enough
- --> $DIR/issue-71955.rs:52:5
+ --> $DIR/issue-71955.rs:57:5
|
LL | foo(bar, "string", |s| s.len() == 5);
| ^^^ implementation of `Parser` is not general enough
@@ -26,7 +26,7 @@ LL | foo(bar, "string", |s| s.len() == 5);
= note: ...but it actually implements `Parser<'1>`, for some specific lifetime `'1`
error: implementation of `Parser` is not general enough
- --> $DIR/issue-71955.rs:52:5
+ --> $DIR/issue-71955.rs:57:5
|
LL | foo(bar, "string", |s| s.len() == 5);
| ^^^ implementation of `Parser` is not general enough
@@ -35,7 +35,7 @@ LL | foo(bar, "string", |s| s.len() == 5);
= note: ...but it actually implements `Parser<'1>`, for some specific lifetime `'1`
error: implementation of `Parser` is not general enough
- --> $DIR/issue-71955.rs:52:5
+ --> $DIR/issue-71955.rs:57:5
|
LL | foo(bar, "string", |s| s.len() == 5);
| ^^^ implementation of `Parser` is not general enough
@@ -44,7 +44,7 @@ LL | foo(bar, "string", |s| s.len() == 5);
= note: ...but it actually implements `Parser<'1>`, for some specific lifetime `'1`
error: implementation of `Parser` is not general enough
- --> $DIR/issue-71955.rs:58:5
+ --> $DIR/issue-71955.rs:63:5
|
LL | foo(baz, "string", |s| s.0.len() == 5);
| ^^^ implementation of `Parser` is not general enough
@@ -53,7 +53,7 @@ LL | foo(baz, "string", |s| s.0.len() == 5);
= note: ...but it actually implements `Parser<'1>`, for some specific lifetime `'1`
error: implementation of `Parser` is not general enough
- --> $DIR/issue-71955.rs:58:5
+ --> $DIR/issue-71955.rs:63:5
|
LL | foo(baz, "string", |s| s.0.len() == 5);
| ^^^ implementation of `Parser` is not general enough
@@ -62,7 +62,7 @@ LL | foo(baz, "string", |s| s.0.len() == 5);
= note: ...but it actually implements `Parser<'1>`, for some specific lifetime `'1`
error: implementation of `Parser` is not general enough
- --> $DIR/issue-71955.rs:58:5
+ --> $DIR/issue-71955.rs:63:5
|
LL | foo(baz, "string", |s| s.0.len() == 5);
| ^^^ implementation of `Parser` is not general enough
@@ -71,7 +71,7 @@ LL | foo(baz, "string", |s| s.0.len() == 5);
= note: ...but it actually implements `Parser<'1>`, for some specific lifetime `'1`
error: implementation of `Parser` is not general enough
- --> $DIR/issue-71955.rs:58:5
+ --> $DIR/issue-71955.rs:63:5
|
LL | foo(baz, "string", |s| s.0.len() == 5);
| ^^^ implementation of `Parser` is not general enough
@@ -80,7 +80,7 @@ LL | foo(baz, "string", |s| s.0.len() == 5);
= note: ...but it actually implements `Parser<'1>`, for some specific lifetime `'1`
error: implementation of `Parser` is not general enough
- --> $DIR/issue-71955.rs:58:5
+ --> $DIR/issue-71955.rs:63:5
|
LL | foo(baz, "string", |s| s.0.len() == 5);
| ^^^ implementation of `Parser` is not general enough
diff --git a/src/test/ui/higher-rank-trait-bounds/normalize-under-binder/issue-71955.nll.stderr b/src/test/ui/higher-rank-trait-bounds/normalize-under-binder/issue-71955.nll.stderr
index 69ab446bc7a..c2feaa91280 100644
--- a/src/test/ui/higher-rank-trait-bounds/normalize-under-binder/issue-71955.nll.stderr
+++ b/src/test/ui/higher-rank-trait-bounds/normalize-under-binder/issue-71955.nll.stderr
@@ -1,5 +1,5 @@
error: fatal error triggered by #[rustc_error]
- --> $DIR/issue-71955.rs:42:1
+ --> $DIR/issue-71955.rs:47:1
|
LL | fn main() {
| ^^^^^^^^^
diff --git a/src/test/ui/higher-rank-trait-bounds/normalize-under-binder/issue-71955.rs b/src/test/ui/higher-rank-trait-bounds/normalize-under-binder/issue-71955.rs
index 95e3b3d4e1b..3d6778b6942 100644
--- a/src/test/ui/higher-rank-trait-bounds/normalize-under-binder/issue-71955.rs
+++ b/src/test/ui/higher-rank-trait-bounds/normalize-under-binder/issue-71955.rs
@@ -3,6 +3,11 @@
// [nll]compile-flags: -Zborrowck=mir
// check-fail
+// Since we are testing nll (and migration) explicitly as a separate
+// revisions, don't worry about the --compare-mode=nll on this test.
+
+// ignore-compare-mode-nll
+
#![feature(rustc_attrs)]
trait Parser<'s> {
diff --git a/src/test/ui/hrtb/issue-30786.migrate.stderr b/src/test/ui/hrtb/issue-30786.migrate.stderr
index a497c6257da..a2ab1f1856d 100644
--- a/src/test/ui/hrtb/issue-30786.migrate.stderr
+++ b/src/test/ui/hrtb/issue-30786.migrate.stderr
@@ -1,5 +1,5 @@
-error[E0599]: the method `filterx` exists for struct `Map<Repeat, [closure@$DIR/issue-30786.rs:127:27: 127:36]>`, but its trait bounds were not satisfied
- --> $DIR/issue-30786.rs:128:22
+error[E0599]: the method `filterx` exists for struct `Map<Repeat, [closure@$DIR/issue-30786.rs:126:27: 126:36]>`, but its trait bounds were not satisfied
+ --> $DIR/issue-30786.rs:127:22
|
LL | pub struct Map<S, F> {
| --------------------
@@ -8,19 +8,19 @@ LL | pub struct Map<S, F> {
| doesn't satisfy `_: StreamExt`
...
LL | let filter = map.filterx(|x: &_| true);
- | ^^^^^^^ method cannot be called on `Map<Repeat, [closure@$DIR/issue-30786.rs:127:27: 127:36]>` due to unsatisfied trait bounds
+ | ^^^^^^^ method cannot be called on `Map<Repeat, [closure@$DIR/issue-30786.rs:126:27: 126:36]>` due to unsatisfied trait bounds
|
note: the following trait bounds were not satisfied because of the requirements of the implementation of `StreamExt` for `_`:
- `&'a mut Map<Repeat, [closure@$DIR/issue-30786.rs:127:27: 127:36]>: Stream`
- `&'a mut &Map<Repeat, [closure@$DIR/issue-30786.rs:127:27: 127:36]>: Stream`
- `&'a mut &mut Map<Repeat, [closure@$DIR/issue-30786.rs:127:27: 127:36]>: Stream`
- --> $DIR/issue-30786.rs:106:9
+ `&'a mut Map<Repeat, [closure@$DIR/issue-30786.rs:126:27: 126:36]>: Stream`
+ `&'a mut &Map<Repeat, [closure@$DIR/issue-30786.rs:126:27: 126:36]>: Stream`
+ `&'a mut &mut Map<Repeat, [closure@$DIR/issue-30786.rs:126:27: 126:36]>: Stream`
+ --> $DIR/issue-30786.rs:105:9
|
LL | impl<T> StreamExt for T where for<'a> &'a mut T: Stream {}
| ^^^^^^^^^ ^
-error[E0599]: the method `countx` exists for struct `Filter<Map<Repeat, for<'r> fn(&'r u64) -> &'r u64 {identity::<u64>}>, [closure@$DIR/issue-30786.rs:140:30: 140:42]>`, but its trait bounds were not satisfied
- --> $DIR/issue-30786.rs:141:24
+error[E0599]: the method `countx` exists for struct `Filter<Map<Repeat, for<'r> fn(&'r u64) -> &'r u64 {identity::<u64>}>, [closure@$DIR/issue-30786.rs:139:30: 139:42]>`, but its trait bounds were not satisfied
+ --> $DIR/issue-30786.rs:140:24
|
LL | pub struct Filter<S, F> {
| -----------------------
@@ -29,13 +29,13 @@ LL | pub struct Filter<S, F> {
| doesn't satisfy `_: StreamExt`
...
LL | let count = filter.countx();
- | ^^^^^^ method cannot be called on `Filter<Map<Repeat, for<'r> fn(&'r u64) -> &'r u64 {identity::<u64>}>, [closure@$DIR/issue-30786.rs:140:30: 140:42]>` due to unsatisfied trait bounds
+ | ^^^^^^ method cannot be called on `Filter<Map<Repeat, for<'r> fn(&'r u64) -> &'r u64 {identity::<u64>}>, [closure@$DIR/issue-30786.rs:139:30: 139:42]>` due to unsatisfied trait bounds
|
note: the following trait bounds were not satisfied because of the requirements of the implementation of `StreamExt` for `_`:
- `&'a mut Filter<Map<Repeat, for<'r> fn(&'r u64) -> &'r u64 {identity::<u64>}>, [closure@$DIR/issue-30786.rs:140:30: 140:42]>: Stream`
- `&'a mut &Filter<Map<Repeat, for<'r> fn(&'r u64) -> &'r u64 {identity::<u64>}>, [closure@$DIR/issue-30786.rs:140:30: 140:42]>: Stream`
- `&'a mut &mut Filter<Map<Repeat, for<'r> fn(&'r u64) -> &'r u64 {identity::<u64>}>, [closure@$DIR/issue-30786.rs:140:30: 140:42]>: Stream`
- --> $DIR/issue-30786.rs:106:9
+ `&'a mut Filter<Map<Repeat, for<'r> fn(&'r u64) -> &'r u64 {identity::<u64>}>, [closure@$DIR/issue-30786.rs:139:30: 139:42]>: Stream`
+ `&'a mut &Filter<Map<Repeat, for<'r> fn(&'r u64) -> &'r u64 {identity::<u64>}>, [closure@$DIR/issue-30786.rs:139:30: 139:42]>: Stream`
+ `&'a mut &mut Filter<Map<Repeat, for<'r> fn(&'r u64) -> &'r u64 {identity::<u64>}>, [closure@$DIR/issue-30786.rs:139:30: 139:42]>: Stream`
+ --> $DIR/issue-30786.rs:105:9
|
LL | impl<T> StreamExt for T where for<'a> &'a mut T: Stream {}
| ^^^^^^^^^ ^
diff --git a/src/test/ui/hrtb/issue-30786.nll.stderr b/src/test/ui/hrtb/issue-30786.nll.stderr
index a497c6257da..a2ab1f1856d 100644
--- a/src/test/ui/hrtb/issue-30786.nll.stderr
+++ b/src/test/ui/hrtb/issue-30786.nll.stderr
@@ -1,5 +1,5 @@
-error[E0599]: the method `filterx` exists for struct `Map<Repeat, [closure@$DIR/issue-30786.rs:127:27: 127:36]>`, but its trait bounds were not satisfied
- --> $DIR/issue-30786.rs:128:22
+error[E0599]: the method `filterx` exists for struct `Map<Repeat, [closure@$DIR/issue-30786.rs:126:27: 126:36]>`, but its trait bounds were not satisfied
+ --> $DIR/issue-30786.rs:127:22
|
LL | pub struct Map<S, F> {
| --------------------
@@ -8,19 +8,19 @@ LL | pub struct Map<S, F> {
| doesn't satisfy `_: StreamExt`
...
LL | let filter = map.filterx(|x: &_| true);
- | ^^^^^^^ method cannot be called on `Map<Repeat, [closure@$DIR/issue-30786.rs:127:27: 127:36]>` due to unsatisfied trait bounds
+ | ^^^^^^^ method cannot be called on `Map<Repeat, [closure@$DIR/issue-30786.rs:126:27: 126:36]>` due to unsatisfied trait bounds
|
note: the following trait bounds were not satisfied because of the requirements of the implementation of `StreamExt` for `_`:
- `&'a mut Map<Repeat, [closure@$DIR/issue-30786.rs:127:27: 127:36]>: Stream`
- `&'a mut &Map<Repeat, [closure@$DIR/issue-30786.rs:127:27: 127:36]>: Stream`
- `&'a mut &mut Map<Repeat, [closure@$DIR/issue-30786.rs:127:27: 127:36]>: Stream`
- --> $DIR/issue-30786.rs:106:9
+ `&'a mut Map<Repeat, [closure@$DIR/issue-30786.rs:126:27: 126:36]>: Stream`
+ `&'a mut &Map<Repeat, [closure@$DIR/issue-30786.rs:126:27: 126:36]>: Stream`
+ `&'a mut &mut Map<Repeat, [closure@$DIR/issue-30786.rs:126:27: 126:36]>: Stream`
+ --> $DIR/issue-30786.rs:105:9
|
LL | impl<T> StreamExt for T where for<'a> &'a mut T: Stream {}
| ^^^^^^^^^ ^
-error[E0599]: the method `countx` exists for struct `Filter<Map<Repeat, for<'r> fn(&'r u64) -> &'r u64 {identity::<u64>}>, [closure@$DIR/issue-30786.rs:140:30: 140:42]>`, but its trait bounds were not satisfied
- --> $DIR/issue-30786.rs:141:24
+error[E0599]: the method `countx` exists for struct `Filter<Map<Repeat, for<'r> fn(&'r u64) -> &'r u64 {identity::<u64>}>, [closure@$DIR/issue-30786.rs:139:30: 139:42]>`, but its trait bounds were not satisfied
+ --> $DIR/issue-30786.rs:140:24
|
LL | pub struct Filter<S, F> {
| -----------------------
@@ -29,13 +29,13 @@ LL | pub struct Filter<S, F> {
| doesn't satisfy `_: StreamExt`
...
LL | let count = filter.countx();
- | ^^^^^^ method cannot be called on `Filter<Map<Repeat, for<'r> fn(&'r u64) -> &'r u64 {identity::<u64>}>, [closure@$DIR/issue-30786.rs:140:30: 140:42]>` due to unsatisfied trait bounds
+ | ^^^^^^ method cannot be called on `Filter<Map<Repeat, for<'r> fn(&'r u64) -> &'r u64 {identity::<u64>}>, [closure@$DIR/issue-30786.rs:139:30: 139:42]>` due to unsatisfied trait bounds
|
note: the following trait bounds were not satisfied because of the requirements of the implementation of `StreamExt` for `_`:
- `&'a mut Filter<Map<Repeat, for<'r> fn(&'r u64) -> &'r u64 {identity::<u64>}>, [closure@$DIR/issue-30786.rs:140:30: 140:42]>: Stream`
- `&'a mut &Filter<Map<Repeat, for<'r> fn(&'r u64) -> &'r u64 {identity::<u64>}>, [closure@$DIR/issue-30786.rs:140:30: 140:42]>: Stream`
- `&'a mut &mut Filter<Map<Repeat, for<'r> fn(&'r u64) -> &'r u64 {identity::<u64>}>, [closure@$DIR/issue-30786.rs:140:30: 140:42]>: Stream`
- --> $DIR/issue-30786.rs:106:9
+ `&'a mut Filter<Map<Repeat, for<'r> fn(&'r u64) -> &'r u64 {identity::<u64>}>, [closure@$DIR/issue-30786.rs:139:30: 139:42]>: Stream`
+ `&'a mut &Filter<Map<Repeat, for<'r> fn(&'r u64) -> &'r u64 {identity::<u64>}>, [closure@$DIR/issue-30786.rs:139:30: 139:42]>: Stream`
+ `&'a mut &mut Filter<Map<Repeat, for<'r> fn(&'r u64) -> &'r u64 {identity::<u64>}>, [closure@$DIR/issue-30786.rs:139:30: 139:42]>: Stream`
+ --> $DIR/issue-30786.rs:105:9
|
LL | impl<T> StreamExt for T where for<'a> &'a mut T: Stream {}
| ^^^^^^^^^ ^
diff --git a/src/test/ui/hrtb/issue-30786.rs b/src/test/ui/hrtb/issue-30786.rs
index 278c5441ecf..540c26c358b 100644
--- a/src/test/ui/hrtb/issue-30786.rs
+++ b/src/test/ui/hrtb/issue-30786.rs
@@ -7,6 +7,7 @@
// through again.
// revisions: migrate nll
+//[nll]compile-flags: -Z borrowck=mir
// Since we are testing nll (and migration) explicitly as a separate
// revisions, don't worry about the --compare-mode=nll on this test.
@@ -14,8 +15,6 @@
// ignore-compare-mode-nll
// ignore-compare-mode-polonius
-//[nll]compile-flags: -Z borrowck=mir
-
pub trait Stream {
type Item;
fn next(self) -> Option<Self::Item>;
diff --git a/src/test/ui/hrtb/issue-62203-hrtb-ice.stderr b/src/test/ui/hrtb/issue-62203-hrtb-ice.stderr
index 5db17cb1bf4..0ebba37e4ec 100644
--- a/src/test/ui/hrtb/issue-62203-hrtb-ice.stderr
+++ b/src/test/ui/hrtb/issue-62203-hrtb-ice.stderr
@@ -2,8 +2,13 @@ error[E0271]: type mismatch resolving `for<'r> <L<[closure@$DIR/issue-62203-hrtb
--> $DIR/issue-62203-hrtb-ice.rs:38:19
|
LL | let v = Unit2.m(
- | ^ expected associated type, found struct `Unit4`
+ | ^ type mismatch resolving `for<'r> <L<[closure@$DIR/issue-62203-hrtb-ice.rs:42:17: 42:39]> as T0<'r, (&'r u8,)>>::O == <_ as Ty<'r>>::V`
|
+note: expected this to be `<_ as Ty<'_>>::V`
+ --> $DIR/issue-62203-hrtb-ice.rs:21:14
+ |
+LL | type O = T::Output;
+ | ^^^^^^^^^
= note: expected associated type `<_ as Ty<'_>>::V`
found struct `Unit4`
= help: consider constraining the associated type `<_ as Ty<'_>>::V` to `Unit4` or calling a method that returns `<_ as Ty<'_>>::V`
diff --git a/src/test/ui/hygiene/unpretty-debug.stdout b/src/test/ui/hygiene/unpretty-debug.stdout
index ffb9f9eed41..51c21043db8 100644
--- a/src/test/ui/hygiene/unpretty-debug.stdout
+++ b/src/test/ui/hygiene/unpretty-debug.stdout
@@ -15,7 +15,7 @@ fn bar /* 0#0 */() {
y /* 0#1 */ + x /* 0#0 */
}
-fn y /* 0#0 */() { }
+fn y /* 0#0 */() {}
/*
Expansions:
diff --git a/src/test/ui/impl-header-lifetime-elision/dyn-trait.stderr b/src/test/ui/impl-header-lifetime-elision/dyn-trait.stderr
index b3bef677d19..2307572cc3f 100644
--- a/src/test/ui/impl-header-lifetime-elision/dyn-trait.stderr
+++ b/src/test/ui/impl-header-lifetime-elision/dyn-trait.stderr
@@ -4,7 +4,7 @@ error[E0759]: `x` has lifetime `'a` but it needs to satisfy a `'static` lifetime
LL | fn with_dyn_debug_static<'a>(x: Box<dyn Debug + 'a>) {
| ------------------- this data with lifetime `'a`...
LL | static_val(x);
- | ^ ...is captured here...
+ | ^ ...is used here...
|
note: ...and is required to live as long as `'static` here
--> $DIR/dyn-trait.rs:20:5
diff --git a/src/test/ui/impl-trait/auto-trait-leak2.stderr b/src/test/ui/impl-trait/auto-trait-leak2.stderr
index 8c53b4105bb..37ae3c68029 100644
--- a/src/test/ui/impl-trait/auto-trait-leak2.stderr
+++ b/src/test/ui/impl-trait/auto-trait-leak2.stderr
@@ -2,16 +2,16 @@ error[E0277]: `Rc<Cell<i32>>` cannot be sent between threads safely
--> $DIR/auto-trait-leak2.rs:13:10
|
LL | fn before() -> impl Fn(i32) {
- | ------------ within this `impl Fn<(i32,)>`
+ | ------------ within this `impl Fn(i32)`
...
LL | send(before());
| ---- ^^^^^^^^ `Rc<Cell<i32>>` cannot be sent between threads safely
| |
| required by a bound introduced by this call
|
- = help: within `impl Fn<(i32,)>`, the trait `Send` is not implemented for `Rc<Cell<i32>>`
+ = help: within `impl Fn(i32)`, the trait `Send` is not implemented for `Rc<Cell<i32>>`
= note: required because it appears within the type `[closure@$DIR/auto-trait-leak2.rs:7:5: 7:22]`
- = note: required because it appears within the type `impl Fn<(i32,)>`
+ = note: required because it appears within the type `impl Fn(i32)`
note: required by a bound in `send`
--> $DIR/auto-trait-leak2.rs:10:12
|
@@ -27,11 +27,11 @@ LL | send(after());
| required by a bound introduced by this call
...
LL | fn after() -> impl Fn(i32) {
- | ------------ within this `impl Fn<(i32,)>`
+ | ------------ within this `impl Fn(i32)`
|
- = help: within `impl Fn<(i32,)>`, the trait `Send` is not implemented for `Rc<Cell<i32>>`
+ = help: within `impl Fn(i32)`, the trait `Send` is not implemented for `Rc<Cell<i32>>`
= note: required because it appears within the type `[closure@$DIR/auto-trait-leak2.rs:24:5: 24:22]`
- = note: required because it appears within the type `impl Fn<(i32,)>`
+ = note: required because it appears within the type `impl Fn(i32)`
note: required by a bound in `send`
--> $DIR/auto-trait-leak2.rs:10:12
|
diff --git a/src/test/ui/impl-trait/bound-normalization-fail.stderr b/src/test/ui/impl-trait/bound-normalization-fail.stderr
index 3c720f50d48..afa21c1a858 100644
--- a/src/test/ui/impl-trait/bound-normalization-fail.stderr
+++ b/src/test/ui/impl-trait/bound-normalization-fail.stderr
@@ -2,8 +2,13 @@ error[E0271]: type mismatch resolving `<Foo<()> as FooLike>::Output == <T as imp
--> $DIR/bound-normalization-fail.rs:25:32
|
LL | fn foo_fail<T: Trait>() -> impl FooLike<Output = T::Assoc> {
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected associated type, found `()`
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type mismatch resolving `<Foo<()> as FooLike>::Output == <T as impl_trait::Trait>::Assoc`
|
+note: expected this to be `<T as impl_trait::Trait>::Assoc`
+ --> $DIR/bound-normalization-fail.rs:14:19
+ |
+LL | type Output = T;
+ | ^
= note: expected associated type `<T as impl_trait::Trait>::Assoc`
found unit type `()`
help: consider constraining the associated type `<T as impl_trait::Trait>::Assoc` to `()`
@@ -21,8 +26,13 @@ error[E0271]: type mismatch resolving `<Foo<()> as FooLike>::Output == <T as lif
--> $DIR/bound-normalization-fail.rs:41:41
|
LL | fn foo2_fail<'a, T: Trait<'a>>() -> impl FooLike<Output = T::Assoc> {
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected associated type, found `()`
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type mismatch resolving `<Foo<()> as FooLike>::Output == <T as lifetimes::Trait<'static>>::Assoc`
+ |
+note: expected this to be `<T as lifetimes::Trait<'static>>::Assoc`
+ --> $DIR/bound-normalization-fail.rs:14:19
|
+LL | type Output = T;
+ | ^
= note: expected associated type `<T as lifetimes::Trait<'static>>::Assoc`
found unit type `()`
help: consider constraining the associated type `<T as lifetimes::Trait<'static>>::Assoc` to `()`
diff --git a/src/test/ui/impl-trait/hidden-lifetimes.stderr b/src/test/ui/impl-trait/hidden-lifetimes.stderr
index 60d3409a8ac..c6d11293eec 100644
--- a/src/test/ui/impl-trait/hidden-lifetimes.stderr
+++ b/src/test/ui/impl-trait/hidden-lifetimes.stderr
@@ -6,7 +6,7 @@ LL | fn hide_ref<'a, 'b, T: 'static>(x: &'a mut &'b T) -> impl Swap + 'a {
| |
| hidden type `&'a mut &'b T` captures the lifetime `'b` as defined here
|
-help: to declare that the `impl Trait` captures 'b, you can add an explicit `'b` lifetime bound
+help: to declare that the `impl Trait` captures `'b`, you can add an explicit `'b` lifetime bound
|
LL | fn hide_ref<'a, 'b, T: 'static>(x: &'a mut &'b T) -> impl Swap + 'a + 'b {
| ++++
@@ -19,7 +19,7 @@ LL | fn hide_rc_refcell<'a, 'b: 'a, T: 'static>(x: Rc<RefCell<&'b T>>) -> impl S
| |
| hidden type `Rc<RefCell<&'b T>>` captures the lifetime `'b` as defined here
|
-help: to declare that the `impl Trait` captures 'b, you can add an explicit `'b` lifetime bound
+help: to declare that the `impl Trait` captures `'b`, you can add an explicit `'b` lifetime bound
|
LL | fn hide_rc_refcell<'a, 'b: 'a, T: 'static>(x: Rc<RefCell<&'b T>>) -> impl Swap + 'a + 'b {
| ++++
diff --git a/src/test/ui/impl-trait/impl-generic-mismatch-ab.stderr b/src/test/ui/impl-trait/impl-generic-mismatch-ab.stderr
index d37670db085..acf768d5795 100644
--- a/src/test/ui/impl-trait/impl-generic-mismatch-ab.stderr
+++ b/src/test/ui/impl-trait/impl-generic-mismatch-ab.stderr
@@ -1,9 +1,6 @@
error[E0053]: method `foo` has an incompatible type for trait
--> $DIR/impl-generic-mismatch-ab.rs:8:32
|
-LL | fn foo<A: Debug>(&self, a: &A, b: &impl Debug);
- | -- type in trait
-...
LL | fn foo<B: Debug>(&self, a: &impl Debug, b: &B) { }
| - ^^^^^^^^^^^
| | |
@@ -11,6 +8,11 @@ LL | fn foo<B: Debug>(&self, a: &impl Debug, b: &B) { }
| | help: change the parameter type to match the trait: `&B`
| expected type parameter
|
+note: type in trait
+ --> $DIR/impl-generic-mismatch-ab.rs:4:32
+ |
+LL | fn foo<A: Debug>(&self, a: &A, b: &impl Debug);
+ | ^^
= note: expected fn pointer `fn(&(), &B, &impl Debug)`
found fn pointer `fn(&(), &impl Debug, &B)`
= note: a type parameter was expected, but a different one was found; you might be missing a type parameter or trait bound
diff --git a/src/test/ui/impl-trait/impl-trait-in-macro.stderr b/src/test/ui/impl-trait/impl-trait-in-macro.stderr
index b5f9986ce40..7cfbe3447b8 100644
--- a/src/test/ui/impl-trait/impl-trait-in-macro.stderr
+++ b/src/test/ui/impl-trait/impl-trait-in-macro.stderr
@@ -7,6 +7,8 @@ LL | ($($tr:tt)*) => { impl $($tr)* };
| expected type parameter
| found type parameter
...
+LL | let mut a = x;
+ | - expected due to this value
LL | a = y;
| ^ expected type parameter `impl Debug`, found a different type parameter `impl Debug`
|
diff --git a/src/test/ui/impl-trait/issue-55872-2.rs b/src/test/ui/impl-trait/issue-55872-2.rs
index 9546d01ac5c..a519397806e 100644
--- a/src/test/ui/impl-trait/issue-55872-2.rs
+++ b/src/test/ui/impl-trait/issue-55872-2.rs
@@ -13,7 +13,7 @@ impl<S> Bar for S {
type E = impl std::marker::Copy;
fn foo<T>() -> Self::E {
//~^ ERROR type parameter `T` is part of concrete type but not used in parameter list for the `impl Trait` type alias
- //~| ERROR the trait bound `impl Future: Copy` is not satisfied [E0277]
+ //~| ERROR the trait bound `impl Future<Output = [async output]>: Copy` is not satisfied
async {}
}
}
diff --git a/src/test/ui/impl-trait/issue-55872-2.stderr b/src/test/ui/impl-trait/issue-55872-2.stderr
index 31b8fbd299c..97545ba3d11 100644
--- a/src/test/ui/impl-trait/issue-55872-2.stderr
+++ b/src/test/ui/impl-trait/issue-55872-2.stderr
@@ -1,8 +1,8 @@
-error[E0277]: the trait bound `impl Future: Copy` is not satisfied
+error[E0277]: the trait bound `impl Future<Output = [async output]>: Copy` is not satisfied
--> $DIR/issue-55872-2.rs:14:20
|
LL | fn foo<T>() -> Self::E {
- | ^^^^^^^ the trait `Copy` is not implemented for `impl Future`
+ | ^^^^^^^ the trait `Copy` is not implemented for `impl Future<Output = [async output]>`
error: type parameter `T` is part of concrete type but not used in parameter list for the `impl Trait` type alias
--> $DIR/issue-55872-2.rs:14:28
diff --git a/src/test/ui/impl-trait/issue-72911.stderr b/src/test/ui/impl-trait/issue-72911.stderr
index 17748ae4277..e57fbf104dc 100644
--- a/src/test/ui/impl-trait/issue-72911.stderr
+++ b/src/test/ui/impl-trait/issue-72911.stderr
@@ -19,14 +19,14 @@ LL |
LL | lint_files().flat_map(|f| gather_from_file(&f))
| -----------------------------------------------
| |
- | returning here with type `FlatMap<impl Iterator, [type error], [closure@$DIR/issue-72911.rs:9:27: 9:51]>`
- | returning here with type `FlatMap<impl Iterator, [type error], [closure@$DIR/issue-72911.rs:9:27: 9:51]>`
+ | returning here with type `FlatMap<impl Iterator<Item = [type error]>, [type error], [closure@$DIR/issue-72911.rs:9:27: 9:51]>`
+ | returning here with type `FlatMap<impl Iterator<Item = [type error]>, [type error], [closure@$DIR/issue-72911.rs:9:27: 9:51]>`
...
LL | fn gather_from_file(dir_entry: &foo::MissingItem) -> impl Iterator<Item = Lint> {
- | -------------------------- returning this opaque type `FlatMap<impl Iterator, [type error], [closure@$DIR/issue-72911.rs:9:27: 9:51]>`
+ | -------------------------- returning this opaque type `FlatMap<impl Iterator<Item = [type error]>, [type error], [closure@$DIR/issue-72911.rs:9:27: 9:51]>`
...
LL | fn lint_files() -> impl Iterator<Item = foo::MissingItem> {
- | -------------------------------------- returning this opaque type `FlatMap<impl Iterator, [type error], [closure@$DIR/issue-72911.rs:9:27: 9:51]>`
+ | -------------------------------------- returning this opaque type `FlatMap<impl Iterator<Item = [type error]>, [type error], [closure@$DIR/issue-72911.rs:9:27: 9:51]>`
error: aborting due to 3 previous errors
diff --git a/src/test/ui/impl-trait/issue-87450.stderr b/src/test/ui/impl-trait/issue-87450.stderr
index 83eb33efc6b..5019e544bd5 100644
--- a/src/test/ui/impl-trait/issue-87450.stderr
+++ b/src/test/ui/impl-trait/issue-87450.stderr
@@ -17,10 +17,10 @@ LL | fn foo() -> impl Fn() {
| ^^^^^^^^^ recursive opaque type
...
LL | wrap(wrap(wrap(wrap(wrap(wrap(wrap(foo())))))))
- | ----------------------------------------------- returning here with type `impl Fn<()>`
+ | ----------------------------------------------- returning here with type `impl Fn()`
...
LL | fn wrap(f: impl Fn()) -> impl Fn() {
- | --------- returning this opaque type `impl Fn<()>`
+ | --------- returning this opaque type `impl Fn()`
error: aborting due to previous error; 1 warning emitted
diff --git a/src/test/ui/impl-trait/issues/issue-70877.stderr b/src/test/ui/impl-trait/issues/issue-70877.stderr
index b6861039f6a..fe48e92da5e 100644
--- a/src/test/ui/impl-trait/issues/issue-70877.stderr
+++ b/src/test/ui/impl-trait/issues/issue-70877.stderr
@@ -5,8 +5,13 @@ LL | type FooRet = impl std::fmt::Debug;
| -------------------- the found opaque type
...
LL | type Foo = impl Iterator<Item = FooItem>;
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected enum `Option`, found opaque type
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type mismatch resolving `<Bar as Iterator>::Item == Box<(dyn for<'r> Fn(&'r (dyn ToString + 'r)) -> Option<String> + 'static)>`
|
+note: expected this to be `Box<(dyn for<'r> Fn(&'r (dyn ToString + 'r)) -> Option<String> + 'static)>`
+ --> $DIR/issue-70877.rs:13:17
+ |
+LL | type Item = FooItem;
+ | ^^^^^^^
= note: expected struct `Box<(dyn for<'r> Fn(&'r (dyn ToString + 'r)) -> Option<String> + 'static)>`
found struct `Box<(dyn for<'r> Fn(&'r (dyn ToString + 'r)) -> impl Debug + 'static)>`
diff --git a/src/test/ui/impl-trait/issues/issue-78722.stderr b/src/test/ui/impl-trait/issues/issue-78722.stderr
index 86bde9a0cdd..130678de237 100644
--- a/src/test/ui/impl-trait/issues/issue-78722.stderr
+++ b/src/test/ui/impl-trait/issues/issue-78722.stderr
@@ -15,7 +15,7 @@ LL | pub const fn from_generator<T>(gen: T) -> impl Future<Output = T::Return>
| ------------------------------- the found opaque type
|
= note: expected opaque type `impl Future<Output = u8>`
- found opaque type `impl Future`
+ found opaque type `impl Future<Output = [async output]>`
= note: distinct uses of `impl Trait` result in different opaque types
error: aborting due to previous error
diff --git a/src/test/ui/impl-trait/issues/issue-86201.rs b/src/test/ui/impl-trait/issues/issue-86201.rs
index 8cc4fef890a..e3386d29def 100644
--- a/src/test/ui/impl-trait/issues/issue-86201.rs
+++ b/src/test/ui/impl-trait/issues/issue-86201.rs
@@ -2,9 +2,9 @@
#![feature(type_alias_impl_trait)]
type FunType = impl Fn<()>;
-//~^ could not find defining uses
+//~^ ERROR could not find defining uses
static STATIC_FN: FunType = some_fn;
-//~^ mismatched types
+//~^ ERROR mismatched types
fn some_fn() {}
diff --git a/src/test/ui/impl-trait/multiple-lifetimes/ordinary-bounds-unrelated.stderr b/src/test/ui/impl-trait/multiple-lifetimes/ordinary-bounds-unrelated.stderr
index bfe656c7e2b..32829a0a1b2 100644
--- a/src/test/ui/impl-trait/multiple-lifetimes/ordinary-bounds-unrelated.stderr
+++ b/src/test/ui/impl-trait/multiple-lifetimes/ordinary-bounds-unrelated.stderr
@@ -6,7 +6,7 @@ LL | fn upper_bounds<'a, 'b, 'c, 'd, 'e>(a: Ordinary<'a>, b: Ordinary<'b>) -> im
| |
| hidden type `Ordinary<'b>` captures the lifetime `'b` as defined here
|
-help: to declare that the `impl Trait` captures 'b, you can add an explicit `'b` lifetime bound
+help: to declare that the `impl Trait` captures `'b`, you can add an explicit `'b` lifetime bound
|
LL | fn upper_bounds<'a, 'b, 'c, 'd, 'e>(a: Ordinary<'a>, b: Ordinary<'b>) -> impl Trait<'d, 'e> + 'b
| ++++
diff --git a/src/test/ui/impl-trait/multiple-lifetimes/ordinary-bounds-unsuited.stderr b/src/test/ui/impl-trait/multiple-lifetimes/ordinary-bounds-unsuited.stderr
index 75c2dd8e9d3..83ad23b253b 100644
--- a/src/test/ui/impl-trait/multiple-lifetimes/ordinary-bounds-unsuited.stderr
+++ b/src/test/ui/impl-trait/multiple-lifetimes/ordinary-bounds-unsuited.stderr
@@ -6,7 +6,7 @@ LL | fn upper_bounds<'a, 'b>(a: Ordinary<'a>, b: Ordinary<'b>) -> impl Trait<'a,
| |
| hidden type `Ordinary<'b>` captures the lifetime `'b` as defined here
|
-help: to declare that the `impl Trait` captures 'b, you can add an explicit `'b` lifetime bound
+help: to declare that the `impl Trait` captures `'b`, you can add an explicit `'b` lifetime bound
|
LL | fn upper_bounds<'a, 'b>(a: Ordinary<'a>, b: Ordinary<'b>) -> impl Trait<'a, 'b> + 'b
| ++++
diff --git a/src/test/ui/impl-trait/must_outlive_least_region_or_bound.nll.stderr b/src/test/ui/impl-trait/must_outlive_least_region_or_bound.nll.stderr
index eaf341248a1..2f6bd8ff377 100644
--- a/src/test/ui/impl-trait/must_outlive_least_region_or_bound.nll.stderr
+++ b/src/test/ui/impl-trait/must_outlive_least_region_or_bound.nll.stderr
@@ -6,7 +6,7 @@ LL | fn elided(x: &i32) -> impl Copy { x }
| |
| hidden type `&i32` captures the anonymous lifetime defined here
|
-help: to declare that the `impl Trait` captures '_, you can add an explicit `'_` lifetime bound
+help: to declare that the `impl Trait` captures `'_`, you can add an explicit `'_` lifetime bound
|
LL | fn elided(x: &i32) -> impl Copy + '_ { x }
| ++++
@@ -19,7 +19,7 @@ LL | fn explicit<'a>(x: &'a i32) -> impl Copy { x }
| |
| hidden type `&'a i32` captures the lifetime `'a` as defined here
|
-help: to declare that the `impl Trait` captures 'a, you can add an explicit `'a` lifetime bound
+help: to declare that the `impl Trait` captures `'a`, you can add an explicit `'a` lifetime bound
|
LL | fn explicit<'a>(x: &'a i32) -> impl Copy + 'a { x }
| ++++
@@ -74,7 +74,7 @@ LL | fn move_lifetime_into_fn<'a, 'b>(x: &'a u32, y: &'b u32) -> impl Fn(&'a u32
| |
| hidden type `[closure@$DIR/must_outlive_least_region_or_bound.rs:35:5: 35:31]` captures the lifetime `'b` as defined here
|
-help: to declare that the `impl Trait` captures 'b, you can add an explicit `'b` lifetime bound
+help: to declare that the `impl Trait` captures `'b`, you can add an explicit `'b` lifetime bound
|
LL | fn move_lifetime_into_fn<'a, 'b>(x: &'a u32, y: &'b u32) -> impl Fn(&'a u32) + 'b {
| ++++
diff --git a/src/test/ui/impl-trait/must_outlive_least_region_or_bound.stderr b/src/test/ui/impl-trait/must_outlive_least_region_or_bound.stderr
index d65dea7adc9..07ac0a8db35 100644
--- a/src/test/ui/impl-trait/must_outlive_least_region_or_bound.stderr
+++ b/src/test/ui/impl-trait/must_outlive_least_region_or_bound.stderr
@@ -6,7 +6,7 @@ LL | fn elided(x: &i32) -> impl Copy { x }
| |
| hidden type `&i32` captures the anonymous lifetime defined here
|
-help: to declare that the `impl Trait` captures '_, you can add an explicit `'_` lifetime bound
+help: to declare that the `impl Trait` captures `'_`, you can add an explicit `'_` lifetime bound
|
LL | fn elided(x: &i32) -> impl Copy + '_ { x }
| ++++
@@ -19,7 +19,7 @@ LL | fn explicit<'a>(x: &'a i32) -> impl Copy { x }
| |
| hidden type `&'a i32` captures the lifetime `'a` as defined here
|
-help: to declare that the `impl Trait` captures 'a, you can add an explicit `'a` lifetime bound
+help: to declare that the `impl Trait` captures `'a`, you can add an explicit `'a` lifetime bound
|
LL | fn explicit<'a>(x: &'a i32) -> impl Copy + 'a { x }
| ++++
@@ -28,7 +28,7 @@ error[E0759]: `x` has an anonymous lifetime `'_` but it needs to satisfy a `'sta
--> $DIR/must_outlive_least_region_or_bound.rs:9:46
|
LL | fn elided2(x: &i32) -> impl Copy + 'static { x }
- | ---- ^ ...is captured here...
+ | ---- ^ ...is used here...
| |
| this data with an anonymous lifetime `'_`...
|
@@ -50,7 +50,7 @@ error[E0759]: `x` has lifetime `'a` but it needs to satisfy a `'static` lifetime
--> $DIR/must_outlive_least_region_or_bound.rs:11:55
|
LL | fn explicit2<'a>(x: &'a i32) -> impl Copy + 'static { x }
- | ------- ^ ...is captured here...
+ | ------- ^ ...is used here...
| |
| this data with lifetime `'a`...
|
@@ -80,7 +80,7 @@ error[E0759]: `x` has an anonymous lifetime `'_` but it needs to satisfy a `'sta
--> $DIR/must_outlive_least_region_or_bound.rs:24:65
|
LL | fn elided5(x: &i32) -> (Box<dyn Debug>, impl Debug) { (Box::new(x), x) }
- | ---- this data with an anonymous lifetime `'_`... ^ ...is captured here, requiring it to live as long as `'static`
+ | ---- this data with an anonymous lifetime `'_`... ^ ...is used and required to live as long as `'static` here
|
help: to declare that the trait object captures data from argument `x`, you can add an explicit `'_` lifetime bound
|
@@ -95,7 +95,7 @@ error[E0759]: `x` has lifetime `'a` but it needs to satisfy a `'static` lifetime
--> $DIR/must_outlive_least_region_or_bound.rs:29:69
|
LL | fn with_bound<'a>(x: &'a i32) -> impl LifetimeTrait<'a> + 'static { x }
- | ------- this data with lifetime `'a`... ^ ...is captured here...
+ | ------- this data with lifetime `'a`... ^ ...is used here...
|
note: ...and is required to live as long as `'static` here
--> $DIR/must_outlive_least_region_or_bound.rs:29:34
@@ -119,7 +119,7 @@ LL | fn move_lifetime_into_fn<'a, 'b>(x: &'a u32, y: &'b u32) -> impl Fn(&'a u32
| |
| hidden type `[closure@$DIR/must_outlive_least_region_or_bound.rs:35:5: 35:31]` captures the lifetime `'b` as defined here
|
-help: to declare that the `impl Trait` captures 'b, you can add an explicit `'b` lifetime bound
+help: to declare that the `impl Trait` captures `'b`, you can add an explicit `'b` lifetime bound
|
LL | fn move_lifetime_into_fn<'a, 'b>(x: &'a u32, y: &'b u32) -> impl Fn(&'a u32) + 'b {
| ++++
@@ -136,10 +136,17 @@ error[E0759]: `x` has an anonymous lifetime `'_` but it needs to satisfy a `'sta
--> $DIR/must_outlive_least_region_or_bound.rs:16:50
|
LL | fn elided3(x: &i32) -> Box<dyn Debug> { Box::new(x) }
- | ---- ^ ...is captured here, requiring it to live as long as `'static`
+ | ---- ^ ...is used and required to live as long as `'static` here
| |
| this data with an anonymous lifetime `'_`...
|
+note: `'static` lifetime requirement introduced by the return type
+ --> $DIR/must_outlive_least_region_or_bound.rs:16:28
+ |
+LL | fn elided3(x: &i32) -> Box<dyn Debug> { Box::new(x) }
+ | ^^^^^^^^^ ----------- because of this returned expression
+ | |
+ | `'static` requirement introduced here
help: to declare that the trait object captures data from argument `x`, you can add an explicit `'_` lifetime bound
|
LL | fn elided3(x: &i32) -> Box<dyn Debug + '_> { Box::new(x) }
@@ -149,10 +156,17 @@ error[E0759]: `x` has lifetime `'a` but it needs to satisfy a `'static` lifetime
--> $DIR/must_outlive_least_region_or_bound.rs:18:59
|
LL | fn explicit3<'a>(x: &'a i32) -> Box<dyn Debug> { Box::new(x) }
- | ------- ^ ...is captured here, requiring it to live as long as `'static`
+ | ------- ^ ...is used and required to live as long as `'static` here
| |
| this data with lifetime `'a`...
|
+note: `'static` lifetime requirement introduced by the return type
+ --> $DIR/must_outlive_least_region_or_bound.rs:18:37
+ |
+LL | fn explicit3<'a>(x: &'a i32) -> Box<dyn Debug> { Box::new(x) }
+ | ^^^^^^^^^ ----------- because of this returned expression
+ | |
+ | `'static` requirement introduced here
help: to declare that the trait object captures data from argument `x`, you can add an explicit `'a` lifetime bound
|
LL | fn explicit3<'a>(x: &'a i32) -> Box<dyn Debug + 'a> { Box::new(x) }
@@ -162,10 +176,17 @@ error[E0759]: `x` has an anonymous lifetime `'_` but it needs to satisfy a `'sta
--> $DIR/must_outlive_least_region_or_bound.rs:20:60
|
LL | fn elided4(x: &i32) -> Box<dyn Debug + 'static> { Box::new(x) }
- | ---- ^ ...is captured here, requiring it to live as long as `'static`
+ | ---- ^ ...is used and required to live as long as `'static` here
| |
| this data with an anonymous lifetime `'_`...
|
+note: `'static` lifetime requirement introduced by the return type
+ --> $DIR/must_outlive_least_region_or_bound.rs:20:40
+ |
+LL | fn elided4(x: &i32) -> Box<dyn Debug + 'static> { Box::new(x) }
+ | ^^^^^^^ ----------- because of this returned expression
+ | |
+ | `'static` requirement introduced here
help: consider changing the trait object's explicit `'static` bound to the lifetime of argument `x`
|
LL | fn elided4(x: &i32) -> Box<dyn Debug + '_> { Box::new(x) }
@@ -179,8 +200,15 @@ error[E0759]: `x` has lifetime `'a` but it needs to satisfy a `'static` lifetime
--> $DIR/must_outlive_least_region_or_bound.rs:22:69
|
LL | fn explicit4<'a>(x: &'a i32) -> Box<dyn Debug + 'static> { Box::new(x) }
- | ------- this data with lifetime `'a`... ^ ...is captured here, requiring it to live as long as `'static`
+ | ------- this data with lifetime `'a`... ^ ...is used and required to live as long as `'static` here
|
+note: `'static` lifetime requirement introduced by the return type
+ --> $DIR/must_outlive_least_region_or_bound.rs:22:49
+ |
+LL | fn explicit4<'a>(x: &'a i32) -> Box<dyn Debug + 'static> { Box::new(x) }
+ | ^^^^^^^ ----------- because of this returned expression
+ | |
+ | `'static` requirement introduced here
help: consider changing the trait object's explicit `'static` bound to the lifetime of argument `x`
|
LL | fn explicit4<'a>(x: &'a i32) -> Box<dyn Debug + 'a> { Box::new(x) }
diff --git a/src/test/ui/impl-trait/projection-mismatch-in-impl-where-clause.stderr b/src/test/ui/impl-trait/projection-mismatch-in-impl-where-clause.stderr
index 54eb5a96c9d..65daabe419d 100644
--- a/src/test/ui/impl-trait/projection-mismatch-in-impl-where-clause.stderr
+++ b/src/test/ui/impl-trait/projection-mismatch-in-impl-where-clause.stderr
@@ -2,8 +2,13 @@ error[E0271]: type mismatch resolving `<() as Super>::Assoc == ()`
--> $DIR/projection-mismatch-in-impl-where-clause.rs:13:14
|
LL | fn test() -> impl Test {
- | ^^^^^^^^^ expected `()`, found `u8`
+ | ^^^^^^^^^ type mismatch resolving `<() as Super>::Assoc == ()`
|
+note: expected this to be `()`
+ --> $DIR/projection-mismatch-in-impl-where-clause.rs:6:18
+ |
+LL | type Assoc = u8;
+ | ^^
note: required because of the requirements on the impl of `Test` for `()`
--> $DIR/projection-mismatch-in-impl-where-clause.rs:11:9
|
diff --git a/src/test/ui/impl-trait/region-escape-via-bound.stderr b/src/test/ui/impl-trait/region-escape-via-bound.stderr
index 9dc2ea5bc82..cf854f67d04 100644
--- a/src/test/ui/impl-trait/region-escape-via-bound.stderr
+++ b/src/test/ui/impl-trait/region-escape-via-bound.stderr
@@ -7,7 +7,7 @@ LL |
LL | where 'x: 'y
| -- hidden type `Cell<&'x u32>` captures the lifetime `'x` as defined here
|
-help: to declare that the `impl Trait` captures 'x, you can add an explicit `'x` lifetime bound
+help: to declare that the `impl Trait` captures `'x`, you can add an explicit `'x` lifetime bound
|
LL | fn foo(x: Cell<&'x u32>) -> impl Trait<'y> + 'x
| ++++
diff --git a/src/test/ui/impl-trait/static-return-lifetime-infered.stderr b/src/test/ui/impl-trait/static-return-lifetime-infered.stderr
index 0d68f8c825f..7424da76182 100644
--- a/src/test/ui/impl-trait/static-return-lifetime-infered.stderr
+++ b/src/test/ui/impl-trait/static-return-lifetime-infered.stderr
@@ -6,7 +6,7 @@ LL | fn iter_values_anon(&self) -> impl Iterator<Item=u32> {
| |
| hidden type `Map<std::slice::Iter<'_, (u32, u32)>, [closure@$DIR/static-return-lifetime-infered.rs:9:27: 9:34]>` captures the anonymous lifetime defined here
|
-help: to declare that the `impl Trait` captures '_, you can add an explicit `'_` lifetime bound
+help: to declare that the `impl Trait` captures `'_`, you can add an explicit `'_` lifetime bound
|
LL | fn iter_values_anon(&self) -> impl Iterator<Item=u32> + '_ {
| ++++
@@ -19,7 +19,7 @@ LL | fn iter_values_anon(&self) -> impl Iterator<Item=u32> {
| |
| hidden type `Map<std::slice::Iter<'_, (u32, u32)>, [closure@$DIR/static-return-lifetime-infered.rs:9:27: 9:34]>` captures the anonymous lifetime defined here
|
-help: to declare that the `impl Trait` captures '_, you can add an explicit `'_` lifetime bound
+help: to declare that the `impl Trait` captures `'_`, you can add an explicit `'_` lifetime bound
|
LL | fn iter_values_anon(&self) -> impl Iterator<Item=u32> + '_ {
| ++++
@@ -32,7 +32,7 @@ LL | fn iter_values<'a>(&'a self) -> impl Iterator<Item=u32> {
| |
| hidden type `Map<std::slice::Iter<'a, (u32, u32)>, [closure@$DIR/static-return-lifetime-infered.rs:14:27: 14:34]>` captures the lifetime `'a` as defined here
|
-help: to declare that the `impl Trait` captures 'a, you can add an explicit `'a` lifetime bound
+help: to declare that the `impl Trait` captures `'a`, you can add an explicit `'a` lifetime bound
|
LL | fn iter_values<'a>(&'a self) -> impl Iterator<Item=u32> + 'a {
| ++++
@@ -45,7 +45,7 @@ LL | fn iter_values<'a>(&'a self) -> impl Iterator<Item=u32> {
| |
| hidden type `Map<std::slice::Iter<'a, (u32, u32)>, [closure@$DIR/static-return-lifetime-infered.rs:14:27: 14:34]>` captures the lifetime `'a` as defined here
|
-help: to declare that the `impl Trait` captures 'a, you can add an explicit `'a` lifetime bound
+help: to declare that the `impl Trait` captures `'a`, you can add an explicit `'a` lifetime bound
|
LL | fn iter_values<'a>(&'a self) -> impl Iterator<Item=u32> + 'a {
| ++++
diff --git a/src/test/ui/impl-trait/universal-two-impl-traits.stderr b/src/test/ui/impl-trait/universal-two-impl-traits.stderr
index 7c120235fd1..ab8a53d0db3 100644
--- a/src/test/ui/impl-trait/universal-two-impl-traits.stderr
+++ b/src/test/ui/impl-trait/universal-two-impl-traits.stderr
@@ -6,6 +6,7 @@ LL | fn foo(x: impl Debug, y: impl Debug) -> String {
| |
| expected type parameter
LL | let mut a = x;
+ | - expected due to this value
LL | a = y;
| ^ expected type parameter `impl Debug`, found a different type parameter `impl Debug`
|
diff --git a/src/test/ui/imports/extern-crate-self/extern-crate-self-fail.stderr b/src/test/ui/imports/extern-crate-self/extern-crate-self-fail.stderr
index 8f369f1b038..127765727b4 100644
--- a/src/test/ui/imports/extern-crate-self/extern-crate-self-fail.stderr
+++ b/src/test/ui/imports/extern-crate-self/extern-crate-self-fail.stderr
@@ -2,7 +2,12 @@ error: `extern crate self;` requires renaming
--> $DIR/extern-crate-self-fail.rs:1:1
|
LL | extern crate self;
- | ^^^^^^^^^^^^^^^^^^ help: try: `extern crate self as name;`
+ | ^^^^^^^^^^^^^^^^^^
+ |
+help: rename the `self` crate to be able to import it
+ |
+LL | extern crate self as name;
+ | ~~~~~~~~~~~~~~~~~~~~~~~~~~
error: `#[macro_use]` is not supported on `extern crate self`
--> $DIR/extern-crate-self-fail.rs:3:1
diff --git a/src/test/ui/imports/issue-28134.rs b/src/test/ui/imports/issue-28134.rs
index 1ed2d330b51..ef2a5d634a6 100644
--- a/src/test/ui/imports/issue-28134.rs
+++ b/src/test/ui/imports/issue-28134.rs
@@ -2,3 +2,4 @@
#![allow(soft_unstable)]
#![test] //~ ERROR cannot determine resolution for the attribute macro `test`
+//~^ ERROR 4:1: 4:9: `test` attribute cannot be used at crate level
diff --git a/src/test/ui/imports/issue-28134.stderr b/src/test/ui/imports/issue-28134.stderr
index 8ed4d015f32..33cb53f202a 100644
--- a/src/test/ui/imports/issue-28134.stderr
+++ b/src/test/ui/imports/issue-28134.stderr
@@ -6,5 +6,16 @@ LL | #![test]
|
= note: import resolution is stuck, try simplifying macro imports
-error: aborting due to previous error
+error: `test` attribute cannot be used at crate level
+ --> $DIR/issue-28134.rs:4:1
+ |
+LL | #![test]
+ | ^^^^^^^^
+ |
+help: perhaps you meant to use an outer attribute
+ |
+LL | #[test]
+ | ~~~~~~~
+
+error: aborting due to 2 previous errors
diff --git a/src/test/ui/in-band-lifetimes/elided-lifetimes.fixed b/src/test/ui/in-band-lifetimes/elided-lifetimes.fixed
index 2998f05efba..87a79b88137 100644
--- a/src/test/ui/in-band-lifetimes/elided-lifetimes.fixed
+++ b/src/test/ui/in-band-lifetimes/elided-lifetimes.fixed
@@ -5,23 +5,24 @@
#![deny(elided_lifetimes_in_paths)]
//~^ NOTE the lint level is defined here
-use std::cell::{RefCell, Ref};
+use std::cell::{Ref, RefCell};
-
-struct Foo<'a> { x: &'a u32 }
+struct Foo<'a> {
+ x: &'a u32,
+}
fn foo(x: &Foo<'_>) {
//~^ ERROR hidden lifetime parameters in types are deprecated
- //~| HELP indicate the anonymous lifetime
+ //~| NOTE expected named lifetime parameter
+ //~| HELP consider using the `'_` lifetime
}
fn bar(x: &Foo<'_>) {}
-
struct Wrapped<'a>(&'a str);
struct WrappedWithBow<'a> {
- gift: &'a str
+ gift: &'a str,
}
struct MatchedSet<'a, 'b> {
@@ -31,22 +32,34 @@ struct MatchedSet<'a, 'b> {
fn wrap_gift(gift: &str) -> Wrapped<'_> {
//~^ ERROR hidden lifetime parameters in types are deprecated
- //~| HELP indicate the anonymous lifetime
+ //~| NOTE expected named lifetime parameter
+ //~| HELP consider using the `'_` lifetime
Wrapped(gift)
}
fn wrap_gift_with_bow(gift: &str) -> WrappedWithBow<'_> {
//~^ ERROR hidden lifetime parameters in types are deprecated
- //~| HELP indicate the anonymous lifetime
+ //~| NOTE expected named lifetime parameter
+ //~| HELP consider using the `'_` lifetime
WrappedWithBow { gift }
}
fn inspect_matched_set(set: MatchedSet<'_, '_>) {
//~^ ERROR hidden lifetime parameters in types are deprecated
- //~| HELP indicate the anonymous lifetime
+ //~| NOTE expected 2 lifetime parameters
+ //~| HELP consider using the `'_` lifetime
println!("{} {}", set.one, set.another);
}
+// Verify that the lint does not fire, because the added `'_` wouldn't be resolved correctly.
+fn match_sets() -> MatchedSet<'static, 'static> {
+ //~^ ERROR missing lifetime specifiers
+ //~| NOTE expected 2 lifetime parameters
+ //~| HELP this function's return type contains a borrowed value
+ //~| HELP consider using the `'static` lifetime
+ MatchedSet { one: "one", another: "another" }
+}
+
macro_rules! autowrapper {
($type_name:ident, $fn_name:ident, $lt:lifetime) => {
struct $type_name<$lt> {
@@ -55,7 +68,11 @@ macro_rules! autowrapper {
fn $fn_name(gift: &str) -> $type_name<'_> {
//~^ ERROR hidden lifetime parameters in types are deprecated
- //~| HELP indicate the anonymous lifetime
+ //~| NOTE expected named lifetime parameter
+ //~| HELP consider using the `'_` lifetime
+ //~| ERROR hidden lifetime parameters in types are deprecated
+ //~| NOTE expected named lifetime parameter
+ //~| HELP consider using the `'_` lifetime
$type_name { gift }
}
}
@@ -65,19 +82,34 @@ autowrapper!(Autowrapped, autowrap_gift, 'a);
//~^ NOTE in this expansion of autowrapper!
//~| NOTE in this expansion of autowrapper!
+// Verify that rustfix does not try to apply the fix twice.
+autowrapper!(AutowrappedAgain, autowrap_gift_again, 'a);
+//~^ NOTE in this expansion of autowrapper!
+//~| NOTE in this expansion of autowrapper!
+
macro_rules! anytuple_ref_ty {
($($types:ty),*) => {
Ref<'_, ($($types),*)>
//~^ ERROR hidden lifetime parameters in types are deprecated
- //~| HELP indicate the anonymous lifetime
+ //~| NOTE expected named lifetime parameter
+ //~| HELP consider using the `'_` lifetime
}
}
+#[allow(elided_lifetimes_in_paths)]
+mod blah {
+ struct Thing<'a>(&'a i32);
+ struct Bar<T>(T);
+
+ fn foo(b: Bar<Thing>) {}
+}
+
fn main() {
let honesty = RefCell::new((4, 'e'));
let loyalty: Ref<'_, (u32, char)> = honesty.borrow();
//~^ ERROR hidden lifetime parameters in types are deprecated
- //~| HELP indicate the anonymous lifetime
+ //~| NOTE expected named lifetime parameter
+ //~| HELP consider using the `'_` lifetime
let generosity = Ref::map(loyalty, |t| &t.0);
let laughter = RefCell::new((true, "magic"));
diff --git a/src/test/ui/in-band-lifetimes/elided-lifetimes.rs b/src/test/ui/in-band-lifetimes/elided-lifetimes.rs
index b729a15a29e..28323a22427 100644
--- a/src/test/ui/in-band-lifetimes/elided-lifetimes.rs
+++ b/src/test/ui/in-band-lifetimes/elided-lifetimes.rs
@@ -5,23 +5,24 @@
#![deny(elided_lifetimes_in_paths)]
//~^ NOTE the lint level is defined here
-use std::cell::{RefCell, Ref};
+use std::cell::{Ref, RefCell};
-
-struct Foo<'a> { x: &'a u32 }
+struct Foo<'a> {
+ x: &'a u32,
+}
fn foo(x: &Foo) {
//~^ ERROR hidden lifetime parameters in types are deprecated
- //~| HELP indicate the anonymous lifetime
+ //~| NOTE expected named lifetime parameter
+ //~| HELP consider using the `'_` lifetime
}
fn bar(x: &Foo<'_>) {}
-
struct Wrapped<'a>(&'a str);
struct WrappedWithBow<'a> {
- gift: &'a str
+ gift: &'a str,
}
struct MatchedSet<'a, 'b> {
@@ -31,22 +32,34 @@ struct MatchedSet<'a, 'b> {
fn wrap_gift(gift: &str) -> Wrapped {
//~^ ERROR hidden lifetime parameters in types are deprecated
- //~| HELP indicate the anonymous lifetime
+ //~| NOTE expected named lifetime parameter
+ //~| HELP consider using the `'_` lifetime
Wrapped(gift)
}
fn wrap_gift_with_bow(gift: &str) -> WrappedWithBow {
//~^ ERROR hidden lifetime parameters in types are deprecated
- //~| HELP indicate the anonymous lifetime
+ //~| NOTE expected named lifetime parameter
+ //~| HELP consider using the `'_` lifetime
WrappedWithBow { gift }
}
fn inspect_matched_set(set: MatchedSet) {
//~^ ERROR hidden lifetime parameters in types are deprecated
- //~| HELP indicate the anonymous lifetime
+ //~| NOTE expected 2 lifetime parameters
+ //~| HELP consider using the `'_` lifetime
println!("{} {}", set.one, set.another);
}
+// Verify that the lint does not fire, because the added `'_` wouldn't be resolved correctly.
+fn match_sets() -> MatchedSet {
+ //~^ ERROR missing lifetime specifiers
+ //~| NOTE expected 2 lifetime parameters
+ //~| HELP this function's return type contains a borrowed value
+ //~| HELP consider using the `'static` lifetime
+ MatchedSet { one: "one", another: "another" }
+}
+
macro_rules! autowrapper {
($type_name:ident, $fn_name:ident, $lt:lifetime) => {
struct $type_name<$lt> {
@@ -55,7 +68,11 @@ macro_rules! autowrapper {
fn $fn_name(gift: &str) -> $type_name {
//~^ ERROR hidden lifetime parameters in types are deprecated
- //~| HELP indicate the anonymous lifetime
+ //~| NOTE expected named lifetime parameter
+ //~| HELP consider using the `'_` lifetime
+ //~| ERROR hidden lifetime parameters in types are deprecated
+ //~| NOTE expected named lifetime parameter
+ //~| HELP consider using the `'_` lifetime
$type_name { gift }
}
}
@@ -65,19 +82,34 @@ autowrapper!(Autowrapped, autowrap_gift, 'a);
//~^ NOTE in this expansion of autowrapper!
//~| NOTE in this expansion of autowrapper!
+// Verify that rustfix does not try to apply the fix twice.
+autowrapper!(AutowrappedAgain, autowrap_gift_again, 'a);
+//~^ NOTE in this expansion of autowrapper!
+//~| NOTE in this expansion of autowrapper!
+
macro_rules! anytuple_ref_ty {
($($types:ty),*) => {
Ref<($($types),*)>
//~^ ERROR hidden lifetime parameters in types are deprecated
- //~| HELP indicate the anonymous lifetime
+ //~| NOTE expected named lifetime parameter
+ //~| HELP consider using the `'_` lifetime
}
}
+#[allow(elided_lifetimes_in_paths)]
+mod blah {
+ struct Thing<'a>(&'a i32);
+ struct Bar<T>(T);
+
+ fn foo(b: Bar<Thing>) {}
+}
+
fn main() {
let honesty = RefCell::new((4, 'e'));
let loyalty: Ref<(u32, char)> = honesty.borrow();
//~^ ERROR hidden lifetime parameters in types are deprecated
- //~| HELP indicate the anonymous lifetime
+ //~| NOTE expected named lifetime parameter
+ //~| HELP consider using the `'_` lifetime
let generosity = Ref::map(loyalty, |t| &t.0);
let laughter = RefCell::new((true, "magic"));
diff --git a/src/test/ui/in-band-lifetimes/elided-lifetimes.stderr b/src/test/ui/in-band-lifetimes/elided-lifetimes.stderr
index 037ce401b3c..2e65461b321 100644
--- a/src/test/ui/in-band-lifetimes/elided-lifetimes.stderr
+++ b/src/test/ui/in-band-lifetimes/elided-lifetimes.stderr
@@ -1,60 +1,120 @@
error: hidden lifetime parameters in types are deprecated
- --> $DIR/elided-lifetimes.rs:13:12
+ --> $DIR/elided-lifetimes.rs:14:12
|
LL | fn foo(x: &Foo) {
- | ^^^- help: indicate the anonymous lifetime: `<'_>`
+ | ^^^ expected named lifetime parameter
|
note: the lint level is defined here
--> $DIR/elided-lifetimes.rs:5:9
|
LL | #![deny(elided_lifetimes_in_paths)]
| ^^^^^^^^^^^^^^^^^^^^^^^^^
+help: consider using the `'_` lifetime
+ |
+LL | fn foo(x: &Foo<'_>) {
+ | ~~~~~~~
error: hidden lifetime parameters in types are deprecated
- --> $DIR/elided-lifetimes.rs:32:29
+ --> $DIR/elided-lifetimes.rs:33:29
|
LL | fn wrap_gift(gift: &str) -> Wrapped {
- | ^^^^^^^- help: indicate the anonymous lifetime: `<'_>`
+ | ^^^^^^^ expected named lifetime parameter
+ |
+help: consider using the `'_` lifetime
+ |
+LL | fn wrap_gift(gift: &str) -> Wrapped<'_> {
+ | ~~~~~~~~~~~
error: hidden lifetime parameters in types are deprecated
- --> $DIR/elided-lifetimes.rs:38:38
+ --> $DIR/elided-lifetimes.rs:40:38
|
LL | fn wrap_gift_with_bow(gift: &str) -> WrappedWithBow {
- | ^^^^^^^^^^^^^^- help: indicate the anonymous lifetime: `<'_>`
+ | ^^^^^^^^^^^^^^ expected named lifetime parameter
+ |
+help: consider using the `'_` lifetime
+ |
+LL | fn wrap_gift_with_bow(gift: &str) -> WrappedWithBow<'_> {
+ | ~~~~~~~~~~~~~~~~~~
error: hidden lifetime parameters in types are deprecated
- --> $DIR/elided-lifetimes.rs:44:29
+ --> $DIR/elided-lifetimes.rs:47:29
|
LL | fn inspect_matched_set(set: MatchedSet) {
- | ^^^^^^^^^^- help: indicate the anonymous lifetimes: `<'_, '_>`
+ | ^^^^^^^^^^ expected 2 lifetime parameters
+ |
+help: consider using the `'_` lifetime
+ |
+LL | fn inspect_matched_set(set: MatchedSet<'_, '_>) {
+ | ~~~~~~~~~~~~~~~~~~
+
+error[E0106]: missing lifetime specifiers
+ --> $DIR/elided-lifetimes.rs:55:20
+ |
+LL | fn match_sets() -> MatchedSet {
+ | ^^^^^^^^^^ expected 2 lifetime parameters
+ |
+ = help: this function's return type contains a borrowed value, but there is no value for it to be borrowed from
+help: consider using the `'static` lifetime
+ |
+LL | fn match_sets() -> MatchedSet<'static, 'static> {
+ | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~
error: hidden lifetime parameters in types are deprecated
- --> $DIR/elided-lifetimes.rs:56:36
+ --> $DIR/elided-lifetimes.rs:69:36
|
LL | fn $fn_name(gift: &str) -> $type_name {
- | ^^^^^^^^^^- help: indicate the anonymous lifetime: `<'_>`
+ | ^^^^^^^^^^ expected named lifetime parameter
...
LL | autowrapper!(Autowrapped, autowrap_gift, 'a);
| -------------------------------------------- in this macro invocation
|
= note: this error originates in the macro `autowrapper` (in Nightly builds, run with -Z macro-backtrace for more info)
+help: consider using the `'_` lifetime
+ |
+LL | fn $fn_name(gift: &str) -> $type_name<'_> {
+ | ~~~~~~~~~~~~~~
error: hidden lifetime parameters in types are deprecated
- --> $DIR/elided-lifetimes.rs:78:18
+ --> $DIR/elided-lifetimes.rs:69:36
+ |
+LL | fn $fn_name(gift: &str) -> $type_name {
+ | ^^^^^^^^^^ expected named lifetime parameter
+...
+LL | autowrapper!(AutowrappedAgain, autowrap_gift_again, 'a);
+ | ------------------------------------------------------- in this macro invocation
+ |
+ = note: this error originates in the macro `autowrapper` (in Nightly builds, run with -Z macro-backtrace for more info)
+help: consider using the `'_` lifetime
+ |
+LL | fn $fn_name(gift: &str) -> $type_name<'_> {
+ | ~~~~~~~~~~~~~~
+
+error: hidden lifetime parameters in types are deprecated
+ --> $DIR/elided-lifetimes.rs:109:22
|
LL | let loyalty: Ref<(u32, char)> = honesty.borrow();
- | ^^^^^^^^^^^^^^^^ help: indicate the anonymous lifetime: `Ref<'_, (u32, char)>`
+ | ^ expected named lifetime parameter
+ |
+help: consider using the `'_` lifetime
+ |
+LL | let loyalty: Ref<'_, (u32, char)> = honesty.borrow();
+ | +++
error: hidden lifetime parameters in types are deprecated
- --> $DIR/elided-lifetimes.rs:70:9
+ --> $DIR/elided-lifetimes.rs:92:13
|
LL | Ref<($($types),*)>
- | ^^^^^^^^^^^^^^^^^^ help: indicate the anonymous lifetime: `Ref<'_, ($($types),*)>`
+ | ^ expected named lifetime parameter
...
LL | let yellow: anytuple_ref_ty!(bool, &str) = laughter.borrow();
| ---------------------------- in this macro invocation
|
= note: this error originates in the macro `anytuple_ref_ty` (in Nightly builds, run with -Z macro-backtrace for more info)
+help: consider using the `'_` lifetime
+ |
+LL | Ref<'_, ($($types),*)>
+ | +++
-error: aborting due to 7 previous errors
+error: aborting due to 9 previous errors
+For more information about this error, try `rustc --explain E0106`.
diff --git a/src/test/ui/inference/cannot-infer-partial-try-return.rs b/src/test/ui/inference/cannot-infer-partial-try-return.rs
index e1058e96cef..6e897a3edfd 100644
--- a/src/test/ui/inference/cannot-infer-partial-try-return.rs
+++ b/src/test/ui/inference/cannot-infer-partial-try-return.rs
@@ -16,7 +16,7 @@ fn infallible() -> Result<(), std::convert::Infallible> {
fn main() {
let x = || -> Result<_, QualifiedError<_>> {
- infallible()?; //~ERROR type annotations needed
+ infallible()?; //~ ERROR type annotations needed
Ok(())
};
}
diff --git a/src/test/ui/inference/erase-type-params-in-label.rs b/src/test/ui/inference/erase-type-params-in-label.rs
new file mode 100644
index 00000000000..1fea2da92da
--- /dev/null
+++ b/src/test/ui/inference/erase-type-params-in-label.rs
@@ -0,0 +1,27 @@
+fn main() {
+ let foo = foo(1, ""); //~ ERROR E0283
+}
+fn baz() {
+ let bar = bar(1, ""); //~ ERROR E0283
+}
+
+struct Bar<T, K, N: Default> {
+ t: T,
+ k: K,
+ n: N,
+}
+
+fn bar<T, K, Z: Default>(t: T, k: K) -> Bar<T, K, Z> {
+ Bar { t, k, n: Default::default() }
+}
+
+struct Foo<T, K, N: Default, M: Default> {
+ t: T,
+ k: K,
+ n: N,
+ m: M,
+}
+
+fn foo<T, K, W: Default, Z: Default>(t: T, k: K) -> Foo<T, K, W, Z> {
+ Foo { t, k, n: Default::default(), m: Default::default() }
+}
diff --git a/src/test/ui/inference/erase-type-params-in-label.stderr b/src/test/ui/inference/erase-type-params-in-label.stderr
new file mode 100644
index 00000000000..d0b06cde9d6
--- /dev/null
+++ b/src/test/ui/inference/erase-type-params-in-label.stderr
@@ -0,0 +1,41 @@
+error[E0283]: type annotations needed for `Foo<i32, &str, W, Z>`
+ --> $DIR/erase-type-params-in-label.rs:2:15
+ |
+LL | let foo = foo(1, "");
+ | --- ^^^ cannot infer type for type parameter `W` declared on the function `foo`
+ | |
+ | consider giving `foo` the explicit type `Foo<_, _, W, Z>`, where the type parameter `W` is specified
+ |
+ = note: cannot satisfy `_: Default`
+note: required by a bound in `foo`
+ --> $DIR/erase-type-params-in-label.rs:25:17
+ |
+LL | fn foo<T, K, W: Default, Z: Default>(t: T, k: K) -> Foo<T, K, W, Z> {
+ | ^^^^^^^ required by this bound in `foo`
+help: consider specifying the type arguments in the function call
+ |
+LL | let foo = foo::<T, K, W, Z>(1, "");
+ | ++++++++++++++
+
+error[E0283]: type annotations needed for `Bar<i32, &str, Z>`
+ --> $DIR/erase-type-params-in-label.rs:5:15
+ |
+LL | let bar = bar(1, "");
+ | --- ^^^ cannot infer type for type parameter `Z` declared on the function `bar`
+ | |
+ | consider giving `bar` the explicit type `Bar<_, _, Z>`, where the type parameter `Z` is specified
+ |
+ = note: cannot satisfy `_: Default`
+note: required by a bound in `bar`
+ --> $DIR/erase-type-params-in-label.rs:14:17
+ |
+LL | fn bar<T, K, Z: Default>(t: T, k: K) -> Bar<T, K, Z> {
+ | ^^^^^^^ required by this bound in `bar`
+help: consider specifying the type arguments in the function call
+ |
+LL | let bar = bar::<T, K, Z>(1, "");
+ | +++++++++++
+
+error: aborting due to 2 previous errors
+
+For more information about this error, try `rustc --explain E0283`.
diff --git a/src/test/ui/inference/issue-83606.stderr b/src/test/ui/inference/issue-83606.stderr
index 65f3336b935..9ca8f35fd54 100644
--- a/src/test/ui/inference/issue-83606.stderr
+++ b/src/test/ui/inference/issue-83606.stderr
@@ -4,7 +4,7 @@ error[E0282]: type annotations needed for `[usize; _]`
LL | let _ = foo("foo"); //<- Do not suggest `foo::<N>("foo");`!
| - ^^^ cannot infer the value of const parameter `N` declared on the function `foo`
| |
- | consider giving this pattern the explicit type `[usize; _]`, where the type parameter `N` is specified
+ | consider giving this pattern the explicit type `[_; N]`, where the const parameter `N` is specified
error: aborting due to previous error
diff --git a/src/test/ui/infinite/infinite-struct.stderr b/src/test/ui/infinite/infinite-struct.stderr
index 369645f9030..383e13fd4b0 100644
--- a/src/test/ui/infinite/infinite-struct.stderr
+++ b/src/test/ui/infinite/infinite-struct.stderr
@@ -19,7 +19,7 @@ LL | struct Take(Take);
| ^^^^^^^^^^^^^^^^^^
|
= note: ...which immediately requires computing drop-check constraints for `Take` again
- = note: cycle used when computing dropck types for `Canonical { max_universe: U0, variables: [], value: ParamEnvAnd { param_env: ParamEnv { caller_bounds: [], reveal: UserFacing }, value: Take } }`
+ = note: cycle used when computing dropck types for `Canonical { max_universe: U0, variables: [], value: ParamEnvAnd { param_env: ParamEnv { caller_bounds: [], reveal: UserFacing, constness: NotConst }, value: Take } }`
error: aborting due to 2 previous errors
diff --git a/src/test/ui/infinite/infinite-tag-type-recursion.stderr b/src/test/ui/infinite/infinite-tag-type-recursion.stderr
index 61b5e946775..1802c7599a3 100644
--- a/src/test/ui/infinite/infinite-tag-type-recursion.stderr
+++ b/src/test/ui/infinite/infinite-tag-type-recursion.stderr
@@ -18,7 +18,7 @@ LL | enum MList { Cons(isize, MList), Nil }
| ^^^^^^^^^^
|
= note: ...which immediately requires computing drop-check constraints for `MList` again
- = note: cycle used when computing dropck types for `Canonical { max_universe: U0, variables: [], value: ParamEnvAnd { param_env: ParamEnv { caller_bounds: [], reveal: UserFacing }, value: MList } }`
+ = note: cycle used when computing dropck types for `Canonical { max_universe: U0, variables: [], value: ParamEnvAnd { param_env: ParamEnv { caller_bounds: [], reveal: UserFacing, constness: NotConst }, value: MList } }`
error: aborting due to 2 previous errors
diff --git a/src/test/ui/inline-const/const-expr-array-init.rs b/src/test/ui/inline-const/const-expr-array-init.rs
index 8bb5dab1fa0..8a92cdbc0f9 100644
--- a/src/test/ui/inline-const/const-expr-array-init.rs
+++ b/src/test/ui/inline-const/const-expr-array-init.rs
@@ -1,6 +1,5 @@
// build-pass
-#![allow(incomplete_features)]
#![feature(inline_const)]
use std::cell::Cell;
diff --git a/src/test/ui/inline-const/const-expr-basic.rs b/src/test/ui/inline-const/const-expr-basic.rs
index 9254c96a1e7..dac46fe25ec 100644
--- a/src/test/ui/inline-const/const-expr-basic.rs
+++ b/src/test/ui/inline-const/const-expr-basic.rs
@@ -1,7 +1,7 @@
// run-pass
-#![allow(incomplete_features)]
#![feature(inline_const)]
+
fn foo() -> i32 {
const {
let x = 5 + 10;
diff --git a/src/test/ui/inline-const/const-expr-inference.rs b/src/test/ui/inline-const/const-expr-inference.rs
index 6aa2a2f3367..0d5892a74d9 100644
--- a/src/test/ui/inline-const/const-expr-inference.rs
+++ b/src/test/ui/inline-const/const-expr-inference.rs
@@ -1,7 +1,6 @@
// check-pass
#![feature(inline_const)]
-#![allow(incomplete_features)]
pub fn todo<T>() -> T {
const { todo!() }
diff --git a/src/test/ui/inline-const/const-expr-lifetime-err.rs b/src/test/ui/inline-const/const-expr-lifetime-err.rs
index e56cbc94038..0a032a7338a 100644
--- a/src/test/ui/inline-const/const-expr-lifetime-err.rs
+++ b/src/test/ui/inline-const/const-expr-lifetime-err.rs
@@ -1,4 +1,3 @@
-#![allow(incomplete_features)]
#![feature(const_mut_refs)]
#![feature(inline_const)]
diff --git a/src/test/ui/inline-const/const-expr-lifetime-err.stderr b/src/test/ui/inline-const/const-expr-lifetime-err.stderr
index 30ecd338a85..a23f7c9a796 100644
--- a/src/test/ui/inline-const/const-expr-lifetime-err.stderr
+++ b/src/test/ui/inline-const/const-expr-lifetime-err.stderr
@@ -1,5 +1,5 @@
error[E0597]: `y` does not live long enough
- --> $DIR/const-expr-lifetime-err.rs:24:30
+ --> $DIR/const-expr-lifetime-err.rs:23:30
|
LL | fn foo<'a>() {
| -- lifetime `'a` defined here
diff --git a/src/test/ui/inline-const/const-expr-lifetime.rs b/src/test/ui/inline-const/const-expr-lifetime.rs
index f622f2cbddf..d883deb2845 100644
--- a/src/test/ui/inline-const/const-expr-lifetime.rs
+++ b/src/test/ui/inline-const/const-expr-lifetime.rs
@@ -1,6 +1,5 @@
// run-pass
-#![allow(incomplete_features)]
#![feature(const_mut_refs)]
#![feature(inline_const)]
diff --git a/src/test/ui/inline-const/const-expr-macro.rs b/src/test/ui/inline-const/const-expr-macro.rs
index 66b58571751..041f3e15a29 100644
--- a/src/test/ui/inline-const/const-expr-macro.rs
+++ b/src/test/ui/inline-const/const-expr-macro.rs
@@ -1,7 +1,7 @@
// run-pass
-#![allow(incomplete_features)]
#![feature(inline_const)]
+
macro_rules! do_const_block{
($val:block) => { const $val }
}
diff --git a/src/test/ui/inline-const/const-expr-reference.rs b/src/test/ui/inline-const/const-expr-reference.rs
index 747f14e4bd0..a54d879f69d 100644
--- a/src/test/ui/inline-const/const-expr-reference.rs
+++ b/src/test/ui/inline-const/const-expr-reference.rs
@@ -1,6 +1,5 @@
// run-pass
-#![allow(incomplete_features)]
#![feature(inline_const)]
const fn bar() -> i32 {
diff --git a/src/test/ui/inline-const/const-match-pat-generic.rs b/src/test/ui/inline-const/const-match-pat-generic.rs
index 61680d653d0..be7e1d8d449 100644
--- a/src/test/ui/inline-const/const-match-pat-generic.rs
+++ b/src/test/ui/inline-const/const-match-pat-generic.rs
@@ -1,16 +1,31 @@
#![allow(incomplete_features)]
-#![feature(inline_const)]
+#![feature(inline_const_pat)]
+#![feature(generic_const_exprs)]
// rust-lang/rust#82518: ICE with inline-const in match referencing const-generic parameter
fn foo<const V: usize>() {
- match 0 {
- const { V } => {},
- //~^ ERROR const parameters cannot be referenced in patterns [E0158]
- _ => {},
- }
+ match 0 {
+ const { V } => {},
+ //~^ ERROR const parameters cannot be referenced in patterns [E0158]
+ _ => {},
+ }
+}
+
+const fn f(x: usize) -> usize {
+ x + 1
+}
+
+fn bar<const V: usize>() where [(); f(V)]: {
+ match 0 {
+ const { f(V) } => {},
+ //~^ ERROR constant pattern depends on a generic parameter
+ //~| ERROR constant pattern depends on a generic parameter
+ _ => {},
+ }
}
fn main() {
foo::<1>();
+ bar::<1>();
}
diff --git a/src/test/ui/inline-const/const-match-pat-generic.stderr b/src/test/ui/inline-const/const-match-pat-generic.stderr
index a3ed41a3f6a..5fe5a7a6dad 100644
--- a/src/test/ui/inline-const/const-match-pat-generic.stderr
+++ b/src/test/ui/inline-const/const-match-pat-generic.stderr
@@ -1,9 +1,21 @@
error[E0158]: const parameters cannot be referenced in patterns
- --> $DIR/const-match-pat-generic.rs:8:11
+ --> $DIR/const-match-pat-generic.rs:9:9
|
-LL | const { V } => {},
- | ^^^^^
+LL | const { V } => {},
+ | ^^^^^^^^^^^
-error: aborting due to previous error
+error: constant pattern depends on a generic parameter
+ --> $DIR/const-match-pat-generic.rs:21:9
+ |
+LL | const { f(V) } => {},
+ | ^^^^^^^^^^^^^^
+
+error: constant pattern depends on a generic parameter
+ --> $DIR/const-match-pat-generic.rs:21:9
+ |
+LL | const { f(V) } => {},
+ | ^^^^^^^^^^^^^^
+
+error: aborting due to 3 previous errors
For more information about this error, try `rustc --explain E0158`.
diff --git a/src/test/ui/inline-const/const-match-pat-inference.rs b/src/test/ui/inline-const/const-match-pat-inference.rs
index 61188ed5d47..d83ae6e9834 100644
--- a/src/test/ui/inline-const/const-match-pat-inference.rs
+++ b/src/test/ui/inline-const/const-match-pat-inference.rs
@@ -1,6 +1,6 @@
// check-pass
-#![feature(inline_const)]
+#![feature(inline_const_pat)]
#![allow(incomplete_features)]
fn main() {
diff --git a/src/test/ui/inline-const/const-match-pat-lifetime-err.rs b/src/test/ui/inline-const/const-match-pat-lifetime-err.rs
index bc5aa248944..436b8037f30 100644
--- a/src/test/ui/inline-const/const-match-pat-lifetime-err.rs
+++ b/src/test/ui/inline-const/const-match-pat-lifetime-err.rs
@@ -2,7 +2,7 @@
#![allow(incomplete_features)]
#![feature(const_mut_refs)]
-#![feature(inline_const)]
+#![feature(inline_const_pat)]
use std::marker::PhantomData;
diff --git a/src/test/ui/inline-const/const-match-pat-lifetime.rs b/src/test/ui/inline-const/const-match-pat-lifetime.rs
index 3d986f0d9ee..6d943bbcc01 100644
--- a/src/test/ui/inline-const/const-match-pat-lifetime.rs
+++ b/src/test/ui/inline-const/const-match-pat-lifetime.rs
@@ -3,6 +3,7 @@
#![allow(incomplete_features)]
#![feature(const_mut_refs)]
#![feature(inline_const)]
+#![feature(inline_const_pat)]
use std::marker::PhantomData;
diff --git a/src/test/ui/inline-const/const-match-pat-range.rs b/src/test/ui/inline-const/const-match-pat-range.rs
index eefe43a1a22..7dc8c11355a 100644
--- a/src/test/ui/inline-const/const-match-pat-range.rs
+++ b/src/test/ui/inline-const/const-match-pat-range.rs
@@ -1,7 +1,7 @@
// build-pass
#![allow(incomplete_features)]
-#![feature(inline_const, half_open_range_patterns, exclusive_range_pattern)]
+#![feature(inline_const_pat, half_open_range_patterns, exclusive_range_pattern)]
fn main() {
const N: u32 = 10;
let x: u32 = 3;
diff --git a/src/test/ui/inline-const/const-match-pat.rs b/src/test/ui/inline-const/const-match-pat.rs
index c0dc90d971a..2f55e16b35c 100644
--- a/src/test/ui/inline-const/const-match-pat.rs
+++ b/src/test/ui/inline-const/const-match-pat.rs
@@ -1,7 +1,7 @@
// run-pass
#![allow(incomplete_features)]
-#![feature(inline_const)]
+#![feature(inline_const_pat)]
const MMIO_BIT1: u8 = 4;
const MMIO_BIT2: u8 = 5;
diff --git a/src/test/ui/integral-variable-unification-error.rs b/src/test/ui/integral-variable-unification-error.rs
index 5200b4a829d..8d1621321e8 100644
--- a/src/test/ui/integral-variable-unification-error.rs
+++ b/src/test/ui/integral-variable-unification-error.rs
@@ -1,6 +1,8 @@
fn main() {
- let mut x = 2;
+ let mut x //~ NOTE expected due to the type of this binding
+ =
+ 2; //~ NOTE expected due to this value
x = 5.0;
//~^ ERROR mismatched types
- //~| expected integer, found floating-point number
+ //~| NOTE expected integer, found floating-point number
}
diff --git a/src/test/ui/integral-variable-unification-error.stderr b/src/test/ui/integral-variable-unification-error.stderr
index b49bff1b0d8..f77c265a2ad 100644
--- a/src/test/ui/integral-variable-unification-error.stderr
+++ b/src/test/ui/integral-variable-unification-error.stderr
@@ -1,6 +1,11 @@
error[E0308]: mismatched types
- --> $DIR/integral-variable-unification-error.rs:3:9
+ --> $DIR/integral-variable-unification-error.rs:5:9
|
+LL | let mut x
+ | ----- expected due to the type of this binding
+LL | =
+LL | 2;
+ | - expected due to this value
LL | x = 5.0;
| ^^^ expected integer, found floating-point number
diff --git a/src/test/ui/intrinsics/panic-uninitialized-zeroed.rs b/src/test/ui/intrinsics/panic-uninitialized-zeroed.rs
index 324bba15e43..a1cfee944c8 100644
--- a/src/test/ui/intrinsics/panic-uninitialized-zeroed.rs
+++ b/src/test/ui/intrinsics/panic-uninitialized-zeroed.rs
@@ -1,4 +1,5 @@
// run-pass
+// needs-unwind
// ignore-wasm32-bare compiled with panic=abort by default
// revisions: mir thir
// [thir]compile-flags: -Zthir-unsafeck
diff --git a/src/test/ui/issues-71798.stderr b/src/test/ui/issues-71798.stderr
index bbcdd3e37a9..bc4dc9ebf9e 100644
--- a/src/test/ui/issues-71798.stderr
+++ b/src/test/ui/issues-71798.stderr
@@ -11,6 +11,7 @@ LL | fn test_ref(x: &u32) -> impl std::future::Future<Output = u32> + '_ {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `u32` is not a future
|
= help: the trait `Future` is not implemented for `u32`
+ = note: u32 must be a future or must implement `IntoFuture` to be awaited
error: aborting due to 2 previous errors
diff --git a/src/test/ui/issues/issue-11844.stderr b/src/test/ui/issues/issue-11844.stderr
index 9d7470e7af9..ecab1074a29 100644
--- a/src/test/ui/issues/issue-11844.stderr
+++ b/src/test/ui/issues/issue-11844.stderr
@@ -1,8 +1,6 @@
error[E0308]: mismatched types
--> $DIR/issue-11844.rs:6:9
|
-LL | match a {
- | - this expression has type `Option<Box<{integer}>>`
LL | Ok(a) =>
| ^^^^^ expected enum `Option`, found enum `Result`
|
diff --git a/src/test/ui/issues/issue-12552.stderr b/src/test/ui/issues/issue-12552.stderr
index 3d8852ca748..1ba6852b17c 100644
--- a/src/test/ui/issues/issue-12552.stderr
+++ b/src/test/ui/issues/issue-12552.stderr
@@ -1,8 +1,6 @@
error[E0308]: mismatched types
--> $DIR/issue-12552.rs:6:5
|
-LL | match t {
- | - this expression has type `Result<_, {integer}>`
LL | Some(k) => match k {
| ^^^^^^^ expected enum `Result`, found enum `Option`
|
@@ -12,9 +10,6 @@ LL | Some(k) => match k {
error[E0308]: mismatched types
--> $DIR/issue-12552.rs:9:5
|
-LL | match t {
- | - this expression has type `Result<_, {integer}>`
-...
LL | None => ()
| ^^^^ expected enum `Result`, found enum `Option`
|
diff --git a/src/test/ui/issues/issue-13033.stderr b/src/test/ui/issues/issue-13033.stderr
index 6c3651ff121..72e549813e8 100644
--- a/src/test/ui/issues/issue-13033.stderr
+++ b/src/test/ui/issues/issue-13033.stderr
@@ -1,15 +1,17 @@
error[E0053]: method `bar` has an incompatible type for trait
--> $DIR/issue-13033.rs:8:30
|
-LL | fn bar(&mut self, other: &mut dyn Foo);
- | ------------ type in trait
-...
LL | fn bar(&mut self, other: &dyn Foo) {}
| ^^^^^^^^
| |
| types differ in mutability
| help: change the parameter type to match the trait: `&mut dyn Foo`
|
+note: type in trait
+ --> $DIR/issue-13033.rs:2:30
+ |
+LL | fn bar(&mut self, other: &mut dyn Foo);
+ | ^^^^^^^^^^^^
= note: expected fn pointer `fn(&mut Baz, &mut dyn Foo)`
found fn pointer `fn(&mut Baz, &dyn Foo)`
diff --git a/src/test/ui/issues/issue-13407.rs b/src/test/ui/issues/issue-13407.rs
index fa53d55f5b3..7ea81ffb59e 100644
--- a/src/test/ui/issues/issue-13407.rs
+++ b/src/test/ui/issues/issue-13407.rs
@@ -5,6 +5,5 @@ mod A {
fn main() {
A::C = 1;
//~^ ERROR: invalid left-hand side of assignment
- //~| ERROR: mismatched types
//~| ERROR: struct `C` is private
}
diff --git a/src/test/ui/issues/issue-13407.stderr b/src/test/ui/issues/issue-13407.stderr
index 4df1813a710..54b6c640d9d 100644
--- a/src/test/ui/issues/issue-13407.stderr
+++ b/src/test/ui/issues/issue-13407.stderr
@@ -18,13 +18,7 @@ LL | A::C = 1;
| |
| cannot assign to this expression
-error[E0308]: mismatched types
- --> $DIR/issue-13407.rs:6:12
- |
-LL | A::C = 1;
- | ^ expected struct `C`, found integer
-
-error: aborting due to 3 previous errors
+error: aborting due to 2 previous errors
-Some errors have detailed explanations: E0070, E0308, E0603.
+Some errors have detailed explanations: E0070, E0603.
For more information about an error, try `rustc --explain E0070`.
diff --git a/src/test/ui/issues/issue-13466.stderr b/src/test/ui/issues/issue-13466.stderr
index c78466f4e8c..15ee49a5fdd 100644
--- a/src/test/ui/issues/issue-13466.stderr
+++ b/src/test/ui/issues/issue-13466.stderr
@@ -1,8 +1,6 @@
error[E0308]: mismatched types
--> $DIR/issue-13466.rs:8:9
|
-LL | let _x: usize = match Some(1) {
- | ------- this expression has type `Option<{integer}>`
LL | Ok(u) => u,
| ^^^^^ expected enum `Option`, found enum `Result`
|
@@ -12,9 +10,6 @@ LL | Ok(u) => u,
error[E0308]: mismatched types
--> $DIR/issue-13466.rs:14:9
|
-LL | let _x: usize = match Some(1) {
- | ------- this expression has type `Option<{integer}>`
-...
LL | Err(e) => panic!(e)
| ^^^^^^ expected enum `Option`, found enum `Result`
|
diff --git a/src/test/ui/issues/issue-14875.rs b/src/test/ui/issues/issue-14875.rs
index 0d95d168b3d..aaef2aab9fc 100644
--- a/src/test/ui/issues/issue-14875.rs
+++ b/src/test/ui/issues/issue-14875.rs
@@ -1,4 +1,5 @@
// run-pass
+// needs-unwind
// ignore-wasm32-bare compiled with panic=abort by default
// Check that values are not leaked when a dtor panics (#14875)
diff --git a/src/test/ui/issues/issue-16538.mir.stderr b/src/test/ui/issues/issue-16538.mir.stderr
index d7e8c08bb01..5a276f27886 100644
--- a/src/test/ui/issues/issue-16538.mir.stderr
+++ b/src/test/ui/issues/issue-16538.mir.stderr
@@ -1,27 +1,26 @@
error[E0015]: calls in statics are limited to constant functions, tuple structs and tuple variants
- --> $DIR/issue-16538.rs:14:27
+ --> $DIR/issue-16538.rs:15:23
|
-LL | static foo: *const Y::X = Y::foo(Y::x as *const Y::X);
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^
+LL | static foo: &Y::X = &*Y::foo(Y::x as *const Y::X);
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^
-error[E0277]: `*const usize` cannot be shared between threads safely
- --> $DIR/issue-16538.rs:14:1
+error[E0133]: use of extern static is unsafe and requires unsafe function or block
+ --> $DIR/issue-16538.rs:15:30
|
-LL | static foo: *const Y::X = Y::foo(Y::x as *const Y::X);
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `*const usize` cannot be shared between threads safely
+LL | static foo: &Y::X = &*Y::foo(Y::x as *const Y::X);
+ | ^^^^ use of extern static
|
- = help: the trait `Sync` is not implemented for `*const usize`
- = note: shared static variables must have a type that implements `Sync`
+ = note: extern statics are not controlled by the Rust type system: invalid data, aliasing violations or data races will cause undefined behavior
-error[E0133]: use of extern static is unsafe and requires unsafe function or block
- --> $DIR/issue-16538.rs:14:34
+error[E0133]: dereference of raw pointer is unsafe and requires unsafe function or block
+ --> $DIR/issue-16538.rs:15:21
|
-LL | static foo: *const Y::X = Y::foo(Y::x as *const Y::X);
- | ^^^^ use of extern static
+LL | static foo: &Y::X = &*Y::foo(Y::x as *const Y::X);
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ dereference of raw pointer
|
- = note: extern statics are not controlled by the Rust type system: invalid data, aliasing violations or data races will cause undefined behavior
+ = note: raw pointers may be null, dangling or unaligned; they can violate aliasing rules and cause data races: all of these are undefined behavior
error: aborting due to 3 previous errors
-Some errors have detailed explanations: E0015, E0133, E0277.
+Some errors have detailed explanations: E0015, E0133.
For more information about an error, try `rustc --explain E0015`.
diff --git a/src/test/ui/issues/issue-16538.rs b/src/test/ui/issues/issue-16538.rs
index 1e8ecf015c8..b6891deb937 100644
--- a/src/test/ui/issues/issue-16538.rs
+++ b/src/test/ui/issues/issue-16538.rs
@@ -1,6 +1,7 @@
// revisions: mir thir
// [thir]compile-flags: -Z thir-unsafeck
+#![feature(const_raw_ptr_deref)]
mod Y {
pub type X = usize;
extern "C" {
@@ -11,8 +12,8 @@ mod Y {
}
}
-static foo: *const Y::X = Y::foo(Y::x as *const Y::X);
-//~^ ERROR `*const usize` cannot be shared between threads safely [E0277]
+static foo: &Y::X = &*Y::foo(Y::x as *const Y::X);
+//~^ ERROR dereference of raw pointer
//~| ERROR E0015
//~| ERROR use of extern static is unsafe and requires
diff --git a/src/test/ui/issues/issue-16538.thir.stderr b/src/test/ui/issues/issue-16538.thir.stderr
index 435334c3228..8365a1dbf6e 100644
--- a/src/test/ui/issues/issue-16538.thir.stderr
+++ b/src/test/ui/issues/issue-16538.thir.stderr
@@ -1,27 +1,26 @@
+error[E0133]: dereference of raw pointer is unsafe and requires unsafe function or block
+ --> $DIR/issue-16538.rs:15:22
+ |
+LL | static foo: &Y::X = &*Y::foo(Y::x as *const Y::X);
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ dereference of raw pointer
+ |
+ = note: raw pointers may be null, dangling or unaligned; they can violate aliasing rules and cause data races: all of these are undefined behavior
+
error[E0133]: use of extern static is unsafe and requires unsafe function or block
- --> $DIR/issue-16538.rs:14:34
+ --> $DIR/issue-16538.rs:15:30
|
-LL | static foo: *const Y::X = Y::foo(Y::x as *const Y::X);
- | ^^^^ use of extern static
+LL | static foo: &Y::X = &*Y::foo(Y::x as *const Y::X);
+ | ^^^^ use of extern static
|
= note: extern statics are not controlled by the Rust type system: invalid data, aliasing violations or data races will cause undefined behavior
error[E0015]: calls in statics are limited to constant functions, tuple structs and tuple variants
- --> $DIR/issue-16538.rs:14:27
- |
-LL | static foo: *const Y::X = Y::foo(Y::x as *const Y::X);
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^
-
-error[E0277]: `*const usize` cannot be shared between threads safely
- --> $DIR/issue-16538.rs:14:1
- |
-LL | static foo: *const Y::X = Y::foo(Y::x as *const Y::X);
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `*const usize` cannot be shared between threads safely
+ --> $DIR/issue-16538.rs:15:23
|
- = help: the trait `Sync` is not implemented for `*const usize`
- = note: shared static variables must have a type that implements `Sync`
+LL | static foo: &Y::X = &*Y::foo(Y::x as *const Y::X);
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^
error: aborting due to 3 previous errors
-Some errors have detailed explanations: E0015, E0133, E0277.
+Some errors have detailed explanations: E0015, E0133.
For more information about an error, try `rustc --explain E0015`.
diff --git a/src/test/ui/issues/issue-16922.stderr b/src/test/ui/issues/issue-16922.stderr
index 8b09b7d5907..53405a660f8 100644
--- a/src/test/ui/issues/issue-16922.stderr
+++ b/src/test/ui/issues/issue-16922.stderr
@@ -4,7 +4,7 @@ error[E0759]: `value` has an anonymous lifetime `'_` but it needs to satisfy a `
LL | fn foo<T: Any>(value: &T) -> Box<dyn Any> {
| -- this data with an anonymous lifetime `'_`...
LL | Box::new(value) as Box<dyn Any>
- | ^^^^^ ...is captured here, requiring it to live as long as `'static`
+ | ^^^^^ ...is used and required to live as long as `'static` here
|
help: to declare that the trait object captures data from argument `value`, you can add an explicit `'_` lifetime bound
|
diff --git a/src/test/ui/issues/issue-17718-static-sync.stderr b/src/test/ui/issues/issue-17718-static-sync.stderr
index 4cd85124c35..bc6e45e5925 100644
--- a/src/test/ui/issues/issue-17718-static-sync.stderr
+++ b/src/test/ui/issues/issue-17718-static-sync.stderr
@@ -1,8 +1,8 @@
error[E0277]: `Foo` cannot be shared between threads safely
- --> $DIR/issue-17718-static-sync.rs:9:1
+ --> $DIR/issue-17718-static-sync.rs:9:13
|
LL | static BAR: Foo = Foo;
- | ^^^^^^^^^^^^^^^^^^^^^^ `Foo` cannot be shared between threads safely
+ | ^^^ `Foo` cannot be shared between threads safely
|
= help: the trait `Sync` is not implemented for `Foo`
= note: shared static variables must have a type that implements `Sync`
diff --git a/src/test/ui/issues/issue-24446.rs b/src/test/ui/issues/issue-24446.rs
index ffd6dfabc28..9ab952ade9c 100644
--- a/src/test/ui/issues/issue-24446.rs
+++ b/src/test/ui/issues/issue-24446.rs
@@ -1,6 +1,7 @@
fn main() {
static foo: dyn Fn() -> u32 = || -> u32 {
//~^ ERROR the size for values of type
+ //~| ERROR cannot be shared between threads safely
0
};
}
diff --git a/src/test/ui/issues/issue-24446.stderr b/src/test/ui/issues/issue-24446.stderr
index 1674fa8af28..4afb87c4825 100644
--- a/src/test/ui/issues/issue-24446.stderr
+++ b/src/test/ui/issues/issue-24446.stderr
@@ -6,6 +6,15 @@ LL | static foo: dyn Fn() -> u32 = || -> u32 {
|
= help: the trait `Sized` is not implemented for `(dyn Fn() -> u32 + 'static)`
-error: aborting due to previous error
+error[E0277]: `(dyn Fn() -> u32 + 'static)` cannot be shared between threads safely
+ --> $DIR/issue-24446.rs:2:17
+ |
+LL | static foo: dyn Fn() -> u32 = || -> u32 {
+ | ^^^^^^^^^^^^^^^ `(dyn Fn() -> u32 + 'static)` cannot be shared between threads safely
+ |
+ = help: the trait `Sync` is not implemented for `(dyn Fn() -> u32 + 'static)`
+ = note: shared static variables must have a type that implements `Sync`
+
+error: aborting due to 2 previous errors
For more information about this error, try `rustc --explain E0277`.
diff --git a/src/test/ui/issues/issue-25089.rs b/src/test/ui/issues/issue-25089.rs
index cf261d43c55..0f0f78623a2 100644
--- a/src/test/ui/issues/issue-25089.rs
+++ b/src/test/ui/issues/issue-25089.rs
@@ -1,4 +1,5 @@
// run-pass
+// needs-unwind
// ignore-emscripten no threads support
use std::thread;
diff --git a/src/test/ui/issues/issue-26655.rs b/src/test/ui/issues/issue-26655.rs
index 4c01183a440..cb386c908a4 100644
--- a/src/test/ui/issues/issue-26655.rs
+++ b/src/test/ui/issues/issue-26655.rs
@@ -1,4 +1,5 @@
// run-pass
+// needs-unwind
// ignore-emscripten no threads support
// Check that the destructors of simple enums are run on unwinding
diff --git a/src/test/ui/issues/issue-28344.rs b/src/test/ui/issues/issue-28344.rs
index 4da7ee21baa..1a6a7f46b27 100644
--- a/src/test/ui/issues/issue-28344.rs
+++ b/src/test/ui/issues/issue-28344.rs
@@ -4,8 +4,12 @@ fn main() {
let x: u8 = BitXor::bitor(0 as u8, 0 as u8);
//~^ ERROR must be specified
//~| no function or associated item named
+ //~| WARN trait objects without an explicit `dyn` are deprecated
+ //~| WARN this is accepted in the current edition
let g = BitXor::bitor;
//~^ ERROR must be specified
//~| no function or associated item named
+ //~| WARN trait objects without an explicit `dyn` are deprecated
+ //~| WARN this is accepted in the current edition
}
diff --git a/src/test/ui/issues/issue-28344.stderr b/src/test/ui/issues/issue-28344.stderr
index 4955dea564d..b1d1c01b27a 100644
--- a/src/test/ui/issues/issue-28344.stderr
+++ b/src/test/ui/issues/issue-28344.stderr
@@ -1,3 +1,17 @@
+warning: trait objects without an explicit `dyn` are deprecated
+ --> $DIR/issue-28344.rs:4:17
+ |
+LL | let x: u8 = BitXor::bitor(0 as u8, 0 as u8);
+ | ^^^^^^
+ |
+ = note: `#[warn(bare_trait_objects)]` on by default
+ = warning: this is accepted in the current edition (Rust 2015) but is a hard error in Rust 2021!
+ = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2021/warnings-promoted-to-error.html>
+help: use `dyn`
+ |
+LL | let x: u8 = <dyn BitXor>::bitor(0 as u8, 0 as u8);
+ | ++++ +
+
error[E0191]: the value of the associated type `Output` (from trait `BitXor`) must be specified
--> $DIR/issue-28344.rs:4:17
|
@@ -13,14 +27,27 @@ LL | let x: u8 = BitXor::bitor(0 as u8, 0 as u8);
| function or associated item not found in `dyn BitXor<_>`
| help: there is an associated function with a similar name: `bitxor`
+warning: trait objects without an explicit `dyn` are deprecated
+ --> $DIR/issue-28344.rs:10:13
+ |
+LL | let g = BitXor::bitor;
+ | ^^^^^^
+ |
+ = warning: this is accepted in the current edition (Rust 2015) but is a hard error in Rust 2021!
+ = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2021/warnings-promoted-to-error.html>
+help: use `dyn`
+ |
+LL | let g = <dyn BitXor>::bitor;
+ | ++++ +
+
error[E0191]: the value of the associated type `Output` (from trait `BitXor`) must be specified
- --> $DIR/issue-28344.rs:8:13
+ --> $DIR/issue-28344.rs:10:13
|
LL | let g = BitXor::bitor;
| ^^^^^^ help: specify the associated type: `BitXor<Output = Type>`
error[E0599]: no function or associated item named `bitor` found for trait object `dyn BitXor<_>` in the current scope
- --> $DIR/issue-28344.rs:8:21
+ --> $DIR/issue-28344.rs:10:21
|
LL | let g = BitXor::bitor;
| ^^^^^
@@ -28,7 +55,7 @@ LL | let g = BitXor::bitor;
| function or associated item not found in `dyn BitXor<_>`
| help: there is an associated function with a similar name: `bitxor`
-error: aborting due to 4 previous errors
+error: aborting due to 4 previous errors; 2 warnings emitted
Some errors have detailed explanations: E0191, E0599.
For more information about an error, try `rustc --explain E0191`.
diff --git a/src/test/ui/issues/issue-29485.rs b/src/test/ui/issues/issue-29485.rs
index 6b2fb7126e3..8d58ee6d92c 100644
--- a/src/test/ui/issues/issue-29485.rs
+++ b/src/test/ui/issues/issue-29485.rs
@@ -1,6 +1,7 @@
// run-pass
#![allow(unused_attributes)]
// aux-build:issue-29485.rs
+// needs-unwind
// ignore-emscripten no threads
#[feature(recover)]
diff --git a/src/test/ui/issues/issue-2951.stderr b/src/test/ui/issues/issue-2951.stderr
index b966b339389..538bbe2f502 100644
--- a/src/test/ui/issues/issue-2951.stderr
+++ b/src/test/ui/issues/issue-2951.stderr
@@ -6,6 +6,7 @@ LL | fn foo<T, U>(x: T, y: U) {
| |
| expected type parameter
LL | let mut xx = x;
+ | - expected due to this value
LL | xx = y;
| ^ expected type parameter `T`, found type parameter `U`
|
diff --git a/src/test/ui/issues/issue-29948.rs b/src/test/ui/issues/issue-29948.rs
index 8ede8143ea6..01c3ec64861 100644
--- a/src/test/ui/issues/issue-29948.rs
+++ b/src/test/ui/issues/issue-29948.rs
@@ -1,4 +1,5 @@
// run-pass
+// needs-unwind
// ignore-wasm32-bare compiled with panic=abort by default
use std::panic;
diff --git a/src/test/ui/issues/issue-30018-panic.rs b/src/test/ui/issues/issue-30018-panic.rs
index 50749b0c742..cba3055a221 100644
--- a/src/test/ui/issues/issue-30018-panic.rs
+++ b/src/test/ui/issues/issue-30018-panic.rs
@@ -4,6 +4,7 @@
// spawned thread to isolate the expected error result from the
// SIGTRAP injected by the drop-flag consistency checking.
+// needs-unwind
// ignore-emscripten no threads support
struct Foo;
diff --git a/src/test/ui/issues/issue-33941.stderr b/src/test/ui/issues/issue-33941.stderr
index eb98a3a29a6..c6650d60c21 100644
--- a/src/test/ui/issues/issue-33941.stderr
+++ b/src/test/ui/issues/issue-33941.stderr
@@ -16,10 +16,10 @@ error[E0271]: type mismatch resolving `<std::collections::hash_map::Iter<'_, _,
--> $DIR/issue-33941.rs:4:14
|
LL | for _ in HashMap::new().iter().cloned() {}
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected reference, found tuple
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected tuple, found reference
|
- = note: expected reference `&_`
- found tuple `(&_, &_)`
+ = note: expected tuple `(&_, &_)`
+ found reference `&_`
= note: required because of the requirements on the impl of `Iterator` for `Cloned<std::collections::hash_map::Iter<'_, _, _>>`
= note: required because of the requirements on the impl of `IntoIterator` for `Cloned<std::collections::hash_map::Iter<'_, _, _>>`
diff --git a/src/test/ui/issues/issue-35869.stderr b/src/test/ui/issues/issue-35869.stderr
index 71b2a9df095..0780109b843 100644
--- a/src/test/ui/issues/issue-35869.stderr
+++ b/src/test/ui/issues/issue-35869.stderr
@@ -1,60 +1,68 @@
error[E0053]: method `foo` has an incompatible type for trait
--> $DIR/issue-35869.rs:11:15
|
-LL | fn foo(_: fn(u8) -> ());
- | ------------ type in trait
-...
LL | fn foo(_: fn(u16) -> ()) {}
| ^^^^^^^^^^^^^
| |
| expected `u8`, found `u16`
| help: change the parameter type to match the trait: `fn(u8)`
|
+note: type in trait
+ --> $DIR/issue-35869.rs:2:15
+ |
+LL | fn foo(_: fn(u8) -> ());
+ | ^^^^^^^^^^^^
= note: expected fn pointer `fn(fn(u8))`
found fn pointer `fn(fn(u16))`
error[E0053]: method `bar` has an incompatible type for trait
--> $DIR/issue-35869.rs:13:15
|
-LL | fn bar(_: Option<u8>);
- | ---------- type in trait
-...
LL | fn bar(_: Option<u16>) {}
| ^^^^^^^^^^^
| |
| expected `u8`, found `u16`
| help: change the parameter type to match the trait: `Option<u8>`
|
+note: type in trait
+ --> $DIR/issue-35869.rs:3:15
+ |
+LL | fn bar(_: Option<u8>);
+ | ^^^^^^^^^^
= note: expected fn pointer `fn(Option<u8>)`
found fn pointer `fn(Option<u16>)`
error[E0053]: method `baz` has an incompatible type for trait
--> $DIR/issue-35869.rs:15:15
|
-LL | fn baz(_: (u8, u16));
- | --------- type in trait
-...
LL | fn baz(_: (u16, u16)) {}
| ^^^^^^^^^^
| |
| expected `u8`, found `u16`
| help: change the parameter type to match the trait: `(u8, u16)`
|
+note: type in trait
+ --> $DIR/issue-35869.rs:4:15
+ |
+LL | fn baz(_: (u8, u16));
+ | ^^^^^^^^^
= note: expected fn pointer `fn((u8, _))`
found fn pointer `fn((u16, _))`
error[E0053]: method `qux` has an incompatible type for trait
--> $DIR/issue-35869.rs:17:17
|
-LL | fn qux() -> u8;
- | -- type in trait
-...
LL | fn qux() -> u16 { 5u16 }
| ^^^
| |
| expected `u8`, found `u16`
| help: change the output type to match the trait: `u8`
|
+note: type in trait
+ --> $DIR/issue-35869.rs:5:17
+ |
+LL | fn qux() -> u8;
+ | ^^
= note: expected fn pointer `fn() -> u8`
found fn pointer `fn() -> u16`
diff --git a/src/test/ui/issues/issue-3680.stderr b/src/test/ui/issues/issue-3680.stderr
index e8fafa76b91..8dc0dfa2356 100644
--- a/src/test/ui/issues/issue-3680.stderr
+++ b/src/test/ui/issues/issue-3680.stderr
@@ -1,8 +1,6 @@
error[E0308]: mismatched types
--> $DIR/issue-3680.rs:3:9
|
-LL | match None {
- | ---- this expression has type `Option<_>`
LL | Err(_) => ()
| ^^^^^^ expected enum `Option`, found enum `Result`
|
diff --git a/src/test/ui/issues/issue-37131.stderr b/src/test/ui/issues/issue-37131.stderr
index b45574f0c49..9ecae3e7a2b 100644
--- a/src/test/ui/issues/issue-37131.stderr
+++ b/src/test/ui/issues/issue-37131.stderr
@@ -4,6 +4,8 @@ error[E0463]: can't find crate for `std`
= help: consider downloading the target with `rustup target add thumbv6m-none-eabi`
= help: consider building the standard library from source with `cargo build -Zbuild-std`
-error: aborting due to previous error
+error: requires `sized` lang_item
+
+error: aborting due to 2 previous errors
For more information about this error, try `rustc --explain E0463`.
diff --git a/src/test/ui/issues/issue-38821.stderr b/src/test/ui/issues/issue-38821.stderr
index e53a543f3a0..cdf1f0dfc53 100644
--- a/src/test/ui/issues/issue-38821.stderr
+++ b/src/test/ui/issues/issue-38821.stderr
@@ -10,6 +10,10 @@ note: required because of the requirements on the impl of `IntoNullable` for `<C
LL | impl<T: NotNull> IntoNullable for T {
| ^^^^^^^^^^^^ ^
= note: this error originates in the derive macro `Copy` (in Nightly builds, run with -Z macro-backtrace for more info)
+help: consider further restricting the associated type
+ |
+LL | Expr: Expression<SqlType=<Col::SqlType as IntoNullable>::Nullable>, <Col as Expression>::SqlType: NotNull,
+ | +++++++++++++++++++++++++++++++++++++++
error: aborting due to previous error
diff --git a/src/test/ui/issues/issue-39970.stderr b/src/test/ui/issues/issue-39970.stderr
index ffcac1f4705..1f64a90bc1c 100644
--- a/src/test/ui/issues/issue-39970.stderr
+++ b/src/test/ui/issues/issue-39970.stderr
@@ -2,8 +2,13 @@ error[E0271]: type mismatch resolving `for<'a> <() as Array<'a>>::Element == ()`
--> $DIR/issue-39970.rs:19:5
|
LL | <() as Visit>::visit();
- | ^^^^^^^^^^^^^^^^^^^^ expected `()`, found `&()`
+ | ^^^^^^^^^^^^^^^^^^^^ type mismatch resolving `for<'a> <() as Array<'a>>::Element == ()`
|
+note: expected this to be `()`
+ --> $DIR/issue-39970.rs:10:20
+ |
+LL | type Element = &'a ();
+ | ^^^^^^
note: required because of the requirements on the impl of `Visit` for `()`
--> $DIR/issue-39970.rs:13:6
|
diff --git a/src/test/ui/issues/issue-42796.stderr b/src/test/ui/issues/issue-42796.stderr
index 61cf3f25d0d..4a1debf37a0 100644
--- a/src/test/ui/issues/issue-42796.stderr
+++ b/src/test/ui/issues/issue-42796.stderr
@@ -8,6 +8,8 @@ LL | let mut s_copy = s;
...
LL | println!("{}", s);
| ^ value borrowed here after move
+ |
+ = note: this error originates in the macro `$crate::format_args_nl` (in Nightly builds, run with -Z macro-backtrace for more info)
error: aborting due to previous error
diff --git a/src/test/ui/issues/issue-43853.rs b/src/test/ui/issues/issue-43853.rs
index 47c3ab59aa2..3162c091c87 100644
--- a/src/test/ui/issues/issue-43853.rs
+++ b/src/test/ui/issues/issue-43853.rs
@@ -1,4 +1,5 @@
// run-pass
+// needs-unwind
// ignore-wasm32-bare compiled with panic=abort by default
use std::panic;
diff --git a/src/test/ui/issues/issue-46519.rs b/src/test/ui/issues/issue-46519.rs
index cca0995d4ca..9bd3c094851 100644
--- a/src/test/ui/issues/issue-46519.rs
+++ b/src/test/ui/issues/issue-46519.rs
@@ -1,6 +1,7 @@
// run-pass
// compile-flags:--test -O
+// needs-unwind
// ignore-wasm32-bare compiled with panic=abort by default
#[test]
diff --git a/src/test/ui/issues/issue-46983.stderr b/src/test/ui/issues/issue-46983.stderr
index 77fb130f519..ed9f1884c42 100644
--- a/src/test/ui/issues/issue-46983.stderr
+++ b/src/test/ui/issues/issue-46983.stderr
@@ -4,7 +4,7 @@ error[E0759]: `x` has an anonymous lifetime `'_` but it needs to satisfy a `'sta
LL | fn foo(x: &u32) -> &'static u32 {
| ---- this data with an anonymous lifetime `'_`...
LL | &*x
- | ^^^ ...is captured and required to live as long as `'static` here
+ | ^^^ ...is used and required to live as long as `'static` here
error: aborting due to previous error
diff --git a/src/test/ui/issues/issue-47646.stderr b/src/test/ui/issues/issue-47646.stderr
index eff1de3e017..32e8588b3c0 100644
--- a/src/test/ui/issues/issue-47646.stderr
+++ b/src/test/ui/issues/issue-47646.stderr
@@ -12,6 +12,8 @@ LL | println!("{:?}", heap);
...
LL | };
| - ... and the mutable borrow might be used here, when that temporary is dropped and runs the destructor for type `(Option<PeekMut<'_, i32>>, ())`
+ |
+ = note: this error originates in the macro `$crate::format_args_nl` (in Nightly builds, run with -Z macro-backtrace for more info)
error: aborting due to previous error
diff --git a/src/test/ui/issues/issue-47706-trait.stderr b/src/test/ui/issues/issue-47706-trait.stderr
index eb0c80f8f0d..d596b4a69f3 100644
--- a/src/test/ui/issues/issue-47706-trait.stderr
+++ b/src/test/ui/issues/issue-47706-trait.stderr
@@ -11,8 +11,8 @@ LL | None::<()>.map(Self::f);
note: required by a bound in `Option::<T>::map`
--> $SRC_DIR/core/src/option.rs:LL:COL
|
-LL | pub fn map<U, F: FnOnce(T) -> U>(self, f: F) -> Option<U> {
- | ^^^^^^^^^^^^^^ required by this bound in `Option::<T>::map`
+LL | F: ~const FnOnce(T) -> U,
+ | ^^^^^^^^^^^^^^^^^^^^^ required by this bound in `Option::<T>::map`
error: aborting due to previous error
diff --git a/src/test/ui/issues/issue-47706.stderr b/src/test/ui/issues/issue-47706.stderr
index 237b2b9e798..0b4f84a330a 100644
--- a/src/test/ui/issues/issue-47706.stderr
+++ b/src/test/ui/issues/issue-47706.stderr
@@ -12,8 +12,8 @@ LL | self.foo.map(Foo::new)
note: required by a bound in `Option::<T>::map`
--> $SRC_DIR/core/src/option.rs:LL:COL
|
-LL | pub fn map<U, F: FnOnce(T) -> U>(self, f: F) -> Option<U> {
- | ^^^^^^^^^^^^^^ required by this bound in `Option::<T>::map`
+LL | F: ~const FnOnce(T) -> U,
+ | ^^^^^^^^^^^^^^^^^^^^^ required by this bound in `Option::<T>::map`
error[E0593]: function is expected to take 0 arguments, but it takes 1 argument
--> $DIR/issue-47706.rs:27:9
diff --git a/src/test/ui/issues/issue-49851/compiler-builtins-error.rs b/src/test/ui/issues/issue-49851/compiler-builtins-error.rs
index ddb070ddf9f..4e56cca33d6 100644
--- a/src/test/ui/issues/issue-49851/compiler-builtins-error.rs
+++ b/src/test/ui/issues/issue-49851/compiler-builtins-error.rs
@@ -1,4 +1,5 @@
-//~ ERROR 1:1: 1:1: can't find crate for `core` [E0463]
+//~ ERROR can't find crate for `core`
+//~^ ERROR can't find crate for `compiler_builtins`
// compile-flags: --target thumbv7em-none-eabihf
// needs-llvm-components: arm
@@ -7,3 +8,6 @@
#![no_std]
extern crate cortex_m;
+//~^ ERROR can't find crate for `cortex_m`
+
+fn main() {}
diff --git a/src/test/ui/issues/issue-49851/compiler-builtins-error.stderr b/src/test/ui/issues/issue-49851/compiler-builtins-error.stderr
index d963c07ea91..fcfa2bf119c 100644
--- a/src/test/ui/issues/issue-49851/compiler-builtins-error.stderr
+++ b/src/test/ui/issues/issue-49851/compiler-builtins-error.stderr
@@ -4,6 +4,16 @@ error[E0463]: can't find crate for `core`
= help: consider downloading the target with `rustup target add thumbv7em-none-eabihf`
= help: consider building the standard library from source with `cargo build -Zbuild-std`
-error: aborting due to previous error
+error[E0463]: can't find crate for `compiler_builtins`
+
+error[E0463]: can't find crate for `cortex_m`
+ --> $DIR/compiler-builtins-error.rs:10:1
+ |
+LL | extern crate cortex_m;
+ | ^^^^^^^^^^^^^^^^^^^^^^ can't find crate
+
+error: requires `sized` lang_item
+
+error: aborting due to 4 previous errors
For more information about this error, try `rustc --explain E0463`.
diff --git a/src/test/ui/issues/issue-50480.rs b/src/test/ui/issues/issue-50480.rs
index deb63872f69..10597caf5b2 100644
--- a/src/test/ui/issues/issue-50480.rs
+++ b/src/test/ui/issues/issue-50480.rs
@@ -1,8 +1,17 @@
#[derive(Clone, Copy)]
//~^ ERROR the trait `Copy` may not be implemented for this type
-struct Foo(NotDefined, <i32 as Iterator>::Item, Vec<i32>, String);
+struct Foo(N, NotDefined, <i32 as Iterator>::Item, Vec<i32>, String);
//~^ ERROR cannot find type `NotDefined` in this scope
//~| ERROR cannot find type `NotDefined` in this scope
+//~| ERROR cannot find type `N` in this scope
+//~| ERROR cannot find type `N` in this scope
+//~| ERROR `i32` is not an iterator
+
+#[derive(Clone, Copy)]
+//~^ ERROR the trait `Copy` may not be implemented for this type
+struct Bar<T>(T, N, NotDefined, <i32 as Iterator>::Item, Vec<i32>, String);
+//~^ ERROR cannot find type `NotDefined` in this scope
+//~| ERROR cannot find type `N` in this scope
//~| ERROR `i32` is not an iterator
fn main() {}
diff --git a/src/test/ui/issues/issue-50480.stderr b/src/test/ui/issues/issue-50480.stderr
index 15f38c89267..0bb1f9ae035 100644
--- a/src/test/ui/issues/issue-50480.stderr
+++ b/src/test/ui/issues/issue-50480.stderr
@@ -1,20 +1,61 @@
-error[E0412]: cannot find type `NotDefined` in this scope
+error[E0412]: cannot find type `N` in this scope
--> $DIR/issue-50480.rs:3:12
|
-LL | struct Foo(NotDefined, <i32 as Iterator>::Item, Vec<i32>, String);
- | ^^^^^^^^^^ not found in this scope
+LL | struct Foo(N, NotDefined, <i32 as Iterator>::Item, Vec<i32>, String);
+ | -^ not found in this scope
+ | |
+ | help: you might be missing a type parameter: `<N>`
error[E0412]: cannot find type `NotDefined` in this scope
+ --> $DIR/issue-50480.rs:3:15
+ |
+LL | struct Foo(N, NotDefined, <i32 as Iterator>::Item, Vec<i32>, String);
+ | ^^^^^^^^^^ not found in this scope
+
+error[E0412]: cannot find type `N` in this scope
--> $DIR/issue-50480.rs:3:12
|
-LL | struct Foo(NotDefined, <i32 as Iterator>::Item, Vec<i32>, String);
- | ^^^^^^^^^^ not found in this scope
+LL | struct Foo(N, NotDefined, <i32 as Iterator>::Item, Vec<i32>, String);
+ | -^ not found in this scope
+ | |
+ | help: you might be missing a type parameter: `<N>`
+
+error[E0412]: cannot find type `NotDefined` in this scope
+ --> $DIR/issue-50480.rs:3:15
+ |
+LL | struct Foo(N, NotDefined, <i32 as Iterator>::Item, Vec<i32>, String);
+ | - ^^^^^^^^^^ not found in this scope
+ | |
+ | help: you might be missing a type parameter: `<NotDefined>`
+
+error[E0412]: cannot find type `N` in this scope
+ --> $DIR/issue-50480.rs:12:18
+ |
+LL | struct Bar<T>(T, N, NotDefined, <i32 as Iterator>::Item, Vec<i32>, String);
+ | - ^
+ | |
+ | similarly named type parameter `T` defined here
+ |
+help: a type parameter with a similar name exists
+ |
+LL | struct Bar<T>(T, T, NotDefined, <i32 as Iterator>::Item, Vec<i32>, String);
+ | ~
+help: you might be missing a type parameter
+ |
+LL | struct Bar<T, N>(T, N, NotDefined, <i32 as Iterator>::Item, Vec<i32>, String);
+ | +++
+
+error[E0412]: cannot find type `NotDefined` in this scope
+ --> $DIR/issue-50480.rs:12:21
+ |
+LL | struct Bar<T>(T, N, NotDefined, <i32 as Iterator>::Item, Vec<i32>, String);
+ | ^^^^^^^^^^ not found in this scope
error[E0277]: `i32` is not an iterator
- --> $DIR/issue-50480.rs:3:24
+ --> $DIR/issue-50480.rs:3:27
|
-LL | struct Foo(NotDefined, <i32 as Iterator>::Item, Vec<i32>, String);
- | ^^^^^^^^^^^^^^^^^^^^^^^ `i32` is not an iterator
+LL | struct Foo(N, NotDefined, <i32 as Iterator>::Item, Vec<i32>, String);
+ | ^^^^^^^^^^^^^^^^^^^^^^^ `i32` is not an iterator
|
= help: the trait `Iterator` is not implemented for `i32`
= note: if you want to iterate between `start` until a value `end`, use the exclusive range syntax `start..end` or the inclusive range syntax `start..=end`
@@ -25,14 +66,36 @@ error[E0204]: the trait `Copy` may not be implemented for this type
LL | #[derive(Clone, Copy)]
| ^^^^
LL |
-LL | struct Foo(NotDefined, <i32 as Iterator>::Item, Vec<i32>, String);
- | -------- ------ this field does not implement `Copy`
- | |
- | this field does not implement `Copy`
+LL | struct Foo(N, NotDefined, <i32 as Iterator>::Item, Vec<i32>, String);
+ | -------- ------ this field does not implement `Copy`
+ | |
+ | this field does not implement `Copy`
+ |
+ = note: this error originates in the derive macro `Copy` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error[E0277]: `i32` is not an iterator
+ --> $DIR/issue-50480.rs:12:33
+ |
+LL | struct Bar<T>(T, N, NotDefined, <i32 as Iterator>::Item, Vec<i32>, String);
+ | ^^^^^^^^^^^^^^^^^^^^^^^ `i32` is not an iterator
+ |
+ = help: the trait `Iterator` is not implemented for `i32`
+ = note: if you want to iterate between `start` until a value `end`, use the exclusive range syntax `start..end` or the inclusive range syntax `start..=end`
+
+error[E0204]: the trait `Copy` may not be implemented for this type
+ --> $DIR/issue-50480.rs:10:17
+ |
+LL | #[derive(Clone, Copy)]
+ | ^^^^
+LL |
+LL | struct Bar<T>(T, N, NotDefined, <i32 as Iterator>::Item, Vec<i32>, String);
+ | -------- ------ this field does not implement `Copy`
+ | |
+ | this field does not implement `Copy`
|
= note: this error originates in the derive macro `Copy` (in Nightly builds, run with -Z macro-backtrace for more info)
-error: aborting due to 4 previous errors
+error: aborting due to 10 previous errors
Some errors have detailed explanations: E0204, E0277, E0412.
For more information about an error, try `rustc --explain E0204`.
diff --git a/src/test/ui/issues/issue-5216.rs b/src/test/ui/issues/issue-5216.rs
index 35b343edfbd..4072a57cb10 100644
--- a/src/test/ui/issues/issue-5216.rs
+++ b/src/test/ui/issues/issue-5216.rs
@@ -1,10 +1,10 @@
fn f() { }
-struct S(Box<dyn FnMut()>);
+struct S(Box<dyn FnMut() + Sync>);
pub static C: S = S(f); //~ ERROR mismatched types
fn g() { }
-type T = Box<dyn FnMut()>;
+type T = Box<dyn FnMut() + Sync>;
pub static D: T = g; //~ ERROR mismatched types
fn main() {}
diff --git a/src/test/ui/issues/issue-5216.stderr b/src/test/ui/issues/issue-5216.stderr
index 7a1f42adf65..29c95e4fb62 100644
--- a/src/test/ui/issues/issue-5216.stderr
+++ b/src/test/ui/issues/issue-5216.stderr
@@ -4,7 +4,7 @@ error[E0308]: mismatched types
LL | pub static C: S = S(f);
| ^ expected struct `Box`, found fn item
|
- = note: expected struct `Box<(dyn FnMut() + 'static)>`
+ = note: expected struct `Box<(dyn FnMut() + Sync + 'static)>`
found fn item `fn() {f}`
error[E0308]: mismatched types
@@ -13,7 +13,7 @@ error[E0308]: mismatched types
LL | pub static D: T = g;
| ^ expected struct `Box`, found fn item
|
- = note: expected struct `Box<(dyn FnMut() + 'static)>`
+ = note: expected struct `Box<(dyn FnMut() + Sync + 'static)>`
found fn item `fn() {g}`
error: aborting due to 2 previous errors
diff --git a/src/test/ui/issues/issue-53348.rs b/src/test/ui/issues/issue-53348.rs
index 65f4656b022..d2f8c77c0ce 100644
--- a/src/test/ui/issues/issue-53348.rs
+++ b/src/test/ui/issues/issue-53348.rs
@@ -5,7 +5,7 @@ fn main() {
v.into_iter().map(|s|s.to_owned()).collect::<Vec<_>>();
- let mut a = String::new();
+ let mut a = String::new(); //~ NOTE expected due to this value
for i in v {
a = *i.to_string();
//~^ ERROR mismatched types
diff --git a/src/test/ui/issues/issue-53348.stderr b/src/test/ui/issues/issue-53348.stderr
index 8f500261243..71d9f5b3dbb 100644
--- a/src/test/ui/issues/issue-53348.stderr
+++ b/src/test/ui/issues/issue-53348.stderr
@@ -1,6 +1,9 @@
error[E0308]: mismatched types
--> $DIR/issue-53348.rs:10:13
|
+LL | let mut a = String::new();
+ | ------------- expected due to this value
+LL | for i in v {
LL | a = *i.to_string();
| ^^^^^^^^^^^^^^ expected struct `String`, found `str`
diff --git a/src/test/ui/issues/issue-58734.rs b/src/test/ui/issues/issue-58734.rs
index b253c135b8c..c838fde5d73 100644
--- a/src/test/ui/issues/issue-58734.rs
+++ b/src/test/ui/issues/issue-58734.rs
@@ -19,4 +19,6 @@ fn main() {
// no object safety error
Trait::nonexistent(());
//~^ ERROR no function or associated item named `nonexistent` found
+ //~| WARN trait objects without an explicit `dyn` are deprecated
+ //~| WARN this is accepted in the current edition
}
diff --git a/src/test/ui/issues/issue-58734.stderr b/src/test/ui/issues/issue-58734.stderr
index 5e98cfadf8a..a91a1b3778e 100644
--- a/src/test/ui/issues/issue-58734.stderr
+++ b/src/test/ui/issues/issue-58734.stderr
@@ -1,9 +1,23 @@
+warning: trait objects without an explicit `dyn` are deprecated
+ --> $DIR/issue-58734.rs:20:5
+ |
+LL | Trait::nonexistent(());
+ | ^^^^^
+ |
+ = note: `#[warn(bare_trait_objects)]` on by default
+ = warning: this is accepted in the current edition (Rust 2015) but is a hard error in Rust 2021!
+ = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2021/warnings-promoted-to-error.html>
+help: use `dyn`
+ |
+LL | <dyn Trait>::nonexistent(());
+ | ++++ +
+
error[E0599]: no function or associated item named `nonexistent` found for trait object `dyn Trait` in the current scope
--> $DIR/issue-58734.rs:20:12
|
LL | Trait::nonexistent(());
| ^^^^^^^^^^^ function or associated item not found in `dyn Trait`
-error: aborting due to previous error
+error: aborting due to previous error; 1 warning emitted
For more information about this error, try `rustc --explain E0599`.
diff --git a/src/test/ui/issues/issue-59488.stderr b/src/test/ui/issues/issue-59488.stderr
index f739557e001..47fd9fdb654 100644
--- a/src/test/ui/issues/issue-59488.stderr
+++ b/src/test/ui/issues/issue-59488.stderr
@@ -5,7 +5,11 @@ LL | foo > 12;
| --- ^ -- {integer}
| |
| fn() -> i32 {foo}
- | help: you might have forgotten to call this function: `foo()`
+ |
+help: you might have forgotten to call this function
+ |
+LL | foo() > 12;
+ | ++
error[E0308]: mismatched types
--> $DIR/issue-59488.rs:14:11
@@ -23,7 +27,11 @@ LL | bar > 13;
| --- ^ -- {integer}
| |
| fn(i64) -> i64 {bar}
- | help: you might have forgotten to call this function: `bar( /* arguments */ )`
+ |
+help: you might have forgotten to call this function
+ |
+LL | bar( /* arguments */ ) > 13;
+ | +++++++++++++++++++
error[E0308]: mismatched types
--> $DIR/issue-59488.rs:18:11
@@ -45,11 +53,11 @@ LL | foo > foo;
help: you might have forgotten to call this function
|
LL | foo() > foo;
- | ~~~~~
+ | ++
help: you might have forgotten to call this function
|
LL | foo > foo();
- | ~~~~~
+ | ++
error[E0369]: binary operation `>` cannot be applied to type `fn() -> i32 {foo}`
--> $DIR/issue-59488.rs:25:9
diff --git a/src/test/ui/issues/issue-59494.rs b/src/test/ui/issues/issue-59494.rs
index 06b8eb777c0..a53e28f7246 100644
--- a/src/test/ui/issues/issue-59494.rs
+++ b/src/test/ui/issues/issue-59494.rs
@@ -19,5 +19,5 @@ fn main() {
let g = |(a, _)| a;
let t7 = |env| |a| |b| t7p(f, g)(((env, a), b));
let t8 = t8n(t7, t7p(f, g));
- //~^ ERROR: expected a `Fn<(_,)>` closure, found `impl Fn<(((_, _), _),)>
+ //~^ ERROR: expected a `Fn<(_,)>` closure, found `impl Fn(((_, _), _))` [E0277]
}
diff --git a/src/test/ui/issues/issue-59494.stderr b/src/test/ui/issues/issue-59494.stderr
index 9b7fe1ef786..a9284535e4d 100644
--- a/src/test/ui/issues/issue-59494.stderr
+++ b/src/test/ui/issues/issue-59494.stderr
@@ -1,12 +1,12 @@
-error[E0277]: expected a `Fn<(_,)>` closure, found `impl Fn<(((_, _), _),)>`
+error[E0277]: expected a `Fn<(_,)>` closure, found `impl Fn(((_, _), _))`
--> $DIR/issue-59494.rs:21:22
|
LL | let t8 = t8n(t7, t7p(f, g));
- | --- ^^^^^^^^^ expected an `Fn<(_,)>` closure, found `impl Fn<(((_, _), _),)>`
+ | --- ^^^^^^^^^ expected an `Fn<(_,)>` closure, found `impl Fn(((_, _), _))`
| |
| required by a bound introduced by this call
|
- = help: the trait `Fn<(_,)>` is not implemented for `impl Fn<(((_, _), _),)>`
+ = help: the trait `Fn<(_,)>` is not implemented for `impl Fn(((_, _), _))`
note: required by a bound in `t8n`
--> $DIR/issue-59494.rs:5:45
|
diff --git a/src/test/ui/issues/issue-66706.stderr b/src/test/ui/issues/issue-66706.stderr
index f0b93ac9111..3e933a0f01b 100644
--- a/src/test/ui/issues/issue-66706.stderr
+++ b/src/test/ui/issues/issue-66706.stderr
@@ -36,7 +36,7 @@ error[E0308]: mismatched types
--> $DIR/issue-66706.rs:2:5
|
LL | fn a() {
- | - help: try adding a return type: `-> [{integer}; _]`
+ | - possibly return type missing here?
LL | [0; [|_: _ &_| ()].len()]
| ^^^^^^^^^^^^^^^^^^^^^^^^^ expected `()`, found array `[{integer}; _]`
@@ -44,7 +44,7 @@ error[E0308]: mismatched types
--> $DIR/issue-66706.rs:14:5
|
LL | fn c() {
- | - help: try adding a return type: `-> [{integer}; _]`
+ | - possibly return type missing here?
LL | [0; [|&_: _ &_| {}; 0 ].len()]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected `()`, found array `[{integer}; _]`
@@ -52,7 +52,7 @@ error[E0308]: mismatched types
--> $DIR/issue-66706.rs:20:5
|
LL | fn d() {
- | - help: try adding a return type: `-> [{integer}; _]`
+ | - possibly return type missing here?
LL | [0; match [|f @ &ref _| () ] {} ]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected `()`, found array `[{integer}; _]`
diff --git a/src/test/ui/issues/issue-70724-add_type_neq_err_label-unwrap.stderr b/src/test/ui/issues/issue-70724-add_type_neq_err_label-unwrap.stderr
index cd4cc969200..4c11f354494 100644
--- a/src/test/ui/issues/issue-70724-add_type_neq_err_label-unwrap.stderr
+++ b/src/test/ui/issues/issue-70724-add_type_neq_err_label-unwrap.stderr
@@ -6,9 +6,12 @@ LL | assert_eq!(a, 0);
| |
| fn() -> i32 {a}
| {integer}
- | help: you might have forgotten to call this function: `*left_val()`
|
= note: this error originates in the macro `assert_eq` (in Nightly builds, run with -Z macro-backtrace for more info)
+help: you might have forgotten to call this function
+ |
+LL | if !(*left_val() == *right_val) {
+ | ++
error[E0308]: mismatched types
--> $DIR/issue-70724-add_type_neq_err_label-unwrap.rs:6:5
diff --git a/src/test/ui/issues/issue-72574-1.stderr b/src/test/ui/issues/issue-72574-1.stderr
index 653869a237d..5d3d390a95d 100644
--- a/src/test/ui/issues/issue-72574-1.stderr
+++ b/src/test/ui/issues/issue-72574-1.stderr
@@ -21,8 +21,6 @@ LL | (_a, _x @ ..) => {}
error[E0308]: mismatched types
--> $DIR/issue-72574-1.rs:4:9
|
-LL | match x {
- | - this expression has type `({integer}, {integer}, {integer})`
LL | (_a, _x @ ..) => {}
| ^^^^^^^^^^^^^ expected a tuple with 3 elements, found one with 2 elements
|
diff --git a/src/test/ui/issues/issue-7364.rs b/src/test/ui/issues/issue-7364.rs
index 29a1644673d..83c52d286a1 100644
--- a/src/test/ui/issues/issue-7364.rs
+++ b/src/test/ui/issues/issue-7364.rs
@@ -4,7 +4,6 @@ use std::cell::RefCell;
// Regression test for issue 7364
static boxed: Box<RefCell<isize>> = box RefCell::new(0);
-//~^ ERROR allocations are not allowed in statics
-//~| ERROR `RefCell<isize>` cannot be shared between threads safely [E0277]
+//~^ ERROR `RefCell<isize>` cannot be shared between threads safely [E0277]
fn main() { }
diff --git a/src/test/ui/issues/issue-7364.stderr b/src/test/ui/issues/issue-7364.stderr
index 8ceb3be7ec9..f2e80f45169 100644
--- a/src/test/ui/issues/issue-7364.stderr
+++ b/src/test/ui/issues/issue-7364.stderr
@@ -1,21 +1,14 @@
-error[E0010]: allocations are not allowed in statics
- --> $DIR/issue-7364.rs:6:37
- |
-LL | static boxed: Box<RefCell<isize>> = box RefCell::new(0);
- | ^^^^^^^^^^^^^^^^^^^ allocation not allowed in statics
-
error[E0277]: `RefCell<isize>` cannot be shared between threads safely
- --> $DIR/issue-7364.rs:6:1
+ --> $DIR/issue-7364.rs:6:15
|
LL | static boxed: Box<RefCell<isize>> = box RefCell::new(0);
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `RefCell<isize>` cannot be shared between threads safely
+ | ^^^^^^^^^^^^^^^^^^^ `RefCell<isize>` cannot be shared between threads safely
|
= help: the trait `Sync` is not implemented for `RefCell<isize>`
= note: required because of the requirements on the impl of `Sync` for `Unique<RefCell<isize>>`
= note: required because it appears within the type `Box<RefCell<isize>>`
= note: shared static variables must have a type that implements `Sync`
-error: aborting due to 2 previous errors
+error: aborting due to previous error
-Some errors have detailed explanations: E0010, E0277.
-For more information about an error, try `rustc --explain E0010`.
+For more information about this error, try `rustc --explain E0277`.
diff --git a/src/test/ui/issues/issue-77218.rs b/src/test/ui/issues/issue-77218.rs
deleted file mode 100644
index a6a2401795f..00000000000
--- a/src/test/ui/issues/issue-77218.rs
+++ /dev/null
@@ -1,11 +0,0 @@
-fn main() {
- let value = [7u8];
- while Some(0) = value.get(0) { //~ ERROR destructuring assignments are unstable
- //~| ERROR invalid left-hand side of assignment
- //~| ERROR mismatched types
- //~| ERROR mismatched types
-
- // FIXME The following diagnostic should also be emitted
- // HELP you might have meant to use pattern matching
- }
-}
diff --git a/src/test/ui/issues/issue-77218.stderr b/src/test/ui/issues/issue-77218.stderr
deleted file mode 100644
index ce70c0111be..00000000000
--- a/src/test/ui/issues/issue-77218.stderr
+++ /dev/null
@@ -1,40 +0,0 @@
-error[E0658]: destructuring assignments are unstable
- --> $DIR/issue-77218.rs:3:19
- |
-LL | while Some(0) = value.get(0) {
- | ------- ^
- | |
- | cannot assign to this expression
- |
- = note: see issue #71126 <https://github.com/rust-lang/rust/issues/71126> for more information
- = help: add `#![feature(destructuring_assignment)]` to the crate attributes to enable
-
-error[E0070]: invalid left-hand side of assignment
- --> $DIR/issue-77218.rs:3:19
- |
-LL | while Some(0) = value.get(0) {
- | - ^
- | |
- | cannot assign to this expression
-
-error[E0308]: mismatched types
- --> $DIR/issue-77218.rs:3:16
- |
-LL | while Some(0) = value.get(0) {
- | ^ expected integer, found `&u8`
- |
-help: consider dereferencing the borrow
- |
-LL | while Some(*0) = value.get(0) {
- | +
-
-error[E0308]: mismatched types
- --> $DIR/issue-77218.rs:3:11
- |
-LL | while Some(0) = value.get(0) {
- | ^^^^^^^^^^^^^^^^^^^^^^ expected `bool`, found `()`
-
-error: aborting due to 4 previous errors
-
-Some errors have detailed explanations: E0070, E0308, E0658.
-For more information about an error, try `rustc --explain E0070`.
diff --git a/src/test/ui/issues/issue-77218/issue-77218-2.fixed b/src/test/ui/issues/issue-77218/issue-77218-2.fixed
new file mode 100644
index 00000000000..0e835d49c6d
--- /dev/null
+++ b/src/test/ui/issues/issue-77218/issue-77218-2.fixed
@@ -0,0 +1,6 @@
+// run-rustfix
+fn main() {
+ let value = [7u8];
+ while let Some(0) = value.get(0) { //~ ERROR invalid left-hand side of assignment
+ }
+}
diff --git a/src/test/ui/issues/issue-77218/issue-77218-2.rs b/src/test/ui/issues/issue-77218/issue-77218-2.rs
new file mode 100644
index 00000000000..01dca1ae16c
--- /dev/null
+++ b/src/test/ui/issues/issue-77218/issue-77218-2.rs
@@ -0,0 +1,6 @@
+// run-rustfix
+fn main() {
+ let value = [7u8];
+ while Some(0) = value.get(0) { //~ ERROR invalid left-hand side of assignment
+ }
+}
diff --git a/src/test/ui/issues/issue-77218/issue-77218-2.stderr b/src/test/ui/issues/issue-77218/issue-77218-2.stderr
new file mode 100644
index 00000000000..58c1c18f9a9
--- /dev/null
+++ b/src/test/ui/issues/issue-77218/issue-77218-2.stderr
@@ -0,0 +1,16 @@
+error[E0070]: invalid left-hand side of assignment
+ --> $DIR/issue-77218-2.rs:4:19
+ |
+LL | while Some(0) = value.get(0) {
+ | - ^
+ | |
+ | cannot assign to this expression
+ |
+help: you might have meant to use pattern destructuring
+ |
+LL | while let Some(0) = value.get(0) {
+ | +++
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0070`.
diff --git a/src/test/ui/issues/issue-77218/issue-77218.fixed b/src/test/ui/issues/issue-77218/issue-77218.fixed
new file mode 100644
index 00000000000..4907b43b9a9
--- /dev/null
+++ b/src/test/ui/issues/issue-77218/issue-77218.fixed
@@ -0,0 +1,5 @@
+// run-rustfix
+fn main() {
+ let value = [7u8];
+ while let Some(0) = value.get(0) {} //~ ERROR invalid left-hand side of assignment
+}
diff --git a/src/test/ui/issues/issue-77218/issue-77218.rs b/src/test/ui/issues/issue-77218/issue-77218.rs
new file mode 100644
index 00000000000..0ed154bf4d8
--- /dev/null
+++ b/src/test/ui/issues/issue-77218/issue-77218.rs
@@ -0,0 +1,5 @@
+// run-rustfix
+fn main() {
+ let value = [7u8];
+ while Some(0) = value.get(0) {} //~ ERROR invalid left-hand side of assignment
+}
diff --git a/src/test/ui/issues/issue-77218/issue-77218.stderr b/src/test/ui/issues/issue-77218/issue-77218.stderr
new file mode 100644
index 00000000000..eda635646df
--- /dev/null
+++ b/src/test/ui/issues/issue-77218/issue-77218.stderr
@@ -0,0 +1,16 @@
+error[E0070]: invalid left-hand side of assignment
+ --> $DIR/issue-77218.rs:4:19
+ |
+LL | while Some(0) = value.get(0) {}
+ | - ^
+ | |
+ | cannot assign to this expression
+ |
+help: you might have meant to use pattern destructuring
+ |
+LL | while let Some(0) = value.get(0) {}
+ | +++
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0070`.
diff --git a/src/test/ui/issues/issue-80512-param-reordering-with-defaults.stderr b/src/test/ui/issues/issue-80512-param-reordering-with-defaults.stderr
index a1e9a903f81..119b1a0d207 100644
--- a/src/test/ui/issues/issue-80512-param-reordering-with-defaults.stderr
+++ b/src/test/ui/issues/issue-80512-param-reordering-with-defaults.stderr
@@ -2,7 +2,7 @@ error: lifetime parameters must be declared prior to type parameters
--> $DIR/issue-80512-param-reordering-with-defaults.rs:3:18
|
LL | struct S<T = (), 'a>(&'a T);
- | ---------^^- help: reorder the parameters: lifetimes, then types, then consts: `<'a, T = ()>`
+ | ---------^^- help: reorder the parameters: lifetimes, then consts and types: `<'a, T = ()>`
error: aborting due to previous error
diff --git a/src/test/ui/issues/issue-85461.rs b/src/test/ui/issues/issue-85461.rs
new file mode 100644
index 00000000000..4c6c83f2612
--- /dev/null
+++ b/src/test/ui/issues/issue-85461.rs
@@ -0,0 +1,27 @@
+// compile-flags: -Zinstrument-coverage -Ccodegen-units=4 --crate-type dylib -Copt-level=0
+// build-pass
+// needs-profiler-support
+
+// Regression test for #85461 where MSVC sometimes fails to link instrument-coverage binaries
+// with dead code and #[inline(always)].
+
+#![allow(dead_code)]
+
+mod foo {
+ #[inline(always)]
+ pub fn called() { }
+
+ fn uncalled() { }
+}
+
+pub mod bar {
+ pub fn call_me() {
+ super::foo::called();
+ }
+}
+
+pub mod baz {
+ pub fn call_me() {
+ super::foo::called();
+ }
+}
diff --git a/src/test/ui/issues/issue-86756.stderr b/src/test/ui/issues/issue-86756.stderr
index 0d576909a35..5b2f04ffa83 100644
--- a/src/test/ui/issues/issue-86756.stderr
+++ b/src/test/ui/issues/issue-86756.stderr
@@ -18,11 +18,16 @@ warning: trait objects without an explicit `dyn` are deprecated
--> $DIR/issue-86756.rs:5:15
|
LL | eq::<dyn, Foo>
- | ^^^ help: use `dyn`: `dyn Foo`
+ | ^^^
|
= note: `#[warn(bare_trait_objects)]` on by default
= warning: this is accepted in the current edition (Rust 2015) but is a hard error in Rust 2021!
= note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2021/warnings-promoted-to-error.html>
+help: use `dyn`
+ |
+LL - eq::<dyn, Foo>
+LL + eq::<dyn, dyn Foo>
+ |
error[E0107]: missing generics for trait `Foo`
--> $DIR/issue-86756.rs:5:15
diff --git a/src/test/ui/issues/issue-87490.rs b/src/test/ui/issues/issue-87490.rs
new file mode 100644
index 00000000000..998f61a6bd3
--- /dev/null
+++ b/src/test/ui/issues/issue-87490.rs
@@ -0,0 +1,10 @@
+fn main() {}
+trait StreamOnce {
+ type Position;
+}
+impl StreamOnce for &str {
+ type Position = usize;
+}
+fn follow(_: &str) -> <&str as StreamOnce>::Position {
+ String::new //~ ERROR mismatched types
+}
diff --git a/src/test/ui/issues/issue-87490.stderr b/src/test/ui/issues/issue-87490.stderr
new file mode 100644
index 00000000000..f359dd638ad
--- /dev/null
+++ b/src/test/ui/issues/issue-87490.stderr
@@ -0,0 +1,14 @@
+error[E0308]: mismatched types
+ --> $DIR/issue-87490.rs:9:5
+ |
+LL | fn follow(_: &str) -> <&str as StreamOnce>::Position {
+ | ------------------------------ expected `usize` because of return type
+LL | String::new
+ | ^^^^^^^^^^^ expected `usize`, found fn item
+ |
+ = note: expected type `usize`
+ found fn item `fn() -> String {String::new}`
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0308`.
diff --git a/src/test/ui/issues/issue-88150.rs b/src/test/ui/issues/issue-88150.rs
new file mode 100644
index 00000000000..555a38637a4
--- /dev/null
+++ b/src/test/ui/issues/issue-88150.rs
@@ -0,0 +1,21 @@
+// run-pass
+// compile-flags:-C debuginfo=2
+// edition:2018
+
+use core::marker::PhantomData;
+
+pub struct Foo<T: ?Sized, A>(
+ PhantomData<(A, T)>,
+);
+
+enum Never {}
+
+impl<T: ?Sized> Foo<T, Never> {
+ fn new_foo() -> Foo<T, Never> {
+ Foo(PhantomData)
+ }
+}
+
+fn main() {
+ let _ = Foo::<[()], Never>::new_foo();
+}
diff --git a/src/test/ui/issues/issue-91489.rs b/src/test/ui/issues/issue-91489.rs
new file mode 100644
index 00000000000..f028a4a3c6a
--- /dev/null
+++ b/src/test/ui/issues/issue-91489.rs
@@ -0,0 +1,40 @@
+// check-pass
+
+// regression test for #91489
+
+use std::borrow::Borrow;
+use std::borrow::Cow;
+
+pub struct VariantType {}
+pub struct VariantTy {}
+
+impl Borrow<VariantTy> for VariantType {
+ fn borrow(&self) -> &VariantTy {
+ unimplemented!()
+ }
+}
+
+impl ToOwned for VariantTy {
+ type Owned = VariantType;
+ fn to_owned(&self) -> VariantType {
+ unimplemented!()
+ }
+}
+
+impl VariantTy {
+ pub fn as_str(&self) -> () {}
+}
+
+// the presence of this was causing all attempts to call `as_str` on
+// `Cow<'_, VariantTy>, including in itself, to not find the method
+static _TYP: () = {
+ let _ = || {
+ // should be found
+ Cow::Borrowed(&VariantTy {}).as_str();
+ };
+};
+
+fn main() {
+ // should be found
+ Cow::Borrowed(&VariantTy {}).as_str()
+}
diff --git a/src/test/ui/iterators/iter-count-overflow-debug.rs b/src/test/ui/iterators/iter-count-overflow-debug.rs
index 5a0394ae760..15f25f1ca53 100644
--- a/src/test/ui/iterators/iter-count-overflow-debug.rs
+++ b/src/test/ui/iterators/iter-count-overflow-debug.rs
@@ -1,5 +1,6 @@
// run-pass
// only-32bit too impatient for 2⁶⁴ items
+// needs-unwind
// ignore-wasm32-bare compiled with panic=abort by default
// compile-flags: -C debug_assertions=yes -C opt-level=3
diff --git a/src/test/ui/iterators/iter-position-overflow-debug.rs b/src/test/ui/iterators/iter-position-overflow-debug.rs
index 733ee0c46cc..65124c28241 100644
--- a/src/test/ui/iterators/iter-position-overflow-debug.rs
+++ b/src/test/ui/iterators/iter-position-overflow-debug.rs
@@ -1,5 +1,6 @@
// run-pass
// only-32bit too impatient for 2⁶⁴ items
+// needs-unwind
// ignore-wasm32-bare compiled with panic=abort by default
// compile-flags: -C debug_assertions=yes -C opt-level=3
diff --git a/src/test/ui/iterators/iter-step-overflow-debug.rs b/src/test/ui/iterators/iter-step-overflow-debug.rs
index 67605d2fcc2..e16f984de79 100644
--- a/src/test/ui/iterators/iter-step-overflow-debug.rs
+++ b/src/test/ui/iterators/iter-step-overflow-debug.rs
@@ -1,4 +1,5 @@
// run-pass
+// needs-unwind
// ignore-wasm32-bare compiled with panic=abort by default
// compile-flags: -C debug_assertions=yes
diff --git a/src/test/ui/iterators/iter-sum-overflow-debug.rs b/src/test/ui/iterators/iter-sum-overflow-debug.rs
index b7667d1bbf6..d8ce43848a7 100644
--- a/src/test/ui/iterators/iter-sum-overflow-debug.rs
+++ b/src/test/ui/iterators/iter-sum-overflow-debug.rs
@@ -1,4 +1,5 @@
// run-pass
+// needs-unwind
// ignore-wasm32-bare compiled with panic=abort by default
// compile-flags: -C debug_assertions=yes
diff --git a/src/test/ui/iterators/iter-sum-overflow-overflow-checks.rs b/src/test/ui/iterators/iter-sum-overflow-overflow-checks.rs
index 04ca7f8a315..bc8dcbdbb0e 100644
--- a/src/test/ui/iterators/iter-sum-overflow-overflow-checks.rs
+++ b/src/test/ui/iterators/iter-sum-overflow-overflow-checks.rs
@@ -1,4 +1,5 @@
// run-pass
+// needs-unwind
// ignore-wasm32-bare compiled with panic=abort by default
// compile-flags: -C overflow-checks
diff --git a/src/test/ui/keyword/keyword-self-as-type-param.rs b/src/test/ui/keyword/keyword-self-as-type-param.rs
index 785d64ec8ea..55c7ac128ff 100644
--- a/src/test/ui/keyword/keyword-self-as-type-param.rs
+++ b/src/test/ui/keyword/keyword-self-as-type-param.rs
@@ -1,10 +1,10 @@
// Regression test of #36638.
struct Foo<Self>(Self);
-//~^ ERROR expected identifier, found keyword `Self`
-//~^^ ERROR E0392
+//~^ ERROR unexpected keyword `Self` in generic parameters
+//~| ERROR recursive type `Foo` has infinite size
trait Bar<Self> {}
-//~^ ERROR expected identifier, found keyword `Self`
+//~^ ERROR unexpected keyword `Self` in generic parameters
fn main() {}
diff --git a/src/test/ui/keyword/keyword-self-as-type-param.stderr b/src/test/ui/keyword/keyword-self-as-type-param.stderr
index cc3df2e36f7..fd101b32b4c 100644
--- a/src/test/ui/keyword/keyword-self-as-type-param.stderr
+++ b/src/test/ui/keyword/keyword-self-as-type-param.stderr
@@ -1,24 +1,33 @@
-error: expected identifier, found keyword `Self`
+error: unexpected keyword `Self` in generic parameters
--> $DIR/keyword-self-as-type-param.rs:3:12
|
LL | struct Foo<Self>(Self);
- | ^^^^ expected identifier, found keyword
+ | ^^^^
+ |
+ = note: you cannot use `Self` as a generic parameter because it is reserved for associated items
-error: expected identifier, found keyword `Self`
+error: unexpected keyword `Self` in generic parameters
--> $DIR/keyword-self-as-type-param.rs:7:11
|
LL | trait Bar<Self> {}
- | ^^^^ expected identifier, found keyword
+ | ^^^^
+ |
+ = note: you cannot use `Self` as a generic parameter because it is reserved for associated items
-error[E0392]: parameter `Self` is never used
- --> $DIR/keyword-self-as-type-param.rs:3:12
+error[E0072]: recursive type `Foo` has infinite size
+ --> $DIR/keyword-self-as-type-param.rs:3:1
|
LL | struct Foo<Self>(Self);
- | ^^^^ unused parameter
+ | ^^^^^^^^^^^^^^^^^----^^
+ | | |
+ | | recursive without indirection
+ | recursive type has infinite size
+ |
+help: insert some indirection (e.g., a `Box`, `Rc`, or `&`) to make `Foo` representable
|
- = help: consider removing `Self`, referring to it in a field, or using a marker such as `PhantomData`
- = help: if you intended `Self` to be a const parameter, use `const Self: usize` instead
+LL | struct Foo<Self>(Box<Self>);
+ | ++++ +
error: aborting due to 3 previous errors
-For more information about this error, try `rustc --explain E0392`.
+For more information about this error, try `rustc --explain E0072`.
diff --git a/src/test/ui/let-else/issue-89960.rs b/src/test/ui/let-else/issue-89960.rs
deleted file mode 100644
index 8fd55adbfd4..00000000000
--- a/src/test/ui/let-else/issue-89960.rs
+++ /dev/null
@@ -1,7 +0,0 @@
-#![feature(let_else)]
-
-fn main() {
- // FIXME: more precise diagnostics
- let Some(ref mut meow) = Some(()) else { return };
- //~^ ERROR: cannot borrow value as mutable, as `val` is not declared as mutable
-}
diff --git a/src/test/ui/let-else/issue-89960.stderr b/src/test/ui/let-else/issue-89960.stderr
deleted file mode 100644
index 697f04d6d27..00000000000
--- a/src/test/ui/let-else/issue-89960.stderr
+++ /dev/null
@@ -1,12 +0,0 @@
-error[E0596]: cannot borrow value as mutable, as `val` is not declared as mutable
- --> $DIR/issue-89960.rs:5:14
- |
-LL | let Some(ref mut meow) = Some(()) else { return };
- | ---------^^^^^^^^^^^^-----------------------------
- | | |
- | | cannot borrow as mutable
- | help: consider changing this to be mutable: `mut val`
-
-error: aborting due to previous error
-
-For more information about this error, try `rustc --explain E0596`.
diff --git a/src/test/ui/let-else/let-else-allow-unused.rs b/src/test/ui/let-else/let-else-allow-unused.rs
new file mode 100644
index 00000000000..bcd8c987628
--- /dev/null
+++ b/src/test/ui/let-else/let-else-allow-unused.rs
@@ -0,0 +1,14 @@
+// check-pass
+// issue #89807
+
+#![feature(let_else)]
+
+#[deny(unused_variables)]
+
+fn main() {
+ let value = Some(String::new());
+ #[allow(unused)]
+ let banana = 1;
+ #[allow(unused)]
+ let Some(chaenomeles) = value else { return }; // OK
+}
diff --git a/src/test/ui/let-else/let-else-binding-explicit-mut-annotated.rs b/src/test/ui/let-else/let-else-binding-explicit-mut-annotated.rs
new file mode 100644
index 00000000000..b65fa13c1de
--- /dev/null
+++ b/src/test/ui/let-else/let-else-binding-explicit-mut-annotated.rs
@@ -0,0 +1,16 @@
+// from rfc2005 test suite
+
+#![feature(let_else)]
+
+// Verify the binding mode shifts - only when no `&` are auto-dereferenced is the
+// final default binding mode mutable.
+
+fn main() {
+ let Some(n): &mut Option<i32> = &&Some(5i32) else { return }; //~ ERROR mismatched types
+ *n += 1;
+ let _ = n;
+
+ let Some(n): &mut Option<i32> = &&mut Some(5i32) else { return }; //~ ERROR mismatched types
+ *n += 1;
+ let _ = n;
+}
diff --git a/src/test/ui/let-else/let-else-binding-explicit-mut-annotated.stderr b/src/test/ui/let-else/let-else-binding-explicit-mut-annotated.stderr
new file mode 100644
index 00000000000..fdec7e7f6a7
--- /dev/null
+++ b/src/test/ui/let-else/let-else-binding-explicit-mut-annotated.stderr
@@ -0,0 +1,21 @@
+error[E0308]: mismatched types
+ --> $DIR/let-else-binding-explicit-mut-annotated.rs:9:37
+ |
+LL | let Some(n): &mut Option<i32> = &&Some(5i32) else { return };
+ | ^^^^^^^^^^^^ types differ in mutability
+ |
+ = note: expected mutable reference `&mut Option<i32>`
+ found reference `&&Option<i32>`
+
+error[E0308]: mismatched types
+ --> $DIR/let-else-binding-explicit-mut-annotated.rs:13:37
+ |
+LL | let Some(n): &mut Option<i32> = &&mut Some(5i32) else { return };
+ | ^^^^^^^^^^^^^^^^ types differ in mutability
+ |
+ = note: expected mutable reference `&mut Option<i32>`
+ found reference `&&mut Option<i32>`
+
+error: aborting due to 2 previous errors
+
+For more information about this error, try `rustc --explain E0308`.
diff --git a/src/test/ui/let-else/let-else-binding-explicit-mut-borrow.rs b/src/test/ui/let-else/let-else-binding-explicit-mut-borrow.rs
new file mode 100644
index 00000000000..63b35df76aa
--- /dev/null
+++ b/src/test/ui/let-else/let-else-binding-explicit-mut-borrow.rs
@@ -0,0 +1,13 @@
+#![feature(let_else)]
+
+// Slightly different from explicit-mut-annotated -- this won't show an error until borrowck.
+// Should it show a type error instead?
+
+fn main() {
+ let Some(n): &mut Option<i32> = &mut &Some(5i32) else {
+ //~^ ERROR cannot borrow data in a `&` reference as mutable
+ return
+ };
+ *n += 1;
+ let _ = n;
+}
diff --git a/src/test/ui/let-else/let-else-binding-explicit-mut-borrow.stderr b/src/test/ui/let-else/let-else-binding-explicit-mut-borrow.stderr
new file mode 100644
index 00000000000..023fab8fe4a
--- /dev/null
+++ b/src/test/ui/let-else/let-else-binding-explicit-mut-borrow.stderr
@@ -0,0 +1,9 @@
+error[E0596]: cannot borrow data in a `&` reference as mutable
+ --> $DIR/let-else-binding-explicit-mut-borrow.rs:7:37
+ |
+LL | let Some(n): &mut Option<i32> = &mut &Some(5i32) else {
+ | ^^^^^^^^^^^^^^^^ cannot borrow as mutable
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0596`.
diff --git a/src/test/ui/let-else/let-else-binding-explicit-mut-pass.rs b/src/test/ui/let-else/let-else-binding-explicit-mut-pass.rs
new file mode 100644
index 00000000000..305be922192
--- /dev/null
+++ b/src/test/ui/let-else/let-else-binding-explicit-mut-pass.rs
@@ -0,0 +1,13 @@
+// check-pass
+
+#![feature(let_else)]
+
+fn main() {
+ let Some(n) = &mut &mut Some(5i32) else { return; };
+ *n += 1; // OK
+ let _ = n;
+
+ let Some(n): &mut Option<i32> = &mut &mut Some(5i32) else { return; };
+ *n += 1; // OK
+ let _ = n;
+}
diff --git a/src/test/ui/let-else/let-else-binding-explicit-mut.rs b/src/test/ui/let-else/let-else-binding-explicit-mut.rs
new file mode 100644
index 00000000000..dbe4715b1a9
--- /dev/null
+++ b/src/test/ui/let-else/let-else-binding-explicit-mut.rs
@@ -0,0 +1,20 @@
+// from rfc2005 test suite
+
+#![feature(let_else)]
+
+// Verify the binding mode shifts - only when no `&` are auto-dereferenced is the
+// final default binding mode mutable.
+
+fn main() {
+ let Some(n) = &&Some(5i32) else { return };
+ *n += 1; //~ ERROR cannot assign to `*n`, which is behind a `&` reference
+ let _ = n;
+
+ let Some(n) = &mut &Some(5i32) else { return };
+ *n += 1; //~ ERROR cannot assign to `*n`, which is behind a `&` reference
+ let _ = n;
+
+ let Some(n) = &&mut Some(5i32) else { return };
+ *n += 1; //~ ERROR cannot assign to `*n`, which is behind a `&` reference
+ let _ = n;
+}
diff --git a/src/test/ui/let-else/let-else-binding-explicit-mut.stderr b/src/test/ui/let-else/let-else-binding-explicit-mut.stderr
new file mode 100644
index 00000000000..45f2b6b3bce
--- /dev/null
+++ b/src/test/ui/let-else/let-else-binding-explicit-mut.stderr
@@ -0,0 +1,21 @@
+error[E0594]: cannot assign to `*n`, which is behind a `&` reference
+ --> $DIR/let-else-binding-explicit-mut.rs:10:5
+ |
+LL | *n += 1;
+ | ^^^^^^^ `n` is a `&` reference, so the data it refers to cannot be written
+
+error[E0594]: cannot assign to `*n`, which is behind a `&` reference
+ --> $DIR/let-else-binding-explicit-mut.rs:14:5
+ |
+LL | *n += 1;
+ | ^^^^^^^ `n` is a `&` reference, so the data it refers to cannot be written
+
+error[E0594]: cannot assign to `*n`, which is behind a `&` reference
+ --> $DIR/let-else-binding-explicit-mut.rs:18:5
+ |
+LL | *n += 1;
+ | ^^^^^^^ `n` is a `&` reference, so the data it refers to cannot be written
+
+error: aborting due to 3 previous errors
+
+For more information about this error, try `rustc --explain E0594`.
diff --git a/src/test/ui/let-else/let-else-binding-immutable.rs b/src/test/ui/let-else/let-else-binding-immutable.rs
new file mode 100644
index 00000000000..96de0ffe26e
--- /dev/null
+++ b/src/test/ui/let-else/let-else-binding-immutable.rs
@@ -0,0 +1,10 @@
+// from rfc2005 test suite
+
+#![feature(let_else)]
+
+pub fn main() {
+ let Some(x) = &Some(3) else {
+ panic!();
+ };
+ *x += 1; //~ ERROR: cannot assign to `*x`, which is behind a `&` reference
+}
diff --git a/src/test/ui/let-else/let-else-binding-immutable.stderr b/src/test/ui/let-else/let-else-binding-immutable.stderr
new file mode 100644
index 00000000000..dd1365a9ef0
--- /dev/null
+++ b/src/test/ui/let-else/let-else-binding-immutable.stderr
@@ -0,0 +1,9 @@
+error[E0594]: cannot assign to `*x`, which is behind a `&` reference
+ --> $DIR/let-else-binding-immutable.rs:9:5
+ |
+LL | *x += 1;
+ | ^^^^^^^ `x` is a `&` reference, so the data it refers to cannot be written
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0594`.
diff --git a/src/test/ui/let-else/let-else-bindings.rs b/src/test/ui/let-else/let-else-bindings.rs
new file mode 100644
index 00000000000..d5121e744da
--- /dev/null
+++ b/src/test/ui/let-else/let-else-bindings.rs
@@ -0,0 +1,75 @@
+// run-pass
+// adapted from src/test/ui/binding/if-let.rs
+#![feature(let_else)]
+#![allow(dead_code)]
+
+fn none() -> bool {
+ let None = Some("test") else {
+ return true;
+ };
+ false
+}
+
+fn ok() -> bool {
+ let Ok(()) = Err::<(),&'static str>("test") else {
+ return true;
+ };
+ false
+}
+
+pub fn main() {
+ let x = Some(3);
+ let Some(y) = x else {
+ panic!("let-else panicked");
+ };
+ assert_eq!(y, 3);
+ let Some(_) = x else {
+ panic!("bad match");
+ };
+ assert!(none());
+ assert!(ok());
+
+ assert!((|| {
+ let 1 = 2 else {
+ return true;
+ };
+ false
+ })());
+
+ enum Foo {
+ One,
+ Two(usize),
+ Three(String, isize),
+ }
+
+ let foo = Foo::Three("three".to_string(), 42);
+ let one = || {
+ let Foo::One = foo else {
+ return true;
+ };
+ false
+ };
+ assert!(one());
+ let two = || {
+ let Foo::Two(_x) = foo else {
+ return true;
+ };
+ false
+ };
+ assert!(two());
+ let three = || {
+ let Foo::Three(s, _x) = foo else {
+ return false;
+ };
+ s == "three"
+ };
+ assert!(three());
+
+ let a@Foo::Two(_) = Foo::Two(42_usize) else {
+ panic!("bad match")
+ };
+ let Foo::Two(b) = a else {
+ panic!("panic in nested `if let`");
+ };
+ assert_eq!(b, 42_usize);
+}
diff --git a/src/test/ui/let-else/let-else-deref-coercion-annotated.rs b/src/test/ui/let-else/let-else-deref-coercion-annotated.rs
new file mode 100644
index 00000000000..65d88a6d828
--- /dev/null
+++ b/src/test/ui/let-else/let-else-deref-coercion-annotated.rs
@@ -0,0 +1,77 @@
+// check-pass
+//
+// Taken from https://github.com/rust-lang/rust/blob/6cc0a764e082d9c0abcf37a768d5889247ba13e2/compiler/rustc_typeck/src/check/_match.rs#L445-L462
+//
+// We attempt to `let Bar::Present(_): &mut Bar = foo else { ... }` where foo is meant to
+// Deref/DerefMut to Bar. You can do this with an irrefutable binding, so it should work with
+// let-else too.
+
+#![feature(let_else)]
+use std::ops::{Deref, DerefMut};
+
+struct Foo(Bar);
+
+enum Bar {
+ Present(u32),
+ Absent,
+}
+impl Deref for Foo {
+ type Target = Bar;
+ fn deref(&self) -> &Bar {
+ &self.0
+ }
+}
+impl DerefMut for Foo {
+ fn deref_mut(&mut self) -> &mut Bar {
+ &mut self.0
+ }
+}
+impl Bar {
+ fn bar(&self) -> Option<u32> {
+ let Bar::Present(z): &Bar = self else {
+ return None;
+ };
+ return Some(*z);
+ }
+}
+impl Foo {
+ fn set_bar_annotated(&mut self, value: u32) {
+ let Bar::Present(z): &mut Bar = self else { // OK
+ return;
+ };
+ *z = value;
+ }
+}
+
+fn main() {
+ let mut foo = Foo(Bar::Present(1));
+ foo.set_bar_annotated(42);
+ assert_eq!(foo.bar(), Some(42));
+ irrefutable::inner();
+}
+
+// The original, to show it works for irrefutable let decls
+mod irrefutable {
+ use std::ops::{Deref, DerefMut};
+ struct Foo(Bar);
+ struct Bar(u32);
+ impl Deref for Foo {
+ type Target = Bar;
+ fn deref(&self) -> &Bar {
+ &self.0
+ }
+ }
+ impl DerefMut for Foo {
+ fn deref_mut(&mut self) -> &mut Bar {
+ &mut self.0
+ }
+ }
+ fn foo(x: &mut Foo) {
+ let Bar(z): &mut Bar = x; // OK
+ *z = 42;
+ assert_eq!((x.0).0, 42);
+ }
+ pub fn inner() {
+ foo(&mut Foo(Bar(1)));
+ }
+}
diff --git a/src/test/ui/let-else/let-else-deref-coercion.rs b/src/test/ui/let-else/let-else-deref-coercion.rs
new file mode 100644
index 00000000000..87489d84bbf
--- /dev/null
+++ b/src/test/ui/let-else/let-else-deref-coercion.rs
@@ -0,0 +1,75 @@
+// Taken from https://github.com/rust-lang/rust/blob/6cc0a764e082d9c0abcf37a768d5889247ba13e2/compiler/rustc_typeck/src/check/_match.rs#L445-L462
+//
+// We attempt to `let Bar::Present(_) = foo else { ... }` where foo is meant to Deref/DerefMut to
+// Bar. This fails, you must add a type annotation like `let _: &mut Bar = _ else { ... }`
+
+#![feature(let_else)]
+use std::ops::{Deref, DerefMut};
+
+struct Foo(Bar);
+
+enum Bar {
+ Present(u32),
+ Absent,
+}
+impl Deref for Foo {
+ type Target = Bar;
+ fn deref(&self) -> &Bar {
+ &self.0
+ }
+}
+impl DerefMut for Foo {
+ fn deref_mut(&mut self) -> &mut Bar {
+ &mut self.0
+ }
+}
+impl Bar {
+ fn bar(&self) -> Option<u32> {
+ let Bar::Present(z): &Bar = self else {
+ return None;
+ };
+ return Some(*z);
+ }
+}
+impl Foo {
+ // Try without the type annotation
+ fn set_bar_unannotated(&mut self, value: u32) {
+ let Bar::Present(z) = self else { //~ ERROR mismatched types
+ return;
+ };
+ *z = value;
+ }
+}
+
+fn main() {
+ let mut foo = Foo(Bar::Present(1));
+ foo.set_bar_unannotated(54);
+ assert_eq!(foo.bar(), Some(54));
+ irrefutable::inner();
+}
+
+// The original, to show it fails for irrefutable let decls
+mod irrefutable {
+ use std::ops::{Deref, DerefMut};
+ struct Foo(Bar);
+ struct Bar(u32);
+ impl Deref for Foo {
+ type Target = Bar;
+ fn deref(&self) -> &Bar {
+ &self.0
+ }
+ }
+ impl DerefMut for Foo {
+ fn deref_mut(&mut self) -> &mut Bar {
+ &mut self.0
+ }
+ }
+ fn foo(x: &mut Foo) {
+ let Bar(z) = x; //~ ERROR mismatched types
+ *z = 54;
+ assert_eq!((x.0).0, 54);
+ }
+ pub fn inner() {
+ foo(&mut Foo(Bar(1)));
+ }
+}
diff --git a/src/test/ui/let-else/let-else-deref-coercion.stderr b/src/test/ui/let-else/let-else-deref-coercion.stderr
new file mode 100644
index 00000000000..addcd798f4f
--- /dev/null
+++ b/src/test/ui/let-else/let-else-deref-coercion.stderr
@@ -0,0 +1,19 @@
+error[E0308]: mismatched types
+ --> $DIR/let-else-deref-coercion.rs:37:13
+ |
+LL | let Bar::Present(z) = self else {
+ | ^^^^^^^^^^^^^^^ ---- this expression has type `&mut Foo`
+ | |
+ | expected struct `Foo`, found enum `Bar`
+
+error[E0308]: mismatched types
+ --> $DIR/let-else-deref-coercion.rs:68:13
+ |
+LL | let Bar(z) = x;
+ | ^^^^^^ - this expression has type `&mut irrefutable::Foo`
+ | |
+ | expected struct `irrefutable::Foo`, found struct `irrefutable::Bar`
+
+error: aborting due to 2 previous errors
+
+For more information about this error, try `rustc --explain E0308`.
diff --git a/src/test/ui/let-else/let-else-no-double-error.rs b/src/test/ui/let-else/let-else-no-double-error.rs
new file mode 100644
index 00000000000..35dcdd3f6be
--- /dev/null
+++ b/src/test/ui/let-else/let-else-no-double-error.rs
@@ -0,0 +1,12 @@
+// from rfc2005 test suite
+
+#![feature(let_else)]
+
+// Without caching type lookups in FnCtxt.resolve_ty_and_def_ufcs
+// the error below would be reported twice (once when checking
+// for a non-ref pattern, once when processing the pattern).
+
+fn main() {
+ let foo = 22;
+ let u32::XXX = foo else { return }; //~ ERROR: no associated item named `XXX` found for type `u32` in the current scope [E0599]
+}
diff --git a/src/test/ui/let-else/let-else-no-double-error.stderr b/src/test/ui/let-else/let-else-no-double-error.stderr
new file mode 100644
index 00000000000..941e588b176
--- /dev/null
+++ b/src/test/ui/let-else/let-else-no-double-error.stderr
@@ -0,0 +1,9 @@
+error[E0599]: no associated item named `XXX` found for type `u32` in the current scope
+ --> $DIR/let-else-no-double-error.rs:11:14
+ |
+LL | let u32::XXX = foo else { return };
+ | ^^^ associated item not found in `u32`
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0599`.
diff --git a/src/test/ui/let-else/let-else-non-copy.rs b/src/test/ui/let-else/let-else-non-copy.rs
new file mode 100644
index 00000000000..79ed82dd124
--- /dev/null
+++ b/src/test/ui/let-else/let-else-non-copy.rs
@@ -0,0 +1,45 @@
+// run-pass
+//
+// This is derived from a change to compiler/rustc_codegen_llvm/src/debuginfo/metadata.rs, in
+// preparation for adopting let-else within the compiler (thanks @est31):
+//
+// ```
+// - let place = if let mir::VarDebugInfoContents::Place(p) = var.value { p } else { continue };
+// + let mir::VarDebugInfoContents::Place(place) = var.value else { continue };
+// ```
+//
+// The move was due to mir::Place being Copy, but mir::VarDebugInfoContents not being Copy.
+
+#![feature(let_else)]
+
+#[derive(Copy, Clone)]
+struct Copyable;
+
+enum NonCopy {
+ Thing(Copyable),
+ #[allow(unused)]
+ Other,
+}
+
+struct Wrapper {
+ field: NonCopy,
+}
+
+fn let_else() {
+ let vec = vec![Wrapper { field: NonCopy::Thing(Copyable) }];
+ for item in &vec {
+ let NonCopy::Thing(_copyable) = item.field else { continue };
+ }
+}
+
+fn if_let() {
+ let vec = vec![Wrapper { field: NonCopy::Thing(Copyable) }];
+ for item in &vec {
+ let _copyable = if let NonCopy::Thing(copyable) = item.field { copyable } else { continue };
+ }
+}
+
+fn main() {
+ let_else();
+ if_let();
+}
diff --git a/src/test/ui/let-else/let-else-ref-bindings-pass.rs b/src/test/ui/let-else/let-else-ref-bindings-pass.rs
new file mode 100644
index 00000000000..f4abd6cc2df
--- /dev/null
+++ b/src/test/ui/let-else/let-else-ref-bindings-pass.rs
@@ -0,0 +1,71 @@
+// check-pass
+
+#![feature(let_else)]
+#![allow(unused_variables)]
+
+fn ref_() {
+ let bytes: Vec<u8> = b"Hello"[..].to_vec();
+ let some = Some(bytes);
+
+ let Some(ref a) = Some(()) else { return };
+
+ // | ref | type annotation | & |
+ // | --- | --------------- | - |
+ // | x | x | | error
+ // | x | x | x | error
+ // | | x | | error
+ // | | x | x | error
+ // | x | | |
+ let Some(ref a) = some else { return }; // OK
+ let b: &[u8] = a;
+
+ // | x | | x |
+ let Some(ref a) = &some else { return }; // OK
+ let b: &[u8] = a;
+
+
+ // | | | x |
+ let Some(a) = &some else { return }; // OK
+ let b: &[u8] = a;
+
+ let Some(a): Option<&[u8]> = some.as_deref() else { return }; // OK
+ let b: &[u8] = a;
+ let Some(ref a): Option<&[u8]> = some.as_deref() else { return }; // OK
+ let b: &[u8] = a;
+}
+
+fn ref_mut() {
+ // This `ref mut` case had an ICE, see issue #89960
+ let Some(ref mut a) = Some(()) else { return };
+
+ let bytes: Vec<u8> = b"Hello"[..].to_vec();
+ let mut some = Some(bytes);
+
+ // | ref mut | type annotation | &mut |
+ // | ------- | --------------- | ---- |
+ // | x | x | | error
+ // | x | x | x | error
+ // | | x | | error
+ // | | x | x | error
+ // | x | | |
+ let Some(ref mut a) = some else { return }; // OK
+ let b: &mut [u8] = a;
+
+ // | x | | x |
+ let Some(ref mut a) = &mut some else { return }; // OK
+ let b: &mut [u8] = a;
+
+ // | | | x |
+ let Some(a) = &mut some else { return }; // OK
+ let b: &mut [u8] = a;
+
+ let Some(a): Option<&mut [u8]> = some.as_deref_mut() else { return }; // OK
+ let b: &mut [u8] = a;
+ let Some(ref mut a): Option<&mut [u8]> = some.as_deref_mut() else { return }; // OK
+ let b: &mut [u8] = a;
+}
+
+fn main() {
+ ref_();
+ ref_mut();
+}
diff --git a/src/test/ui/let-else/let-else-ref-bindings.rs b/src/test/ui/let-else/let-else-ref-bindings.rs
new file mode 100644
index 00000000000..a4cd8e8c47d
--- /dev/null
+++ b/src/test/ui/let-else/let-else-ref-bindings.rs
@@ -0,0 +1,62 @@
+#![feature(let_else)]
+#![allow(unused_variables)]
+
+fn ref_() {
+ let bytes: Vec<u8> = b"Hello"[..].to_vec();
+ let some = Some(bytes);
+
+ let Some(ref a) = Some(()) else { return };
+
+ // | ref | type annotation | & |
+ // | --- | --------------- | - |
+ // | x | | | OK
+ // | x | | x | OK
+ // | | | x | OK
+ // | x | x | |
+ let Some(ref a): Option<&[u8]> = some else { return }; //~ ERROR mismatched types
+ let b: & [u8] = a;
+
+ // | x | x | x |
+ let Some(ref a): Option<&[u8]> = &some else { return }; //~ ERROR mismatched types
+ let b: & [u8] = a;
+
+ // | | x | |
+ let Some(a): Option<&[u8]> = some else { return }; //~ ERROR mismatched types
+ let b: &[u8] = a;
+ // | | x | x |
+ let Some(a): Option<&[u8]> = &some else { return }; //~ ERROR mismatched types
+ let b: &[u8] = a;
+}
+
+fn ref_mut() {
+ // This `ref mut` case had an ICE, see issue #89960
+ let Some(ref mut a) = Some(()) else { return };
+
+ let bytes: Vec<u8> = b"Hello"[..].to_vec();
+ let mut some = Some(bytes);
+
+ // | ref mut | type annotation | &mut |
+ // | ------- | --------------- | ---- |
+ // | x | | | OK
+ // | x | | x | OK
+ // | | | x | OK
+ // | x | x | |
+ let Some(ref mut a): Option<&mut [u8]> = some else { return }; //~ ERROR mismatched types
+ let b: &mut [u8] = a;
+
+ // | x | x | x | (nope)
+ let Some(ref mut a): Option<&mut [u8]> = &mut some else { return }; //~ ERROR mismatched types
+ let b: &mut [u8] = a;
+
+ // | | x | |
+ let Some(a): Option<&mut [u8]> = some else { return }; //~ ERROR mismatched types
+ let b: &mut [u8] = a;
+ // | | x | x |
+ let Some(a): Option<&mut [u8]> = &mut some else { return }; //~ ERROR mismatched types
+ let b: &mut [u8] = a;
+}
+
+fn main() {
+ ref_();
+ ref_mut();
+}
diff --git a/src/test/ui/let-else/let-else-ref-bindings.stderr b/src/test/ui/let-else/let-else-ref-bindings.stderr
new file mode 100644
index 00000000000..650f4ec5e77
--- /dev/null
+++ b/src/test/ui/let-else/let-else-ref-bindings.stderr
@@ -0,0 +1,75 @@
+error[E0308]: mismatched types
+ --> $DIR/let-else-ref-bindings.rs:16:38
+ |
+LL | let Some(ref a): Option<&[u8]> = some else { return };
+ | ^^^^ expected `&[u8]`, found struct `Vec`
+ |
+ = note: expected enum `Option<&[u8]>`
+ found enum `Option<Vec<u8>>`
+
+error[E0308]: mismatched types
+ --> $DIR/let-else-ref-bindings.rs:20:38
+ |
+LL | let Some(ref a): Option<&[u8]> = &some else { return };
+ | ^^^^^ expected enum `Option`, found `&Option<Vec<u8>>`
+ |
+ = note: expected enum `Option<&[u8]>`
+ found reference `&Option<Vec<u8>>`
+
+error[E0308]: mismatched types
+ --> $DIR/let-else-ref-bindings.rs:24:34
+ |
+LL | let Some(a): Option<&[u8]> = some else { return };
+ | ^^^^ expected `&[u8]`, found struct `Vec`
+ |
+ = note: expected enum `Option<&[u8]>`
+ found enum `Option<Vec<u8>>`
+
+error[E0308]: mismatched types
+ --> $DIR/let-else-ref-bindings.rs:27:34
+ |
+LL | let Some(a): Option<&[u8]> = &some else { return };
+ | ^^^^^ expected enum `Option`, found `&Option<Vec<u8>>`
+ |
+ = note: expected enum `Option<&[u8]>`
+ found reference `&Option<Vec<u8>>`
+
+error[E0308]: mismatched types
+ --> $DIR/let-else-ref-bindings.rs:44:46
+ |
+LL | let Some(ref mut a): Option<&mut [u8]> = some else { return };
+ | ^^^^ expected `&mut [u8]`, found struct `Vec`
+ |
+ = note: expected enum `Option<&mut [u8]>`
+ found enum `Option<Vec<u8>>`
+
+error[E0308]: mismatched types
+ --> $DIR/let-else-ref-bindings.rs:48:46
+ |
+LL | let Some(ref mut a): Option<&mut [u8]> = &mut some else { return };
+ | ^^^^^^^^^ expected enum `Option`, found mutable reference
+ |
+ = note: expected enum `Option<&mut [u8]>`
+ found mutable reference `&mut Option<Vec<u8>>`
+
+error[E0308]: mismatched types
+ --> $DIR/let-else-ref-bindings.rs:52:38
+ |
+LL | let Some(a): Option<&mut [u8]> = some else { return };
+ | ^^^^ expected `&mut [u8]`, found struct `Vec`
+ |
+ = note: expected enum `Option<&mut [u8]>`
+ found enum `Option<Vec<u8>>`
+
+error[E0308]: mismatched types
+ --> $DIR/let-else-ref-bindings.rs:55:38
+ |
+LL | let Some(a): Option<&mut [u8]> = &mut some else { return };
+ | ^^^^^^^^^ expected enum `Option`, found mutable reference
+ |
+ = note: expected enum `Option<&mut [u8]>`
+ found mutable reference `&mut Option<Vec<u8>>`
+
+error: aborting due to 8 previous errors
+
+For more information about this error, try `rustc --explain E0308`.
diff --git a/src/test/ui/let-else/let-else-source-expr-nomove-pass.rs b/src/test/ui/let-else/let-else-source-expr-nomove-pass.rs
new file mode 100644
index 00000000000..2aa17ae8ceb
--- /dev/null
+++ b/src/test/ui/let-else/let-else-source-expr-nomove-pass.rs
@@ -0,0 +1,17 @@
+// run-pass
+// issue #89688
+
+#![feature(let_else)]
+
+fn example_let_else(value: Option<String>) {
+ let Some(inner) = value else {
+ println!("other: {:?}", value); // OK
+ return;
+ };
+ println!("inner: {}", inner);
+}
+
+fn main() {
+ example_let_else(Some("foo".into()));
+ example_let_else(None);
+}
diff --git a/src/test/ui/parser/lex-bad-binary-literal.rs b/src/test/ui/lexer/lex-bad-binary-literal.rs
index 7df98073e35..7df98073e35 100644
--- a/src/test/ui/parser/lex-bad-binary-literal.rs
+++ b/src/test/ui/lexer/lex-bad-binary-literal.rs
diff --git a/src/test/ui/parser/lex-bad-binary-literal.stderr b/src/test/ui/lexer/lex-bad-binary-literal.stderr
index 992b3d2487e..992b3d2487e 100644
--- a/src/test/ui/parser/lex-bad-binary-literal.stderr
+++ b/src/test/ui/lexer/lex-bad-binary-literal.stderr
diff --git a/src/test/ui/parser/lex-bad-char-literals-1.rs b/src/test/ui/lexer/lex-bad-char-literals-1.rs
index e7951cfd2d2..e7951cfd2d2 100644
--- a/src/test/ui/parser/lex-bad-char-literals-1.rs
+++ b/src/test/ui/lexer/lex-bad-char-literals-1.rs
diff --git a/src/test/ui/parser/lex-bad-char-literals-1.stderr b/src/test/ui/lexer/lex-bad-char-literals-1.stderr
index ed129a1d133..ed129a1d133 100644
--- a/src/test/ui/parser/lex-bad-char-literals-1.stderr
+++ b/src/test/ui/lexer/lex-bad-char-literals-1.stderr
diff --git a/src/test/ui/parser/lex-bad-char-literals-2.rs b/src/test/ui/lexer/lex-bad-char-literals-2.rs
index d35dafd9a34..d35dafd9a34 100644
--- a/src/test/ui/parser/lex-bad-char-literals-2.rs
+++ b/src/test/ui/lexer/lex-bad-char-literals-2.rs
diff --git a/src/test/ui/parser/lex-bad-char-literals-2.stderr b/src/test/ui/lexer/lex-bad-char-literals-2.stderr
index c2b19a7ad5f..c2b19a7ad5f 100644
--- a/src/test/ui/parser/lex-bad-char-literals-2.stderr
+++ b/src/test/ui/lexer/lex-bad-char-literals-2.stderr
diff --git a/src/test/ui/parser/lex-bad-char-literals-3.rs b/src/test/ui/lexer/lex-bad-char-literals-3.rs
index 5194ff4d935..5194ff4d935 100644
--- a/src/test/ui/parser/lex-bad-char-literals-3.rs
+++ b/src/test/ui/lexer/lex-bad-char-literals-3.rs
diff --git a/src/test/ui/parser/lex-bad-char-literals-3.stderr b/src/test/ui/lexer/lex-bad-char-literals-3.stderr
index 62a5e424cb4..62a5e424cb4 100644
--- a/src/test/ui/parser/lex-bad-char-literals-3.stderr
+++ b/src/test/ui/lexer/lex-bad-char-literals-3.stderr
diff --git a/src/test/ui/parser/lex-bad-char-literals-4.rs b/src/test/ui/lexer/lex-bad-char-literals-4.rs
index de0a19df993..de0a19df993 100644
--- a/src/test/ui/parser/lex-bad-char-literals-4.rs
+++ b/src/test/ui/lexer/lex-bad-char-literals-4.rs
diff --git a/src/test/ui/parser/lex-bad-char-literals-4.stderr b/src/test/ui/lexer/lex-bad-char-literals-4.stderr
index fec4421c48a..fec4421c48a 100644
--- a/src/test/ui/parser/lex-bad-char-literals-4.stderr
+++ b/src/test/ui/lexer/lex-bad-char-literals-4.stderr
diff --git a/src/test/ui/parser/lex-bad-char-literals-5.rs b/src/test/ui/lexer/lex-bad-char-literals-5.rs
index 0c4339edc4f..0c4339edc4f 100644
--- a/src/test/ui/parser/lex-bad-char-literals-5.rs
+++ b/src/test/ui/lexer/lex-bad-char-literals-5.rs
diff --git a/src/test/ui/parser/lex-bad-char-literals-5.stderr b/src/test/ui/lexer/lex-bad-char-literals-5.stderr
index 184817a6579..184817a6579 100644
--- a/src/test/ui/parser/lex-bad-char-literals-5.stderr
+++ b/src/test/ui/lexer/lex-bad-char-literals-5.stderr
diff --git a/src/test/ui/parser/lex-bad-char-literals-6.rs b/src/test/ui/lexer/lex-bad-char-literals-6.rs
index 4379b4fa6d7..4379b4fa6d7 100644
--- a/src/test/ui/parser/lex-bad-char-literals-6.rs
+++ b/src/test/ui/lexer/lex-bad-char-literals-6.rs
diff --git a/src/test/ui/parser/lex-bad-char-literals-6.stderr b/src/test/ui/lexer/lex-bad-char-literals-6.stderr
index 4332bdefcb2..4332bdefcb2 100644
--- a/src/test/ui/parser/lex-bad-char-literals-6.stderr
+++ b/src/test/ui/lexer/lex-bad-char-literals-6.stderr
diff --git a/src/test/ui/parser/lex-bad-char-literals-7.rs b/src/test/ui/lexer/lex-bad-char-literals-7.rs
index c675df2f3cc..c675df2f3cc 100644
--- a/src/test/ui/parser/lex-bad-char-literals-7.rs
+++ b/src/test/ui/lexer/lex-bad-char-literals-7.rs
diff --git a/src/test/ui/parser/lex-bad-char-literals-7.stderr b/src/test/ui/lexer/lex-bad-char-literals-7.stderr
index 255b9c68999..255b9c68999 100644
--- a/src/test/ui/parser/lex-bad-char-literals-7.stderr
+++ b/src/test/ui/lexer/lex-bad-char-literals-7.stderr
diff --git a/src/test/ui/parser/lex-bad-numeric-literals.rs b/src/test/ui/lexer/lex-bad-numeric-literals.rs
index cf8440ca488..cf8440ca488 100644
--- a/src/test/ui/parser/lex-bad-numeric-literals.rs
+++ b/src/test/ui/lexer/lex-bad-numeric-literals.rs
diff --git a/src/test/ui/parser/lex-bad-numeric-literals.stderr b/src/test/ui/lexer/lex-bad-numeric-literals.stderr
index f05d6160302..f05d6160302 100644
--- a/src/test/ui/parser/lex-bad-numeric-literals.stderr
+++ b/src/test/ui/lexer/lex-bad-numeric-literals.stderr
diff --git a/src/test/ui/parser/lex-bad-octal-literal.rs b/src/test/ui/lexer/lex-bad-octal-literal.rs
index 49631f16bdb..49631f16bdb 100644
--- a/src/test/ui/parser/lex-bad-octal-literal.rs
+++ b/src/test/ui/lexer/lex-bad-octal-literal.rs
diff --git a/src/test/ui/parser/lex-bad-octal-literal.stderr b/src/test/ui/lexer/lex-bad-octal-literal.stderr
index 2cb8ca5ded0..2cb8ca5ded0 100644
--- a/src/test/ui/parser/lex-bad-octal-literal.stderr
+++ b/src/test/ui/lexer/lex-bad-octal-literal.stderr
diff --git a/src/test/ui/parser/lex-bad-token.rs b/src/test/ui/lexer/lex-bad-token.rs
index 9e482461112..9e482461112 100644
--- a/src/test/ui/parser/lex-bad-token.rs
+++ b/src/test/ui/lexer/lex-bad-token.rs
diff --git a/src/test/ui/parser/lex-bad-token.stderr b/src/test/ui/lexer/lex-bad-token.stderr
index 43c43721b19..43c43721b19 100644
--- a/src/test/ui/parser/lex-bad-token.stderr
+++ b/src/test/ui/lexer/lex-bad-token.stderr
diff --git a/src/test/ui/parser/lex-bare-cr-nondoc-comment.rs b/src/test/ui/lexer/lex-bare-cr-nondoc-comment.rs
index 5b528d6e1e1..5b528d6e1e1 100644
--- a/src/test/ui/parser/lex-bare-cr-nondoc-comment.rs
+++ b/src/test/ui/lexer/lex-bare-cr-nondoc-comment.rs
diff --git a/src/test/ui/parser/lex-bare-cr-string-literal-doc-comment.rs b/src/test/ui/lexer/lex-bare-cr-string-literal-doc-comment.rs
index b7752e1f0c4..b7752e1f0c4 100644
--- a/src/test/ui/parser/lex-bare-cr-string-literal-doc-comment.rs
+++ b/src/test/ui/lexer/lex-bare-cr-string-literal-doc-comment.rs
diff --git a/src/test/ui/parser/lex-bare-cr-string-literal-doc-comment.stderr b/src/test/ui/lexer/lex-bare-cr-string-literal-doc-comment.stderr
index 1a21fed63bd..1a21fed63bd 100644
--- a/src/test/ui/parser/lex-bare-cr-string-literal-doc-comment.stderr
+++ b/src/test/ui/lexer/lex-bare-cr-string-literal-doc-comment.stderr
diff --git a/src/test/ui/parser/lex-stray-backslash.rs b/src/test/ui/lexer/lex-stray-backslash.rs
index bb27f44c279..bb27f44c279 100644
--- a/src/test/ui/parser/lex-stray-backslash.rs
+++ b/src/test/ui/lexer/lex-stray-backslash.rs
diff --git a/src/test/ui/parser/lex-stray-backslash.stderr b/src/test/ui/lexer/lex-stray-backslash.stderr
index 06dc0f2b537..06dc0f2b537 100644
--- a/src/test/ui/parser/lex-stray-backslash.stderr
+++ b/src/test/ui/lexer/lex-stray-backslash.stderr
diff --git a/src/test/ui/parser/lexer-crlf-line-endings-string-literal-doc-comment.rs b/src/test/ui/lexer/lexer-crlf-line-endings-string-literal-doc-comment.rs
index 802be7f5afb..802be7f5afb 100644
--- a/src/test/ui/parser/lexer-crlf-line-endings-string-literal-doc-comment.rs
+++ b/src/test/ui/lexer/lexer-crlf-line-endings-string-literal-doc-comment.rs
diff --git a/src/test/ui/lifetimes/auxiliary/issue-91763-aux.rs b/src/test/ui/lifetimes/auxiliary/issue-91763-aux.rs
new file mode 100644
index 00000000000..0335f72b784
--- /dev/null
+++ b/src/test/ui/lifetimes/auxiliary/issue-91763-aux.rs
@@ -0,0 +1,47 @@
+// force-host
+// no-prefer-dynamic
+
+#![crate_type = "proc-macro"]
+
+//#![feature(proc_macro_diagnostic, proc_macro_span, proc_macro_def_site)]
+
+extern crate proc_macro;
+
+use proc_macro::{Delimiter, Group, Ident, Punct, Spacing, Span, TokenStream, TokenTree};
+use std::iter::FromIterator;
+
+#[proc_macro_attribute]
+pub fn repro(_args: TokenStream, input: TokenStream) -> TokenStream {
+ let call_site = Span::call_site();
+ let span = input.into_iter().nth(8).unwrap().span();
+
+ //fn f(_: &::std::fmt::Formatter) {}
+ TokenStream::from_iter([
+ TokenTree::Ident(Ident::new("fn", call_site)),
+ TokenTree::Ident(Ident::new("f", call_site)),
+ TokenTree::Group(Group::new(
+ Delimiter::Parenthesis,
+ TokenStream::from_iter([
+ TokenTree::Ident(Ident::new("_", call_site)),
+ TokenTree::Punct(punct(':', Spacing::Alone, call_site)),
+ TokenTree::Punct(punct('&', Spacing::Alone, call_site)),
+ TokenTree::Punct(punct(':', Spacing::Joint, span)),
+ TokenTree::Punct(punct(':', Spacing::Alone, span)),
+ TokenTree::Ident(Ident::new("std", span)),
+ TokenTree::Punct(punct(':', Spacing::Joint, span)),
+ TokenTree::Punct(punct(':', Spacing::Alone, span)),
+ TokenTree::Ident(Ident::new("fmt", span)),
+ TokenTree::Punct(punct(':', Spacing::Joint, span)),
+ TokenTree::Punct(punct(':', Spacing::Alone, span)),
+ TokenTree::Ident(Ident::new("Formatter", span)),
+ ]),
+ )),
+ TokenTree::Group(Group::new(Delimiter::Brace, TokenStream::new())),
+ ])
+}
+
+fn punct(ch: char, spacing: Spacing, span: Span) -> Punct {
+ let mut punct = Punct::new(ch, spacing);
+ punct.set_span(span);
+ punct
+}
diff --git a/src/test/ui/lifetimes/issue-76168-hr-outlives.rs b/src/test/ui/lifetimes/issue-76168-hr-outlives.rs
new file mode 100644
index 00000000000..9366e94c90f
--- /dev/null
+++ b/src/test/ui/lifetimes/issue-76168-hr-outlives.rs
@@ -0,0 +1,19 @@
+// edition:2018
+// check-pass
+
+#![feature(unboxed_closures)]
+use std::future::Future;
+
+async fn wrapper<F>(f: F)
+where for<'a> F: FnOnce<(&'a mut i32,)>,
+ for<'a> <F as FnOnce<(&'a mut i32,)>>::Output: Future<Output=()> + 'a
+{
+ let mut i = 41;
+ f(&mut i).await;
+}
+
+async fn add_one(i: &mut i32) {
+ *i = *i + 1;
+}
+
+fn main() {}
diff --git a/src/test/ui/lifetimes/issue-90600-expected-return-static-indirect.stderr b/src/test/ui/lifetimes/issue-90600-expected-return-static-indirect.stderr
index 3f65d3af725..e06255e4ea3 100644
--- a/src/test/ui/lifetimes/issue-90600-expected-return-static-indirect.stderr
+++ b/src/test/ui/lifetimes/issue-90600-expected-return-static-indirect.stderr
@@ -4,7 +4,7 @@ error[E0759]: `foo` has an anonymous lifetime `'_` but it needs to satisfy a `'s
LL | fn inner(mut foo: &[u8]) {
| ----- this data with an anonymous lifetime `'_`...
LL | let refcell = RefCell::new(&mut foo);
- | ^^^^^^^^ ...is captured here...
+ | ^^^^^^^^ ...is used here...
...
LL | read_thing(read);
| ---- ...and is required to live as long as `'static` here
diff --git a/src/test/ui/lifetimes/issue-91763.rs b/src/test/ui/lifetimes/issue-91763.rs
new file mode 100644
index 00000000000..2e8807fe639
--- /dev/null
+++ b/src/test/ui/lifetimes/issue-91763.rs
@@ -0,0 +1,11 @@
+// aux-build:issue-91763-aux.rs
+
+#![deny(elided_lifetimes_in_paths)]
+
+extern crate issue_91763_aux;
+
+#[issue_91763_aux::repro]
+fn f() -> Ptr<Thing>;
+//~^ ERROR hidden lifetime parameters in types are deprecated
+
+fn main() {}
diff --git a/src/test/ui/lifetimes/issue-91763.stderr b/src/test/ui/lifetimes/issue-91763.stderr
new file mode 100644
index 00000000000..1b1912c8e45
--- /dev/null
+++ b/src/test/ui/lifetimes/issue-91763.stderr
@@ -0,0 +1,14 @@
+error: hidden lifetime parameters in types are deprecated
+ --> $DIR/issue-91763.rs:8:20
+ |
+LL | fn f() -> Ptr<Thing>;
+ | ^ expected named lifetime parameter
+ |
+note: the lint level is defined here
+ --> $DIR/issue-91763.rs:3:9
+ |
+LL | #![deny(elided_lifetimes_in_paths)]
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: aborting due to previous error
+
diff --git a/src/test/ui/lifetimes/undeclared-lifetime-used-in-debug-macro-issue-70152.stderr b/src/test/ui/lifetimes/undeclared-lifetime-used-in-debug-macro-issue-70152.stderr
index e18d725faef..a2086895234 100644
--- a/src/test/ui/lifetimes/undeclared-lifetime-used-in-debug-macro-issue-70152.stderr
+++ b/src/test/ui/lifetimes/undeclared-lifetime-used-in-debug-macro-issue-70152.stderr
@@ -11,9 +11,8 @@ LL | a: &'b str,
error[E0261]: use of undeclared lifetime name `'b`
--> $DIR/undeclared-lifetime-used-in-debug-macro-issue-70152.rs:3:9
|
-LL | #[derive(Eq, PartialEq)]
- | -- lifetime `'b` is missing in item created through this procedural macro
LL | struct Test {
+ | - help: consider introducing lifetime `'b` here: `<'b>`
LL | a: &'b str,
| ^^ undeclared lifetime
|
diff --git a/src/test/ui/limits/issue-55878.stderr b/src/test/ui/limits/issue-55878.stderr
index a7e38247902..90411353f08 100644
--- a/src/test/ui/limits/issue-55878.stderr
+++ b/src/test/ui/limits/issue-55878.stderr
@@ -18,6 +18,7 @@ LL | println!("Size: {}", std::mem::size_of::<[u8; u64::MAX as usize]>());
= note: `#[deny(const_err)]` on by default
= warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
= note: for more information, see issue #71800 <https://github.com/rust-lang/rust/issues/71800>
+ = note: this error originates in the macro `$crate::format_args_nl` (in Nightly builds, run with -Z macro-backtrace for more info)
error: aborting due to 2 previous errors
diff --git a/src/test/ui/lint/bare-trait-objects-path.rs b/src/test/ui/lint/bare-trait-objects-path.rs
index 0a7c5a8dbd1..0e2294715cd 100644
--- a/src/test/ui/lint/bare-trait-objects-path.rs
+++ b/src/test/ui/lint/bare-trait-objects-path.rs
@@ -21,4 +21,6 @@ fn main() {
//~^ WARN trait objects without an explicit `dyn` are deprecated
//~| WARN this is accepted in the current edition
let _: Dyn::Ty; //~ ERROR ambiguous associated type
+ //~^ WARN trait objects without an explicit `dyn` are deprecated
+ //~| WARN this is accepted in the current edition
}
diff --git a/src/test/ui/lint/bare-trait-objects-path.stderr b/src/test/ui/lint/bare-trait-objects-path.stderr
index 3477b01b6b5..4b8c2b539d5 100644
--- a/src/test/ui/lint/bare-trait-objects-path.stderr
+++ b/src/test/ui/lint/bare-trait-objects-path.stderr
@@ -1,3 +1,17 @@
+warning: trait objects without an explicit `dyn` are deprecated
+ --> $DIR/bare-trait-objects-path.rs:23:12
+ |
+LL | let _: Dyn::Ty;
+ | ^^^
+ |
+ = note: `#[warn(bare_trait_objects)]` on by default
+ = warning: this is accepted in the current edition (Rust 2015) but is a hard error in Rust 2021!
+ = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2021/warnings-promoted-to-error.html>
+help: use `dyn`
+ |
+LL | let _: <dyn Dyn>::Ty;
+ | ++++ +
+
error[E0223]: ambiguous associated type
--> $DIR/bare-trait-objects-path.rs:23:12
|
@@ -8,30 +22,41 @@ warning: trait objects without an explicit `dyn` are deprecated
--> $DIR/bare-trait-objects-path.rs:14:5
|
LL | Dyn::func();
- | ^^^ help: use `dyn`: `<dyn Dyn>`
+ | ^^^
|
- = note: `#[warn(bare_trait_objects)]` on by default
= warning: this is accepted in the current edition (Rust 2015) but is a hard error in Rust 2021!
= note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2021/warnings-promoted-to-error.html>
+help: use `dyn`
+ |
+LL | <dyn Dyn>::func();
+ | ++++ +
warning: trait objects without an explicit `dyn` are deprecated
--> $DIR/bare-trait-objects-path.rs:17:5
|
LL | ::Dyn::func();
- | ^^^^^ help: use `dyn`: `<dyn (::Dyn)>`
+ | ^^^^^
|
= warning: this is accepted in the current edition (Rust 2015) but is a hard error in Rust 2021!
= note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2021/warnings-promoted-to-error.html>
+help: use `dyn`
+ |
+LL | <dyn (::Dyn)>::func();
+ | ++++++ ++
warning: trait objects without an explicit `dyn` are deprecated
--> $DIR/bare-trait-objects-path.rs:20:5
|
LL | Dyn::CONST;
- | ^^^ help: use `dyn`: `<dyn Dyn>`
+ | ^^^
|
= warning: this is accepted in the current edition (Rust 2015) but is a hard error in Rust 2021!
= note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2021/warnings-promoted-to-error.html>
+help: use `dyn`
+ |
+LL | <dyn Dyn>::CONST;
+ | ++++ +
-error: aborting due to previous error; 3 warnings emitted
+error: aborting due to previous error; 4 warnings emitted
For more information about this error, try `rustc --explain E0223`.
diff --git a/src/test/ui/lint/dead-code/anon-const-in-pat.rs b/src/test/ui/lint/dead-code/anon-const-in-pat.rs
index 4c6211a279a..d3e39c0de69 100644
--- a/src/test/ui/lint/dead-code/anon-const-in-pat.rs
+++ b/src/test/ui/lint/dead-code/anon-const-in-pat.rs
@@ -1,5 +1,5 @@
// check-pass
-#![feature(inline_const)]
+#![feature(inline_const_pat)]
#![allow(incomplete_features)]
#![deny(dead_code)]
diff --git a/src/test/ui/lint/force-warn/allowed-by-default-lint.stderr b/src/test/ui/lint/force-warn/allowed-by-default-lint.stderr
index baa47cbb10f..f5e8b41b163 100644
--- a/src/test/ui/lint/force-warn/allowed-by-default-lint.stderr
+++ b/src/test/ui/lint/force-warn/allowed-by-default-lint.stderr
@@ -2,9 +2,13 @@ warning: hidden lifetime parameters in types are deprecated
--> $DIR/allowed-by-default-lint.rs:9:12
|
LL | fn foo(x: &Foo) {}
- | ^^^- help: indicate the anonymous lifetime: `<'_>`
+ | ^^^ expected named lifetime parameter
|
= note: requested on the command line with `--force-warn elided-lifetimes-in-paths`
+help: consider using the `'_` lifetime
+ |
+LL | fn foo(x: &Foo<'_>) {}
+ | ~~~~~~~
warning: 1 warning emitted
diff --git a/src/test/ui/lint/force-warn/allowed-group-warn-by-default-lint.rs b/src/test/ui/lint/force-warn/allowed-group-warn-by-default-lint.rs
index 9b1edba41aa..631a8cb2f08 100644
--- a/src/test/ui/lint/force-warn/allowed-group-warn-by-default-lint.rs
+++ b/src/test/ui/lint/force-warn/allowed-group-warn-by-default-lint.rs
@@ -10,5 +10,9 @@ pub trait SomeTrait {}
pub fn function(_x: Box<SomeTrait>) {}
//~^ WARN trait objects without an explicit `dyn` are deprecated
//~| WARN this is accepted in the current edition
+//~| WARN trait objects without an explicit `dyn` are deprecated
+//~| WARN this is accepted in the current edition
+//~| WARN trait objects without an explicit `dyn` are deprecated
+//~| WARN this is accepted in the current edition
fn main() {}
diff --git a/src/test/ui/lint/force-warn/allowed-group-warn-by-default-lint.stderr b/src/test/ui/lint/force-warn/allowed-group-warn-by-default-lint.stderr
index d945cc3347a..99d97ba52a0 100644
--- a/src/test/ui/lint/force-warn/allowed-group-warn-by-default-lint.stderr
+++ b/src/test/ui/lint/force-warn/allowed-group-warn-by-default-lint.stderr
@@ -2,11 +2,44 @@ warning: trait objects without an explicit `dyn` are deprecated
--> $DIR/allowed-group-warn-by-default-lint.rs:10:25
|
LL | pub fn function(_x: Box<SomeTrait>) {}
- | ^^^^^^^^^ help: use `dyn`: `dyn SomeTrait`
+ | ^^^^^^^^^
|
= note: requested on the command line with `--force-warn bare-trait-objects`
= warning: this is accepted in the current edition (Rust 2015) but is a hard error in Rust 2021!
= note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2021/warnings-promoted-to-error.html>
+help: use `dyn`
+ |
+LL - pub fn function(_x: Box<SomeTrait>) {}
+LL + pub fn function(_x: Box<dyn SomeTrait>) {}
+ |
+
+warning: trait objects without an explicit `dyn` are deprecated
+ --> $DIR/allowed-group-warn-by-default-lint.rs:10:25
+ |
+LL | pub fn function(_x: Box<SomeTrait>) {}
+ | ^^^^^^^^^
+ |
+ = warning: this is accepted in the current edition (Rust 2015) but is a hard error in Rust 2021!
+ = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2021/warnings-promoted-to-error.html>
+help: use `dyn`
+ |
+LL - pub fn function(_x: Box<SomeTrait>) {}
+LL + pub fn function(_x: Box<dyn SomeTrait>) {}
+ |
+
+warning: trait objects without an explicit `dyn` are deprecated
+ --> $DIR/allowed-group-warn-by-default-lint.rs:10:25
+ |
+LL | pub fn function(_x: Box<SomeTrait>) {}
+ | ^^^^^^^^^
+ |
+ = warning: this is accepted in the current edition (Rust 2015) but is a hard error in Rust 2021!
+ = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2021/warnings-promoted-to-error.html>
+help: use `dyn`
+ |
+LL - pub fn function(_x: Box<SomeTrait>) {}
+LL + pub fn function(_x: Box<dyn SomeTrait>) {}
+ |
-warning: 1 warning emitted
+warning: 3 warnings emitted
diff --git a/src/test/ui/lint/force-warn/cap-lints-allow.rs b/src/test/ui/lint/force-warn/cap-lints-allow.rs
index 9609ea99431..fdba7f4105e 100644
--- a/src/test/ui/lint/force-warn/cap-lints-allow.rs
+++ b/src/test/ui/lint/force-warn/cap-lints-allow.rs
@@ -8,5 +8,9 @@ pub trait SomeTrait {}
pub fn function(_x: Box<SomeTrait>) {}
//~^ WARN trait objects without an explicit `dyn` are deprecated
//~| WARN this is accepted in the current edition
+//~| WARN trait objects without an explicit `dyn` are deprecated
+//~| WARN this is accepted in the current edition
+//~| WARN trait objects without an explicit `dyn` are deprecated
+//~| WARN this is accepted in the current edition
fn main() {}
diff --git a/src/test/ui/lint/force-warn/cap-lints-allow.stderr b/src/test/ui/lint/force-warn/cap-lints-allow.stderr
index f3ae16b5657..90496ca7d20 100644
--- a/src/test/ui/lint/force-warn/cap-lints-allow.stderr
+++ b/src/test/ui/lint/force-warn/cap-lints-allow.stderr
@@ -2,11 +2,44 @@ warning: trait objects without an explicit `dyn` are deprecated
--> $DIR/cap-lints-allow.rs:8:25
|
LL | pub fn function(_x: Box<SomeTrait>) {}
- | ^^^^^^^^^ help: use `dyn`: `dyn SomeTrait`
+ | ^^^^^^^^^
|
= note: requested on the command line with `--force-warn bare-trait-objects`
= warning: this is accepted in the current edition (Rust 2015) but is a hard error in Rust 2021!
= note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2021/warnings-promoted-to-error.html>
+help: use `dyn`
+ |
+LL - pub fn function(_x: Box<SomeTrait>) {}
+LL + pub fn function(_x: Box<dyn SomeTrait>) {}
+ |
+
+warning: trait objects without an explicit `dyn` are deprecated
+ --> $DIR/cap-lints-allow.rs:8:25
+ |
+LL | pub fn function(_x: Box<SomeTrait>) {}
+ | ^^^^^^^^^
+ |
+ = warning: this is accepted in the current edition (Rust 2015) but is a hard error in Rust 2021!
+ = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2021/warnings-promoted-to-error.html>
+help: use `dyn`
+ |
+LL - pub fn function(_x: Box<SomeTrait>) {}
+LL + pub fn function(_x: Box<dyn SomeTrait>) {}
+ |
+
+warning: trait objects without an explicit `dyn` are deprecated
+ --> $DIR/cap-lints-allow.rs:8:25
+ |
+LL | pub fn function(_x: Box<SomeTrait>) {}
+ | ^^^^^^^^^
+ |
+ = warning: this is accepted in the current edition (Rust 2015) but is a hard error in Rust 2021!
+ = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2021/warnings-promoted-to-error.html>
+help: use `dyn`
+ |
+LL - pub fn function(_x: Box<SomeTrait>) {}
+LL + pub fn function(_x: Box<dyn SomeTrait>) {}
+ |
-warning: 1 warning emitted
+warning: 3 warnings emitted
diff --git a/src/test/ui/lint/force-warn/lint-group-allowed-cli-warn-by-default-lint.rs b/src/test/ui/lint/force-warn/lint-group-allowed-cli-warn-by-default-lint.rs
index 9736027452a..7ad7462ddc5 100644
--- a/src/test/ui/lint/force-warn/lint-group-allowed-cli-warn-by-default-lint.rs
+++ b/src/test/ui/lint/force-warn/lint-group-allowed-cli-warn-by-default-lint.rs
@@ -8,5 +8,9 @@ pub trait SomeTrait {}
pub fn function(_x: Box<SomeTrait>) {}
//~^ WARN trait objects without an explicit `dyn` are deprecated
//~| WARN this is accepted in the current edition
+//~| WARN trait objects without an explicit `dyn` are deprecated
+//~| WARN this is accepted in the current edition
+//~| WARN trait objects without an explicit `dyn` are deprecated
+//~| WARN this is accepted in the current edition
fn main() {}
diff --git a/src/test/ui/lint/force-warn/lint-group-allowed-cli-warn-by-default-lint.stderr b/src/test/ui/lint/force-warn/lint-group-allowed-cli-warn-by-default-lint.stderr
index dc62521bf89..b6d36eaac44 100644
--- a/src/test/ui/lint/force-warn/lint-group-allowed-cli-warn-by-default-lint.stderr
+++ b/src/test/ui/lint/force-warn/lint-group-allowed-cli-warn-by-default-lint.stderr
@@ -2,11 +2,44 @@ warning: trait objects without an explicit `dyn` are deprecated
--> $DIR/lint-group-allowed-cli-warn-by-default-lint.rs:8:25
|
LL | pub fn function(_x: Box<SomeTrait>) {}
- | ^^^^^^^^^ help: use `dyn`: `dyn SomeTrait`
+ | ^^^^^^^^^
|
= note: `--force-warn bare-trait-objects` implied by `--force-warn rust-2018-idioms`
= warning: this is accepted in the current edition (Rust 2015) but is a hard error in Rust 2021!
= note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2021/warnings-promoted-to-error.html>
+help: use `dyn`
+ |
+LL - pub fn function(_x: Box<SomeTrait>) {}
+LL + pub fn function(_x: Box<dyn SomeTrait>) {}
+ |
+
+warning: trait objects without an explicit `dyn` are deprecated
+ --> $DIR/lint-group-allowed-cli-warn-by-default-lint.rs:8:25
+ |
+LL | pub fn function(_x: Box<SomeTrait>) {}
+ | ^^^^^^^^^
+ |
+ = warning: this is accepted in the current edition (Rust 2015) but is a hard error in Rust 2021!
+ = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2021/warnings-promoted-to-error.html>
+help: use `dyn`
+ |
+LL - pub fn function(_x: Box<SomeTrait>) {}
+LL + pub fn function(_x: Box<dyn SomeTrait>) {}
+ |
+
+warning: trait objects without an explicit `dyn` are deprecated
+ --> $DIR/lint-group-allowed-cli-warn-by-default-lint.rs:8:25
+ |
+LL | pub fn function(_x: Box<SomeTrait>) {}
+ | ^^^^^^^^^
+ |
+ = warning: this is accepted in the current edition (Rust 2015) but is a hard error in Rust 2021!
+ = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2021/warnings-promoted-to-error.html>
+help: use `dyn`
+ |
+LL - pub fn function(_x: Box<SomeTrait>) {}
+LL + pub fn function(_x: Box<dyn SomeTrait>) {}
+ |
-warning: 1 warning emitted
+warning: 3 warnings emitted
diff --git a/src/test/ui/lint/force-warn/lint-group-allowed-lint-group.rs b/src/test/ui/lint/force-warn/lint-group-allowed-lint-group.rs
index 99cad614c25..ee5a18c3829 100644
--- a/src/test/ui/lint/force-warn/lint-group-allowed-lint-group.rs
+++ b/src/test/ui/lint/force-warn/lint-group-allowed-lint-group.rs
@@ -10,5 +10,9 @@ pub trait SomeTrait {}
pub fn function(_x: Box<SomeTrait>) {}
//~^ WARN trait objects without an explicit `dyn` are deprecated
//~| WARN this is accepted in the current edition
+//~| WARN trait objects without an explicit `dyn` are deprecated
+//~| WARN this is accepted in the current edition
+//~| WARN trait objects without an explicit `dyn` are deprecated
+//~| WARN this is accepted in the current edition
fn main() {}
diff --git a/src/test/ui/lint/force-warn/lint-group-allowed-lint-group.stderr b/src/test/ui/lint/force-warn/lint-group-allowed-lint-group.stderr
index fcbae024eb6..e8fdaa72cc0 100644
--- a/src/test/ui/lint/force-warn/lint-group-allowed-lint-group.stderr
+++ b/src/test/ui/lint/force-warn/lint-group-allowed-lint-group.stderr
@@ -2,11 +2,44 @@ warning: trait objects without an explicit `dyn` are deprecated
--> $DIR/lint-group-allowed-lint-group.rs:10:25
|
LL | pub fn function(_x: Box<SomeTrait>) {}
- | ^^^^^^^^^ help: use `dyn`: `dyn SomeTrait`
+ | ^^^^^^^^^
|
= note: `--force-warn bare-trait-objects` implied by `--force-warn rust-2018-idioms`
= warning: this is accepted in the current edition (Rust 2015) but is a hard error in Rust 2021!
= note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2021/warnings-promoted-to-error.html>
+help: use `dyn`
+ |
+LL - pub fn function(_x: Box<SomeTrait>) {}
+LL + pub fn function(_x: Box<dyn SomeTrait>) {}
+ |
+
+warning: trait objects without an explicit `dyn` are deprecated
+ --> $DIR/lint-group-allowed-lint-group.rs:10:25
+ |
+LL | pub fn function(_x: Box<SomeTrait>) {}
+ | ^^^^^^^^^
+ |
+ = warning: this is accepted in the current edition (Rust 2015) but is a hard error in Rust 2021!
+ = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2021/warnings-promoted-to-error.html>
+help: use `dyn`
+ |
+LL - pub fn function(_x: Box<SomeTrait>) {}
+LL + pub fn function(_x: Box<dyn SomeTrait>) {}
+ |
+
+warning: trait objects without an explicit `dyn` are deprecated
+ --> $DIR/lint-group-allowed-lint-group.rs:10:25
+ |
+LL | pub fn function(_x: Box<SomeTrait>) {}
+ | ^^^^^^^^^
+ |
+ = warning: this is accepted in the current edition (Rust 2015) but is a hard error in Rust 2021!
+ = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2021/warnings-promoted-to-error.html>
+help: use `dyn`
+ |
+LL - pub fn function(_x: Box<SomeTrait>) {}
+LL + pub fn function(_x: Box<dyn SomeTrait>) {}
+ |
-warning: 1 warning emitted
+warning: 3 warnings emitted
diff --git a/src/test/ui/lint/force-warn/lint-group-allowed-warn-by-default-lint.rs b/src/test/ui/lint/force-warn/lint-group-allowed-warn-by-default-lint.rs
index f0aacd77340..248aece6fe7 100644
--- a/src/test/ui/lint/force-warn/lint-group-allowed-warn-by-default-lint.rs
+++ b/src/test/ui/lint/force-warn/lint-group-allowed-warn-by-default-lint.rs
@@ -10,5 +10,9 @@ pub trait SomeTrait {}
pub fn function(_x: Box<SomeTrait>) {}
//~^ WARN trait objects without an explicit `dyn` are deprecated
//~| WARN this is accepted in the current edition
+//~| WARN trait objects without an explicit `dyn` are deprecated
+//~| WARN this is accepted in the current edition
+//~| WARN trait objects without an explicit `dyn` are deprecated
+//~| WARN this is accepted in the current edition
fn main() {}
diff --git a/src/test/ui/lint/force-warn/lint-group-allowed-warn-by-default-lint.stderr b/src/test/ui/lint/force-warn/lint-group-allowed-warn-by-default-lint.stderr
index 1212ae083c2..2de30d0c2f4 100644
--- a/src/test/ui/lint/force-warn/lint-group-allowed-warn-by-default-lint.stderr
+++ b/src/test/ui/lint/force-warn/lint-group-allowed-warn-by-default-lint.stderr
@@ -2,11 +2,44 @@ warning: trait objects without an explicit `dyn` are deprecated
--> $DIR/lint-group-allowed-warn-by-default-lint.rs:10:25
|
LL | pub fn function(_x: Box<SomeTrait>) {}
- | ^^^^^^^^^ help: use `dyn`: `dyn SomeTrait`
+ | ^^^^^^^^^
|
= note: `--force-warn bare-trait-objects` implied by `--force-warn rust-2018-idioms`
= warning: this is accepted in the current edition (Rust 2015) but is a hard error in Rust 2021!
= note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2021/warnings-promoted-to-error.html>
+help: use `dyn`
+ |
+LL - pub fn function(_x: Box<SomeTrait>) {}
+LL + pub fn function(_x: Box<dyn SomeTrait>) {}
+ |
+
+warning: trait objects without an explicit `dyn` are deprecated
+ --> $DIR/lint-group-allowed-warn-by-default-lint.rs:10:25
+ |
+LL | pub fn function(_x: Box<SomeTrait>) {}
+ | ^^^^^^^^^
+ |
+ = warning: this is accepted in the current edition (Rust 2015) but is a hard error in Rust 2021!
+ = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2021/warnings-promoted-to-error.html>
+help: use `dyn`
+ |
+LL - pub fn function(_x: Box<SomeTrait>) {}
+LL + pub fn function(_x: Box<dyn SomeTrait>) {}
+ |
+
+warning: trait objects without an explicit `dyn` are deprecated
+ --> $DIR/lint-group-allowed-warn-by-default-lint.rs:10:25
+ |
+LL | pub fn function(_x: Box<SomeTrait>) {}
+ | ^^^^^^^^^
+ |
+ = warning: this is accepted in the current edition (Rust 2015) but is a hard error in Rust 2021!
+ = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2021/warnings-promoted-to-error.html>
+help: use `dyn`
+ |
+LL - pub fn function(_x: Box<SomeTrait>) {}
+LL + pub fn function(_x: Box<dyn SomeTrait>) {}
+ |
-warning: 1 warning emitted
+warning: 3 warnings emitted
diff --git a/src/test/ui/lint/future-incompat-test.rs b/src/test/ui/lint/future-incompat-test.rs
index ce8c118dab2..c5f477cc450 100644
--- a/src/test/ui/lint/future-incompat-test.rs
+++ b/src/test/ui/lint/future-incompat-test.rs
@@ -1,4 +1,4 @@
-// compile-flags: -Zfuture-incompat-test -Zemit-future-incompat-report
+// compile-flags: -Zfuture-incompat-test
// check-pass
// The `-Zfuture-incompat-test flag causes any normal warning to be included
diff --git a/src/test/ui/lint/issue-87308.stdout b/src/test/ui/lint/issue-87308.stdout
index 68a076c93be..4f81ee8b7e6 100644
--- a/src/test/ui/lint/issue-87308.stdout
+++ b/src/test/ui/lint/issue-87308.stdout
@@ -11,4 +11,4 @@ extern crate std;
macro_rules! foo { () => { break 'x ; } }
-pub fn main() { loop { } }
+pub fn main() { loop {} }
diff --git a/src/test/ui/lint/lint-ctypes-73251-2.rs b/src/test/ui/lint/lint-ctypes-73251-2.rs
index 79effd054b0..717ca4986f7 100644
--- a/src/test/ui/lint/lint-ctypes-73251-2.rs
+++ b/src/test/ui/lint/lint-ctypes-73251-2.rs
@@ -33,7 +33,7 @@ fn use_of_b() -> AliasB {
}
extern "C" {
- pub fn lint_me() -> <AliasB as TraitB>::Assoc; //~ ERROR: uses type `impl TraitA`
+ pub fn lint_me() -> <AliasB as TraitB>::Assoc; //~ ERROR: uses type `impl TraitA<Assoc = u32>`
}
fn main() {}
diff --git a/src/test/ui/lint/lint-ctypes-73251-2.stderr b/src/test/ui/lint/lint-ctypes-73251-2.stderr
index 94ee95d422e..d7e10db441e 100644
--- a/src/test/ui/lint/lint-ctypes-73251-2.stderr
+++ b/src/test/ui/lint/lint-ctypes-73251-2.stderr
@@ -1,4 +1,4 @@
-error: `extern` block uses type `impl TraitA`, which is not FFI-safe
+error: `extern` block uses type `impl TraitA<Assoc = u32>`, which is not FFI-safe
--> $DIR/lint-ctypes-73251-2.rs:36:25
|
LL | pub fn lint_me() -> <AliasB as TraitB>::Assoc;
diff --git a/src/test/ui/lint/must_not_suspend/boxed.stderr b/src/test/ui/lint/must_not_suspend/boxed.stderr
index edc62b6d687..b3c9b43810c 100644
--- a/src/test/ui/lint/must_not_suspend/boxed.stderr
+++ b/src/test/ui/lint/must_not_suspend/boxed.stderr
@@ -4,7 +4,7 @@ error: boxed `Umm` held across a suspend point, but should not be
LL | let _guard = bar();
| ^^^^^^
LL | other().await;
- | ------------- the value is held across this suspend point
+ | ------ the value is held across this suspend point
|
note: the lint level is defined here
--> $DIR/boxed.rs:3:9
diff --git a/src/test/ui/lint/must_not_suspend/dedup.stderr b/src/test/ui/lint/must_not_suspend/dedup.stderr
index 542b7a3bc7e..bc1b611299a 100644
--- a/src/test/ui/lint/must_not_suspend/dedup.stderr
+++ b/src/test/ui/lint/must_not_suspend/dedup.stderr
@@ -2,7 +2,7 @@ error: `No` held across a suspend point, but should not be
--> $DIR/dedup.rs:16:12
|
LL | wheeee(No {}).await;
- | -------^^^^^------- the value is held across this suspend point
+ | ^^^^^ ------ the value is held across this suspend point
|
note: the lint level is defined here
--> $DIR/dedup.rs:3:9
diff --git a/src/test/ui/lint/must_not_suspend/gated.stderr b/src/test/ui/lint/must_not_suspend/gated.stderr
index be077deb3f1..0d4319670e6 100644
--- a/src/test/ui/lint/must_not_suspend/gated.stderr
+++ b/src/test/ui/lint/must_not_suspend/gated.stderr
@@ -31,7 +31,7 @@ error: `MutexGuard` held across a suspend point, but should not be
LL | let _guard = m.lock().unwrap();
| ^^^^^^
LL | other().await;
- | ------------- the value is held across this suspend point
+ | ------ the value is held across this suspend point
|
note: the lint level is defined here
--> $DIR/gated.rs:2:9
diff --git a/src/test/ui/lint/must_not_suspend/mutex.stderr b/src/test/ui/lint/must_not_suspend/mutex.stderr
index dde506c19e7..a968b7ca033 100644
--- a/src/test/ui/lint/must_not_suspend/mutex.stderr
+++ b/src/test/ui/lint/must_not_suspend/mutex.stderr
@@ -4,7 +4,7 @@ error: `MutexGuard` held across a suspend point, but should not be
LL | let _guard = m.lock().unwrap();
| ^^^^^^
LL | other().await;
- | ------------- the value is held across this suspend point
+ | ------ the value is held across this suspend point
|
note: the lint level is defined here
--> $DIR/mutex.rs:3:9
diff --git a/src/test/ui/lint/must_not_suspend/ref.stderr b/src/test/ui/lint/must_not_suspend/ref.stderr
index 78b44b00625..6d30f134ec4 100644
--- a/src/test/ui/lint/must_not_suspend/ref.stderr
+++ b/src/test/ui/lint/must_not_suspend/ref.stderr
@@ -5,7 +5,7 @@ LL | let guard = &mut self.u;
| ^^^^^^
LL |
LL | other().await;
- | ------------- the value is held across this suspend point
+ | ------ the value is held across this suspend point
|
note: the lint level is defined here
--> $DIR/ref.rs:3:9
diff --git a/src/test/ui/lint/must_not_suspend/trait.stderr b/src/test/ui/lint/must_not_suspend/trait.stderr
index d19ffddd482..dd3978b02a8 100644
--- a/src/test/ui/lint/must_not_suspend/trait.stderr
+++ b/src/test/ui/lint/must_not_suspend/trait.stderr
@@ -5,7 +5,7 @@ LL | let _guard1 = r#impl();
| ^^^^^^^
...
LL | other().await;
- | ------------- the value is held across this suspend point
+ | ------ the value is held across this suspend point
|
note: the lint level is defined here
--> $DIR/trait.rs:3:9
@@ -25,7 +25,7 @@ LL | let _guard2 = r#dyn();
| ^^^^^^^
LL |
LL | other().await;
- | ------------- the value is held across this suspend point
+ | ------ the value is held across this suspend point
|
help: consider using a block (`{ ... }`) to shrink the value's scope, ending before the suspend point
--> $DIR/trait.rs:22:9
diff --git a/src/test/ui/lint/must_not_suspend/unit.stderr b/src/test/ui/lint/must_not_suspend/unit.stderr
index 425c076823d..42d037b350b 100644
--- a/src/test/ui/lint/must_not_suspend/unit.stderr
+++ b/src/test/ui/lint/must_not_suspend/unit.stderr
@@ -4,7 +4,7 @@ error: `Umm` held across a suspend point, but should not be
LL | let _guard = bar();
| ^^^^^^
LL | other().await;
- | ------------- the value is held across this suspend point
+ | ------ the value is held across this suspend point
|
note: the lint level is defined here
--> $DIR/unit.rs:3:9
diff --git a/src/test/ui/lint/must_not_suspend/warn.stderr b/src/test/ui/lint/must_not_suspend/warn.stderr
index 42374d4acac..417c397dad0 100644
--- a/src/test/ui/lint/must_not_suspend/warn.stderr
+++ b/src/test/ui/lint/must_not_suspend/warn.stderr
@@ -4,7 +4,7 @@ warning: `Umm` held across a suspend point, but should not be
LL | let _guard = bar();
| ^^^^^^
LL | other().await;
- | ------------- the value is held across this suspend point
+ | ------ the value is held across this suspend point
|
note: the lint level is defined here
--> $DIR/warn.rs:4:9
diff --git a/src/test/ui/lint/opaque-ty-ffi-unsafe.rs b/src/test/ui/lint/opaque-ty-ffi-unsafe.rs
index fadb7471952..3a62b6a21a5 100644
--- a/src/test/ui/lint/opaque-ty-ffi-unsafe.rs
+++ b/src/test/ui/lint/opaque-ty-ffi-unsafe.rs
@@ -9,7 +9,7 @@ pub fn ret_closure() -> A {
extern "C" {
pub fn a(_: A);
- //~^ ERROR `extern` block uses type `impl Fn<()>`, which is not FFI-safe
+ //~^ ERROR `extern` block uses type `impl Fn()`, which is not FFI-safe [improper_ctypes]
}
fn main() {}
diff --git a/src/test/ui/lint/opaque-ty-ffi-unsafe.stderr b/src/test/ui/lint/opaque-ty-ffi-unsafe.stderr
index 9d46f6d936e..5afbef778b3 100644
--- a/src/test/ui/lint/opaque-ty-ffi-unsafe.stderr
+++ b/src/test/ui/lint/opaque-ty-ffi-unsafe.stderr
@@ -1,4 +1,4 @@
-error: `extern` block uses type `impl Fn<()>`, which is not FFI-safe
+error: `extern` block uses type `impl Fn()`, which is not FFI-safe
--> $DIR/opaque-ty-ffi-unsafe.rs:11:17
|
LL | pub fn a(_: A);
diff --git a/src/test/ui/lint/reasons.rs b/src/test/ui/lint/reasons.rs
index 34cac4968a8..b1792e2e9cb 100644
--- a/src/test/ui/lint/reasons.rs
+++ b/src/test/ui/lint/reasons.rs
@@ -1,7 +1,6 @@
// check-pass
#![feature(lint_reasons)]
-
#![warn(elided_lifetimes_in_paths,
//~^ NOTE the lint level is defined here
reason = "explicit anonymous lifetimes aid reasoning about ownership")]
@@ -20,8 +19,9 @@ pub struct CheaterDetectionMechanism {}
impl fmt::Debug for CheaterDetectionMechanism {
fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
//~^ WARN hidden lifetime parameters in types are deprecated
+ //~| NOTE expected named lifetime parameter
//~| NOTE explicit anonymous lifetimes aid
- //~| HELP indicate the anonymous lifetime
+ //~| HELP consider using the `'_` lifetime
fmt.debug_struct("CheaterDetectionMechanism").finish()
}
}
diff --git a/src/test/ui/lint/reasons.stderr b/src/test/ui/lint/reasons.stderr
index 150237c6be2..f797c89a032 100644
--- a/src/test/ui/lint/reasons.stderr
+++ b/src/test/ui/lint/reasons.stderr
@@ -1,15 +1,19 @@
warning: hidden lifetime parameters in types are deprecated
- --> $DIR/reasons.rs:21:29
+ --> $DIR/reasons.rs:20:29
|
LL | fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
- | ^^^^^^^^^^^^^^- help: indicate the anonymous lifetime: `<'_>`
+ | ^^^^^^^^^^^^^^ expected named lifetime parameter
|
= note: explicit anonymous lifetimes aid reasoning about ownership
note: the lint level is defined here
- --> $DIR/reasons.rs:5:9
+ --> $DIR/reasons.rs:4:9
|
LL | #![warn(elided_lifetimes_in_paths,
| ^^^^^^^^^^^^^^^^^^^^^^^^^
+help: consider using the `'_` lifetime
+ |
+LL | fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
+ | ~~~~~~~~~~~~~~~~~~
warning: variable `Social_exchange_psychology` should have a snake case name
--> $DIR/reasons.rs:30:9
@@ -20,7 +24,7 @@ LL | let Social_exchange_psychology = CheaterDetectionMechanism {};
= note: people shouldn't have to change their usual style habits
to contribute to our project
note: the lint level is defined here
- --> $DIR/reasons.rs:9:5
+ --> $DIR/reasons.rs:8:5
|
LL | nonstandard_style,
| ^^^^^^^^^^^^^^^^^
diff --git a/src/test/ui/lint/unaligned_references.stderr b/src/test/ui/lint/unaligned_references.stderr
index 6a5cc91963d..53c9380fb7e 100644
--- a/src/test/ui/lint/unaligned_references.stderr
+++ b/src/test/ui/lint/unaligned_references.stderr
@@ -12,6 +12,7 @@ LL | #![deny(unaligned_references)]
= warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
= note: for more information, see issue #82523 <https://github.com/rust-lang/rust/issues/82523>
= note: fields of packed structs are not properly aligned, and creating a misaligned reference is undefined behavior (even if that reference is never dereferenced)
+ = help: copy the field contents to a local variable, or replace the reference with a raw pointer and use `read_unaligned`/`write_unaligned` (loads and stores via `*p` must be properly aligned even when using raw pointers)
error: reference to packed field is unaligned
--> $DIR/unaligned_references.rs:24:17
@@ -22,6 +23,7 @@ LL | let _ = &good.data;
= warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
= note: for more information, see issue #82523 <https://github.com/rust-lang/rust/issues/82523>
= note: fields of packed structs are not properly aligned, and creating a misaligned reference is undefined behavior (even if that reference is never dereferenced)
+ = help: copy the field contents to a local variable, or replace the reference with a raw pointer and use `read_unaligned`/`write_unaligned` (loads and stores via `*p` must be properly aligned even when using raw pointers)
error: reference to packed field is unaligned
--> $DIR/unaligned_references.rs:27:17
@@ -32,6 +34,7 @@ LL | let _ = &good.data as *const _;
= warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
= note: for more information, see issue #82523 <https://github.com/rust-lang/rust/issues/82523>
= note: fields of packed structs are not properly aligned, and creating a misaligned reference is undefined behavior (even if that reference is never dereferenced)
+ = help: copy the field contents to a local variable, or replace the reference with a raw pointer and use `read_unaligned`/`write_unaligned` (loads and stores via `*p` must be properly aligned even when using raw pointers)
error: reference to packed field is unaligned
--> $DIR/unaligned_references.rs:29:27
@@ -42,6 +45,7 @@ LL | let _: *const _ = &good.data;
= warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
= note: for more information, see issue #82523 <https://github.com/rust-lang/rust/issues/82523>
= note: fields of packed structs are not properly aligned, and creating a misaligned reference is undefined behavior (even if that reference is never dereferenced)
+ = help: copy the field contents to a local variable, or replace the reference with a raw pointer and use `read_unaligned`/`write_unaligned` (loads and stores via `*p` must be properly aligned even when using raw pointers)
error: reference to packed field is unaligned
--> $DIR/unaligned_references.rs:32:17
@@ -52,6 +56,7 @@ LL | let _ = good.data.clone();
= warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
= note: for more information, see issue #82523 <https://github.com/rust-lang/rust/issues/82523>
= note: fields of packed structs are not properly aligned, and creating a misaligned reference is undefined behavior (even if that reference is never dereferenced)
+ = help: copy the field contents to a local variable, or replace the reference with a raw pointer and use `read_unaligned`/`write_unaligned` (loads and stores via `*p` must be properly aligned even when using raw pointers)
error: reference to packed field is unaligned
--> $DIR/unaligned_references.rs:35:17
@@ -62,6 +67,7 @@ LL | let _ = &good.data2[0];
= warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
= note: for more information, see issue #82523 <https://github.com/rust-lang/rust/issues/82523>
= note: fields of packed structs are not properly aligned, and creating a misaligned reference is undefined behavior (even if that reference is never dereferenced)
+ = help: copy the field contents to a local variable, or replace the reference with a raw pointer and use `read_unaligned`/`write_unaligned` (loads and stores via `*p` must be properly aligned even when using raw pointers)
error: reference to packed field is unaligned
--> $DIR/unaligned_references.rs:45:17
@@ -72,6 +78,7 @@ LL | let _ = &packed2.x;
= warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
= note: for more information, see issue #82523 <https://github.com/rust-lang/rust/issues/82523>
= note: fields of packed structs are not properly aligned, and creating a misaligned reference is undefined behavior (even if that reference is never dereferenced)
+ = help: copy the field contents to a local variable, or replace the reference with a raw pointer and use `read_unaligned`/`write_unaligned` (loads and stores via `*p` must be properly aligned even when using raw pointers)
error: aborting due to 7 previous errors
diff --git a/src/test/ui/lint/unaligned_references_external_macro.stderr b/src/test/ui/lint/unaligned_references_external_macro.stderr
index 5e84fdca1d3..01e2395049d 100644
--- a/src/test/ui/lint/unaligned_references_external_macro.stderr
+++ b/src/test/ui/lint/unaligned_references_external_macro.stderr
@@ -24,6 +24,7 @@ LL | | }
= warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
= note: for more information, see issue #82523 <https://github.com/rust-lang/rust/issues/82523>
= note: fields of packed structs are not properly aligned, and creating a misaligned reference is undefined behavior (even if that reference is never dereferenced)
+ = help: copy the field contents to a local variable, or replace the reference with a raw pointer and use `read_unaligned`/`write_unaligned` (loads and stores via `*p` must be properly aligned even when using raw pointers)
= note: this error originates in the macro `unaligned_references_external_crate::mac` (in Nightly builds, run with -Z macro-backtrace for more info)
error: aborting due to previous error
diff --git a/src/test/ui/lint/unused/issue-90807-unused-paren-error.rs b/src/test/ui/lint/unused/issue-90807-unused-paren-error.rs
new file mode 100644
index 00000000000..2fca2e26265
--- /dev/null
+++ b/src/test/ui/lint/unused/issue-90807-unused-paren-error.rs
@@ -0,0 +1,9 @@
+// Make sure unused parens lint emit is emitted for loop and match.
+// See https://github.com/rust-lang/rust/issues/90807
+// and https://github.com/rust-lang/rust/pull/91956#discussion_r771647953
+#![deny(unused_parens)]
+
+fn main() {
+ for _ in (1..loop { break 2 }) {} //~ERROR
+ for _ in (1..match () { () => 2 }) {} //~ERROR
+}
diff --git a/src/test/ui/lint/unused/issue-90807-unused-paren-error.stderr b/src/test/ui/lint/unused/issue-90807-unused-paren-error.stderr
new file mode 100644
index 00000000000..4e158e126ac
--- /dev/null
+++ b/src/test/ui/lint/unused/issue-90807-unused-paren-error.stderr
@@ -0,0 +1,31 @@
+error: unnecessary parentheses around `for` iterator expression
+ --> $DIR/issue-90807-unused-paren-error.rs:7:14
+ |
+LL | for _ in (1..loop { break 2 }) {}
+ | ^ ^
+ |
+note: the lint level is defined here
+ --> $DIR/issue-90807-unused-paren-error.rs:4:9
+ |
+LL | #![deny(unused_parens)]
+ | ^^^^^^^^^^^^^
+help: remove these parentheses
+ |
+LL - for _ in (1..loop { break 2 }) {}
+LL + for _ in 1..loop { break 2 } {}
+ |
+
+error: unnecessary parentheses around `for` iterator expression
+ --> $DIR/issue-90807-unused-paren-error.rs:8:14
+ |
+LL | for _ in (1..match () { () => 2 }) {}
+ | ^ ^
+ |
+help: remove these parentheses
+ |
+LL - for _ in (1..match () { () => 2 }) {}
+LL + for _ in 1..match () { () => 2 } {}
+ |
+
+error: aborting due to 2 previous errors
+
diff --git a/src/test/ui/lint/unused/issue-90807-unused-paren.rs b/src/test/ui/lint/unused/issue-90807-unused-paren.rs
new file mode 100644
index 00000000000..4c0930f967d
--- /dev/null
+++ b/src/test/ui/lint/unused/issue-90807-unused-paren.rs
@@ -0,0 +1,8 @@
+// check-pass
+// Make sure unused parens lint doesn't emit a false positive.
+// See https://github.com/rust-lang/rust/issues/90807
+#![deny(unused_parens)]
+
+fn main() {
+ for _ in (1..{ 2 }) {}
+}
diff --git a/src/test/ui/lint/unused/unused-doc-comments-edge-cases.rs b/src/test/ui/lint/unused/unused-doc-comments-edge-cases.rs
index fd9baf8c6b9..258f9e4831f 100644
--- a/src/test/ui/lint/unused/unused-doc-comments-edge-cases.rs
+++ b/src/test/ui/lint/unused/unused-doc-comments-edge-cases.rs
@@ -26,4 +26,7 @@ fn doc_comment_on_expr(num: u8) -> bool {
num == 3
}
+fn doc_comment_on_generic<#[doc = "x"] T>(val: T) {}
+//~^ ERROR: unused doc comment
+
fn main() {}
diff --git a/src/test/ui/lint/unused/unused-doc-comments-edge-cases.stderr b/src/test/ui/lint/unused/unused-doc-comments-edge-cases.stderr
index 403367017c6..3ce1df71a2e 100644
--- a/src/test/ui/lint/unused/unused-doc-comments-edge-cases.stderr
+++ b/src/test/ui/lint/unused/unused-doc-comments-edge-cases.stderr
@@ -41,6 +41,14 @@ LL | num == 3
|
= help: use `//` for a plain comment
+error: unused doc comment
+ --> $DIR/unused-doc-comments-edge-cases.rs:29:27
+ |
+LL | fn doc_comment_on_generic<#[doc = "x"] T>(val: T) {}
+ | ^^^^^^^^^^^^ - rustdoc does not generate documentation for generic parameters
+ |
+ = help: use `//` for a plain comment
+
error[E0308]: mismatched types
--> $DIR/unused-doc-comments-edge-cases.rs:14:9
|
@@ -55,7 +63,7 @@ help: you might have meant to return this value
LL | return true;
| ++++++ +
-error: aborting due to 5 previous errors
+error: aborting due to 6 previous errors
Some errors have detailed explanations: E0308, E0658.
For more information about an error, try `rustc --explain E0308`.
diff --git a/src/test/ui/lint/unused/unused-result.rs b/src/test/ui/lint/unused/unused-result.rs
index a65e98990dc..e283eaa88dd 100644
--- a/src/test/ui/lint/unused/unused-result.rs
+++ b/src/test/ui/lint/unused/unused-result.rs
@@ -31,7 +31,7 @@ fn test2() {
}
fn main() {
- foo::<isize>(); //~ ERROR: unused result
+ foo::<isize>(); //~ ERROR: unused result of type `isize`
foo::<MustUse>(); //~ ERROR: unused `MustUse` that must be used
foo::<MustUseMsg>(); //~ ERROR: unused `MustUseMsg` that must be used
//~^ NOTE: some message
diff --git a/src/test/ui/lint/unused/unused-result.stderr b/src/test/ui/lint/unused/unused-result.stderr
index 1b1dcab3a1b..087e06341cd 100644
--- a/src/test/ui/lint/unused/unused-result.stderr
+++ b/src/test/ui/lint/unused/unused-result.stderr
@@ -18,7 +18,7 @@ LL | foo::<MustUseMsg>();
|
= note: some message
-error: unused result
+error: unused result of type `isize`
--> $DIR/unused-result.rs:34:5
|
LL | foo::<isize>();
diff --git a/src/test/ui/liveness/liveness-asm.rs b/src/test/ui/liveness/liveness-asm.rs
index b51da0e0d8c..ea5f033cb86 100644
--- a/src/test/ui/liveness/liveness-asm.rs
+++ b/src/test/ui/liveness/liveness-asm.rs
@@ -3,11 +3,12 @@
// only-x86_64
// check-pass
-#![feature(asm)]
#![allow(dead_code)]
#![warn(unused_assignments)]
#![warn(unused_variables)]
+use std::arch::asm;
+
// Test the single inout case
unsafe fn f1(mut src: *const u8) {
asm!("/*{0}*/", inout(reg) src); //~ WARN value assigned to `src` is never read
diff --git a/src/test/ui/liveness/liveness-asm.stderr b/src/test/ui/liveness/liveness-asm.stderr
index f385d7a8065..d052aca338c 100644
--- a/src/test/ui/liveness/liveness-asm.stderr
+++ b/src/test/ui/liveness/liveness-asm.stderr
@@ -1,18 +1,18 @@
warning: value assigned to `src` is never read
- --> $DIR/liveness-asm.rs:13:32
+ --> $DIR/liveness-asm.rs:14:32
|
LL | asm!("/*{0}*/", inout(reg) src);
| ^^^
|
note: the lint level is defined here
- --> $DIR/liveness-asm.rs:8:9
+ --> $DIR/liveness-asm.rs:7:9
|
LL | #![warn(unused_assignments)]
| ^^^^^^^^^^^^^^^^^^
= help: maybe it is overwritten before being read?
warning: value assigned to `src` is never read
- --> $DIR/liveness-asm.rs:23:39
+ --> $DIR/liveness-asm.rs:24:39
|
LL | asm!("/*{0}*/", inout(reg) src => src);
| ^^^
diff --git a/src/test/ui/liveness/liveness-move-in-while.stderr b/src/test/ui/liveness/liveness-move-in-while.stderr
index 6a8f239bd09..ff6c02f2110 100644
--- a/src/test/ui/liveness/liveness-move-in-while.stderr
+++ b/src/test/ui/liveness/liveness-move-in-while.stderr
@@ -28,6 +28,8 @@ LL | println!("{}", y);
| ^ value borrowed here after move
LL | while true { while true { while true { x = y; x.clone(); } } }
| - value moved here, in previous iteration of loop
+ |
+ = note: this error originates in the macro `$crate::format_args_nl` (in Nightly builds, run with -Z macro-backtrace for more info)
error: aborting due to previous error; 3 warnings emitted
diff --git a/src/test/ui/liveness/liveness-use-after-move.stderr b/src/test/ui/liveness/liveness-use-after-move.stderr
index 292ce013dcc..df54af9f0f2 100644
--- a/src/test/ui/liveness/liveness-use-after-move.stderr
+++ b/src/test/ui/liveness/liveness-use-after-move.stderr
@@ -8,6 +8,8 @@ LL | let y = x;
LL |
LL | println!("{}", *x);
| ^^ value borrowed here after move
+ |
+ = note: this error originates in the macro `$crate::format_args_nl` (in Nightly builds, run with -Z macro-backtrace for more info)
error: aborting due to previous error
diff --git a/src/test/ui/liveness/liveness-use-after-send.stderr b/src/test/ui/liveness/liveness-use-after-send.stderr
index 50ae98ca9be..becede1ceb6 100644
--- a/src/test/ui/liveness/liveness-use-after-send.stderr
+++ b/src/test/ui/liveness/liveness-use-after-send.stderr
@@ -7,6 +7,8 @@ LL | send(ch, message);
| ------- value moved here
LL | println!("{}", message);
| ^^^^^^^ value borrowed here after move
+ |
+ = note: this error originates in the macro `$crate::format_args_nl` (in Nightly builds, run with -Z macro-backtrace for more info)
error: aborting due to previous error
diff --git a/src/test/ui/loops/loop-proper-liveness.stderr b/src/test/ui/loops/loop-proper-liveness.stderr
index d55f9ff31e3..20d5c66a3f2 100644
--- a/src/test/ui/loops/loop-proper-liveness.stderr
+++ b/src/test/ui/loops/loop-proper-liveness.stderr
@@ -3,6 +3,8 @@ error[E0381]: borrow of possibly-uninitialized variable: `x`
|
LL | println!("{:?}", x);
| ^ use of possibly-uninitialized `x`
+ |
+ = note: this error originates in the macro `$crate::format_args_nl` (in Nightly builds, run with -Z macro-backtrace for more info)
error: aborting due to previous error
diff --git a/src/test/ui/lto/lto-duplicate-symbols.rs b/src/test/ui/lto/lto-duplicate-symbols.rs
index 268cf261219..e540094a3ec 100644
--- a/src/test/ui/lto/lto-duplicate-symbols.rs
+++ b/src/test/ui/lto/lto-duplicate-symbols.rs
@@ -4,7 +4,7 @@
// error-pattern:Linking globals named 'foo': symbol multiply defined!
// compile-flags: -C lto
// no-prefer-dynamic
-
+// normalize-stderr-test: "lto-duplicate-symbols2\.lto_duplicate_symbols2\.[0-9a-zA-Z]+-cgu" -> "lto-duplicate-symbols2.lto_duplicate_symbols2.HASH-cgu"
extern crate lto_duplicate_symbols1;
extern crate lto_duplicate_symbols2;
diff --git a/src/test/ui/lto/lto-duplicate-symbols.stderr b/src/test/ui/lto/lto-duplicate-symbols.stderr
index e4de04ef3cc..50e6b81dcf4 100644
--- a/src/test/ui/lto/lto-duplicate-symbols.stderr
+++ b/src/test/ui/lto/lto-duplicate-symbols.stderr
@@ -1,6 +1,6 @@
warning: Linking globals named 'foo': symbol multiply defined!
-error: failed to load bc of "lto-duplicate-symbols2.lto_duplicate_symbols2.693a75b4-cgu.0.rcgu.o":
+error: failed to load bc of "lto-duplicate-symbols2.lto_duplicate_symbols2.HASH-cgu.0.rcgu.o":
error: aborting due to previous error; 1 warning emitted
diff --git a/src/test/ui/macros/concat-bytes-error.rs b/src/test/ui/macros/concat-bytes-error.rs
new file mode 100644
index 00000000000..9b4a9c2cf81
--- /dev/null
+++ b/src/test/ui/macros/concat-bytes-error.rs
@@ -0,0 +1,42 @@
+#![feature(concat_bytes)]
+
+fn main() {
+ concat_bytes!(pie); //~ ERROR expected a byte literal
+ concat_bytes!(pie, pie); //~ ERROR expected a byte literal
+ concat_bytes!("tnrsi", "tnri"); //~ ERROR cannot concatenate string literals
+ concat_bytes!(2.8); //~ ERROR cannot concatenate float literals
+ concat_bytes!(300); //~ ERROR cannot concatenate numeric literals
+ concat_bytes!('a'); //~ ERROR cannot concatenate character literals
+ concat_bytes!(true, false); //~ ERROR cannot concatenate boolean literals
+ concat_bytes!(42, b"va", b'l'); //~ ERROR cannot concatenate numeric literals
+ concat_bytes!(42, b"va", b'l', [1, 2]); //~ ERROR cannot concatenate numeric literals
+ concat_bytes!([
+ "hi", //~ ERROR cannot concatenate string literals
+ ]);
+ concat_bytes!([
+ 'a', //~ ERROR cannot concatenate character literals
+ ]);
+ concat_bytes!([
+ true, //~ ERROR cannot concatenate boolean literals
+ ]);
+ concat_bytes!([
+ false, //~ ERROR cannot concatenate boolean literals
+ ]);
+ concat_bytes!([
+ 2.6, //~ ERROR cannot concatenate float literals
+ ]);
+ concat_bytes!([
+ 265, //~ ERROR numeric literal is out of bounds
+ ]);
+ concat_bytes!([
+ -33, //~ ERROR expected a byte literal
+ ]);
+ concat_bytes!([
+ b"hi!", //~ ERROR cannot concatenate doubly nested array
+ ]);
+ concat_bytes!([
+ [5, 6, 7], //~ ERROR cannot concatenate doubly nested array
+ ]);
+ concat_bytes!(5u16); //~ ERROR cannot concatenate numeric literals
+ concat_bytes!([5u16]); //~ ERROR numeric literal is not a `u8`
+}
diff --git a/src/test/ui/macros/concat-bytes-error.stderr b/src/test/ui/macros/concat-bytes-error.stderr
new file mode 100644
index 00000000000..1fc2d5c4843
--- /dev/null
+++ b/src/test/ui/macros/concat-bytes-error.stderr
@@ -0,0 +1,131 @@
+error: expected a byte literal
+ --> $DIR/concat-bytes-error.rs:4:19
+ |
+LL | concat_bytes!(pie);
+ | ^^^
+ |
+ = note: only byte literals (like `b"foo"`, `b's'`, and `[3, 4, 5]`) can be passed to `concat_bytes!()`
+
+error: expected a byte literal
+ --> $DIR/concat-bytes-error.rs:5:19
+ |
+LL | concat_bytes!(pie, pie);
+ | ^^^ ^^^
+ |
+ = note: only byte literals (like `b"foo"`, `b's'`, and `[3, 4, 5]`) can be passed to `concat_bytes!()`
+
+error: cannot concatenate string literals
+ --> $DIR/concat-bytes-error.rs:6:19
+ |
+LL | concat_bytes!("tnrsi", "tnri");
+ | ^^^^^^^ help: try using a byte string: `b"tnrsi"`
+
+error: cannot concatenate float literals
+ --> $DIR/concat-bytes-error.rs:7:19
+ |
+LL | concat_bytes!(2.8);
+ | ^^^
+
+error: cannot concatenate numeric literals
+ --> $DIR/concat-bytes-error.rs:8:19
+ |
+LL | concat_bytes!(300);
+ | ^^^ help: try wrapping the number in an array: `[300]`
+
+error: cannot concatenate character literals
+ --> $DIR/concat-bytes-error.rs:9:19
+ |
+LL | concat_bytes!('a');
+ | ^^^ help: try using a byte character: `b'a'`
+
+error: cannot concatenate boolean literals
+ --> $DIR/concat-bytes-error.rs:10:19
+ |
+LL | concat_bytes!(true, false);
+ | ^^^^
+
+error: cannot concatenate numeric literals
+ --> $DIR/concat-bytes-error.rs:11:19
+ |
+LL | concat_bytes!(42, b"va", b'l');
+ | ^^ help: try wrapping the number in an array: `[42]`
+
+error: cannot concatenate numeric literals
+ --> $DIR/concat-bytes-error.rs:12:19
+ |
+LL | concat_bytes!(42, b"va", b'l', [1, 2]);
+ | ^^ help: try wrapping the number in an array: `[42]`
+
+error: cannot concatenate string literals
+ --> $DIR/concat-bytes-error.rs:14:9
+ |
+LL | "hi",
+ | ^^^^
+
+error: cannot concatenate character literals
+ --> $DIR/concat-bytes-error.rs:17:9
+ |
+LL | 'a',
+ | ^^^ help: try using a byte character: `b'a'`
+
+error: cannot concatenate boolean literals
+ --> $DIR/concat-bytes-error.rs:20:9
+ |
+LL | true,
+ | ^^^^
+
+error: cannot concatenate boolean literals
+ --> $DIR/concat-bytes-error.rs:23:9
+ |
+LL | false,
+ | ^^^^^
+
+error: cannot concatenate float literals
+ --> $DIR/concat-bytes-error.rs:26:9
+ |
+LL | 2.6,
+ | ^^^
+
+error: numeric literal is out of bounds
+ --> $DIR/concat-bytes-error.rs:29:9
+ |
+LL | 265,
+ | ^^^
+
+error: expected a byte literal
+ --> $DIR/concat-bytes-error.rs:32:9
+ |
+LL | -33,
+ | ^^^
+ |
+ = note: only byte literals (like `b"foo"`, `b's'`, and `[3, 4, 5]`) can be passed to `concat_bytes!()`
+
+error: cannot concatenate doubly nested array
+ --> $DIR/concat-bytes-error.rs:35:9
+ |
+LL | b"hi!",
+ | ^^^^^^
+ |
+ = note: byte strings are treated as arrays of bytes
+ = help: try flattening the array
+
+error: cannot concatenate doubly nested array
+ --> $DIR/concat-bytes-error.rs:38:9
+ |
+LL | [5, 6, 7],
+ | ^^^^^^^^^
+
+error: cannot concatenate numeric literals
+ --> $DIR/concat-bytes-error.rs:40:19
+ |
+LL | concat_bytes!(5u16);
+ | ^^^^ help: try wrapping the number in an array: `[5u16]`
+
+error: numeric literal is not a `u8`
+ --> $DIR/concat-bytes-error.rs:41:20
+ |
+LL | concat_bytes!([5u16]);
+ | ^^^^
+
+error: aborting due to 20 previous errors
+
diff --git a/src/test/ui/macros/concat-bytes.rs b/src/test/ui/macros/concat-bytes.rs
new file mode 100644
index 00000000000..5415cf3fe22
--- /dev/null
+++ b/src/test/ui/macros/concat-bytes.rs
@@ -0,0 +1,7 @@
+// run-pass
+#![feature(concat_bytes)]
+
+fn main() {
+ assert_eq!(concat_bytes!(), &[]);
+ assert_eq!(concat_bytes!(b'A', b"BC", [68, b'E', 70]), b"ABCDEF");
+}
diff --git a/src/test/ui/macros/global-asm.rs b/src/test/ui/macros/global-asm.rs
index b8903e07cfd..26e90edce0b 100644
--- a/src/test/ui/macros/global-asm.rs
+++ b/src/test/ui/macros/global-asm.rs
@@ -1,7 +1,7 @@
-#![feature(global_asm)]
+use std::arch::global_asm;
fn main() {
- global_asm!(); //~ ERROR requires at least a template string argument
+ global_asm!(); //~ ERROR requires at least a template string argument
global_asm!(struct); //~ ERROR expected expression
global_asm!(123); //~ ERROR asm template must be a string literal
}
diff --git a/src/test/ui/macros/macro-comma-behavior-rpass.rs b/src/test/ui/macros/macro-comma-behavior-rpass.rs
index 780e158fe0b..dfd58b25d08 100644
--- a/src/test/ui/macros/macro-comma-behavior-rpass.rs
+++ b/src/test/ui/macros/macro-comma-behavior-rpass.rs
@@ -1,4 +1,5 @@
// run-pass
+// needs-unwind
#![allow(unused_imports)]
// Ideally, any macro call with a trailing comma should behave
// identically to a call without the comma.
diff --git a/src/test/ui/macros/macro-expanded-include/foo/mod.rs b/src/test/ui/macros/macro-expanded-include/foo/mod.rs
index a8bfa0299f6..cff110470f2 100644
--- a/src/test/ui/macros/macro-expanded-include/foo/mod.rs
+++ b/src/test/ui/macros/macro-expanded-include/foo/mod.rs
@@ -5,5 +5,5 @@ macro_rules! m {
}
macro_rules! n {
- () => { unsafe { asm!(include_str!("file.txt")); } }
+ () => { unsafe { core::arch::asm!(include_str!("file.txt")); } }
}
diff --git a/src/test/ui/macros/macro-expanded-include/test.rs b/src/test/ui/macros/macro-expanded-include/test.rs
index 6a2b5ef7241..20da58a7e8e 100644
--- a/src/test/ui/macros/macro-expanded-include/test.rs
+++ b/src/test/ui/macros/macro-expanded-include/test.rs
@@ -1,13 +1,13 @@
// needs-asm-support
// build-pass (FIXME(62277): could be check-pass?)
-#![feature(asm)]
#![allow(unused)]
#[macro_use]
mod foo;
m!();
-fn f() { n!(); }
-
+fn f() {
+ n!();
+}
fn main() {}
diff --git a/src/test/ui/macros/macro-pat-pattern-followed-by-or-in-2021.stderr b/src/test/ui/macros/macro-pat-pattern-followed-by-or-in-2021.stderr
index a5987a25551..a06487be3d6 100644
--- a/src/test/ui/macros/macro-pat-pattern-followed-by-or-in-2021.stderr
+++ b/src/test/ui/macros/macro-pat-pattern-followed-by-or-in-2021.stderr
@@ -2,7 +2,9 @@ error: `$x:pat` is followed by `|`, which is not allowed for `pat` fragments
--> $DIR/macro-pat-pattern-followed-by-or-in-2021.rs:3:28
|
LL | macro_rules! foo { ($x:pat | $y:pat) => {} }
- | ^ not allowed after `pat` fragments
+ | ------ ^ not allowed after `pat` fragments
+ | |
+ | help: try a `pat_param` fragment specifier instead: `$x:pat_param`
|
= note: allowed there are: `=>`, `,`, `=`, `if` or `in`
@@ -10,7 +12,9 @@ error: `$x:pat` is followed by `|`, which is not allowed for `pat` fragments
--> $DIR/macro-pat-pattern-followed-by-or-in-2021.rs:4:32
|
LL | macro_rules! bar { ($($x:pat)+ | $($y:pat)+) => {} }
- | ^ not allowed after `pat` fragments
+ | ------ ^ not allowed after `pat` fragments
+ | |
+ | help: try a `pat_param` fragment specifier instead: `$x:pat_param`
|
= note: allowed there are: `=>`, `,`, `=`, `if` or `in`
@@ -18,7 +22,9 @@ error: `$pat:pat` may be followed by `|`, which is not allowed for `pat` fragmen
--> $DIR/macro-pat-pattern-followed-by-or-in-2021.rs:7:36
|
LL | ( $expr:expr , $( $( $pat:pat )|+ => $expr_arm:expr ),+ ) => {
- | ^ not allowed after `pat` fragments
+ | -------- ^ not allowed after `pat` fragments
+ | |
+ | help: try a `pat_param` fragment specifier instead: `$pat:pat_param`
|
= note: allowed there are: `=>`, `,`, `=`, `if` or `in`
diff --git a/src/test/ui/macros/macro-pat2021-pattern-followed-by-or.stderr b/src/test/ui/macros/macro-pat2021-pattern-followed-by-or.stderr
index 8aebe98515f..c3754dde080 100644
--- a/src/test/ui/macros/macro-pat2021-pattern-followed-by-or.stderr
+++ b/src/test/ui/macros/macro-pat2021-pattern-followed-by-or.stderr
@@ -2,7 +2,9 @@ error: `$x:pat` is followed by `|`, which is not allowed for `pat` fragments
--> $DIR/macro-pat2021-pattern-followed-by-or.rs:4:28
|
LL | macro_rules! foo { ($x:pat | $y:pat) => {} }
- | ^ not allowed after `pat` fragments
+ | ------ ^ not allowed after `pat` fragments
+ | |
+ | help: try a `pat_param` fragment specifier instead: `$x:pat_param`
|
= note: allowed there are: `=>`, `,`, `=`, `if` or `in`
@@ -10,7 +12,9 @@ error: `$x:pat` is followed by `|`, which is not allowed for `pat` fragments
--> $DIR/macro-pat2021-pattern-followed-by-or.rs:7:28
|
LL | macro_rules! ogg { ($x:pat | $y:pat_param) => {} }
- | ^ not allowed after `pat` fragments
+ | ------ ^ not allowed after `pat` fragments
+ | |
+ | help: try a `pat_param` fragment specifier instead: `$x:pat_param`
|
= note: allowed there are: `=>`, `,`, `=`, `if` or `in`
@@ -18,7 +22,9 @@ error: `$pat:pat` may be followed by `|`, which is not allowed for `pat` fragmen
--> $DIR/macro-pat2021-pattern-followed-by-or.rs:9:35
|
LL | ( $expr:expr , $( $( $pat:pat)|+ => $expr_arm:pat),+ ) => {
- | ^ not allowed after `pat` fragments
+ | -------- ^ not allowed after `pat` fragments
+ | |
+ | help: try a `pat_param` fragment specifier instead: `$pat:pat_param`
|
= note: allowed there are: `=>`, `,`, `=`, `if` or `in`
diff --git a/src/test/ui/macros/macros-nonfatal-errors.rs b/src/test/ui/macros/macros-nonfatal-errors.rs
index 24adc0fb407..3bab95083b6 100644
--- a/src/test/ui/macros/macros-nonfatal-errors.rs
+++ b/src/test/ui/macros/macros-nonfatal-errors.rs
@@ -3,12 +3,14 @@
// test that errors in a (selection) of macros don't kill compilation
// immediately, so that we get more errors listed at a time.
-#![feature(asm, llvm_asm)]
+#![feature(llvm_asm)]
#![feature(trace_macros, concat_idents)]
#![feature(stmt_expr_attributes, arbitrary_enum_discriminant)]
#![feature(derive_default_enum)]
#![allow(deprecated)] // llvm_asm!
+use std::arch::asm;
+
#[derive(Default)]
struct DefaultInnerAttrStruct {
#[default] //~ ERROR the `#[default]` attribute may only be used on unit enum variants
diff --git a/src/test/ui/macros/macros-nonfatal-errors.stderr b/src/test/ui/macros/macros-nonfatal-errors.stderr
index 64065cd272a..9a360206e6e 100644
--- a/src/test/ui/macros/macros-nonfatal-errors.stderr
+++ b/src/test/ui/macros/macros-nonfatal-errors.stderr
@@ -1,41 +1,41 @@
error: the `#[default]` attribute may only be used on unit enum variants
- --> $DIR/macros-nonfatal-errors.rs:14:5
+ --> $DIR/macros-nonfatal-errors.rs:16:5
|
LL | #[default]
| ^^^^^^^^^^
error: the `#[default]` attribute may only be used on unit enum variants
- --> $DIR/macros-nonfatal-errors.rs:19:36
+ --> $DIR/macros-nonfatal-errors.rs:21:36
|
LL | struct DefaultInnerAttrTupleStruct(#[default] ());
| ^^^^^^^^^^
error: the `#[default]` attribute may only be used on unit enum variants
- --> $DIR/macros-nonfatal-errors.rs:23:1
+ --> $DIR/macros-nonfatal-errors.rs:25:1
|
LL | #[default]
| ^^^^^^^^^^
error: the `#[default]` attribute may only be used on unit enum variants
- --> $DIR/macros-nonfatal-errors.rs:27:1
+ --> $DIR/macros-nonfatal-errors.rs:29:1
|
LL | #[default]
| ^^^^^^^^^^
error: the `#[default]` attribute may only be used on unit enum variants
- --> $DIR/macros-nonfatal-errors.rs:37:11
+ --> $DIR/macros-nonfatal-errors.rs:39:11
|
LL | Foo = #[default] 0,
| ^^^^^^^^^^
error: the `#[default]` attribute may only be used on unit enum variants
- --> $DIR/macros-nonfatal-errors.rs:38:14
+ --> $DIR/macros-nonfatal-errors.rs:40:14
|
LL | Bar([u8; #[default] 1]),
| ^^^^^^^^^^
error: no default declared
- --> $DIR/macros-nonfatal-errors.rs:43:10
+ --> $DIR/macros-nonfatal-errors.rs:45:10
|
LL | #[derive(Default)]
| ^^^^^^^
@@ -44,7 +44,7 @@ LL | #[derive(Default)]
= note: this error originates in the derive macro `Default` (in Nightly builds, run with -Z macro-backtrace for more info)
error: multiple declared defaults
- --> $DIR/macros-nonfatal-errors.rs:49:10
+ --> $DIR/macros-nonfatal-errors.rs:51:10
|
LL | #[derive(Default)]
| ^^^^^^^
@@ -62,7 +62,7 @@ LL | Baz,
= note: this error originates in the derive macro `Default` (in Nightly builds, run with -Z macro-backtrace for more info)
error: `#[default]` attribute does not accept a value
- --> $DIR/macros-nonfatal-errors.rs:61:5
+ --> $DIR/macros-nonfatal-errors.rs:63:5
|
LL | #[default = 1]
| ^^^^^^^^^^^^^^
@@ -70,7 +70,7 @@ LL | #[default = 1]
= help: try using `#[default]`
error: multiple `#[default]` attributes
- --> $DIR/macros-nonfatal-errors.rs:69:5
+ --> $DIR/macros-nonfatal-errors.rs:71:5
|
LL | #[default]
| ---------- `#[default]` used here
@@ -81,13 +81,13 @@ LL | Foo,
|
= note: only one `#[default]` attribute is needed
help: try removing this
- --> $DIR/macros-nonfatal-errors.rs:68:5
+ --> $DIR/macros-nonfatal-errors.rs:70:5
|
LL | #[default]
| ^^^^^^^^^^
error: multiple `#[default]` attributes
- --> $DIR/macros-nonfatal-errors.rs:79:5
+ --> $DIR/macros-nonfatal-errors.rs:81:5
|
LL | #[default]
| ---------- `#[default]` used here
@@ -99,7 +99,7 @@ LL | Foo,
|
= note: only one `#[default]` attribute is needed
help: try removing these
- --> $DIR/macros-nonfatal-errors.rs:76:5
+ --> $DIR/macros-nonfatal-errors.rs:78:5
|
LL | #[default]
| ^^^^^^^^^^
@@ -109,7 +109,7 @@ LL | #[default]
| ^^^^^^^^^^
error: the `#[default]` attribute may only be used on unit enum variants
- --> $DIR/macros-nonfatal-errors.rs:86:5
+ --> $DIR/macros-nonfatal-errors.rs:88:5
|
LL | Foo {},
| ^^^
@@ -117,7 +117,7 @@ LL | Foo {},
= help: consider a manual implementation of `Default`
error: default variant must be exhaustive
- --> $DIR/macros-nonfatal-errors.rs:94:5
+ --> $DIR/macros-nonfatal-errors.rs:96:5
|
LL | #[non_exhaustive]
| ----------------- declared `#[non_exhaustive]` here
@@ -127,43 +127,43 @@ LL | Foo,
= help: consider a manual implementation of `Default`
error: asm template must be a string literal
- --> $DIR/macros-nonfatal-errors.rs:99:10
+ --> $DIR/macros-nonfatal-errors.rs:101:10
|
LL | asm!(invalid);
| ^^^^^^^
error: inline assembly must be a string literal
- --> $DIR/macros-nonfatal-errors.rs:100:15
+ --> $DIR/macros-nonfatal-errors.rs:102:15
|
LL | llvm_asm!(invalid);
| ^^^^^^^
error: concat_idents! requires ident args
- --> $DIR/macros-nonfatal-errors.rs:102:5
+ --> $DIR/macros-nonfatal-errors.rs:104:5
|
LL | concat_idents!("not", "idents");
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
error: argument must be a string literal
- --> $DIR/macros-nonfatal-errors.rs:104:17
+ --> $DIR/macros-nonfatal-errors.rs:106:17
|
LL | option_env!(invalid);
| ^^^^^^^
error: expected string literal
- --> $DIR/macros-nonfatal-errors.rs:105:10
+ --> $DIR/macros-nonfatal-errors.rs:107:10
|
LL | env!(invalid);
| ^^^^^^^
error: expected string literal
- --> $DIR/macros-nonfatal-errors.rs:106:10
+ --> $DIR/macros-nonfatal-errors.rs:108:10
|
LL | env!(foo, abr, baz);
| ^^^
error: environment variable `RUST_HOPEFULLY_THIS_DOESNT_EXIST` not defined
- --> $DIR/macros-nonfatal-errors.rs:107:5
+ --> $DIR/macros-nonfatal-errors.rs:109:5
|
LL | env!("RUST_HOPEFULLY_THIS_DOESNT_EXIST");
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -171,7 +171,7 @@ LL | env!("RUST_HOPEFULLY_THIS_DOESNT_EXIST");
= note: this error originates in the macro `env` (in Nightly builds, run with -Z macro-backtrace for more info)
error: format argument must be a string literal
- --> $DIR/macros-nonfatal-errors.rs:109:13
+ --> $DIR/macros-nonfatal-errors.rs:111:13
|
LL | format!(invalid);
| ^^^^^^^
@@ -182,19 +182,19 @@ LL | format!("{}", invalid);
| +++++
error: argument must be a string literal
- --> $DIR/macros-nonfatal-errors.rs:111:14
+ --> $DIR/macros-nonfatal-errors.rs:113:14
|
LL | include!(invalid);
| ^^^^^^^
error: argument must be a string literal
- --> $DIR/macros-nonfatal-errors.rs:113:18
+ --> $DIR/macros-nonfatal-errors.rs:115:18
|
LL | include_str!(invalid);
| ^^^^^^^
error: couldn't read $DIR/i'd be quite surprised if a file with this name existed: $FILE_NOT_FOUND_MSG (os error 2)
- --> $DIR/macros-nonfatal-errors.rs:114:5
+ --> $DIR/macros-nonfatal-errors.rs:116:5
|
LL | include_str!("i'd be quite surprised if a file with this name existed");
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -202,13 +202,13 @@ LL | include_str!("i'd be quite surprised if a file with this name existed")
= note: this error originates in the macro `include_str` (in Nightly builds, run with -Z macro-backtrace for more info)
error: argument must be a string literal
- --> $DIR/macros-nonfatal-errors.rs:115:20
+ --> $DIR/macros-nonfatal-errors.rs:117:20
|
LL | include_bytes!(invalid);
| ^^^^^^^
error: couldn't read $DIR/i'd be quite surprised if a file with this name existed: $FILE_NOT_FOUND_MSG (os error 2)
- --> $DIR/macros-nonfatal-errors.rs:116:5
+ --> $DIR/macros-nonfatal-errors.rs:118:5
|
LL | include_bytes!("i'd be quite surprised if a file with this name existed");
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -216,7 +216,7 @@ LL | include_bytes!("i'd be quite surprised if a file with this name existed
= note: this error originates in the macro `include_bytes` (in Nightly builds, run with -Z macro-backtrace for more info)
error: trace_macros! accepts only `true` or `false`
- --> $DIR/macros-nonfatal-errors.rs:118:5
+ --> $DIR/macros-nonfatal-errors.rs:120:5
|
LL | trace_macros!(invalid);
| ^^^^^^^^^^^^^^^^^^^^^^
diff --git a/src/test/ui/macros/nonterminal-matching.rs b/src/test/ui/macros/nonterminal-matching.rs
index 0ccdf6e5f2e..84fffe44d6a 100644
--- a/src/test/ui/macros/nonterminal-matching.rs
+++ b/src/test/ui/macros/nonterminal-matching.rs
@@ -16,7 +16,7 @@ macro complex_nonterminal($nt_item: item) {
struct S;
}
- n!(a $nt_item b); //~ ERROR no rules expected the token `enum E { }`
+ n!(a $nt_item b); //~ ERROR no rules expected the token `enum E {}`
}
simple_nonterminal!(a, 'a, (x, y, z)); // OK
diff --git a/src/test/ui/macros/nonterminal-matching.stderr b/src/test/ui/macros/nonterminal-matching.stderr
index 155a9425131..585f2355321 100644
--- a/src/test/ui/macros/nonterminal-matching.stderr
+++ b/src/test/ui/macros/nonterminal-matching.stderr
@@ -1,4 +1,4 @@
-error: no rules expected the token `enum E { }`
+error: no rules expected the token `enum E {}`
--> $DIR/nonterminal-matching.rs:19:10
|
LL | macro n(a $nt_item b) {
diff --git a/src/test/ui/match/match-type-err-first-arm.stderr b/src/test/ui/match/match-type-err-first-arm.stderr
index fd489afa84d..1cfe7ce1ed7 100644
--- a/src/test/ui/match/match-type-err-first-arm.stderr
+++ b/src/test/ui/match/match-type-err-first-arm.stderr
@@ -6,6 +6,11 @@ LL | fn test_func1(n: i32) -> i32 {
LL | match n {
LL | 12 => 'b',
| ^^^ expected `i32`, found `char`
+ |
+help: you can cast a `char` to an `i32`, since a `char` always occupies 4 bytes
+ |
+LL | 12 => 'b' as i32,
+ | ++++++
error[E0308]: `match` arms have incompatible types
--> $DIR/match-type-err-first-arm.rs:18:14
diff --git a/src/test/ui/methods/method-ambig-two-traits-cross-crate.stderr b/src/test/ui/methods/method-ambig-two-traits-cross-crate.stderr
index ed03b37fde2..4b2597eed3c 100644
--- a/src/test/ui/methods/method-ambig-two-traits-cross-crate.stderr
+++ b/src/test/ui/methods/method-ambig-two-traits-cross-crate.stderr
@@ -4,20 +4,20 @@ error[E0034]: multiple applicable items in scope
LL | fn main() { 1_usize.me(); }
| ^^ multiple `me` found
|
-note: candidate #1 is defined in an impl of the trait `Me2` for the type `usize`
+ = note: candidate #1 is defined in an impl of the trait `Me` for the type `usize`
+note: candidate #2 is defined in an impl of the trait `Me2` for the type `usize`
--> $DIR/method-ambig-two-traits-cross-crate.rs:10:22
|
LL | impl Me2 for usize { fn me(&self) -> usize { *self } }
| ^^^^^^^^^^^^^^^^^^^^^
- = note: candidate #2 is defined in an impl of the trait `Me` for the type `usize`
help: disambiguate the associated function for candidate #1
|
-LL | fn main() { Me2::me(&1_usize); }
- | ~~~~~~~~~~~~~~~~~
-help: disambiguate the associated function for candidate #2
- |
LL | fn main() { Me::me(&1_usize); }
| ~~~~~~~~~~~~~~~~
+help: disambiguate the associated function for candidate #2
+ |
+LL | fn main() { Me2::me(&1_usize); }
+ | ~~~~~~~~~~~~~~~~~
error: aborting due to previous error
diff --git a/src/test/ui/mir/issue-91745.rs b/src/test/ui/mir/issue-91745.rs
new file mode 100644
index 00000000000..ca3d66b1c8e
--- /dev/null
+++ b/src/test/ui/mir/issue-91745.rs
@@ -0,0 +1,21 @@
+// check-pass
+
+pub trait Foo {
+ type Bar;
+}
+
+pub trait Broken {
+ type Assoc;
+ fn broken(&self) where Self::Assoc: Foo;
+}
+
+impl<T> Broken for T {
+ type Assoc = ();
+ fn broken(&self) where Self::Assoc: Foo {
+ let _x: <Self::Assoc as Foo>::Bar;
+ }
+}
+
+fn main() {
+ let _m: &dyn Broken<Assoc=()> = &();
+}
diff --git a/src/test/ui/mir/mir_calls_to_shims.rs b/src/test/ui/mir/mir_calls_to_shims.rs
index 6f13d5612ce..42eaab77da9 100644
--- a/src/test/ui/mir/mir_calls_to_shims.rs
+++ b/src/test/ui/mir/mir_calls_to_shims.rs
@@ -1,4 +1,5 @@
// run-pass
+// needs-unwind
// ignore-wasm32-bare compiled with panic=abort by default
#![feature(fn_traits)]
diff --git a/src/test/ui/mir/mir_const_prop_identity.rs b/src/test/ui/mir/mir_const_prop_identity.rs
new file mode 100644
index 00000000000..25d2202b909
--- /dev/null
+++ b/src/test/ui/mir/mir_const_prop_identity.rs
@@ -0,0 +1,12 @@
+// Regression test for issue #91725.
+//
+// run-pass
+// compile-flags: -Zmir-opt-level=4
+
+fn main() {
+ let a = true;
+ let _ = &a;
+ let mut b = false;
+ b |= a;
+ assert!(b);
+}
diff --git a/src/test/ui/mir/mir_drop_order.rs b/src/test/ui/mir/mir_drop_order.rs
index 22c804abf5c..853efb0fed2 100644
--- a/src/test/ui/mir/mir_drop_order.rs
+++ b/src/test/ui/mir/mir_drop_order.rs
@@ -1,4 +1,5 @@
// run-pass
+// needs-unwind
// ignore-wasm32-bare compiled with panic=abort by default
use std::cell::RefCell;
diff --git a/src/test/ui/mir/mir_drop_panics.rs b/src/test/ui/mir/mir_drop_panics.rs
index bf269ee901b..b4093d70415 100644
--- a/src/test/ui/mir/mir_drop_panics.rs
+++ b/src/test/ui/mir/mir_drop_panics.rs
@@ -1,4 +1,5 @@
// run-fail
+// needs-unwind
// error-pattern:panic 1
// error-pattern:drop 2
// ignore-emscripten no processes
diff --git a/src/test/ui/mir/mir_dynamic_drops_3.rs b/src/test/ui/mir/mir_dynamic_drops_3.rs
index eb76fdff886..2bcd9fac55c 100644
--- a/src/test/ui/mir/mir_dynamic_drops_3.rs
+++ b/src/test/ui/mir/mir_dynamic_drops_3.rs
@@ -1,4 +1,5 @@
// run-fail
+// needs-unwind
// error-pattern:unwind happens
// error-pattern:drop 3
// error-pattern:drop 2
diff --git a/src/test/ui/mir/mir_overflow_off.rs b/src/test/ui/mir/mir_overflow_off.rs
index 922ec36e531..0098584dd26 100644
--- a/src/test/ui/mir/mir_overflow_off.rs
+++ b/src/test/ui/mir/mir_overflow_off.rs
@@ -1,5 +1,5 @@
// run-pass
-// compile-flags: -Z force-overflow-checks=off
+// compile-flags: -C overflow-checks=off
// Test that with MIR codegen, overflow checks can be
// turned off, even when they're from core::ops::*.
diff --git a/src/test/ui/mir/remove-zsts-query-cycle.rs b/src/test/ui/mir/remove-zsts-query-cycle.rs
index 8f93c6cadff..be4d68f2de7 100644
--- a/src/test/ui/mir/remove-zsts-query-cycle.rs
+++ b/src/test/ui/mir/remove-zsts-query-cycle.rs
@@ -2,7 +2,7 @@
// optimized mir -> remove zsts -> layout of a generator -> optimized mir.
//
// edition:2018
-// compile-flags: --crate-type=lib
+// compile-flags: --crate-type=lib -Zinline-mir=yes
// build-pass
pub async fn listen() -> Result<(), std::io::Error> {
diff --git a/src/test/ui/mismatched_types/E0053.stderr b/src/test/ui/mismatched_types/E0053.stderr
index 6ce8126b9f9..54b41926451 100644
--- a/src/test/ui/mismatched_types/E0053.stderr
+++ b/src/test/ui/mismatched_types/E0053.stderr
@@ -1,30 +1,34 @@
error[E0053]: method `foo` has an incompatible type for trait
--> $DIR/E0053.rs:9:15
|
-LL | fn foo(x: u16);
- | --- type in trait
-...
LL | fn foo(x: i16) { }
| ^^^
| |
| expected `u16`, found `i16`
| help: change the parameter type to match the trait: `u16`
|
+note: type in trait
+ --> $DIR/E0053.rs:2:15
+ |
+LL | fn foo(x: u16);
+ | ^^^
= note: expected fn pointer `fn(u16)`
found fn pointer `fn(i16)`
error[E0053]: method `bar` has an incompatible type for trait
--> $DIR/E0053.rs:11:12
|
-LL | fn bar(&self);
- | ----- type in trait
-...
LL | fn bar(&mut self) { }
| ^^^^^^^^^
| |
| types differ in mutability
| help: change the self-receiver type to match the trait: `self: &Bar`
|
+note: type in trait
+ --> $DIR/E0053.rs:3:12
+ |
+LL | fn bar(&self);
+ | ^^^^^
= note: expected fn pointer `fn(&Bar)`
found fn pointer `fn(&mut Bar)`
diff --git a/src/test/ui/mismatched_types/E0409.stderr b/src/test/ui/mismatched_types/E0409.stderr
index ef03b67b1b0..eb884bcc622 100644
--- a/src/test/ui/mismatched_types/E0409.stderr
+++ b/src/test/ui/mismatched_types/E0409.stderr
@@ -9,8 +9,6 @@ LL | (0, ref y) | (y, 0) => {}
error[E0308]: mismatched types
--> $DIR/E0409.rs:5:23
|
-LL | match x {
- | - this expression has type `({integer}, {integer})`
LL | (0, ref y) | (y, 0) => {}
| ----- ^ expected `&{integer}`, found integer
| |
diff --git a/src/test/ui/mismatched_types/issue-84976.stderr b/src/test/ui/mismatched_types/issue-84976.stderr
index 0c27e172941..f8f2b1f0f57 100644
--- a/src/test/ui/mismatched_types/issue-84976.stderr
+++ b/src/test/ui/mismatched_types/issue-84976.stderr
@@ -7,6 +7,9 @@ LL | length = { foo(&length) };
error[E0308]: mismatched types
--> $DIR/issue-84976.rs:17:14
|
+LL | let mut length = 0;
+ | - expected due to this value
+...
LL | length = foo(&length);
| ^^^^^^^^^^^^ expected `u32`, found `i32`
@@ -19,6 +22,9 @@ LL | float_length = { bar(&float_length) };
error[E0308]: mismatched types
--> $DIR/issue-84976.rs:23:20
|
+LL | let mut float_length = 0.0;
+ | --- expected due to this value
+...
LL | float_length = bar(&float_length);
| ^^^^^^^^^^^^^^^^^^ expected `f32`, found `f64`
diff --git a/src/test/ui/mismatched_types/trait-impl-fn-incompatibility.stderr b/src/test/ui/mismatched_types/trait-impl-fn-incompatibility.stderr
index 2ac4d1c33a9..6b2ba53daa0 100644
--- a/src/test/ui/mismatched_types/trait-impl-fn-incompatibility.stderr
+++ b/src/test/ui/mismatched_types/trait-impl-fn-incompatibility.stderr
@@ -1,30 +1,34 @@
error[E0053]: method `foo` has an incompatible type for trait
--> $DIR/trait-impl-fn-incompatibility.rs:9:15
|
-LL | fn foo(x: u16);
- | --- type in trait
-...
LL | fn foo(x: i16) { }
| ^^^
| |
| expected `u16`, found `i16`
| help: change the parameter type to match the trait: `u16`
|
+note: type in trait
+ --> $DIR/trait-impl-fn-incompatibility.rs:2:15
+ |
+LL | fn foo(x: u16);
+ | ^^^
= note: expected fn pointer `fn(u16)`
found fn pointer `fn(i16)`
error[E0053]: method `bar` has an incompatible type for trait
--> $DIR/trait-impl-fn-incompatibility.rs:10:28
|
-LL | fn bar(&mut self, bar: &mut Bar);
- | -------- type in trait
-...
LL | fn bar(&mut self, bar: &Bar) { }
| ^^^^
| |
| types differ in mutability
| help: change the parameter type to match the trait: `&mut Bar`
|
+note: type in trait
+ --> $DIR/trait-impl-fn-incompatibility.rs:3:28
+ |
+LL | fn bar(&mut self, bar: &mut Bar);
+ | ^^^^^^^^
= note: expected fn pointer `fn(&mut Bar, &mut Bar)`
found fn pointer `fn(&mut Bar, &Bar)`
diff --git a/src/test/ui/missing/missing-alloc_error_handler.stderr b/src/test/ui/missing/missing-alloc_error_handler.stderr
index ed84493deb5..995fa7cf85e 100644
--- a/src/test/ui/missing/missing-alloc_error_handler.stderr
+++ b/src/test/ui/missing/missing-alloc_error_handler.stderr
@@ -1,6 +1,6 @@
error: `#[alloc_error_handler]` function required, but not found
-note: Use `#![feature(default_alloc_error_handler)]` for a default error handler
+note: use `#![feature(default_alloc_error_handler)]` for a default error handler
error: aborting due to previous error
diff --git a/src/test/ui/missing/missing-items/missing-type-parameter2.rs b/src/test/ui/missing/missing-items/missing-type-parameter2.rs
index 15dc5ef797b..e9b32fb7198 100644
--- a/src/test/ui/missing/missing-items/missing-type-parameter2.rs
+++ b/src/test/ui/missing/missing-items/missing-type-parameter2.rs
@@ -1,6 +1,3 @@
-#![allow(incomplete_features)]
-#![feature(const_generics_defaults)]
-
struct X<const N: u8>();
impl X<N> {}
diff --git a/src/test/ui/missing/missing-items/missing-type-parameter2.stderr b/src/test/ui/missing/missing-items/missing-type-parameter2.stderr
index f955659f23d..3b930d7e4ec 100644
--- a/src/test/ui/missing/missing-items/missing-type-parameter2.stderr
+++ b/src/test/ui/missing/missing-items/missing-type-parameter2.stderr
@@ -1,5 +1,5 @@
error[E0412]: cannot find type `N` in this scope
- --> $DIR/missing-type-parameter2.rs:6:8
+ --> $DIR/missing-type-parameter2.rs:3:8
|
LL | struct X<const N: u8>();
| ------------------------ similarly named struct `X` defined here
@@ -17,7 +17,7 @@ LL | impl<N> X<N> {}
| +++
error[E0412]: cannot find type `N` in this scope
- --> $DIR/missing-type-parameter2.rs:9:28
+ --> $DIR/missing-type-parameter2.rs:6:28
|
LL | impl<T, const A: u8 = 2> X<N> {}
| - ^
@@ -34,7 +34,7 @@ LL | impl<T, const A: u8 = 2, N> X<N> {}
| +++
error[E0412]: cannot find type `T` in this scope
- --> $DIR/missing-type-parameter2.rs:14:20
+ --> $DIR/missing-type-parameter2.rs:11:20
|
LL | struct X<const N: u8>();
| ------------------------ similarly named struct `X` defined here
@@ -52,7 +52,7 @@ LL | fn foo<T>(_: T) where T: Send {}
| +++
error[E0412]: cannot find type `T` in this scope
- --> $DIR/missing-type-parameter2.rs:14:11
+ --> $DIR/missing-type-parameter2.rs:11:11
|
LL | struct X<const N: u8>();
| ------------------------ similarly named struct `X` defined here
@@ -70,7 +70,7 @@ LL | fn foo<T>(_: T) where T: Send {}
| +++
error[E0412]: cannot find type `A` in this scope
- --> $DIR/missing-type-parameter2.rs:18:24
+ --> $DIR/missing-type-parameter2.rs:15:24
|
LL | struct X<const N: u8>();
| ------------------------ similarly named struct `X` defined here
@@ -88,7 +88,7 @@ LL | fn bar<const N: u8, A>(_: A) {}
| +++
error[E0747]: unresolved item provided when a constant was expected
- --> $DIR/missing-type-parameter2.rs:6:8
+ --> $DIR/missing-type-parameter2.rs:3:8
|
LL | impl X<N> {}
| ^
@@ -99,13 +99,13 @@ LL | impl X<{ N }> {}
| + +
error: defaults for const parameters are only allowed in `struct`, `enum`, `type`, or `trait` definitions
- --> $DIR/missing-type-parameter2.rs:9:15
+ --> $DIR/missing-type-parameter2.rs:6:15
|
LL | impl<T, const A: u8 = 2> X<N> {}
| ^
error[E0747]: unresolved item provided when a constant was expected
- --> $DIR/missing-type-parameter2.rs:9:28
+ --> $DIR/missing-type-parameter2.rs:6:28
|
LL | impl<T, const A: u8 = 2> X<N> {}
| ^
diff --git a/src/test/ui/moves/move-of-addr-of-mut.rs b/src/test/ui/moves/move-of-addr-of-mut.rs
new file mode 100644
index 00000000000..f2f64e43cd2
--- /dev/null
+++ b/src/test/ui/moves/move-of-addr-of-mut.rs
@@ -0,0 +1,12 @@
+// Ensure that taking a mutable raw ptr to an uninitialized variable does not change its
+// initializedness.
+
+struct S;
+
+fn main() {
+ let mut x: S;
+ std::ptr::addr_of_mut!(x); //~ borrow of
+
+ let y = x; // Should error here if `addr_of_mut` is ever allowed on uninitialized variables
+ drop(y);
+}
diff --git a/src/test/ui/moves/move-of-addr-of-mut.stderr b/src/test/ui/moves/move-of-addr-of-mut.stderr
new file mode 100644
index 00000000000..ce8fb028316
--- /dev/null
+++ b/src/test/ui/moves/move-of-addr-of-mut.stderr
@@ -0,0 +1,11 @@
+error[E0381]: borrow of possibly-uninitialized variable: `x`
+ --> $DIR/move-of-addr-of-mut.rs:8:5
+ |
+LL | std::ptr::addr_of_mut!(x);
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^ use of possibly-uninitialized `x`
+ |
+ = note: this error originates in the macro `std::ptr::addr_of_mut` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0381`.
diff --git a/src/test/ui/moves/moves-based-on-type-capture-clause-bad.stderr b/src/test/ui/moves/moves-based-on-type-capture-clause-bad.stderr
index acb0932f6d6..ac921c18e07 100644
--- a/src/test/ui/moves/moves-based-on-type-capture-clause-bad.stderr
+++ b/src/test/ui/moves/moves-based-on-type-capture-clause-bad.stderr
@@ -10,6 +10,8 @@ LL | println!("{}", x);
LL | });
LL | println!("{}", x);
| ^ value borrowed here after move
+ |
+ = note: this error originates in the macro `$crate::format_args_nl` (in Nightly builds, run with -Z macro-backtrace for more info)
error: aborting due to previous error
diff --git a/src/test/ui/mut/mut-pattern-mismatched.stderr b/src/test/ui/mut/mut-pattern-mismatched.stderr
index cad1cef5155..ccc8ac1278c 100644
--- a/src/test/ui/mut/mut-pattern-mismatched.stderr
+++ b/src/test/ui/mut/mut-pattern-mismatched.stderr
@@ -3,9 +3,6 @@ error[E0308]: mismatched types
|
LL | let &_
| ^^ types differ in mutability
-...
-LL | = foo;
- | --- this expression has type `&mut {integer}`
|
= note: expected mutable reference `&mut {integer}`
found reference `&_`
@@ -15,9 +12,6 @@ error[E0308]: mismatched types
|
LL | let &mut _
| ^^^^^^ types differ in mutability
-...
-LL | = bar;
- | --- this expression has type `&{integer}`
|
= note: expected reference `&{integer}`
found mutable reference `&mut _`
diff --git a/src/test/ui/never_type/diverging-tuple-parts-39485.stderr b/src/test/ui/never_type/diverging-tuple-parts-39485.stderr
index 32967b376ca..e99a38aaaee 100644
--- a/src/test/ui/never_type/diverging-tuple-parts-39485.stderr
+++ b/src/test/ui/never_type/diverging-tuple-parts-39485.stderr
@@ -1,15 +1,13 @@
error[E0308]: mismatched types
--> $DIR/diverging-tuple-parts-39485.rs:8:5
|
+LL | fn g() {
+ | - possibly return type missing here?
LL | &panic!()
| ^^^^^^^^^ expected `()`, found reference
|
= note: expected unit type `()`
found reference `&_`
-help: try adding a return type
- |
-LL | fn g() -> &_ {
- | +++++
help: consider removing the borrow
|
LL - &panic!()
diff --git a/src/test/ui/never_type/issue-51506.stderr b/src/test/ui/never_type/issue-51506.stderr
index 38f299d11c1..293ec3a725d 100644
--- a/src/test/ui/never_type/issue-51506.stderr
+++ b/src/test/ui/never_type/issue-51506.stderr
@@ -1,8 +1,8 @@
error[E0277]: `!` is not an iterator
- --> $DIR/issue-51506.rs:13:5
+ --> $DIR/issue-51506.rs:13:24
|
LL | default type Out = !;
- | ^^^^^^^^^^^^^^^^^^^^^ `!` is not an iterator
+ | ^ `!` is not an iterator
|
= help: the trait `Iterator` is not implemented for `!`
note: required by a bound in `Trait::Out`
diff --git a/src/test/ui/nll/ty-outlives/impl-trait-captures.stderr b/src/test/ui/nll/ty-outlives/impl-trait-captures.stderr
index 21d1eea54e6..5e56e12eda0 100644
--- a/src/test/ui/nll/ty-outlives/impl-trait-captures.stderr
+++ b/src/test/ui/nll/ty-outlives/impl-trait-captures.stderr
@@ -4,11 +4,11 @@ error[E0700]: hidden type for `impl Trait` captures lifetime that does not appea
LL | fn foo<'a, T>(x: &T) -> impl Foo<'a> {
| -- ^^^^^^^^^^^^
| |
- | hidden type `&ReFree(DefId(0:8 ~ impl_trait_captures[e9f4]::foo), BrAnon(0)) T` captures the anonymous lifetime defined here
+ | hidden type `&ReFree(DefId(0:8 ~ impl_trait_captures[HASH]::foo), BrAnon(0)) T` captures the anonymous lifetime defined here
|
-help: to declare that the `impl Trait` captures ReFree(DefId(0:8 ~ impl_trait_captures[e9f4]::foo), BrAnon(0)), you can add an explicit `ReFree(DefId(0:8 ~ impl_trait_captures[e9f4]::foo), BrAnon(0))` lifetime bound
+help: to declare that the `impl Trait` captures `ReFree(DefId(0:8 ~ impl_trait_captures[HASH]::foo), BrAnon(0))`, you can add an explicit `ReFree(DefId(0:8 ~ impl_trait_captures[HASH]::foo), BrAnon(0))` lifetime bound
|
-LL | fn foo<'a, T>(x: &T) -> impl Foo<'a> + ReFree(DefId(0:8 ~ impl_trait_captures[e9f4]::foo), BrAnon(0)) {
+LL | fn foo<'a, T>(x: &T) -> impl Foo<'a> + ReFree(DefId(0:8 ~ impl_trait_captures[HASH]::foo), BrAnon(0)) {
| ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
error: aborting due to previous error
diff --git a/src/test/ui/nll/user-annotations/constant-in-expr-inherent-1.stderr b/src/test/ui/nll/user-annotations/constant-in-expr-inherent-1.stderr
index 1931934a211..4a6378b84f1 100644
--- a/src/test/ui/nll/user-annotations/constant-in-expr-inherent-1.stderr
+++ b/src/test/ui/nll/user-annotations/constant-in-expr-inherent-1.stderr
@@ -4,7 +4,7 @@ error[E0759]: `fn` parameter has lifetime `'a` but it needs to satisfy a `'stati
LL | fn foo<'a>(_: &'a u32) -> &'static u32 {
| ------- this data with lifetime `'a`...
LL | <Foo<'a>>::C
- | ^^^^^^^^^^^^ ...is captured and required to live as long as `'static` here
+ | ^^^^^^^^^^^^ ...is used and required to live as long as `'static` here
error: aborting due to previous error
diff --git a/src/test/ui/numbers-arithmetic/int-abs-overflow.rs b/src/test/ui/numbers-arithmetic/int-abs-overflow.rs
index 10ec3f0c662..d63ba8cb03e 100644
--- a/src/test/ui/numbers-arithmetic/int-abs-overflow.rs
+++ b/src/test/ui/numbers-arithmetic/int-abs-overflow.rs
@@ -1,6 +1,7 @@
// run-pass
-// compile-flags: -Z force-overflow-checks=on
+// compile-flags: -C overflow-checks=on
// ignore-emscripten no threads support
+// needs-unwind
use std::thread;
diff --git a/src/test/ui/numbers-arithmetic/next-power-of-two-overflow-debug.rs b/src/test/ui/numbers-arithmetic/next-power-of-two-overflow-debug.rs
index 101c5d50b20..f857d4f4c7f 100644
--- a/src/test/ui/numbers-arithmetic/next-power-of-two-overflow-debug.rs
+++ b/src/test/ui/numbers-arithmetic/next-power-of-two-overflow-debug.rs
@@ -1,5 +1,6 @@
// run-pass
// compile-flags: -C debug_assertions=yes
+// needs-unwind
// ignore-wasm32-bare compiled with panic=abort by default
// ignore-emscripten dies with an LLVM error
diff --git a/src/test/ui/numeric/numeric-cast.stderr b/src/test/ui/numeric/numeric-cast.stderr
index 3e2bc5bc82d..b8f2d88ab49 100644
--- a/src/test/ui/numeric/numeric-cast.stderr
+++ b/src/test/ui/numeric/numeric-cast.stderr
@@ -994,8 +994,8 @@ error[E0308]: mismatched types
LL | foo::<f64>(x_usize);
| ^^^^^^^ expected `f64`, found `usize`
|
-help: you can cast a `usize` to an `f64`, producing the floating point representation of the integer,
- | rounded if necessary
+help: you can cast a `usize` to an `f64`, producing the floating point representation of the integer, rounded if necessary
+ |
LL | foo::<f64>(x_usize as f64);
| ++++++
@@ -1005,8 +1005,8 @@ error[E0308]: mismatched types
LL | foo::<f64>(x_u64);
| ^^^^^ expected `f64`, found `u64`
|
-help: you can cast a `u64` to an `f64`, producing the floating point representation of the integer,
- | rounded if necessary
+help: you can cast a `u64` to an `f64`, producing the floating point representation of the integer, rounded if necessary
+ |
LL | foo::<f64>(x_u64 as f64);
| ++++++
@@ -1115,8 +1115,8 @@ error[E0308]: mismatched types
LL | foo::<f32>(x_usize);
| ^^^^^^^ expected `f32`, found `usize`
|
-help: you can cast a `usize` to an `f32`, producing the floating point representation of the integer,
- | rounded if necessary
+help: you can cast a `usize` to an `f32`, producing the floating point representation of the integer, rounded if necessary
+ |
LL | foo::<f32>(x_usize as f32);
| ++++++
@@ -1126,8 +1126,8 @@ error[E0308]: mismatched types
LL | foo::<f32>(x_u64);
| ^^^^^ expected `f32`, found `u64`
|
-help: you can cast a `u64` to an `f32`, producing the floating point representation of the integer,
- | rounded if necessary
+help: you can cast a `u64` to an `f32`, producing the floating point representation of the integer, rounded if necessary
+ |
LL | foo::<f32>(x_u64 as f32);
| ++++++
@@ -1137,8 +1137,8 @@ error[E0308]: mismatched types
LL | foo::<f32>(x_u32);
| ^^^^^ expected `f32`, found `u32`
|
-help: you can cast a `u32` to an `f32`, producing the floating point representation of the integer,
- | rounded if necessary
+help: you can cast a `u32` to an `f32`, producing the floating point representation of the integer, rounded if necessary
+ |
LL | foo::<f32>(x_u32 as f32);
| ++++++
diff --git a/src/test/ui/object-lifetime/object-lifetime-default-from-box-error.stderr b/src/test/ui/object-lifetime/object-lifetime-default-from-box-error.stderr
index e0a8534cd28..1708700f77a 100644
--- a/src/test/ui/object-lifetime/object-lifetime-default-from-box-error.stderr
+++ b/src/test/ui/object-lifetime/object-lifetime-default-from-box-error.stderr
@@ -5,8 +5,16 @@ LL | fn load(ss: &mut SomeStruct) -> Box<dyn SomeTrait> {
| --------------- this data with an anonymous lifetime `'_`...
...
LL | ss.r
- | ^^^^ ...is captured and required to live as long as `'static` here
+ | ^^^^ ...is used and required to live as long as `'static` here
|
+note: `'static` lifetime requirement introduced by the return type
+ --> $DIR/object-lifetime-default-from-box-error.rs:14:37
+ |
+LL | fn load(ss: &mut SomeStruct) -> Box<dyn SomeTrait> {
+ | ^^^^^^^^^^^^^ `'static` requirement introduced here
+...
+LL | ss.r
+ | ---- because of this returned expression
help: to declare that the trait object captures data from argument `ss`, you can add an explicit `'_` lifetime bound
|
LL | fn load(ss: &mut SomeStruct) -> Box<dyn SomeTrait + '_> {
diff --git a/src/test/ui/operator-recovery/less-than-greater-than.rs b/src/test/ui/operator-recovery/less-than-greater-than.rs
new file mode 100644
index 00000000000..2beed528ff1
--- /dev/null
+++ b/src/test/ui/operator-recovery/less-than-greater-than.rs
@@ -0,0 +1,4 @@
+fn main() {
+ println!("{}", 1 <> 2);
+ //~^ERROR invalid comparison operator `<>`
+}
diff --git a/src/test/ui/operator-recovery/less-than-greater-than.stderr b/src/test/ui/operator-recovery/less-than-greater-than.stderr
new file mode 100644
index 00000000000..80c921535bd
--- /dev/null
+++ b/src/test/ui/operator-recovery/less-than-greater-than.stderr
@@ -0,0 +1,8 @@
+error: invalid comparison operator `<>`
+ --> $DIR/less-than-greater-than.rs:2:22
+ |
+LL | println!("{}", 1 <> 2);
+ | ^^ help: `<>` is not a valid comparison operator, use `!=`
+
+error: aborting due to previous error
+
diff --git a/src/test/ui/operator-recovery/spaceship.rs b/src/test/ui/operator-recovery/spaceship.rs
new file mode 100644
index 00000000000..a65f9389625
--- /dev/null
+++ b/src/test/ui/operator-recovery/spaceship.rs
@@ -0,0 +1,4 @@
+fn main() {
+ println!("{}", 1 <=> 2);
+ //~^ERROR invalid comparison operator `<=>`
+}
diff --git a/src/test/ui/operator-recovery/spaceship.stderr b/src/test/ui/operator-recovery/spaceship.stderr
new file mode 100644
index 00000000000..ed6bd74c9b9
--- /dev/null
+++ b/src/test/ui/operator-recovery/spaceship.stderr
@@ -0,0 +1,8 @@
+error: invalid comparison operator `<=>`
+ --> $DIR/spaceship.rs:2:22
+ |
+LL | println!("{}", 1 <=> 2);
+ | ^^^ `<=>` is not a valid comparison operator, use `std::cmp::Ordering`
+
+error: aborting due to previous error
+
diff --git a/src/test/ui/optimization-remark.rs b/src/test/ui/optimization-remark.rs
new file mode 100644
index 00000000000..36549cbc554
--- /dev/null
+++ b/src/test/ui/optimization-remark.rs
@@ -0,0 +1,28 @@
+// build-pass
+// ignore-pass
+// no-system-llvm
+// revisions: all inline merge1 merge2
+// compile-flags: --crate-type=lib -Cdebuginfo=1 -Copt-level=2
+//
+// Check that remarks can be enabled individually or with "all":
+//
+// [all] compile-flags: -Cremark=all
+// [inline] compile-flags: -Cremark=inline
+//
+// Check that values of -Cremark flag are accumulated:
+//
+// [merge1] compile-flags: -Cremark=all -Cremark=giraffe
+// [merge2] compile-flags: -Cremark=inline -Cremark=giraffe
+//
+// error-pattern: inline: f not inlined into g
+// dont-check-compiler-stderr
+
+#[no_mangle]
+#[inline(never)]
+pub fn f() {
+}
+
+#[no_mangle]
+pub fn g() {
+ f();
+}
diff --git a/src/test/ui/or-patterns/already-bound-name.stderr b/src/test/ui/or-patterns/already-bound-name.stderr
index 66112165622..92416a0d5cb 100644
--- a/src/test/ui/or-patterns/already-bound-name.stderr
+++ b/src/test/ui/or-patterns/already-bound-name.stderr
@@ -86,9 +86,8 @@ error[E0308]: mismatched types
--> $DIR/already-bound-name.rs:30:32
|
LL | let (B(A(a, _) | B(a)) | A(a, A(a, _) | B(a))) = B(B(1));
- | - ^ ------- this expression has type `E<E<{integer}>>`
- | | |
- | | expected integer, found enum `E`
+ | - ^ expected integer, found enum `E`
+ | |
| first introduced with type `{integer}` here
|
= note: expected type `{integer}`
diff --git a/src/test/ui/or-patterns/inconsistent-modes.stderr b/src/test/ui/or-patterns/inconsistent-modes.stderr
index dae6bb41e74..95e8618808c 100644
--- a/src/test/ui/or-patterns/inconsistent-modes.stderr
+++ b/src/test/ui/or-patterns/inconsistent-modes.stderr
@@ -65,9 +65,8 @@ error[E0308]: mismatched types
--> $DIR/inconsistent-modes.rs:13:32
|
LL | let (Ok((ref a, b)) | Err((ref mut a, ref b))) = Ok((0, &0));
- | ----- ^^^^^^^^^ ----------- this expression has type `Result<({integer}, &{integer}), (_, _)>`
- | | |
- | | types differ in mutability
+ | ----- ^^^^^^^^^ types differ in mutability
+ | |
| first introduced with type `&{integer}` here
|
= note: expected type `&{integer}`
diff --git a/src/test/ui/output-type-mismatch.stderr b/src/test/ui/output-type-mismatch.stderr
index 533bd87c9cc..4507a4df621 100644
--- a/src/test/ui/output-type-mismatch.stderr
+++ b/src/test/ui/output-type-mismatch.stderr
@@ -2,7 +2,9 @@ error[E0308]: mismatched types
--> $DIR/output-type-mismatch.rs:5:31
|
LL | fn main() { let i: isize; i = f(); }
- | ^^^ expected `isize`, found `()`
+ | ----- ^^^ expected `isize`, found `()`
+ | |
+ | expected due to this type
error: aborting due to previous error
diff --git a/src/test/ui/packed/issue-27060.stderr b/src/test/ui/packed/issue-27060.stderr
index 09297884ed3..bba056d59f8 100644
--- a/src/test/ui/packed/issue-27060.stderr
+++ b/src/test/ui/packed/issue-27060.stderr
@@ -12,6 +12,7 @@ LL | #[deny(unaligned_references)]
= warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
= note: for more information, see issue #82523 <https://github.com/rust-lang/rust/issues/82523>
= note: fields of packed structs are not properly aligned, and creating a misaligned reference is undefined behavior (even if that reference is never dereferenced)
+ = help: copy the field contents to a local variable, or replace the reference with a raw pointer and use `read_unaligned`/`write_unaligned` (loads and stores via `*p` must be properly aligned even when using raw pointers)
error: reference to packed field is unaligned
--> $DIR/issue-27060.rs:18:13
@@ -22,6 +23,7 @@ LL | let _ = &good.data2[0];
= warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
= note: for more information, see issue #82523 <https://github.com/rust-lang/rust/issues/82523>
= note: fields of packed structs are not properly aligned, and creating a misaligned reference is undefined behavior (even if that reference is never dereferenced)
+ = help: copy the field contents to a local variable, or replace the reference with a raw pointer and use `read_unaligned`/`write_unaligned` (loads and stores via `*p` must be properly aligned even when using raw pointers)
error: reference to packed field is unaligned
--> $DIR/issue-27060.rs:21:13
@@ -32,6 +34,7 @@ LL | let _ = &good.data;
= warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
= note: for more information, see issue #82523 <https://github.com/rust-lang/rust/issues/82523>
= note: fields of packed structs are not properly aligned, and creating a misaligned reference is undefined behavior (even if that reference is never dereferenced)
+ = help: copy the field contents to a local variable, or replace the reference with a raw pointer and use `read_unaligned`/`write_unaligned` (loads and stores via `*p` must be properly aligned even when using raw pointers)
error: reference to packed field is unaligned
--> $DIR/issue-27060.rs:23:13
@@ -42,6 +45,7 @@ LL | let _ = &good.data2[0];
= warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
= note: for more information, see issue #82523 <https://github.com/rust-lang/rust/issues/82523>
= note: fields of packed structs are not properly aligned, and creating a misaligned reference is undefined behavior (even if that reference is never dereferenced)
+ = help: copy the field contents to a local variable, or replace the reference with a raw pointer and use `read_unaligned`/`write_unaligned` (loads and stores via `*p` must be properly aligned even when using raw pointers)
error: aborting due to 4 previous errors
diff --git a/src/test/ui/packed/packed-struct-borrow-element-64bit.stderr b/src/test/ui/packed/packed-struct-borrow-element-64bit.stderr
index 766d8a72c34..04585b49986 100644
--- a/src/test/ui/packed/packed-struct-borrow-element-64bit.stderr
+++ b/src/test/ui/packed/packed-struct-borrow-element-64bit.stderr
@@ -8,6 +8,7 @@ LL | let brw = &foo.baz;
= warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
= note: for more information, see issue #82523 <https://github.com/rust-lang/rust/issues/82523>
= note: fields of packed structs are not properly aligned, and creating a misaligned reference is undefined behavior (even if that reference is never dereferenced)
+ = help: copy the field contents to a local variable, or replace the reference with a raw pointer and use `read_unaligned`/`write_unaligned` (loads and stores via `*p` must be properly aligned even when using raw pointers)
warning: 1 warning emitted
diff --git a/src/test/ui/packed/packed-struct-borrow-element.stderr b/src/test/ui/packed/packed-struct-borrow-element.stderr
index 5764e951a46..a50b1302001 100644
--- a/src/test/ui/packed/packed-struct-borrow-element.stderr
+++ b/src/test/ui/packed/packed-struct-borrow-element.stderr
@@ -8,6 +8,7 @@ LL | let brw = &foo.baz;
= warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
= note: for more information, see issue #82523 <https://github.com/rust-lang/rust/issues/82523>
= note: fields of packed structs are not properly aligned, and creating a misaligned reference is undefined behavior (even if that reference is never dereferenced)
+ = help: copy the field contents to a local variable, or replace the reference with a raw pointer and use `read_unaligned`/`write_unaligned` (loads and stores via `*p` must be properly aligned even when using raw pointers)
warning: reference to packed field is unaligned
--> $DIR/packed-struct-borrow-element.rs:30:15
@@ -18,6 +19,7 @@ LL | let brw = &foo.baz;
= warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
= note: for more information, see issue #82523 <https://github.com/rust-lang/rust/issues/82523>
= note: fields of packed structs are not properly aligned, and creating a misaligned reference is undefined behavior (even if that reference is never dereferenced)
+ = help: copy the field contents to a local variable, or replace the reference with a raw pointer and use `read_unaligned`/`write_unaligned` (loads and stores via `*p` must be properly aligned even when using raw pointers)
warning: 2 warnings emitted
diff --git a/src/test/ui/packed/packed-struct-drop-aligned.rs b/src/test/ui/packed/packed-struct-drop-aligned.rs
index fab3bbedac6..b95cdbbbaad 100644
--- a/src/test/ui/packed/packed-struct-drop-aligned.rs
+++ b/src/test/ui/packed/packed-struct-drop-aligned.rs
@@ -1,6 +1,10 @@
// run-pass
+#![feature(generators)]
+#![feature(generator_trait)]
use std::cell::Cell;
use std::mem;
+use std::ops::Generator;
+use std::pin::Pin;
struct Aligned<'a> {
drop_count: &'a Cell<usize>
@@ -19,15 +23,35 @@ impl<'a> Drop for Aligned<'a> {
}
}
+#[repr(transparent)]
+struct NotCopy(u8);
+
#[repr(packed)]
-struct Packed<'a>(u8, Aligned<'a>);
+struct Packed<'a>(NotCopy, Aligned<'a>);
fn main() {
let drop_count = &Cell::new(0);
{
- let mut p = Packed(0, Aligned { drop_count });
+ let mut p = Packed(NotCopy(0), Aligned { drop_count });
p.1 = Aligned { drop_count };
assert_eq!(drop_count.get(), 1);
}
assert_eq!(drop_count.get(), 2);
+
+ let drop_count = &Cell::new(0);
+ let mut g = || {
+ let mut p = Packed(NotCopy(0), Aligned { drop_count });
+ let _ = &p;
+ p.1 = Aligned { drop_count };
+ assert_eq!(drop_count.get(), 1);
+ // Test that a generator drop function moves a value from a packed
+ // struct to a separate local before dropping it. We move out the
+ // first field to generate and open drop for the second field.
+ drop(p.0);
+ yield;
+ };
+ Pin::new(&mut g).resume(());
+ assert_eq!(drop_count.get(), 1);
+ drop(g);
+ assert_eq!(drop_count.get(), 2);
}
diff --git a/src/test/ui/panic-handler/weak-lang-item.stderr b/src/test/ui/panic-handler/weak-lang-item.stderr
index 1f14b20e451..cc25f08e33a 100644
--- a/src/test/ui/panic-handler/weak-lang-item.stderr
+++ b/src/test/ui/panic-handler/weak-lang-item.stderr
@@ -11,6 +11,9 @@ LL | extern crate core as other_core;
|
error: language item required, but not found: `eh_personality`
+ |
+ = note: this can occur when a binary crate with `#![no_std]` is compiled for a target where `eh_personality` is defined in the standard library
+ = help: you may be able to compile for a target that doesn't need `eh_personality`, specify a target with `--target` or in `.cargo/config`
error: `#[panic_handler]` function required, but not found
diff --git a/src/test/ui/panics/location-detail-panic-no-column.rs b/src/test/ui/panics/location-detail-panic-no-column.rs
index 673e638ca0d..7cf1bb09c92 100644
--- a/src/test/ui/panics/location-detail-panic-no-column.rs
+++ b/src/test/ui/panics/location-detail-panic-no-column.rs
@@ -1,6 +1,7 @@
// run-fail
// check-run-results
// compile-flags: -Zlocation-detail=line,file
+// exec-env:RUST_BACKTRACE=0
fn main() {
panic!("column-redacted");
diff --git a/src/test/ui/panics/location-detail-panic-no-column.run.stderr b/src/test/ui/panics/location-detail-panic-no-column.run.stderr
index 9f35623fba3..46c9b8448d7 100644
--- a/src/test/ui/panics/location-detail-panic-no-column.run.stderr
+++ b/src/test/ui/panics/location-detail-panic-no-column.run.stderr
@@ -1,2 +1,2 @@
-thread 'main' panicked at 'column-redacted', $DIR/location-detail-panic-no-column.rs:6:0
+thread 'main' panicked at 'column-redacted', $DIR/location-detail-panic-no-column.rs:7:0
note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace
diff --git a/src/test/ui/panics/location-detail-panic-no-file.rs b/src/test/ui/panics/location-detail-panic-no-file.rs
index 0e5d52cfd15..9bcbf01d1c6 100644
--- a/src/test/ui/panics/location-detail-panic-no-file.rs
+++ b/src/test/ui/panics/location-detail-panic-no-file.rs
@@ -1,6 +1,7 @@
// run-fail
// check-run-results
// compile-flags: -Zlocation-detail=line,column
+// exec-env:RUST_BACKTRACE=0
fn main() {
panic!("file-redacted");
diff --git a/src/test/ui/panics/location-detail-panic-no-file.run.stderr b/src/test/ui/panics/location-detail-panic-no-file.run.stderr
index 1e07e3a07af..811f93bf308 100644
--- a/src/test/ui/panics/location-detail-panic-no-file.run.stderr
+++ b/src/test/ui/panics/location-detail-panic-no-file.run.stderr
@@ -1,2 +1,2 @@
-thread 'main' panicked at 'file-redacted', <redacted>:6:5
+thread 'main' panicked at 'file-redacted', <redacted>:7:5
note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace
diff --git a/src/test/ui/panics/location-detail-panic-no-line.rs b/src/test/ui/panics/location-detail-panic-no-line.rs
index 57f6d0ebcb9..25df092e1fb 100644
--- a/src/test/ui/panics/location-detail-panic-no-line.rs
+++ b/src/test/ui/panics/location-detail-panic-no-line.rs
@@ -1,6 +1,7 @@
// run-fail
// check-run-results
// compile-flags: -Zlocation-detail=file,column
+// exec-env:RUST_BACKTRACE=0
fn main() {
panic!("line-redacted");
diff --git a/src/test/ui/panics/location-detail-unwrap-no-file.rs b/src/test/ui/panics/location-detail-unwrap-no-file.rs
index d7f96f058e0..16cf8a17ff1 100644
--- a/src/test/ui/panics/location-detail-unwrap-no-file.rs
+++ b/src/test/ui/panics/location-detail-unwrap-no-file.rs
@@ -1,6 +1,7 @@
// run-fail
// check-run-results
// compile-flags: -Zlocation-detail=line,column
+// exec-env:RUST_BACKTRACE=0
fn main() {
let opt: Option<u32> = None;
diff --git a/src/test/ui/panics/location-detail-unwrap-no-file.run.stderr b/src/test/ui/panics/location-detail-unwrap-no-file.run.stderr
index f8f84b5c49a..7d8e1d93038 100644
--- a/src/test/ui/panics/location-detail-unwrap-no-file.run.stderr
+++ b/src/test/ui/panics/location-detail-unwrap-no-file.run.stderr
@@ -1,2 +1,2 @@
-thread 'main' panicked at 'called `Option::unwrap()` on a `None` value', <redacted>:7:9
+thread 'main' panicked at 'called `Option::unwrap()` on a `None` value', <redacted>:8:9
note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace
diff --git a/src/test/ui/panics/panic-handler-chain.rs b/src/test/ui/panics/panic-handler-chain.rs
index 93044b5cb25..73d6e790dff 100644
--- a/src/test/ui/panics/panic-handler-chain.rs
+++ b/src/test/ui/panics/panic-handler-chain.rs
@@ -1,4 +1,5 @@
// run-pass
+// needs-unwind
#![allow(stable_features)]
// ignore-emscripten no threads support
diff --git a/src/test/ui/panics/panic-handler-flail-wildly.rs b/src/test/ui/panics/panic-handler-flail-wildly.rs
index 6badd203842..679dc7de87a 100644
--- a/src/test/ui/panics/panic-handler-flail-wildly.rs
+++ b/src/test/ui/panics/panic-handler-flail-wildly.rs
@@ -1,4 +1,5 @@
// run-pass
+// needs-unwind
#![allow(stable_features)]
#![allow(unused_must_use)]
diff --git a/src/test/ui/panics/panic-handler-set-twice.rs b/src/test/ui/panics/panic-handler-set-twice.rs
index 0312ed221ca..27445302090 100644
--- a/src/test/ui/panics/panic-handler-set-twice.rs
+++ b/src/test/ui/panics/panic-handler-set-twice.rs
@@ -1,4 +1,5 @@
// run-pass
+// needs-unwind
#![allow(unused_variables)]
#![allow(stable_features)]
diff --git a/src/test/ui/panics/panic-in-dtor-drops-fields.rs b/src/test/ui/panics/panic-in-dtor-drops-fields.rs
index caddd942dc0..c0963aa3114 100644
--- a/src/test/ui/panics/panic-in-dtor-drops-fields.rs
+++ b/src/test/ui/panics/panic-in-dtor-drops-fields.rs
@@ -1,4 +1,5 @@
// run-pass
+// needs-unwind
#![allow(dead_code)]
#![allow(non_upper_case_globals)]
diff --git a/src/test/ui/panics/panic-recover-propagate.rs b/src/test/ui/panics/panic-recover-propagate.rs
index 7969336ca74..e110d94b656 100644
--- a/src/test/ui/panics/panic-recover-propagate.rs
+++ b/src/test/ui/panics/panic-recover-propagate.rs
@@ -1,4 +1,5 @@
// run-pass
+// needs-unwind
// ignore-emscripten no threads support
use std::sync::atomic::{AtomicUsize, Ordering};
diff --git a/src/test/ui/parser/const-param-decl-on-type-instead-of-impl.rs b/src/test/ui/parser/const-param-decl-on-type-instead-of-impl.rs
new file mode 100644
index 00000000000..53e3c6f9605
--- /dev/null
+++ b/src/test/ui/parser/const-param-decl-on-type-instead-of-impl.rs
@@ -0,0 +1,15 @@
+struct NInts<const N: usize>([u8; N]);
+impl NInts<const N: usize> {} //~ ERROR unexpected `const` parameter declaration
+
+fn main() {
+ let _: () = 42; //~ ERROR mismatched types
+}
+
+fn banana(a: <T<const N: usize>>::BAR) {}
+//~^ ERROR unexpected `const` parameter declaration
+//~| ERROR cannot find type `T` in this scope
+fn chaenomeles() {
+ path::path::Struct::<const N: usize>()
+ //~^ ERROR unexpected `const` parameter declaration
+ //~| ERROR failed to resolve: use of undeclared crate or module `path`
+}
diff --git a/src/test/ui/parser/const-param-decl-on-type-instead-of-impl.stderr b/src/test/ui/parser/const-param-decl-on-type-instead-of-impl.stderr
new file mode 100644
index 00000000000..96885d11ee0
--- /dev/null
+++ b/src/test/ui/parser/const-param-decl-on-type-instead-of-impl.stderr
@@ -0,0 +1,47 @@
+error: unexpected `const` parameter declaration
+ --> $DIR/const-param-decl-on-type-instead-of-impl.rs:2:12
+ |
+LL | impl NInts<const N: usize> {}
+ | ^^^^^^^^^^^^^^ expected a `const` expression, not a parameter declaration
+ |
+help: `const` parameters must be declared for the `impl`
+ |
+LL | impl<const N: usize> NInts<N> {}
+ | ++++++++++++++++ ~
+
+error: unexpected `const` parameter declaration
+ --> $DIR/const-param-decl-on-type-instead-of-impl.rs:8:17
+ |
+LL | fn banana(a: <T<const N: usize>>::BAR) {}
+ | ^^^^^^^^^^^^^^ expected a `const` expression, not a parameter declaration
+
+error: unexpected `const` parameter declaration
+ --> $DIR/const-param-decl-on-type-instead-of-impl.rs:12:26
+ |
+LL | path::path::Struct::<const N: usize>()
+ | ^^^^^^^^^^^^^^ expected a `const` expression, not a parameter declaration
+
+error[E0433]: failed to resolve: use of undeclared crate or module `path`
+ --> $DIR/const-param-decl-on-type-instead-of-impl.rs:12:5
+ |
+LL | path::path::Struct::<const N: usize>()
+ | ^^^^ use of undeclared crate or module `path`
+
+error[E0412]: cannot find type `T` in this scope
+ --> $DIR/const-param-decl-on-type-instead-of-impl.rs:8:15
+ |
+LL | fn banana(a: <T<const N: usize>>::BAR) {}
+ | ^ not found in this scope
+
+error[E0308]: mismatched types
+ --> $DIR/const-param-decl-on-type-instead-of-impl.rs:5:17
+ |
+LL | let _: () = 42;
+ | -- ^^ expected `()`, found integer
+ | |
+ | expected due to this
+
+error: aborting due to 6 previous errors
+
+Some errors have detailed explanations: E0308, E0412, E0433.
+For more information about an error, try `rustc --explain E0308`.
diff --git a/src/test/ui/parser/duplicate-visibility.rs b/src/test/ui/parser/duplicate-visibility.rs
index 87ba230eab5..32aeee29472 100644
--- a/src/test/ui/parser/duplicate-visibility.rs
+++ b/src/test/ui/parser/duplicate-visibility.rs
@@ -1,6 +1,9 @@
fn main() {}
-extern "C" {
+extern "C" { //~ NOTE while parsing this item list starting here
pub pub fn foo();
//~^ ERROR expected one of `(`, `async`, `const`, `default`, `extern`, `fn`, `pub`, `unsafe`, or `use`, found keyword `pub`
-}
+ //~| NOTE expected one of 9 possible tokens
+ //~| HELP there is already a visibility modifier, remove one
+ //~| NOTE explicit visibility first seen here
+} //~ NOTE the item list ends here
diff --git a/src/test/ui/parser/duplicate-visibility.stderr b/src/test/ui/parser/duplicate-visibility.stderr
index d9815fc7395..97144ac2f64 100644
--- a/src/test/ui/parser/duplicate-visibility.stderr
+++ b/src/test/ui/parser/duplicate-visibility.stderr
@@ -7,10 +7,16 @@ LL | pub pub fn foo();
| ^^^
| |
| expected one of 9 possible tokens
- | help: visibility `pub` must come before `pub pub`: `pub pub pub`
-LL |
+ | help: there is already a visibility modifier, remove one
+...
LL | }
| - the item list ends here
+ |
+note: explicit visibility first seen here
+ --> $DIR/duplicate-visibility.rs:4:5
+ |
+LL | pub pub fn foo();
+ | ^^^
error: aborting due to previous error
diff --git a/src/test/ui/parser/emoji-identifiers.rs b/src/test/ui/parser/emoji-identifiers.rs
new file mode 100644
index 00000000000..b50c046bcb2
--- /dev/null
+++ b/src/test/ui/parser/emoji-identifiers.rs
@@ -0,0 +1,19 @@
+struct ABig👩‍👩‍👧‍👧Family; //~ ERROR identifiers cannot contain emoji
+struct 👀; //~ ERROR identifiers cannot contain emoji
+impl 👀 {
+ fn full_of_✨() -> 👀 { //~ ERROR identifiers cannot contain emoji
+ 👀
+ }
+}
+fn i_like_to_😅_a_lot() -> 👀 { //~ ERROR identifiers cannot contain emoji
+ 👀::full_of✨() //~ ERROR no function or associated item named `full_of✨` found for struct `👀`
+ //~^ ERROR identifiers cannot contain emoji
+}
+fn main() {
+ let _ = i_like_to_😄_a_lot() ➖ 4; //~ ERROR cannot find function `i_like_to_😄_a_lot` in this scope
+ //~^ ERROR identifiers cannot contain emoji
+ //~| ERROR unknown start of token: \u{2796}
+
+ let 🦀 = 1;//~ ERROR Ferris cannot be used as an identifier
+ dbg!(🦀);
+}
diff --git a/src/test/ui/parser/emoji-identifiers.stderr b/src/test/ui/parser/emoji-identifiers.stderr
new file mode 100644
index 00000000000..7dc589e5563
--- /dev/null
+++ b/src/test/ui/parser/emoji-identifiers.stderr
@@ -0,0 +1,91 @@
+error: unknown start of token: \u{2796}
+ --> $DIR/emoji-identifiers.rs:13:33
+ |
+LL | let _ = i_like_to_😄_a_lot() ➖ 4;
+ | ^^
+ |
+help: Unicode character '➖' (Heavy Minus Sign) looks like '-' (Minus/Hyphen), but it is not
+ |
+LL | let _ = i_like_to_😄_a_lot() - 4;
+ | ~
+
+error[E0425]: cannot find function `i_like_to_😄_a_lot` in this scope
+ --> $DIR/emoji-identifiers.rs:13:13
+ |
+LL | fn i_like_to_😅_a_lot() -> 👀 {
+ | ----------------------------- similarly named function `i_like_to_😅_a_lot` defined here
+...
+LL | let _ = i_like_to_😄_a_lot() ➖ 4;
+ | ^^^^^^^^^^^^^^^^^^ help: a function with a similar name exists: `i_like_to_😅_a_lot`
+
+error: Ferris cannot be used as an identifier
+ --> $DIR/emoji-identifiers.rs:17:9
+ |
+LL | let 🦀 = 1;
+ | ^^ help: try using their name instead: `ferris`
+LL | dbg!(🦀);
+ | ^^
+
+error: identifiers cannot contain emoji: `ABig👩👩👧👧Family`
+ --> $DIR/emoji-identifiers.rs:1:8
+ |
+LL | struct ABig👩👩👧👧Family;
+ | ^^^^^^^^^^^^^^^^^^
+
+error: identifiers cannot contain emoji: `👀`
+ --> $DIR/emoji-identifiers.rs:2:8
+ |
+LL | struct 👀;
+ | ^^
+LL | impl 👀 {
+ | ^^
+LL | fn full_of_✨() -> 👀 {
+ | ^^
+LL | 👀
+ | ^^
+...
+LL | fn i_like_to_😅_a_lot() -> 👀 {
+ | ^^
+LL | 👀::full_of✨()
+ | ^^
+
+error: identifiers cannot contain emoji: `full_of_✨`
+ --> $DIR/emoji-identifiers.rs:4:8
+ |
+LL | fn full_of_✨() -> 👀 {
+ | ^^^^^^^^^^
+
+error: identifiers cannot contain emoji: `i_like_to_😅_a_lot`
+ --> $DIR/emoji-identifiers.rs:8:4
+ |
+LL | fn i_like_to_😅_a_lot() -> 👀 {
+ | ^^^^^^^^^^^^^^^^^^
+
+error: identifiers cannot contain emoji: `full_of✨`
+ --> $DIR/emoji-identifiers.rs:9:8
+ |
+LL | 👀::full_of✨()
+ | ^^^^^^^^^
+
+error: identifiers cannot contain emoji: `i_like_to_😄_a_lot`
+ --> $DIR/emoji-identifiers.rs:13:13
+ |
+LL | let _ = i_like_to_😄_a_lot() ➖ 4;
+ | ^^^^^^^^^^^^^^^^^^
+
+error[E0599]: no function or associated item named `full_of✨` found for struct `👀` in the current scope
+ --> $DIR/emoji-identifiers.rs:9:8
+ |
+LL | struct 👀;
+ | ---------- function or associated item `full_of✨` not found for this
+...
+LL | 👀::full_of✨()
+ | ^^^^^^^^^
+ | |
+ | function or associated item not found in `👀`
+ | help: there is an associated function with a similar name: `full_of_✨`
+
+error: aborting due to 10 previous errors
+
+Some errors have detailed explanations: E0425, E0599.
+For more information about an error, try `rustc --explain E0425`.
diff --git a/src/test/ui/parser/fn-header-semantic-fail.stderr b/src/test/ui/parser/fn-header-semantic-fail.stderr
index 75c60a0ea2a..8eaba559a62 100644
--- a/src/test/ui/parser/fn-header-semantic-fail.stderr
+++ b/src/test/ui/parser/fn-header-semantic-fail.stderr
@@ -183,9 +183,6 @@ LL | const async unsafe extern "C" fn fe5();
error[E0053]: method `ft1` has an incompatible type for trait
--> $DIR/fn-header-semantic-fail.rs:28:24
|
-LL | async fn ft1();
- | - type in trait
-...
LL | async fn ft1() {}
| ^
| |
@@ -193,15 +190,17 @@ LL | async fn ft1() {}
| expected `()`, found opaque type
|
= note: while checking the return type of the `async fn`
+note: type in trait
+ --> $DIR/fn-header-semantic-fail.rs:16:23
+ |
+LL | async fn ft1();
+ | ^
= note: expected fn pointer `fn()`
found fn pointer `fn() -> impl Future<Output = ()>`
error[E0053]: method `ft5` has an incompatible type for trait
--> $DIR/fn-header-semantic-fail.rs:33:48
|
-LL | const async unsafe extern "C" fn ft5();
- | - type in trait
-...
LL | const async unsafe extern "C" fn ft5() {}
| ^
| |
@@ -209,6 +208,11 @@ LL | const async unsafe extern "C" fn ft5() {}
| expected `()`, found opaque type
|
= note: while checking the return type of the `async fn`
+note: type in trait
+ --> $DIR/fn-header-semantic-fail.rs:20:47
+ |
+LL | const async unsafe extern "C" fn ft5();
+ | ^
= note: expected fn pointer `unsafe extern "C" fn()`
found fn pointer `unsafe extern "C" fn() -> impl Future<Output = ()>`
diff --git a/src/test/ui/parser/issue-87694-duplicated-pub.rs b/src/test/ui/parser/issue-87694-duplicated-pub.rs
new file mode 100644
index 00000000000..e3ea61dc4ad
--- /dev/null
+++ b/src/test/ui/parser/issue-87694-duplicated-pub.rs
@@ -0,0 +1,5 @@
+pub const pub fn test() {}
+//~^ ERROR expected one of `async`, `extern`, `fn`, or `unsafe`, found keyword `pub`
+//~| NOTE expected one of `async`, `extern`, `fn`, or `unsafe`
+//~| HELP there is already a visibility modifier, remove one
+//~| NOTE explicit visibility first seen here
diff --git a/src/test/ui/parser/issue-87694-duplicated-pub.stderr b/src/test/ui/parser/issue-87694-duplicated-pub.stderr
new file mode 100644
index 00000000000..8d242bc9de5
--- /dev/null
+++ b/src/test/ui/parser/issue-87694-duplicated-pub.stderr
@@ -0,0 +1,17 @@
+error: expected one of `async`, `extern`, `fn`, or `unsafe`, found keyword `pub`
+ --> $DIR/issue-87694-duplicated-pub.rs:1:11
+ |
+LL | pub const pub fn test() {}
+ | ^^^
+ | |
+ | expected one of `async`, `extern`, `fn`, or `unsafe`
+ | help: there is already a visibility modifier, remove one
+ |
+note: explicit visibility first seen here
+ --> $DIR/issue-87694-duplicated-pub.rs:1:1
+ |
+LL | pub const pub fn test() {}
+ | ^^^
+
+error: aborting due to previous error
+
diff --git a/src/test/ui/parser/issue-87694-misplaced-pub.rs b/src/test/ui/parser/issue-87694-misplaced-pub.rs
new file mode 100644
index 00000000000..3f824617cad
--- /dev/null
+++ b/src/test/ui/parser/issue-87694-misplaced-pub.rs
@@ -0,0 +1,5 @@
+const pub fn test() {}
+//~^ ERROR expected one of `async`, `extern`, `fn`, or `unsafe`, found keyword `pub`
+//~| NOTE expected one of `async`, `extern`, `fn`, or `unsafe`
+//~| HELP visibility `pub` must come before `const`
+//~| SUGGESTION pub const
diff --git a/src/test/ui/parser/issue-87694-misplaced-pub.stderr b/src/test/ui/parser/issue-87694-misplaced-pub.stderr
new file mode 100644
index 00000000000..94c6a29efcb
--- /dev/null
+++ b/src/test/ui/parser/issue-87694-misplaced-pub.stderr
@@ -0,0 +1,11 @@
+error: expected one of `async`, `extern`, `fn`, or `unsafe`, found keyword `pub`
+ --> $DIR/issue-87694-misplaced-pub.rs:1:7
+ |
+LL | const pub fn test() {}
+ | ------^^^
+ | | |
+ | | expected one of `async`, `extern`, `fn`, or `unsafe`
+ | help: visibility `pub` must come before `const`: `pub const`
+
+error: aborting due to previous error
+
diff --git a/src/test/ui/parser/issue-91421.rs b/src/test/ui/parser/issue-91421.rs
new file mode 100644
index 00000000000..9959df56638
--- /dev/null
+++ b/src/test/ui/parser/issue-91421.rs
@@ -0,0 +1,10 @@
+// Regression test for issue #91421.
+
+fn main() {
+ let value = if true && {
+ //~^ ERROR: this `if` expression has a condition, but no block
+ //~| HELP: maybe you forgot the right operand of the condition?
+ 3
+ //~^ ERROR: mismatched types [E0308]
+ } else { 4 };
+}
diff --git a/src/test/ui/parser/issue-91421.stderr b/src/test/ui/parser/issue-91421.stderr
new file mode 100644
index 00000000000..04284d5e3b2
--- /dev/null
+++ b/src/test/ui/parser/issue-91421.stderr
@@ -0,0 +1,21 @@
+error: this `if` expression has a condition, but no block
+ --> $DIR/issue-91421.rs:4:17
+ |
+LL | let value = if true && {
+ | ^^
+ |
+help: maybe you forgot the right operand of the condition?
+ --> $DIR/issue-91421.rs:4:25
+ |
+LL | let value = if true && {
+ | ^^
+
+error[E0308]: mismatched types
+ --> $DIR/issue-91421.rs:7:9
+ |
+LL | 3
+ | ^ expected `bool`, found integer
+
+error: aborting due to 2 previous errors
+
+For more information about this error, try `rustc --explain E0308`.
diff --git a/src/test/ui/parser/issues/issue-14303-enum.stderr b/src/test/ui/parser/issues/issue-14303-enum.stderr
index bcecd75b1ab..55cef4cabac 100644
--- a/src/test/ui/parser/issues/issue-14303-enum.stderr
+++ b/src/test/ui/parser/issues/issue-14303-enum.stderr
@@ -2,7 +2,7 @@ error: lifetime parameters must be declared prior to type parameters
--> $DIR/issue-14303-enum.rs:1:15
|
LL | enum X<'a, T, 'b> {
- | --------^^- help: reorder the parameters: lifetimes, then types, then consts: `<'a, 'b, T>`
+ | --------^^- help: reorder the parameters: lifetimes, then consts and types: `<'a, 'b, T>`
error: aborting due to previous error
diff --git a/src/test/ui/parser/issues/issue-14303-fn-def.stderr b/src/test/ui/parser/issues/issue-14303-fn-def.stderr
index 082c37e0be7..bacc922969d 100644
--- a/src/test/ui/parser/issues/issue-14303-fn-def.stderr
+++ b/src/test/ui/parser/issues/issue-14303-fn-def.stderr
@@ -2,7 +2,7 @@ error: lifetime parameters must be declared prior to type parameters
--> $DIR/issue-14303-fn-def.rs:1:15
|
LL | fn foo<'a, T, 'b>(x: &'a T) {}
- | --------^^- help: reorder the parameters: lifetimes, then types, then consts: `<'a, 'b, T>`
+ | --------^^- help: reorder the parameters: lifetimes, then consts and types: `<'a, 'b, T>`
error: aborting due to previous error
diff --git a/src/test/ui/parser/issues/issue-14303-impl.stderr b/src/test/ui/parser/issues/issue-14303-impl.stderr
index 3b5615d2a9e..d6be02f70fd 100644
--- a/src/test/ui/parser/issues/issue-14303-impl.stderr
+++ b/src/test/ui/parser/issues/issue-14303-impl.stderr
@@ -2,7 +2,7 @@ error: lifetime parameters must be declared prior to type parameters
--> $DIR/issue-14303-impl.rs:3:13
|
LL | impl<'a, T, 'b> X<T> {}
- | --------^^- help: reorder the parameters: lifetimes, then types, then consts: `<'a, 'b, T>`
+ | --------^^- help: reorder the parameters: lifetimes, then consts and types: `<'a, 'b, T>`
error: aborting due to previous error
diff --git a/src/test/ui/parser/issues/issue-14303-struct.stderr b/src/test/ui/parser/issues/issue-14303-struct.stderr
index dbd0b987dd1..fa62a39f241 100644
--- a/src/test/ui/parser/issues/issue-14303-struct.stderr
+++ b/src/test/ui/parser/issues/issue-14303-struct.stderr
@@ -2,7 +2,7 @@ error: lifetime parameters must be declared prior to type parameters
--> $DIR/issue-14303-struct.rs:1:17
|
LL | struct X<'a, T, 'b> {
- | --------^^- help: reorder the parameters: lifetimes, then types, then consts: `<'a, 'b, T>`
+ | --------^^- help: reorder the parameters: lifetimes, then consts and types: `<'a, 'b, T>`
error: aborting due to previous error
diff --git a/src/test/ui/parser/issues/issue-14303-trait.stderr b/src/test/ui/parser/issues/issue-14303-trait.stderr
index 7dfa62d823f..75cd67a9ded 100644
--- a/src/test/ui/parser/issues/issue-14303-trait.stderr
+++ b/src/test/ui/parser/issues/issue-14303-trait.stderr
@@ -2,7 +2,7 @@ error: lifetime parameters must be declared prior to type parameters
--> $DIR/issue-14303-trait.rs:1:18
|
LL | trait Foo<'a, T, 'b> {}
- | --------^^- help: reorder the parameters: lifetimes, then types, then consts: `<'a, 'b, T>`
+ | --------^^- help: reorder the parameters: lifetimes, then consts and types: `<'a, 'b, T>`
error: aborting due to previous error
diff --git a/src/test/ui/parser/issues/issue-24780.rs b/src/test/ui/parser/issues/issue-24780.rs
index 480d9bc2bad..017521f570c 100644
--- a/src/test/ui/parser/issues/issue-24780.rs
+++ b/src/test/ui/parser/issues/issue-24780.rs
@@ -2,7 +2,7 @@
// to happen in #24780. For example, following should be an error:
// expected one of ..., `>`, ... found `>`.
-fn foo() -> Vec<usize>> { //~ ERROR expected one of `!`, `+`, `::`, `;`, `where`, or `{`, found `>`
+fn foo() -> Vec<usize>> { //~ ERROR expected one of `!`, `+`, `::`, `where`, or `{`, found `>`
Vec::new()
}
diff --git a/src/test/ui/parser/issues/issue-24780.stderr b/src/test/ui/parser/issues/issue-24780.stderr
index bdd089bb7a1..d9470191b25 100644
--- a/src/test/ui/parser/issues/issue-24780.stderr
+++ b/src/test/ui/parser/issues/issue-24780.stderr
@@ -1,8 +1,8 @@
-error: expected one of `!`, `+`, `::`, `;`, `where`, or `{`, found `>`
+error: expected one of `!`, `+`, `::`, `where`, or `{`, found `>`
--> $DIR/issue-24780.rs:5:23
|
LL | fn foo() -> Vec<usize>> {
- | ^ expected one of `!`, `+`, `::`, `;`, `where`, or `{`
+ | ^ expected one of `!`, `+`, `::`, `where`, or `{`
error: aborting due to previous error
diff --git a/src/test/ui/parser/issues/issue-58856-1.rs b/src/test/ui/parser/issues/issue-58856-1.rs
index 332a3014416..ea80eb8714f 100644
--- a/src/test/ui/parser/issues/issue-58856-1.rs
+++ b/src/test/ui/parser/issues/issue-58856-1.rs
@@ -2,7 +2,7 @@ impl A {
//~^ ERROR cannot find type `A` in this scope
fn b(self>
//~^ ERROR expected one of `)`, `,`, or `:`, found `>`
- //~| ERROR expected one of `->`, `;`, `where`, or `{`, found `>`
+ //~| ERROR expected one of `->`, `where`, or `{`, found `>`
}
fn main() {}
diff --git a/src/test/ui/parser/issues/issue-58856-1.stderr b/src/test/ui/parser/issues/issue-58856-1.stderr
index 2afb26d1758..96151f3fe07 100644
--- a/src/test/ui/parser/issues/issue-58856-1.stderr
+++ b/src/test/ui/parser/issues/issue-58856-1.stderr
@@ -6,14 +6,14 @@ LL | fn b(self>
| |
| unclosed delimiter
-error: expected one of `->`, `;`, `where`, or `{`, found `>`
+error: expected one of `->`, `where`, or `{`, found `>`
--> $DIR/issue-58856-1.rs:3:14
|
LL | impl A {
| - while parsing this item list starting here
LL |
LL | fn b(self>
- | ^ expected one of `->`, `;`, `where`, or `{`
+ | ^ expected one of `->`, `where`, or `{`
...
LL | }
| - the item list ends here
diff --git a/src/test/ui/parser/issues/issue-68890-2.rs b/src/test/ui/parser/issues/issue-68890-2.rs
index 0a6e26acfc7..29c12352146 100644
--- a/src/test/ui/parser/issues/issue-68890-2.rs
+++ b/src/test/ui/parser/issues/issue-68890-2.rs
@@ -3,5 +3,3 @@ fn main() {}
type X<'a> = (?'a) +;
//~^ ERROR `?` may only modify trait bounds, not lifetime bounds
//~| ERROR at least one trait is required for an object type
-//~| WARN trait objects without an explicit `dyn` are deprecated
-//~| WARN this is accepted in the current edition
diff --git a/src/test/ui/parser/issues/issue-68890-2.stderr b/src/test/ui/parser/issues/issue-68890-2.stderr
index 1a64b9a017d..d9fb7beebdb 100644
--- a/src/test/ui/parser/issues/issue-68890-2.stderr
+++ b/src/test/ui/parser/issues/issue-68890-2.stderr
@@ -4,22 +4,12 @@ error: `?` may only modify trait bounds, not lifetime bounds
LL | type X<'a> = (?'a) +;
| ^
-warning: trait objects without an explicit `dyn` are deprecated
- --> $DIR/issue-68890-2.rs:3:14
- |
-LL | type X<'a> = (?'a) +;
- | ^^^^^^^ help: use `dyn`: `dyn (?'a) +`
- |
- = note: `#[warn(bare_trait_objects)]` on by default
- = warning: this is accepted in the current edition (Rust 2015) but is a hard error in Rust 2021!
- = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2021/warnings-promoted-to-error.html>
-
error[E0224]: at least one trait is required for an object type
--> $DIR/issue-68890-2.rs:3:14
|
LL | type X<'a> = (?'a) +;
| ^^^^^^^
-error: aborting due to 2 previous errors; 1 warning emitted
+error: aborting due to 2 previous errors
For more information about this error, try `rustc --explain E0224`.
diff --git a/src/test/ui/parser/issues/issue-73568-lifetime-after-mut.rs b/src/test/ui/parser/issues/issue-73568-lifetime-after-mut.rs
index e68ee747cfd..5f731f8db77 100644
--- a/src/test/ui/parser/issues/issue-73568-lifetime-after-mut.rs
+++ b/src/test/ui/parser/issues/issue-73568-lifetime-after-mut.rs
@@ -13,11 +13,7 @@ mac!('a);
// avoid false positives
fn y<'a>(y: &mut 'a + Send) {
//~^ ERROR expected a path on the left-hand side of `+`, not `&mut 'a`
- //~| WARNING trait objects without an explicit `dyn` are deprecated
- //~| WARN this is accepted in the current edition
//~| ERROR at least one trait is required for an object type
let z = y as &mut 'a + Send;
//~^ ERROR expected value, found trait `Send`
- //~| WARNING trait objects without an explicit `dyn` are deprecated
- //~| WARN this is accepted in the current edition
}
diff --git a/src/test/ui/parser/issues/issue-73568-lifetime-after-mut.stderr b/src/test/ui/parser/issues/issue-73568-lifetime-after-mut.stderr
index 48c2b2a19d4..799bc16bd6a 100644
--- a/src/test/ui/parser/issues/issue-73568-lifetime-after-mut.stderr
+++ b/src/test/ui/parser/issues/issue-73568-lifetime-after-mut.stderr
@@ -22,37 +22,18 @@ LL | mac!('a);
= note: this error originates in the macro `mac` (in Nightly builds, run with -Z macro-backtrace for more info)
error[E0423]: expected value, found trait `Send`
- --> $DIR/issue-73568-lifetime-after-mut.rs:19:28
+ --> $DIR/issue-73568-lifetime-after-mut.rs:17:28
|
LL | let z = y as &mut 'a + Send;
| ^^^^ not a value
-warning: trait objects without an explicit `dyn` are deprecated
- --> $DIR/issue-73568-lifetime-after-mut.rs:14:18
- |
-LL | fn y<'a>(y: &mut 'a + Send) {
- | ^^ help: use `dyn`: `dyn 'a`
- |
- = note: `#[warn(bare_trait_objects)]` on by default
- = warning: this is accepted in the current edition (Rust 2015) but is a hard error in Rust 2021!
- = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2021/warnings-promoted-to-error.html>
-
-warning: trait objects without an explicit `dyn` are deprecated
- --> $DIR/issue-73568-lifetime-after-mut.rs:19:23
- |
-LL | let z = y as &mut 'a + Send;
- | ^^ help: use `dyn`: `dyn 'a`
- |
- = warning: this is accepted in the current edition (Rust 2015) but is a hard error in Rust 2021!
- = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2021/warnings-promoted-to-error.html>
-
error[E0224]: at least one trait is required for an object type
--> $DIR/issue-73568-lifetime-after-mut.rs:14:18
|
LL | fn y<'a>(y: &mut 'a + Send) {
| ^^
-error: aborting due to 5 previous errors; 2 warnings emitted
+error: aborting due to 5 previous errors
Some errors have detailed explanations: E0178, E0224, E0423.
For more information about an error, try `rustc --explain E0178`.
diff --git a/src/test/ui/parser/issues/issue-84148-1.stderr b/src/test/ui/parser/issues/issue-84148-1.stderr
index 98506568d82..77f0896e9c1 100644
--- a/src/test/ui/parser/issues/issue-84148-1.stderr
+++ b/src/test/ui/parser/issues/issue-84148-1.stderr
@@ -13,11 +13,11 @@ LL | fn f(t:for<>t?)
| expected one of `(`, `)`, `+`, `,`, `::`, or `<`
| help: missing `,`
-error: expected one of `->`, `;`, `where`, or `{`, found `<eof>`
+error: expected one of `->`, `where`, or `{`, found `<eof>`
--> $DIR/issue-84148-1.rs:1:15
|
LL | fn f(t:for<>t?)
- | ^ expected one of `->`, `;`, `where`, or `{`
+ | ^ expected one of `->`, `where`, or `{`
error: aborting due to 3 previous errors
diff --git a/src/test/ui/parser/issues/issue-84148-2.stderr b/src/test/ui/parser/issues/issue-84148-2.stderr
index 6f314da4360..396208316df 100644
--- a/src/test/ui/parser/issues/issue-84148-2.stderr
+++ b/src/test/ui/parser/issues/issue-84148-2.stderr
@@ -21,11 +21,11 @@ LL | fn f(t:for<>t?
| expected one of `(`, `)`, `+`, `,`, `::`, or `<`
| help: missing `,`
-error: expected one of `->`, `;`, `where`, or `{`, found `<eof>`
+error: expected one of `->`, `where`, or `{`, found `<eof>`
--> $DIR/issue-84148-2.rs:4:16
|
LL | fn f(t:for<>t?
- | ^ expected one of `->`, `;`, `where`, or `{`
+ | ^ expected one of `->`, `where`, or `{`
error: aborting due to 4 previous errors
diff --git a/src/test/ui/parser/issues/issue-87086-colon-path-sep.rs b/src/test/ui/parser/issues/issue-87086-colon-path-sep.rs
index 4ee0b2054ff..0b7b67496d6 100644
--- a/src/test/ui/parser/issues/issue-87086-colon-path-sep.rs
+++ b/src/test/ui/parser/issues/issue-87086-colon-path-sep.rs
@@ -1,11 +1,15 @@
// Tests that a suggestion is issued if the user wrote a colon instead of
// a path separator in a match arm.
-enum Foo {
- Bar,
- Baz,
+mod qux {
+ pub enum Foo {
+ Bar,
+ Baz,
+ }
}
+use qux::Foo;
+
fn f() -> Foo { Foo::Bar }
fn g1() {
@@ -16,24 +20,24 @@ fn g1() {
_ => {}
}
match f() {
- Foo::Bar:Baz => {}
+ qux::Foo:Bar => {}
//~^ ERROR: expected one of
//~| HELP: maybe write a path separator here
_ => {}
}
match f() {
- Foo:Bar::Baz => {}
+ qux:Foo::Baz => {}
//~^ ERROR: expected one of
//~| HELP: maybe write a path separator here
_ => {}
}
match f() {
- Foo: Bar::Baz if true => {}
+ qux: Foo::Baz if true => {}
//~^ ERROR: expected one of
//~| HELP: maybe write a path separator here
_ => {}
}
- if let Bar:Baz = f() {
+ if let Foo:Bar = f() {
//~^ ERROR: expected one of
//~| HELP: maybe write a path separator here
}
@@ -41,16 +45,18 @@ fn g1() {
fn g1_neg() {
match f() {
- ref Foo: Bar::Baz => {}
+ ref qux: Foo::Baz => {}
//~^ ERROR: expected one of
+ //~| HELP: maybe write a path separator here
_ => {}
}
}
fn g2_neg() {
match f() {
- mut Foo: Bar::Baz => {}
+ mut qux: Foo::Baz => {}
//~^ ERROR: expected one of
+ //~| HELP: maybe write a path separator here
_ => {}
}
}
@@ -62,5 +68,12 @@ fn main() {
Foo:Bar::Baz => {}
//~^ ERROR: expected one of
//~| HELP: maybe write a path separator here
+ //~| ERROR: failed to resolve: `Bar` is a variant, not a module
+ }
+ match myfoo {
+ Foo::Bar => {}
+ Foo:Bar => {}
+ //~^ ERROR: expected one of
+ //~| HELP: maybe write a path separator here
}
}
diff --git a/src/test/ui/parser/issues/issue-87086-colon-path-sep.stderr b/src/test/ui/parser/issues/issue-87086-colon-path-sep.stderr
index 8f93661a626..2050a16beb3 100644
--- a/src/test/ui/parser/issues/issue-87086-colon-path-sep.stderr
+++ b/src/test/ui/parser/issues/issue-87086-colon-path-sep.stderr
@@ -1,5 +1,5 @@
error: expected one of `@` or `|`, found `:`
- --> $DIR/issue-87086-colon-path-sep.rs:13:12
+ --> $DIR/issue-87086-colon-path-sep.rs:17:12
|
LL | Foo:Bar => {}
| ^
@@ -8,55 +8,61 @@ LL | Foo:Bar => {}
| help: maybe write a path separator here: `::`
error: expected one of `!`, `(`, `...`, `..=`, `..`, `::`, `{`, or `|`, found `:`
- --> $DIR/issue-87086-colon-path-sep.rs:19:17
+ --> $DIR/issue-87086-colon-path-sep.rs:23:17
|
-LL | Foo::Bar:Baz => {}
+LL | qux::Foo:Bar => {}
| ^
| |
| expected one of 8 possible tokens
| help: maybe write a path separator here: `::`
error: expected one of `@` or `|`, found `:`
- --> $DIR/issue-87086-colon-path-sep.rs:25:12
+ --> $DIR/issue-87086-colon-path-sep.rs:29:12
|
-LL | Foo:Bar::Baz => {}
+LL | qux:Foo::Baz => {}
| ^
| |
| expected one of `@` or `|`
| help: maybe write a path separator here: `::`
error: expected one of `@` or `|`, found `:`
- --> $DIR/issue-87086-colon-path-sep.rs:31:12
+ --> $DIR/issue-87086-colon-path-sep.rs:35:12
|
-LL | Foo: Bar::Baz if true => {}
+LL | qux: Foo::Baz if true => {}
| ^
| |
| expected one of `@` or `|`
| help: maybe write a path separator here: `::`
error: expected one of `@` or `|`, found `:`
- --> $DIR/issue-87086-colon-path-sep.rs:36:15
+ --> $DIR/issue-87086-colon-path-sep.rs:40:15
|
-LL | if let Bar:Baz = f() {
+LL | if let Foo:Bar = f() {
| ^
| |
| expected one of `@` or `|`
| help: maybe write a path separator here: `::`
-error: expected one of `=>`, `@`, `if`, or `|`, found `:`
- --> $DIR/issue-87086-colon-path-sep.rs:44:16
+error: expected one of `@` or `|`, found `:`
+ --> $DIR/issue-87086-colon-path-sep.rs:48:16
|
-LL | ref Foo: Bar::Baz => {}
- | ^ expected one of `=>`, `@`, `if`, or `|`
+LL | ref qux: Foo::Baz => {}
+ | ^
+ | |
+ | expected one of `@` or `|`
+ | help: maybe write a path separator here: `::`
-error: expected one of `=>`, `@`, `if`, or `|`, found `:`
- --> $DIR/issue-87086-colon-path-sep.rs:52:16
+error: expected one of `@` or `|`, found `:`
+ --> $DIR/issue-87086-colon-path-sep.rs:57:16
|
-LL | mut Foo: Bar::Baz => {}
- | ^ expected one of `=>`, `@`, `if`, or `|`
+LL | mut qux: Foo::Baz => {}
+ | ^
+ | |
+ | expected one of `@` or `|`
+ | help: maybe write a path separator here: `::`
error: expected one of `@` or `|`, found `:`
- --> $DIR/issue-87086-colon-path-sep.rs:62:12
+ --> $DIR/issue-87086-colon-path-sep.rs:68:12
|
LL | Foo:Bar::Baz => {}
| ^
@@ -64,5 +70,21 @@ LL | Foo:Bar::Baz => {}
| expected one of `@` or `|`
| help: maybe write a path separator here: `::`
-error: aborting due to 8 previous errors
+error: expected one of `@` or `|`, found `:`
+ --> $DIR/issue-87086-colon-path-sep.rs:75:12
+ |
+LL | Foo:Bar => {}
+ | ^
+ | |
+ | expected one of `@` or `|`
+ | help: maybe write a path separator here: `::`
+
+error[E0433]: failed to resolve: `Bar` is a variant, not a module
+ --> $DIR/issue-87086-colon-path-sep.rs:68:13
+ |
+LL | Foo:Bar::Baz => {}
+ | ^^^ `Bar` is a variant, not a module
+
+error: aborting due to 10 previous errors
+For more information about this error, try `rustc --explain E0433`.
diff --git a/src/test/ui/parser/issues/issue-87217-keyword-order/const-async-const.rs b/src/test/ui/parser/issues/issue-87217-keyword-order/const-async-const.rs
index 7c3d915a4c0..df0cd54399a 100644
--- a/src/test/ui/parser/issues/issue-87217-keyword-order/const-async-const.rs
+++ b/src/test/ui/parser/issues/issue-87217-keyword-order/const-async-const.rs
@@ -1,11 +1,9 @@
// edition:2018
-// Test that even when `const` is already present, the proposed fix is `const const async`,
-// like for `pub pub`.
+// Test that even when `const` is already present, the proposed fix is to remove the second `const`
const async const fn test() {}
//~^ ERROR expected one of `extern`, `fn`, or `unsafe`, found keyword `const`
//~| NOTE expected one of `extern`, `fn`, or `unsafe`
-//~| HELP `const` must come before `async`
-//~| SUGGESTION const async
-//~| NOTE keyword order for functions declaration is `default`, `pub`, `const`, `async`, `unsafe`, `extern`
+//~| HELP `const` already used earlier, remove this one
+//~| NOTE `const` first seen here
diff --git a/src/test/ui/parser/issues/issue-87217-keyword-order/const-async-const.stderr b/src/test/ui/parser/issues/issue-87217-keyword-order/const-async-const.stderr
index 56280912540..977c6ebfef3 100644
--- a/src/test/ui/parser/issues/issue-87217-keyword-order/const-async-const.stderr
+++ b/src/test/ui/parser/issues/issue-87217-keyword-order/const-async-const.stderr
@@ -1,13 +1,17 @@
error: expected one of `extern`, `fn`, or `unsafe`, found keyword `const`
- --> $DIR/const-async-const.rs:6:13
+ --> $DIR/const-async-const.rs:5:13
|
LL | const async const fn test() {}
- | ------^^^^^
- | | |
- | | expected one of `extern`, `fn`, or `unsafe`
- | help: `const` must come before `async`: `const async`
+ | ^^^^^
+ | |
+ | expected one of `extern`, `fn`, or `unsafe`
+ | help: `const` already used earlier, remove this one
|
- = note: keyword order for functions declaration is `default`, `pub`, `const`, `async`, `unsafe`, `extern`
+note: `const` first seen here
+ --> $DIR/const-async-const.rs:5:1
+ |
+LL | const async const fn test() {}
+ | ^^^^^
error: aborting due to previous error
diff --git a/src/test/ui/parser/issues/issue-87635.rs b/src/test/ui/parser/issues/issue-87635.rs
index da74c1877b1..f70a87fb0e8 100644
--- a/src/test/ui/parser/issues/issue-87635.rs
+++ b/src/test/ui/parser/issues/issue-87635.rs
@@ -2,8 +2,8 @@ struct Foo {}
impl Foo {
pub fn bar()
- //~^ ERROR: expected `;`, found `}`
- //~| ERROR: associated function in `impl` without body
+ //~^ ERROR: associated function in `impl` without body
}
+//~^ERROR expected one of `->`, `where`, or `{`, found `}`
fn main() {}
diff --git a/src/test/ui/parser/issues/issue-87635.stderr b/src/test/ui/parser/issues/issue-87635.stderr
index 920a9f937dd..0a52d0687b2 100644
--- a/src/test/ui/parser/issues/issue-87635.stderr
+++ b/src/test/ui/parser/issues/issue-87635.stderr
@@ -1,11 +1,13 @@
-error: expected `;`, found `}`
- --> $DIR/issue-87635.rs:4:17
+error: expected one of `->`, `where`, or `{`, found `}`
+ --> $DIR/issue-87635.rs:6:1
|
LL | pub fn bar()
- | ^ help: add `;` here
-...
+ | --- - expected one of `->`, `where`, or `{`
+ | |
+ | while parsing this `fn`
+LL |
LL | }
- | - unexpected token
+ | ^ unexpected token
error: associated function in `impl` without body
--> $DIR/issue-87635.rs:4:5
diff --git a/src/test/ui/parser/issues/issue-91461.rs b/src/test/ui/parser/issues/issue-91461.rs
new file mode 100644
index 00000000000..3e3c411c478
--- /dev/null
+++ b/src/test/ui/parser/issues/issue-91461.rs
@@ -0,0 +1,6 @@
+fn main() {
+ a(_:b:,)
+ //~^ ERROR: expected identifier, found reserved identifier `_`
+ //~| ERROR: expected type, found `,`
+ //~| ERROR: expected type, found `,`
+}
diff --git a/src/test/ui/parser/issues/issue-91461.stderr b/src/test/ui/parser/issues/issue-91461.stderr
new file mode 100644
index 00000000000..94fcf1721d8
--- /dev/null
+++ b/src/test/ui/parser/issues/issue-91461.stderr
@@ -0,0 +1,31 @@
+error: expected identifier, found reserved identifier `_`
+ --> $DIR/issue-91461.rs:2:7
+ |
+LL | a(_:b:,)
+ | ^ expected identifier, found reserved identifier
+
+error: expected type, found `,`
+ --> $DIR/issue-91461.rs:2:11
+ |
+LL | a(_:b:,)
+ | - -^ expected type
+ | | |
+ | | tried to parse a type due to this type ascription
+ | while parsing this struct
+ |
+ = note: `#![feature(type_ascription)]` lets you annotate an expression with a type: `<expr>: <type>`
+ = note: see issue #23416 <https://github.com/rust-lang/rust/issues/23416> for more information
+
+error: expected type, found `,`
+ --> $DIR/issue-91461.rs:2:11
+ |
+LL | a(_:b:,)
+ | -^ expected type
+ | |
+ | tried to parse a type due to this type ascription
+ |
+ = note: `#![feature(type_ascription)]` lets you annotate an expression with a type: `<expr>: <type>`
+ = note: see issue #23416 <https://github.com/rust-lang/rust/issues/23416> for more information
+
+error: aborting due to 3 previous errors
+
diff --git a/src/test/ui/parser/macro/trait-object-macro-matcher.rs b/src/test/ui/parser/macro/trait-object-macro-matcher.rs
index 663739f235a..560195977d0 100644
--- a/src/test/ui/parser/macro/trait-object-macro-matcher.rs
+++ b/src/test/ui/parser/macro/trait-object-macro-matcher.rs
@@ -11,6 +11,4 @@ fn main() {
m!('static);
//~^ ERROR lifetime in trait object type must be followed by `+`
//~| ERROR at least one trait is required for an object type
- //~| WARN trait objects without an explicit `dyn` are deprecated
- //~| WARN this is accepted in the current edition
}
diff --git a/src/test/ui/parser/macro/trait-object-macro-matcher.stderr b/src/test/ui/parser/macro/trait-object-macro-matcher.stderr
index 876bfd389cb..40082564bad 100644
--- a/src/test/ui/parser/macro/trait-object-macro-matcher.stderr
+++ b/src/test/ui/parser/macro/trait-object-macro-matcher.stderr
@@ -4,22 +4,12 @@ error: lifetime in trait object type must be followed by `+`
LL | m!('static);
| ^^^^^^^
-warning: trait objects without an explicit `dyn` are deprecated
- --> $DIR/trait-object-macro-matcher.rs:11:8
- |
-LL | m!('static);
- | ^^^^^^^ help: use `dyn`: `dyn 'static`
- |
- = note: `#[warn(bare_trait_objects)]` on by default
- = warning: this is accepted in the current edition (Rust 2015) but is a hard error in Rust 2021!
- = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2021/warnings-promoted-to-error.html>
-
error[E0224]: at least one trait is required for an object type
--> $DIR/trait-object-macro-matcher.rs:11:8
|
LL | m!('static);
| ^^^^^^^
-error: aborting due to 2 previous errors; 1 warning emitted
+error: aborting due to 2 previous errors
For more information about this error, try `rustc --explain E0224`.
diff --git a/src/test/ui/parser/missing_right_paren.stderr b/src/test/ui/parser/missing_right_paren.stderr
index 22e1c2f97e7..3fe0d0f4273 100644
--- a/src/test/ui/parser/missing_right_paren.stderr
+++ b/src/test/ui/parser/missing_right_paren.stderr
@@ -22,11 +22,11 @@ error: expected one of `:` or `|`, found `)`
LL | fn main((ؼ
| ^ expected one of `:` or `|`
-error: expected one of `->`, `;`, `where`, or `{`, found `<eof>`
+error: expected one of `->`, `where`, or `{`, found `<eof>`
--> $DIR/missing_right_paren.rs:3:11
|
LL | fn main((ؼ
- | ^ expected one of `->`, `;`, `where`, or `{`
+ | ^ expected one of `->`, `where`, or `{`
error: aborting due to 4 previous errors
diff --git a/src/test/ui/parser/misspelled-macro-rules.fixed b/src/test/ui/parser/misspelled-macro-rules.fixed
new file mode 100644
index 00000000000..62be913d85f
--- /dev/null
+++ b/src/test/ui/parser/misspelled-macro-rules.fixed
@@ -0,0 +1,13 @@
+// Regression test for issue #91227.
+
+// run-rustfix
+
+#![allow(unused_macros)]
+
+macro_rules! thing {
+//~^ ERROR: expected one of
+//~| HELP: perhaps you meant to define a macro
+ () => {}
+}
+
+fn main() {}
diff --git a/src/test/ui/parser/misspelled-macro-rules.rs b/src/test/ui/parser/misspelled-macro-rules.rs
new file mode 100644
index 00000000000..4290e6e5e4c
--- /dev/null
+++ b/src/test/ui/parser/misspelled-macro-rules.rs
@@ -0,0 +1,13 @@
+// Regression test for issue #91227.
+
+// run-rustfix
+
+#![allow(unused_macros)]
+
+marco_rules! thing {
+//~^ ERROR: expected one of
+//~| HELP: perhaps you meant to define a macro
+ () => {}
+}
+
+fn main() {}
diff --git a/src/test/ui/parser/misspelled-macro-rules.stderr b/src/test/ui/parser/misspelled-macro-rules.stderr
new file mode 100644
index 00000000000..56df7123819
--- /dev/null
+++ b/src/test/ui/parser/misspelled-macro-rules.stderr
@@ -0,0 +1,10 @@
+error: expected one of `(`, `[`, or `{`, found `thing`
+ --> $DIR/misspelled-macro-rules.rs:7:14
+ |
+LL | marco_rules! thing {
+ | ----------- ^^^^^ expected one of `(`, `[`, or `{`
+ | |
+ | help: perhaps you meant to define a macro: `macro_rules`
+
+error: aborting due to previous error
+
diff --git a/src/test/ui/parser/trait-object-trait-parens.stderr b/src/test/ui/parser/trait-object-trait-parens.stderr
index 657288c70f3..a852337b6fe 100644
--- a/src/test/ui/parser/trait-object-trait-parens.stderr
+++ b/src/test/ui/parser/trait-object-trait-parens.stderr
@@ -20,29 +20,16 @@ warning: trait objects without an explicit `dyn` are deprecated
--> $DIR/trait-object-trait-parens.rs:8:16
|
LL | let _: Box<(Obj) + (?Sized) + (for<'a> Trait<'a>)>;
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `dyn`: `dyn (Obj) + (?Sized) + (for<'a> Trait<'a>)`
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
= note: `#[warn(bare_trait_objects)]` on by default
= warning: this is accepted in the current edition (Rust 2015) but is a hard error in Rust 2021!
= note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2021/warnings-promoted-to-error.html>
-
-warning: trait objects without an explicit `dyn` are deprecated
- --> $DIR/trait-object-trait-parens.rs:13:16
- |
-LL | let _: Box<?Sized + (for<'a> Trait<'a>) + (Obj)>;
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `dyn`: `dyn ?Sized + (for<'a> Trait<'a>) + (Obj)`
+help: use `dyn`
|
- = warning: this is accepted in the current edition (Rust 2015) but is a hard error in Rust 2021!
- = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2021/warnings-promoted-to-error.html>
-
-warning: trait objects without an explicit `dyn` are deprecated
- --> $DIR/trait-object-trait-parens.rs:18:16
- |
-LL | let _: Box<for<'a> Trait<'a> + (Obj) + (?Sized)>;
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `dyn`: `dyn for<'a> Trait<'a> + (Obj) + (?Sized)`
- |
- = warning: this is accepted in the current edition (Rust 2015) but is a hard error in Rust 2021!
- = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2021/warnings-promoted-to-error.html>
+LL - let _: Box<(Obj) + (?Sized) + (for<'a> Trait<'a>)>;
+LL + let _: Box<dyn (Obj) + (?Sized) + (for<'a> Trait<'a>)>;
+ |
error[E0225]: only auto traits can be used as additional traits in a trait object
--> $DIR/trait-object-trait-parens.rs:8:35
@@ -55,6 +42,20 @@ LL | let _: Box<(Obj) + (?Sized) + (for<'a> Trait<'a>)>;
= help: consider creating a new trait with all of these as supertraits and using that trait here instead: `trait NewTrait: Obj + for<'a> Trait<'a> {}`
= note: auto-traits like `Send` and `Sync` are traits that have special properties; for more information on them, visit <https://doc.rust-lang.org/reference/special-types-and-traits.html#auto-traits>
+warning: trait objects without an explicit `dyn` are deprecated
+ --> $DIR/trait-object-trait-parens.rs:13:16
+ |
+LL | let _: Box<?Sized + (for<'a> Trait<'a>) + (Obj)>;
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ |
+ = warning: this is accepted in the current edition (Rust 2015) but is a hard error in Rust 2021!
+ = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2021/warnings-promoted-to-error.html>
+help: use `dyn`
+ |
+LL - let _: Box<?Sized + (for<'a> Trait<'a>) + (Obj)>;
+LL + let _: Box<dyn ?Sized + (for<'a> Trait<'a>) + (Obj)>;
+ |
+
error[E0225]: only auto traits can be used as additional traits in a trait object
--> $DIR/trait-object-trait-parens.rs:13:47
|
@@ -66,6 +67,20 @@ LL | let _: Box<?Sized + (for<'a> Trait<'a>) + (Obj)>;
= help: consider creating a new trait with all of these as supertraits and using that trait here instead: `trait NewTrait: for<'a> Trait<'a> + Obj {}`
= note: auto-traits like `Send` and `Sync` are traits that have special properties; for more information on them, visit <https://doc.rust-lang.org/reference/special-types-and-traits.html#auto-traits>
+warning: trait objects without an explicit `dyn` are deprecated
+ --> $DIR/trait-object-trait-parens.rs:18:16
+ |
+LL | let _: Box<for<'a> Trait<'a> + (Obj) + (?Sized)>;
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ |
+ = warning: this is accepted in the current edition (Rust 2015) but is a hard error in Rust 2021!
+ = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2021/warnings-promoted-to-error.html>
+help: use `dyn`
+ |
+LL - let _: Box<for<'a> Trait<'a> + (Obj) + (?Sized)>;
+LL + let _: Box<dyn for<'a> Trait<'a> + (Obj) + (?Sized)>;
+ |
+
error[E0225]: only auto traits can be used as additional traits in a trait object
--> $DIR/trait-object-trait-parens.rs:18:36
|
diff --git a/src/test/ui/pattern/issue-74702.stderr b/src/test/ui/pattern/issue-74702.stderr
index f2e2c8f021b..53dcf97f81c 100644
--- a/src/test/ui/pattern/issue-74702.stderr
+++ b/src/test/ui/pattern/issue-74702.stderr
@@ -22,9 +22,7 @@ error[E0308]: mismatched types
--> $DIR/issue-74702.rs:2:9
|
LL | let (foo @ ..,) = (0, 0);
- | ^^^^^^^^^^^ ------ this expression has type `({integer}, {integer})`
- | |
- | expected a tuple with 2 elements, found one with 1 element
+ | ^^^^^^^^^^^ expected a tuple with 2 elements, found one with 1 element
|
= note: expected tuple `({integer}, {integer})`
found tuple `(_,)`
diff --git a/src/test/ui/pattern/non-structural-match-types.rs b/src/test/ui/pattern/non-structural-match-types.rs
index 713418fc5b2..5c331547366 100644
--- a/src/test/ui/pattern/non-structural-match-types.rs
+++ b/src/test/ui/pattern/non-structural-match-types.rs
@@ -2,7 +2,7 @@
#![allow(incomplete_features)]
#![allow(unreachable_code)]
#![feature(const_async_blocks)]
-#![feature(inline_const)]
+#![feature(inline_const_pat)]
fn main() {
match loop {} {
diff --git a/src/test/ui/pattern/non-structural-match-types.stderr b/src/test/ui/pattern/non-structural-match-types.stderr
index 91fed81eaef..31168e29eb8 100644
--- a/src/test/ui/pattern/non-structural-match-types.stderr
+++ b/src/test/ui/pattern/non-structural-match-types.stderr
@@ -4,7 +4,7 @@ error: `[closure@$DIR/non-structural-match-types.rs:9:17: 9:22]` cannot be used
LL | const { || {} } => {},
| ^^^^^^^^^^^^^^^
-error: `impl Future` cannot be used in patterns
+error: `impl Future<Output = [async output]>` cannot be used in patterns
--> $DIR/non-structural-match-types.rs:12:9
|
LL | const { async {} } => {},
diff --git a/src/test/ui/pattern/pat-tuple-overfield.stderr b/src/test/ui/pattern/pat-tuple-overfield.stderr
index 1c44f7e5f6f..64b6e5eec55 100644
--- a/src/test/ui/pattern/pat-tuple-overfield.stderr
+++ b/src/test/ui/pattern/pat-tuple-overfield.stderr
@@ -150,8 +150,6 @@ LL | E1::Z0 => {}
error[E0308]: mismatched types
--> $DIR/pat-tuple-overfield.rs:19:9
|
-LL | match (1, 2, 3) {
- | --------- this expression has type `({integer}, {integer}, {integer})`
LL | (1, 2, 3, 4) => {}
| ^^^^^^^^^^^^ expected a tuple with 3 elements, found one with 4 elements
|
@@ -161,9 +159,6 @@ LL | (1, 2, 3, 4) => {}
error[E0308]: mismatched types
--> $DIR/pat-tuple-overfield.rs:20:9
|
-LL | match (1, 2, 3) {
- | --------- this expression has type `({integer}, {integer}, {integer})`
-LL | (1, 2, 3, 4) => {}
LL | (1, 2, .., 3, 4) => {}
| ^^^^^^^^^^^^^^^^ expected a tuple with 3 elements, found one with 4 elements
|
diff --git a/src/test/ui/pattern/usefulness/issue-88747.rs b/src/test/ui/pattern/usefulness/issue-88747.rs
new file mode 100644
index 00000000000..948c99f9ce9
--- /dev/null
+++ b/src/test/ui/pattern/usefulness/issue-88747.rs
@@ -0,0 +1,14 @@
+// check-pass: this used to be a stack overflow because of recursion in `usefulness.rs`
+
+macro_rules! long_tuple_arg {
+ ([$($t:tt)*]#$($h:tt)*) => {
+ long_tuple_arg!{[$($t)*$($t)*]$($h)*}
+ };
+ ([$([$t:tt $y:tt])*]) => {
+ pub fn _f(($($t,)*): ($($y,)*)) {}
+ }
+}
+
+long_tuple_arg!{[[_ u8]]########## ###}
+
+fn main() {}
diff --git a/src/test/ui/privacy/reachable-unnameable-items.rs b/src/test/ui/privacy/reachable-unnameable-items.rs
index f1e53a0d8b4..1c91541e642 100644
--- a/src/test/ui/privacy/reachable-unnameable-items.rs
+++ b/src/test/ui/privacy/reachable-unnameable-items.rs
@@ -1,5 +1,6 @@
// run-pass
// ignore-wasm32-bare compiled with panic=abort by default
+// needs-unwind
// aux-build:reachable-unnameable-items.rs
extern crate reachable_unnameable_items;
diff --git a/src/test/ui/proc-macro/allowed-attr-stmt-expr.stdout b/src/test/ui/proc-macro/allowed-attr-stmt-expr.stdout
index eae169b162f..091862de30f 100644
--- a/src/test/ui/proc-macro/allowed-attr-stmt-expr.stdout
+++ b/src/test/ui/proc-macro/allowed-attr-stmt-expr.stdout
@@ -14,7 +14,7 @@ PRINT-ATTR INPUT (DEBUG): TokenStream [
span: $DIR/allowed-attr-stmt-expr.rs:49:20: 49:21 (#0),
},
]
-PRINT-ATTR INPUT (DISPLAY): #[rustc_dummy] struct Foo { }
+PRINT-ATTR INPUT (DISPLAY): #[rustc_dummy] struct Foo {}
PRINT-ATTR INPUT (DEBUG): TokenStream [
Punct {
ch: '#',
@@ -140,7 +140,7 @@ PRINT-ATTR INPUT (DEBUG): TokenStream [
span: $DIR/allowed-attr-stmt-expr.rs:61:28: 61:29 (#0),
},
]
-PRINT-ATTR INPUT (DISPLAY): second_make_stmt! (#[allow(dead_code)] struct Bar { }) ;
+PRINT-ATTR INPUT (DISPLAY): second_make_stmt! (#[allow(dead_code)] struct Bar {}) ;
PRINT-ATTR INPUT (DEBUG): TokenStream [
Ident {
ident: "second_make_stmt",
@@ -201,7 +201,7 @@ PRINT-ATTR INPUT (DEBUG): TokenStream [
span: $DIR/allowed-attr-stmt-expr.rs:64:57: 64:58 (#0),
},
]
-PRINT-ATTR INPUT (DISPLAY): #[rustc_dummy] #[allow(dead_code)] struct Bar { }
+PRINT-ATTR INPUT (DISPLAY): #[rustc_dummy] #[allow(dead_code)] struct Bar {}
PRINT-ATTR INPUT (DEBUG): TokenStream [
Punct {
ch: '#',
@@ -257,7 +257,7 @@ PRINT-ATTR INPUT (DEBUG): TokenStream [
span: $DIR/allowed-attr-stmt-expr.rs:64:54: 64:56 (#0),
},
]
-PRINT-ATTR INPUT (DISPLAY): #[rustc_dummy] struct Other { }
+PRINT-ATTR INPUT (DISPLAY): #[rustc_dummy] struct Other {}
PRINT-ATTR INPUT (DEBUG): TokenStream [
Punct {
ch: '#',
diff --git a/src/test/ui/proc-macro/attr-complex-fn.stdout b/src/test/ui/proc-macro/attr-complex-fn.stdout
index fbefa3923ee..fc69a13ddb9 100644
--- a/src/test/ui/proc-macro/attr-complex-fn.stdout
+++ b/src/test/ui/proc-macro/attr-complex-fn.stdout
@@ -1,4 +1,4 @@
-PRINT-ATTR INPUT (DISPLAY): fn foo < T : MyTrait < MyStruct < { true } >> > () { }
+PRINT-ATTR INPUT (DISPLAY): fn foo < T : MyTrait < MyStruct < { true } >> > () {}
PRINT-ATTR INPUT (DEBUG): TokenStream [
Ident {
ident: "fn",
diff --git a/src/test/ui/proc-macro/attr-stmt-expr.stdout b/src/test/ui/proc-macro/attr-stmt-expr.stdout
index edb9fbab342..f9b2305c735 100644
--- a/src/test/ui/proc-macro/attr-stmt-expr.stdout
+++ b/src/test/ui/proc-macro/attr-stmt-expr.stdout
@@ -1,4 +1,4 @@
-PRINT-ATTR INPUT (DISPLAY): #[rustc_dummy] struct Foo { }
+PRINT-ATTR INPUT (DISPLAY): #[rustc_dummy] struct Foo {}
PRINT-ATTR INPUT (DEBUG): TokenStream [
Punct {
ch: '#',
@@ -124,7 +124,7 @@ PRINT-ATTR INPUT (DEBUG): TokenStream [
span: $DIR/attr-stmt-expr.rs:53:28: 53:29 (#0),
},
]
-PRINT-ATTR INPUT (DISPLAY): second_make_stmt! (#[allow(dead_code)] struct Bar { }) ;
+PRINT-ATTR INPUT (DISPLAY): second_make_stmt! (#[allow(dead_code)] struct Bar {}) ;
PRINT-ATTR INPUT (DEBUG): TokenStream [
Ident {
ident: "second_make_stmt",
@@ -185,7 +185,7 @@ PRINT-ATTR INPUT (DEBUG): TokenStream [
span: $DIR/attr-stmt-expr.rs:56:57: 56:58 (#0),
},
]
-PRINT-ATTR INPUT (DISPLAY): #[rustc_dummy] #[allow(dead_code)] struct Bar { }
+PRINT-ATTR INPUT (DISPLAY): #[rustc_dummy] #[allow(dead_code)] struct Bar {}
PRINT-ATTR INPUT (DEBUG): TokenStream [
Punct {
ch: '#',
@@ -241,7 +241,7 @@ PRINT-ATTR INPUT (DEBUG): TokenStream [
span: $DIR/attr-stmt-expr.rs:56:54: 56:56 (#0),
},
]
-PRINT-ATTR INPUT (DISPLAY): #[rustc_dummy] struct Other { }
+PRINT-ATTR INPUT (DISPLAY): #[rustc_dummy] struct Other {}
PRINT-ATTR INPUT (DEBUG): TokenStream [
Punct {
ch: '#',
diff --git a/src/test/ui/proc-macro/attribute-after-derive.stdout b/src/test/ui/proc-macro/attribute-after-derive.stdout
index c5b84b0367c..1b17d60476a 100644
--- a/src/test/ui/proc-macro/attribute-after-derive.stdout
+++ b/src/test/ui/proc-macro/attribute-after-derive.stdout
@@ -83,7 +83,7 @@ PRINT-ATTR INPUT (DEBUG): TokenStream [
span: $DIR/attribute-after-derive.rs:16:24: 19:2 (#0),
},
]
-PRINT-DERIVE INPUT (DISPLAY): struct AttributeDerive { }
+PRINT-DERIVE INPUT (DISPLAY): struct AttributeDerive {}
PRINT-DERIVE INPUT (DEBUG): TokenStream [
Ident {
ident: "struct",
@@ -99,7 +99,7 @@ PRINT-DERIVE INPUT (DEBUG): TokenStream [
span: $DIR/attribute-after-derive.rs:16:24: 19:2 (#0),
},
]
-PRINT-DERIVE INPUT (DISPLAY): #[print_attr] struct DeriveAttribute { }
+PRINT-DERIVE INPUT (DISPLAY): #[print_attr] struct DeriveAttribute {}
PRINT-DERIVE INPUT (DEBUG): TokenStream [
Punct {
ch: '#',
diff --git a/src/test/ui/proc-macro/auxiliary/attr-args.rs b/src/test/ui/proc-macro/auxiliary/attr-args.rs
index 8dd2a5ac786..5f76a4484e1 100644
--- a/src/test/ui/proc-macro/auxiliary/attr-args.rs
+++ b/src/test/ui/proc-macro/auxiliary/attr-args.rs
@@ -15,7 +15,7 @@ pub fn attr_with_args(args: TokenStream, input: TokenStream) -> TokenStream {
let input = input.to_string();
- assert_eq!(input, "fn foo() { }");
+ assert_eq!(input, "fn foo() {}");
r#"
fn foo() -> &'static str { "Hello, world!" }
diff --git a/src/test/ui/proc-macro/auxiliary/attr-on-trait.rs b/src/test/ui/proc-macro/auxiliary/attr-on-trait.rs
index d89aaac59f6..3787b8eeccc 100644
--- a/src/test/ui/proc-macro/auxiliary/attr-on-trait.rs
+++ b/src/test/ui/proc-macro/auxiliary/attr-on-trait.rs
@@ -10,6 +10,6 @@ use proc_macro::TokenStream;
#[proc_macro_attribute]
pub fn foo(attr: TokenStream, item: TokenStream) -> TokenStream {
drop(attr);
- assert_eq!(item.to_string(), "fn foo() { }");
+ assert_eq!(item.to_string(), "fn foo() {}");
"fn foo(&self);".parse().unwrap()
}
diff --git a/src/test/ui/proc-macro/auxiliary/custom-quote.rs b/src/test/ui/proc-macro/auxiliary/custom-quote.rs
index 714417deee5..3b7811748ed 100644
--- a/src/test/ui/proc-macro/auxiliary/custom-quote.rs
+++ b/src/test/ui/proc-macro/auxiliary/custom-quote.rs
@@ -6,6 +6,7 @@
#![crate_type = "proc-macro"]
extern crate proc_macro;
+use std::iter::FromIterator;
use std::str::FromStr;
use proc_macro::*;
@@ -23,7 +24,7 @@ pub fn custom_quote(input: TokenStream) -> TokenStream {
let set_span_method = TokenStream::from_str("ident.set_span").unwrap();
let set_span_arg = TokenStream::from(TokenTree::Group(Group::new(Delimiter::Parenthesis, quoted_span)));
let suffix = TokenStream::from_str(";proc_macro::TokenStream::from(proc_macro::TokenTree::Ident(ident))").unwrap();
- let full_stream: TokenStream = std::array::IntoIter::new([prefix, set_span_method, set_span_arg, suffix]).collect();
+ let full_stream = TokenStream::from_iter([prefix, set_span_method, set_span_arg, suffix]);
full_stream
}
_ => unreachable!()
diff --git a/src/test/ui/proc-macro/cfg-eval-inner.stdout b/src/test/ui/proc-macro/cfg-eval-inner.stdout
index 08ead5aaeee..debbad57a86 100644
--- a/src/test/ui/proc-macro/cfg-eval-inner.stdout
+++ b/src/test/ui/proc-macro/cfg-eval-inner.stdout
@@ -3,7 +3,7 @@ PRINT-ATTR INPUT (DISPLAY): impl Foo <
{
#! [rustc_dummy(cursed_inner)] #! [allow(unused)] struct Inner
{ field : [u8 ; { #! [rustc_dummy(another_cursed_inner)] 1 }] } 0
- }] > { #! [rustc_dummy(evaluated_attr)] fn bar() { } }
+ }] > { #! [rustc_dummy(evaluated_attr)] fn bar() {} }
PRINT-ATTR INPUT (DEBUG): TokenStream [
Ident {
ident: "impl",
diff --git a/src/test/ui/proc-macro/crate-attrs-multiple.rs b/src/test/ui/proc-macro/crate-attrs-multiple.rs
new file mode 100644
index 00000000000..29a0eca4172
--- /dev/null
+++ b/src/test/ui/proc-macro/crate-attrs-multiple.rs
@@ -0,0 +1,14 @@
+// Multiple custom crate-level attributes, both inert and active.
+
+// check-pass
+// aux-crate:test_macros=test-macros.rs
+
+#![feature(custom_inner_attributes)]
+#![feature(prelude_import)]
+
+#![test_macros::identity_attr]
+#![rustfmt::skip]
+#![test_macros::identity_attr]
+#![rustfmt::skip]
+
+fn main() {}
diff --git a/src/test/ui/proc-macro/derive-expand-order.stdout b/src/test/ui/proc-macro/derive-expand-order.stdout
index 3ac1adf92c2..dffbbf1494b 100644
--- a/src/test/ui/proc-macro/derive-expand-order.stdout
+++ b/src/test/ui/proc-macro/derive-expand-order.stdout
@@ -1,5 +1,5 @@
-Derive First: #[derive(Second)] #[derive(Third, Fourth)] #[derive(Fifth)] pub struct Foo { }
-Derive Second: #[derive(Third, Fourth)] #[derive(Fifth)] pub struct Foo { }
-Derive Third: #[derive(Fifth)] pub struct Foo { }
-Derive Fourth: #[derive(Fifth)] pub struct Foo { }
-Derive Fifth: pub struct Foo { }
+Derive First: #[derive(Second)] #[derive(Third, Fourth)] #[derive(Fifth)] pub struct Foo {}
+Derive Second: #[derive(Third, Fourth)] #[derive(Fifth)] pub struct Foo {}
+Derive Third: #[derive(Fifth)] pub struct Foo {}
+Derive Fourth: #[derive(Fifth)] pub struct Foo {}
+Derive Fifth: pub struct Foo {}
diff --git a/src/test/ui/proc-macro/expand-with-a-macro.rs b/src/test/ui/proc-macro/expand-with-a-macro.rs
index 418178d0f0e..21a4547d11e 100644
--- a/src/test/ui/proc-macro/expand-with-a-macro.rs
+++ b/src/test/ui/proc-macro/expand-with-a-macro.rs
@@ -1,4 +1,5 @@
// run-pass
+// needs-unwind
// aux-build:expand-with-a-macro.rs
// ignore-wasm32-bare compiled with panic=abort by default
diff --git a/src/test/ui/proc-macro/expr-stmt-nonterminal-tokens.stdout b/src/test/ui/proc-macro/expr-stmt-nonterminal-tokens.stdout
index e37a483cb87..686d53e8876 100644
--- a/src/test/ui/proc-macro/expr-stmt-nonterminal-tokens.stdout
+++ b/src/test/ui/proc-macro/expr-stmt-nonterminal-tokens.stdout
@@ -202,7 +202,7 @@ PRINT-DERIVE INPUT (DEBUG): TokenStream [
span: #8 bytes(430..483),
},
]
-PRINT-DERIVE INPUT (DISPLAY): enum E { V = { let _ = { { } } ; 0 }, }
+PRINT-DERIVE INPUT (DISPLAY): enum E { V = { let _ = { {} } ; 0 }, }
PRINT-DERIVE INPUT (DEBUG): TokenStream [
Ident {
ident: "enum",
diff --git a/src/test/ui/proc-macro/inner-attrs.stdout b/src/test/ui/proc-macro/inner-attrs.stdout
index 9b7865be622..eaa8882d6a6 100644
--- a/src/test/ui/proc-macro/inner-attrs.stdout
+++ b/src/test/ui/proc-macro/inner-attrs.stdout
@@ -269,7 +269,7 @@ PRINT-ATTR_ARGS INPUT (DEBUG): TokenStream [
span: $DIR/inner-attrs.rs:20:30: 20:36 (#0),
},
]
-PRINT-ATTR INPUT (DISPLAY): fn foo() { }
+PRINT-ATTR INPUT (DISPLAY): fn foo() {}
PRINT-ATTR INPUT (DEBUG): TokenStream [
Ident {
ident: "fn",
@@ -552,7 +552,7 @@ PRINT-ATTR_ARGS INPUT (DEBUG): TokenStream [
span: $DIR/inner-attrs.rs:27:30: 27:40 (#0),
},
]
-PRINT-ATTR INPUT (DISPLAY): mod inline_mod { }
+PRINT-ATTR INPUT (DISPLAY): mod inline_mod {}
PRINT-ATTR INPUT (DEBUG): TokenStream [
Ident {
ident: "mod",
@@ -933,7 +933,7 @@ PRINT-ATTR_ARGS INPUT (DEBUG): TokenStream [
span: $DIR/inner-attrs.rs:82:42: 82:47 (#0),
},
]
-PRINT-ATTR INPUT (DISPLAY): fn weird_extern() { }
+PRINT-ATTR INPUT (DISPLAY): fn weird_extern() {}
PRINT-ATTR INPUT (DEBUG): TokenStream [
Ident {
ident: "fn",
diff --git a/src/test/ui/proc-macro/input-interpolated.stdout b/src/test/ui/proc-macro/input-interpolated.stdout
index 866608e4d8e..44baa37577c 100644
--- a/src/test/ui/proc-macro/input-interpolated.stdout
+++ b/src/test/ui/proc-macro/input-interpolated.stdout
@@ -53,7 +53,7 @@ PRINT-ATTR INPUT (DEBUG): TokenStream [
span: #4 bytes(432..433),
},
]
-PRINT-DERIVE INPUT (DISPLAY): struct A { }
+PRINT-DERIVE INPUT (DISPLAY): struct A {}
PRINT-DERIVE INPUT (DEBUG): TokenStream [
Ident {
ident: "struct",
diff --git a/src/test/ui/proc-macro/issue-59191-replace-root-with-fn.rs b/src/test/ui/proc-macro/issue-59191-replace-root-with-fn.rs
index 039878af56e..a4161d4fc3d 100644
--- a/src/test/ui/proc-macro/issue-59191-replace-root-with-fn.rs
+++ b/src/test/ui/proc-macro/issue-59191-replace-root-with-fn.rs
@@ -1,7 +1,10 @@
-// edition:2018
-// aux-crate:issue_59191=issue-59191.rs
// Test that using a macro to replace the entire crate tree with a non-'mod' item errors out nicely.
// `issue_59191::no_main` replaces whatever's passed in with `fn main() {}`.
+
+// edition:2018
+// aux-crate:issue_59191=issue-59191.rs
+// error-pattern: requires `sized` lang_item
+
#![feature(custom_inner_attributes)]
#![issue_59191::no_main]
-//~^ ERROR expected crate top-level item to be a module after macro expansion, found a function
+#![issue_59191::no_main]
diff --git a/src/test/ui/proc-macro/issue-59191-replace-root-with-fn.stderr b/src/test/ui/proc-macro/issue-59191-replace-root-with-fn.stderr
index 126c52db548..f7516c7d377 100644
--- a/src/test/ui/proc-macro/issue-59191-replace-root-with-fn.stderr
+++ b/src/test/ui/proc-macro/issue-59191-replace-root-with-fn.stderr
@@ -1,10 +1,4 @@
-error: expected crate top-level item to be a module after macro expansion, found a function
- --> $DIR/issue-59191-replace-root-with-fn.rs:6:1
- |
-LL | #![issue_59191::no_main]
- | ^^^^^^^^^^^^^^^^^^^^^^^^
- |
- = note: this error originates in the attribute macro `issue_59191::no_main` (in Nightly builds, run with -Z macro-backtrace for more info)
+error: requires `sized` lang_item
error: aborting due to previous error
diff --git a/src/test/ui/proc-macro/issue-75734-pp-paren.stdout b/src/test/ui/proc-macro/issue-75734-pp-paren.stdout
index ea03653c52f..0fda6654ff3 100644
--- a/src/test/ui/proc-macro/issue-75734-pp-paren.stdout
+++ b/src/test/ui/proc-macro/issue-75734-pp-paren.stdout
@@ -1,4 +1,4 @@
-PRINT-ATTR INPUT (DISPLAY): fn main() { & | _ : u8 | { } ; mul_2! (1 + 1) ; }
+PRINT-ATTR INPUT (DISPLAY): fn main() { & | _ : u8 | {} ; mul_2! (1 + 1) ; }
PRINT-ATTR INPUT (DEBUG): TokenStream [
Ident {
ident: "fn",
diff --git a/src/test/ui/proc-macro/issue-75930-derive-cfg.stdout b/src/test/ui/proc-macro/issue-75930-derive-cfg.stdout
index 81b2b219c43..fdd178a5229 100644
--- a/src/test/ui/proc-macro/issue-75930-derive-cfg.stdout
+++ b/src/test/ui/proc-macro/issue-75930-derive-cfg.stdout
@@ -8,8 +8,8 @@ struct Foo < #[cfg(FALSE)] A, B >
#[cfg(FALSE)] struct Bar ; #[cfg(not(FALSE))] struct Inner ;
#[cfg(FALSE)] let a = 25 ; match true
{
- #[cfg(FALSE)] true => { },
- #[cfg_attr(not(FALSE), allow(warnings))] false => { }, _ => { }
+ #[cfg(FALSE)] true => {},
+ #[cfg_attr(not(FALSE), allow(warnings))] false => {}, _ => {}
} ; #[print_helper(should_be_removed)] fn removed_fn()
{ #! [cfg(FALSE)] } #[print_helper(c)] #[cfg(not(FALSE))] fn
kept_fn() { #! [cfg(not(FALSE))] let my_val = true ; } enum TupleEnum
@@ -1278,7 +1278,7 @@ PRINT-DERIVE INPUT (DISPLAY): #[print_helper(a)] #[allow(dead_code)] #[print_hel
[u8 ;
{
#[cfg(not(FALSE))] struct Inner ; match true
- { #[allow(warnings)] false => { }, _ => { } } ; #[print_helper(c)]
+ { #[allow(warnings)] false => {}, _ => {} } ; #[print_helper(c)]
#[cfg(not(FALSE))] fn kept_fn()
{ #! [cfg(not(FALSE))] let my_val = true ; } enum TupleEnum
{ Foo(#[cfg(not(FALSE))] i32, u8) } struct
diff --git a/src/test/ui/proc-macro/issue-81007-item-attrs.stdout b/src/test/ui/proc-macro/issue-81007-item-attrs.stdout
index 6f880a12021..3c001e9954b 100644
--- a/src/test/ui/proc-macro/issue-81007-item-attrs.stdout
+++ b/src/test/ui/proc-macro/issue-81007-item-attrs.stdout
@@ -1,4 +1,4 @@
-PRINT-ATTR INPUT (DISPLAY): #[doc = r" A doc comment"] struct Foo { }
+PRINT-ATTR INPUT (DISPLAY): #[doc = r" A doc comment"] struct Foo {}
PRINT-ATTR INPUT (DEBUG): TokenStream [
Punct {
ch: '#',
@@ -40,7 +40,7 @@ PRINT-ATTR INPUT (DEBUG): TokenStream [
span: $DIR/issue-81007-item-attrs.rs:22:16: 22:18 (#0),
},
]
-PRINT-ATTR INPUT (DISPLAY): #[rustc_dummy] #[doc = r" Another comment comment"] struct Bar { }
+PRINT-ATTR INPUT (DISPLAY): #[rustc_dummy] #[doc = r" Another comment comment"] struct Bar {}
PRINT-ATTR INPUT (DEBUG): TokenStream [
Punct {
ch: '#',
diff --git a/src/test/ui/proc-macro/macro-brackets.stderr b/src/test/ui/proc-macro/macro-brackets.stderr
index 9aaf612eb54..d3516375291 100644
--- a/src/test/ui/proc-macro/macro-brackets.stderr
+++ b/src/test/ui/proc-macro/macro-brackets.stderr
@@ -3,6 +3,11 @@ error[E0308]: mismatched types
|
LL | id![static X: u32 = 'a';];
| ^^^ expected `u32`, found `char`
+ |
+help: you can cast a `char` to a `u32`, since a `char` always occupies 4 bytes
+ |
+LL | id![static X: u32 = 'a' as u32;];
+ | ++++++
error: aborting due to previous error
diff --git a/src/test/ui/proc-macro/nested-macro-rules.stdout b/src/test/ui/proc-macro/nested-macro-rules.stdout
index 8292617fc16..68f30c23a8d 100644
--- a/src/test/ui/proc-macro/nested-macro-rules.stdout
+++ b/src/test/ui/proc-macro/nested-macro-rules.stdout
@@ -11,7 +11,7 @@ PRINT-BANG INPUT (DEBUG): TokenStream [
span: $DIR/auxiliary/nested-macro-rules.rs:9:30: 9:35 (#6),
},
]
-PRINT-ATTR INPUT (DISPLAY): struct FirstAttrStruct { }
+PRINT-ATTR INPUT (DISPLAY): struct FirstAttrStruct {}
PRINT-ATTR INPUT (DEBUG): TokenStream [
Ident {
ident: "struct",
@@ -46,7 +46,7 @@ PRINT-BANG INPUT (DEBUG): TokenStream [
span: $DIR/auxiliary/nested-macro-rules.rs:9:30: 9:35 (#15),
},
]
-PRINT-ATTR INPUT (DISPLAY): struct SecondAttrStruct { }
+PRINT-ATTR INPUT (DISPLAY): struct SecondAttrStruct {}
PRINT-ATTR INPUT (DEBUG): TokenStream [
Ident {
ident: "struct",
diff --git a/src/test/ui/proc-macro/nonterminal-token-hygiene.stdout b/src/test/ui/proc-macro/nonterminal-token-hygiene.stdout
index 709b2a2169e..c08e5308138 100644
--- a/src/test/ui/proc-macro/nonterminal-token-hygiene.stdout
+++ b/src/test/ui/proc-macro/nonterminal-token-hygiene.stdout
@@ -64,7 +64,7 @@ macro inner /* 0#4 */ { () => { print_bang! { struct S; } } }
struct S /* 0#5 */;
// OK, not a duplicate definition of `S`
-fn main /* 0#0 */() { }
+fn main /* 0#0 */() {}
/*
Expansions:
diff --git a/src/test/ui/proc-macro/trailing-plus.stdout b/src/test/ui/proc-macro/trailing-plus.stdout
index d60f400af2b..b90057cd6d5 100644
--- a/src/test/ui/proc-macro/trailing-plus.stdout
+++ b/src/test/ui/proc-macro/trailing-plus.stdout
@@ -1,4 +1,4 @@
-PRINT-ATTR INPUT (DISPLAY): fn foo < T > () where T : Copy + { }
+PRINT-ATTR INPUT (DISPLAY): fn foo < T > () where T : Copy + {}
PRINT-ATTR INPUT (DEBUG): TokenStream [
Ident {
ident: "fn",
diff --git a/src/test/ui/proc-macro/weird-braces.stdout b/src/test/ui/proc-macro/weird-braces.stdout
index dc35df1159f..9bf56221734 100644
--- a/src/test/ui/proc-macro/weird-braces.stdout
+++ b/src/test/ui/proc-macro/weird-braces.stdout
@@ -445,7 +445,7 @@ PRINT-ATTR_ARGS INPUT (DEBUG): TokenStream [
span: $DIR/weird-braces.rs:20:30: 20:42 (#0),
},
]
-PRINT-ATTR INPUT (DISPLAY): impl Bar < { 1 > 0 } > for Foo < { true } > { }
+PRINT-ATTR INPUT (DISPLAY): impl Bar < { 1 > 0 } > for Foo < { true } > {}
PRINT-ATTR INPUT (DEBUG): TokenStream [
Ident {
ident: "impl",
diff --git a/src/test/ui/regions/region-object-lifetime-in-coercion.stderr b/src/test/ui/regions/region-object-lifetime-in-coercion.stderr
index 04d22e58a1d..d8932c067ac 100644
--- a/src/test/ui/regions/region-object-lifetime-in-coercion.stderr
+++ b/src/test/ui/regions/region-object-lifetime-in-coercion.stderr
@@ -4,7 +4,7 @@ error[E0759]: `v` has an anonymous lifetime `'_` but it needs to satisfy a `'sta
LL | fn a(v: &[u8]) -> Box<dyn Foo + 'static> {
| ----- this data with an anonymous lifetime `'_`...
LL | let x: Box<dyn Foo + 'static> = Box::new(v);
- | ^ ...is captured here, requiring it to live as long as `'static`
+ | ^ ...is used and required to live as long as `'static` here
|
help: consider changing the trait object's explicit `'static` bound to the lifetime of argument `v`
|
@@ -21,8 +21,15 @@ error[E0759]: `v` has an anonymous lifetime `'_` but it needs to satisfy a `'sta
LL | fn b(v: &[u8]) -> Box<dyn Foo + 'static> {
| ----- this data with an anonymous lifetime `'_`...
LL | Box::new(v)
- | ^ ...is captured here, requiring it to live as long as `'static`
+ | ^ ...is used and required to live as long as `'static` here
|
+note: `'static` lifetime requirement introduced by the return type
+ --> $DIR/region-object-lifetime-in-coercion.rs:12:33
+ |
+LL | fn b(v: &[u8]) -> Box<dyn Foo + 'static> {
+ | ^^^^^^^ `'static` requirement introduced here
+LL | Box::new(v)
+ | ----------- because of this returned expression
help: consider changing the trait object's explicit `'static` bound to the lifetime of argument `v`
|
LL | fn b(v: &[u8]) -> Box<dyn Foo + '_> {
@@ -39,8 +46,16 @@ LL | fn c(v: &[u8]) -> Box<dyn Foo> {
| ----- this data with an anonymous lifetime `'_`...
...
LL | Box::new(v)
- | ^ ...is captured here, requiring it to live as long as `'static`
+ | ^ ...is used and required to live as long as `'static` here
+ |
+note: `'static` lifetime requirement introduced by the return type
+ --> $DIR/region-object-lifetime-in-coercion.rs:16:23
|
+LL | fn c(v: &[u8]) -> Box<dyn Foo> {
+ | ^^^^^^^ `'static` requirement introduced here
+...
+LL | Box::new(v)
+ | ----------- because of this returned expression
help: to declare that the trait object captures data from argument `v`, you can add an explicit `'_` lifetime bound
|
LL | fn c(v: &[u8]) -> Box<dyn Foo + '_> {
diff --git a/src/test/ui/regions/regions-addr-of-self.stderr b/src/test/ui/regions/regions-addr-of-self.stderr
index 738691fd695..3453c6458f1 100644
--- a/src/test/ui/regions/regions-addr-of-self.stderr
+++ b/src/test/ui/regions/regions-addr-of-self.stderr
@@ -4,7 +4,7 @@ error[E0759]: `self` has an anonymous lifetime `'_` but it needs to satisfy a `'
LL | pub fn chase_cat(&mut self) {
| --------- this data with an anonymous lifetime `'_`...
LL | let p: &'static mut usize = &mut self.cats_chased;
- | ^^^^^^^^^^^^^^^^^^^^^ ...is captured and required to live as long as `'static` here
+ | ^^^^^^^^^^^^^^^^^^^^^ ...is used and required to live as long as `'static` here
error: aborting due to previous error
diff --git a/src/test/ui/regions/regions-assoc-type-in-supertrait-outlives-container.migrate.nll.stderr b/src/test/ui/regions/regions-assoc-type-in-supertrait-outlives-container.migrate.nll.stderr
deleted file mode 100644
index 9bb385b0dcd..00000000000
--- a/src/test/ui/regions/regions-assoc-type-in-supertrait-outlives-container.migrate.nll.stderr
+++ /dev/null
@@ -1,15 +0,0 @@
-error: lifetime may not live long enough
- --> $DIR/regions-assoc-type-in-supertrait-outlives-container.rs:39:12
- |
-LL | fn with_assoc<'a,'b>() {
- | -- -- lifetime `'b` defined here
- | |
- | lifetime `'a` defined here
-...
-LL | let _: &'a WithAssoc<TheType<'b>> = loop { };
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^ type annotation requires that `'b` must outlive `'a`
- |
- = help: consider adding the following bound: `'b: 'a`
-
-error: aborting due to previous error
-
diff --git a/src/test/ui/regions/regions-assoc-type-in-supertrait-outlives-container.migrate.stderr b/src/test/ui/regions/regions-assoc-type-in-supertrait-outlives-container.migrate.stderr
index 6ae70ec672c..d9fd1aebf27 100644
--- a/src/test/ui/regions/regions-assoc-type-in-supertrait-outlives-container.migrate.stderr
+++ b/src/test/ui/regions/regions-assoc-type-in-supertrait-outlives-container.migrate.stderr
@@ -1,16 +1,16 @@
error[E0491]: in type `&'a WithAssoc<TheType<'b>>`, reference has a longer lifetime than the data it references
- --> $DIR/regions-assoc-type-in-supertrait-outlives-container.rs:39:12
+ --> $DIR/regions-assoc-type-in-supertrait-outlives-container.rs:44:12
|
LL | let _: &'a WithAssoc<TheType<'b>> = loop { };
| ^^^^^^^^^^^^^^^^^^^^^^^^^^
|
note: the pointer is valid for the lifetime `'a` as defined here
- --> $DIR/regions-assoc-type-in-supertrait-outlives-container.rs:33:15
+ --> $DIR/regions-assoc-type-in-supertrait-outlives-container.rs:38:15
|
LL | fn with_assoc<'a,'b>() {
| ^^
note: but the referenced data is only valid for the lifetime `'b` as defined here
- --> $DIR/regions-assoc-type-in-supertrait-outlives-container.rs:33:18
+ --> $DIR/regions-assoc-type-in-supertrait-outlives-container.rs:38:18
|
LL | fn with_assoc<'a,'b>() {
| ^^
diff --git a/src/test/ui/regions/regions-assoc-type-in-supertrait-outlives-container.nll.stderr b/src/test/ui/regions/regions-assoc-type-in-supertrait-outlives-container.nll.stderr
index 9bb385b0dcd..ba7572ebe31 100644
--- a/src/test/ui/regions/regions-assoc-type-in-supertrait-outlives-container.nll.stderr
+++ b/src/test/ui/regions/regions-assoc-type-in-supertrait-outlives-container.nll.stderr
@@ -1,5 +1,5 @@
error: lifetime may not live long enough
- --> $DIR/regions-assoc-type-in-supertrait-outlives-container.rs:39:12
+ --> $DIR/regions-assoc-type-in-supertrait-outlives-container.rs:44:12
|
LL | fn with_assoc<'a,'b>() {
| -- -- lifetime `'b` defined here
diff --git a/src/test/ui/regions/regions-assoc-type-in-supertrait-outlives-container.rs b/src/test/ui/regions/regions-assoc-type-in-supertrait-outlives-container.rs
index 046d010002e..08bc64926fa 100644
--- a/src/test/ui/regions/regions-assoc-type-in-supertrait-outlives-container.rs
+++ b/src/test/ui/regions/regions-assoc-type-in-supertrait-outlives-container.rs
@@ -6,6 +6,11 @@
// revisions: migrate nll
//[nll]compile-flags: -Z borrowck=mir
+// Since we are testing nll (and migration) explicitly as a separate
+// revisions, don't worry about the --compare-mode=nll on this test.
+
+// ignore-compare-mode-nll
+
#![allow(dead_code)]
pub trait TheTrait {
diff --git a/src/test/ui/regions/regions-assoc-type-region-bound-in-trait-not-met.stderr b/src/test/ui/regions/regions-assoc-type-region-bound-in-trait-not-met.stderr
index f4153b2a816..ac6154139e2 100644
--- a/src/test/ui/regions/regions-assoc-type-region-bound-in-trait-not-met.stderr
+++ b/src/test/ui/regions/regions-assoc-type-region-bound-in-trait-not-met.stderr
@@ -1,8 +1,8 @@
error[E0477]: the type `&'a i32` does not fulfill the required lifetime
- --> $DIR/regions-assoc-type-region-bound-in-trait-not-met.rs:15:5
+ --> $DIR/regions-assoc-type-region-bound-in-trait-not-met.rs:15:18
|
LL | type Value = &'a i32;
- | ^^^^^^^^^^^^^^^^^^^^^
+ | ^^^^^^^
|
note: type must satisfy the static lifetime as required by this binding
--> $DIR/regions-assoc-type-region-bound-in-trait-not-met.rs:5:17
@@ -11,10 +11,10 @@ LL | type Value: 'a;
| ^^
error[E0477]: the type `&'a i32` does not fulfill the required lifetime
- --> $DIR/regions-assoc-type-region-bound-in-trait-not-met.rs:20:5
+ --> $DIR/regions-assoc-type-region-bound-in-trait-not-met.rs:20:18
|
LL | type Value = &'a i32;
- | ^^^^^^^^^^^^^^^^^^^^^
+ | ^^^^^^^
|
note: type must outlive the lifetime `'b` as defined here as required by this binding
--> $DIR/regions-assoc-type-region-bound-in-trait-not-met.rs:19:10
diff --git a/src/test/ui/regions/regions-assoc-type-static-bound-in-trait-not-met.stderr b/src/test/ui/regions/regions-assoc-type-static-bound-in-trait-not-met.stderr
index a03210db6df..a96f5612fa2 100644
--- a/src/test/ui/regions/regions-assoc-type-static-bound-in-trait-not-met.stderr
+++ b/src/test/ui/regions/regions-assoc-type-static-bound-in-trait-not-met.stderr
@@ -1,8 +1,8 @@
error[E0477]: the type `&'a i32` does not fulfill the required lifetime
- --> $DIR/regions-assoc-type-static-bound-in-trait-not-met.rs:10:5
+ --> $DIR/regions-assoc-type-static-bound-in-trait-not-met.rs:10:18
|
LL | type Value = &'a i32;
- | ^^^^^^^^^^^^^^^^^^^^^
+ | ^^^^^^^
|
note: type must satisfy the static lifetime as required by this binding
--> $DIR/regions-assoc-type-static-bound-in-trait-not-met.rs:5:17
diff --git a/src/test/ui/regions/regions-close-object-into-object-2.stderr b/src/test/ui/regions/regions-close-object-into-object-2.stderr
index 9a7df8c0188..4153f4f29bc 100644
--- a/src/test/ui/regions/regions-close-object-into-object-2.stderr
+++ b/src/test/ui/regions/regions-close-object-into-object-2.stderr
@@ -4,8 +4,15 @@ error[E0759]: `v` has lifetime `'a` but it needs to satisfy a `'static` lifetime
LL | fn g<'a, T: 'static>(v: Box<dyn A<T> + 'a>) -> Box<dyn X + 'static> {
| ------------------ this data with lifetime `'a`...
LL | Box::new(B(&*v)) as Box<dyn X>
- | ^^^ ...is captured here, requiring it to live as long as `'static`
+ | ^^^ ...is used and required to live as long as `'static` here
|
+note: `'static` lifetime requirement introduced by the return type
+ --> $DIR/regions-close-object-into-object-2.rs:8:60
+ |
+LL | fn g<'a, T: 'static>(v: Box<dyn A<T> + 'a>) -> Box<dyn X + 'static> {
+ | ^^^^^^^ `'static` requirement introduced here
+LL | Box::new(B(&*v)) as Box<dyn X>
+ | ------------------------------ because of this returned expression
help: consider changing the trait object's explicit `'static` bound to the lifetime of argument `v`
|
LL | fn g<'a, T: 'static>(v: Box<dyn A<T> + 'a>) -> Box<dyn X + 'a> {
diff --git a/src/test/ui/regions/regions-close-object-into-object-4.stderr b/src/test/ui/regions/regions-close-object-into-object-4.stderr
index a7a9b16b080..2ea4b431b38 100644
--- a/src/test/ui/regions/regions-close-object-into-object-4.stderr
+++ b/src/test/ui/regions/regions-close-object-into-object-4.stderr
@@ -4,8 +4,15 @@ error[E0759]: `v` has lifetime `'a` but it needs to satisfy a `'static` lifetime
LL | fn i<'a, T, U>(v: Box<dyn A<U>+'a>) -> Box<dyn X + 'static> {
| ---------------- this data with lifetime `'a`...
LL | Box::new(B(&*v)) as Box<dyn X>
- | ^^^ ...is captured here, requiring it to live as long as `'static`
+ | ^^^ ...is used and required to live as long as `'static` here
|
+note: `'static` lifetime requirement introduced by the return type
+ --> $DIR/regions-close-object-into-object-4.rs:8:52
+ |
+LL | fn i<'a, T, U>(v: Box<dyn A<U>+'a>) -> Box<dyn X + 'static> {
+ | ^^^^^^^ `'static` requirement introduced here
+LL | Box::new(B(&*v)) as Box<dyn X>
+ | ------------------------------ because of this returned expression
help: consider changing the trait object's explicit `'static` bound to the lifetime of argument `v`
|
LL | fn i<'a, T, U>(v: Box<dyn A<U>+'a>) -> Box<dyn X + 'a> {
diff --git a/src/test/ui/regions/regions-free-region-ordering-caller.migrate.nll.stderr b/src/test/ui/regions/regions-free-region-ordering-caller.migrate.nll.stderr
deleted file mode 100644
index 0d4694a64d0..00000000000
--- a/src/test/ui/regions/regions-free-region-ordering-caller.migrate.nll.stderr
+++ /dev/null
@@ -1,39 +0,0 @@
-error: lifetime may not live long enough
- --> $DIR/regions-free-region-ordering-caller.rs:11:12
- |
-LL | fn call2<'a, 'b>(a: &'a usize, b: &'b usize) {
- | -- -- lifetime `'b` defined here
- | |
- | lifetime `'a` defined here
-LL | let z: Option<&'b &'a usize> = None;
- | ^^^^^^^^^^^^^^^^^^^^^ type annotation requires that `'a` must outlive `'b`
- |
- = help: consider adding the following bound: `'a: 'b`
-
-error: lifetime may not live long enough
- --> $DIR/regions-free-region-ordering-caller.rs:17:12
- |
-LL | fn call3<'a, 'b>(a: &'a usize, b: &'b usize) {
- | -- -- lifetime `'b` defined here
- | |
- | lifetime `'a` defined here
-LL | let y: Paramd<'a> = Paramd { x: a };
-LL | let z: Option<&'b Paramd<'a>> = None;
- | ^^^^^^^^^^^^^^^^^^^^^^ type annotation requires that `'a` must outlive `'b`
- |
- = help: consider adding the following bound: `'a: 'b`
-
-error: lifetime may not live long enough
- --> $DIR/regions-free-region-ordering-caller.rs:22:12
- |
-LL | fn call4<'a, 'b>(a: &'a usize, b: &'b usize) {
- | -- -- lifetime `'b` defined here
- | |
- | lifetime `'a` defined here
-LL | let z: Option<&'a &'b usize> = None;
- | ^^^^^^^^^^^^^^^^^^^^^ type annotation requires that `'b` must outlive `'a`
- |
- = help: consider adding the following bound: `'b: 'a`
-
-error: aborting due to 3 previous errors
-
diff --git a/src/test/ui/regions/regions-free-region-ordering-caller.migrate.stderr b/src/test/ui/regions/regions-free-region-ordering-caller.migrate.stderr
index c0f3b24f68c..a27a010d7f3 100644
--- a/src/test/ui/regions/regions-free-region-ordering-caller.migrate.stderr
+++ b/src/test/ui/regions/regions-free-region-ordering-caller.migrate.stderr
@@ -1,50 +1,50 @@
error[E0491]: in type `&'b &'a usize`, reference has a longer lifetime than the data it references
- --> $DIR/regions-free-region-ordering-caller.rs:11:12
+ --> $DIR/regions-free-region-ordering-caller.rs:16:12
|
LL | let z: Option<&'b &'a usize> = None;
| ^^^^^^^^^^^^^^^^^^^^^
|
note: the pointer is valid for the lifetime `'b` as defined here
- --> $DIR/regions-free-region-ordering-caller.rs:10:14
+ --> $DIR/regions-free-region-ordering-caller.rs:15:14
|
LL | fn call2<'a, 'b>(a: &'a usize, b: &'b usize) {
| ^^
note: but the referenced data is only valid for the lifetime `'a` as defined here
- --> $DIR/regions-free-region-ordering-caller.rs:10:10
+ --> $DIR/regions-free-region-ordering-caller.rs:15:10
|
LL | fn call2<'a, 'b>(a: &'a usize, b: &'b usize) {
| ^^
error[E0491]: in type `&'b Paramd<'a>`, reference has a longer lifetime than the data it references
- --> $DIR/regions-free-region-ordering-caller.rs:17:12
+ --> $DIR/regions-free-region-ordering-caller.rs:22:12
|
LL | let z: Option<&'b Paramd<'a>> = None;
| ^^^^^^^^^^^^^^^^^^^^^^
|
note: the pointer is valid for the lifetime `'b` as defined here
- --> $DIR/regions-free-region-ordering-caller.rs:15:14
+ --> $DIR/regions-free-region-ordering-caller.rs:20:14
|
LL | fn call3<'a, 'b>(a: &'a usize, b: &'b usize) {
| ^^
note: but the referenced data is only valid for the lifetime `'a` as defined here
- --> $DIR/regions-free-region-ordering-caller.rs:15:10
+ --> $DIR/regions-free-region-ordering-caller.rs:20:10
|
LL | fn call3<'a, 'b>(a: &'a usize, b: &'b usize) {
| ^^
error[E0491]: in type `&'a &'b usize`, reference has a longer lifetime than the data it references
- --> $DIR/regions-free-region-ordering-caller.rs:22:12
+ --> $DIR/regions-free-region-ordering-caller.rs:27:12
|
LL | let z: Option<&'a &'b usize> = None;
| ^^^^^^^^^^^^^^^^^^^^^
|
note: the pointer is valid for the lifetime `'a` as defined here
- --> $DIR/regions-free-region-ordering-caller.rs:21:10
+ --> $DIR/regions-free-region-ordering-caller.rs:26:10
|
LL | fn call4<'a, 'b>(a: &'a usize, b: &'b usize) {
| ^^
note: but the referenced data is only valid for the lifetime `'b` as defined here
- --> $DIR/regions-free-region-ordering-caller.rs:21:14
+ --> $DIR/regions-free-region-ordering-caller.rs:26:14
|
LL | fn call4<'a, 'b>(a: &'a usize, b: &'b usize) {
| ^^
diff --git a/src/test/ui/regions/regions-free-region-ordering-caller.nll.stderr b/src/test/ui/regions/regions-free-region-ordering-caller.nll.stderr
index 0d4694a64d0..546eb93d8ec 100644
--- a/src/test/ui/regions/regions-free-region-ordering-caller.nll.stderr
+++ b/src/test/ui/regions/regions-free-region-ordering-caller.nll.stderr
@@ -1,5 +1,5 @@
error: lifetime may not live long enough
- --> $DIR/regions-free-region-ordering-caller.rs:11:12
+ --> $DIR/regions-free-region-ordering-caller.rs:16:12
|
LL | fn call2<'a, 'b>(a: &'a usize, b: &'b usize) {
| -- -- lifetime `'b` defined here
@@ -11,7 +11,7 @@ LL | let z: Option<&'b &'a usize> = None;
= help: consider adding the following bound: `'a: 'b`
error: lifetime may not live long enough
- --> $DIR/regions-free-region-ordering-caller.rs:17:12
+ --> $DIR/regions-free-region-ordering-caller.rs:22:12
|
LL | fn call3<'a, 'b>(a: &'a usize, b: &'b usize) {
| -- -- lifetime `'b` defined here
@@ -24,7 +24,7 @@ LL | let z: Option<&'b Paramd<'a>> = None;
= help: consider adding the following bound: `'a: 'b`
error: lifetime may not live long enough
- --> $DIR/regions-free-region-ordering-caller.rs:22:12
+ --> $DIR/regions-free-region-ordering-caller.rs:27:12
|
LL | fn call4<'a, 'b>(a: &'a usize, b: &'b usize) {
| -- -- lifetime `'b` defined here
diff --git a/src/test/ui/regions/regions-free-region-ordering-caller.rs b/src/test/ui/regions/regions-free-region-ordering-caller.rs
index 2bf4734cf73..11997a5fb56 100644
--- a/src/test/ui/regions/regions-free-region-ordering-caller.rs
+++ b/src/test/ui/regions/regions-free-region-ordering-caller.rs
@@ -5,6 +5,11 @@
// revisions: migrate nll
//[nll]compile-flags: -Z borrowck=mir
+// Since we are testing nll (and migration) explicitly as a separate
+// revisions, don't worry about the --compare-mode=nll on this test.
+
+// ignore-compare-mode-nll
+
struct Paramd<'a> { x: &'a usize }
fn call2<'a, 'b>(a: &'a usize, b: &'b usize) {
diff --git a/src/test/ui/regions/regions-outlives-projection-container-hrtb.migrate.nll.stderr b/src/test/ui/regions/regions-outlives-projection-container-hrtb.migrate.nll.stderr
deleted file mode 100644
index 29e92f33ec9..00000000000
--- a/src/test/ui/regions/regions-outlives-projection-container-hrtb.migrate.nll.stderr
+++ /dev/null
@@ -1,28 +0,0 @@
-error: lifetime may not live long enough
- --> $DIR/regions-outlives-projection-container-hrtb.rs:30:12
- |
-LL | fn with_assoc<'a,'b>() {
- | -- -- lifetime `'b` defined here
- | |
- | lifetime `'a` defined here
-...
-LL | let _: &'a WithHrAssoc<TheType<'b>> = loop { };
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type annotation requires that `'b` must outlive `'a`
- |
- = help: consider adding the following bound: `'b: 'a`
-
-error: lifetime may not live long enough
- --> $DIR/regions-outlives-projection-container-hrtb.rs:50:12
- |
-LL | fn with_assoc_sub<'a,'b>() {
- | -- -- lifetime `'b` defined here
- | |
- | lifetime `'a` defined here
-...
-LL | let _: &'a WithHrAssocSub<TheType<'b>> = loop { };
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type annotation requires that `'b` must outlive `'a`
- |
- = help: consider adding the following bound: `'b: 'a`
-
-error: aborting due to 2 previous errors
-
diff --git a/src/test/ui/regions/regions-outlives-projection-container-hrtb.migrate.stderr b/src/test/ui/regions/regions-outlives-projection-container-hrtb.migrate.stderr
index 60c115b3f59..f2308bb7c78 100644
--- a/src/test/ui/regions/regions-outlives-projection-container-hrtb.migrate.stderr
+++ b/src/test/ui/regions/regions-outlives-projection-container-hrtb.migrate.stderr
@@ -1,33 +1,33 @@
error[E0491]: in type `&'a WithHrAssoc<TheType<'b>>`, reference has a longer lifetime than the data it references
- --> $DIR/regions-outlives-projection-container-hrtb.rs:30:12
+ --> $DIR/regions-outlives-projection-container-hrtb.rs:35:12
|
LL | let _: &'a WithHrAssoc<TheType<'b>> = loop { };
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
note: the pointer is valid for the lifetime `'a` as defined here
- --> $DIR/regions-outlives-projection-container-hrtb.rs:27:15
+ --> $DIR/regions-outlives-projection-container-hrtb.rs:32:15
|
LL | fn with_assoc<'a,'b>() {
| ^^
note: but the referenced data is only valid for the lifetime `'b` as defined here
- --> $DIR/regions-outlives-projection-container-hrtb.rs:27:18
+ --> $DIR/regions-outlives-projection-container-hrtb.rs:32:18
|
LL | fn with_assoc<'a,'b>() {
| ^^
error[E0491]: in type `&'a WithHrAssocSub<TheType<'b>>`, reference has a longer lifetime than the data it references
- --> $DIR/regions-outlives-projection-container-hrtb.rs:50:12
+ --> $DIR/regions-outlives-projection-container-hrtb.rs:55:12
|
LL | let _: &'a WithHrAssocSub<TheType<'b>> = loop { };
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
note: the pointer is valid for the lifetime `'a` as defined here
- --> $DIR/regions-outlives-projection-container-hrtb.rs:46:19
+ --> $DIR/regions-outlives-projection-container-hrtb.rs:51:19
|
LL | fn with_assoc_sub<'a,'b>() {
| ^^
note: but the referenced data is only valid for the lifetime `'b` as defined here
- --> $DIR/regions-outlives-projection-container-hrtb.rs:46:22
+ --> $DIR/regions-outlives-projection-container-hrtb.rs:51:22
|
LL | fn with_assoc_sub<'a,'b>() {
| ^^
diff --git a/src/test/ui/regions/regions-outlives-projection-container-hrtb.nll.stderr b/src/test/ui/regions/regions-outlives-projection-container-hrtb.nll.stderr
index 29e92f33ec9..472323772c1 100644
--- a/src/test/ui/regions/regions-outlives-projection-container-hrtb.nll.stderr
+++ b/src/test/ui/regions/regions-outlives-projection-container-hrtb.nll.stderr
@@ -1,5 +1,5 @@
error: lifetime may not live long enough
- --> $DIR/regions-outlives-projection-container-hrtb.rs:30:12
+ --> $DIR/regions-outlives-projection-container-hrtb.rs:35:12
|
LL | fn with_assoc<'a,'b>() {
| -- -- lifetime `'b` defined here
@@ -12,7 +12,7 @@ LL | let _: &'a WithHrAssoc<TheType<'b>> = loop { };
= help: consider adding the following bound: `'b: 'a`
error: lifetime may not live long enough
- --> $DIR/regions-outlives-projection-container-hrtb.rs:50:12
+ --> $DIR/regions-outlives-projection-container-hrtb.rs:55:12
|
LL | fn with_assoc_sub<'a,'b>() {
| -- -- lifetime `'b` defined here
diff --git a/src/test/ui/regions/regions-outlives-projection-container-hrtb.rs b/src/test/ui/regions/regions-outlives-projection-container-hrtb.rs
index cee741184ca..695a81dca27 100644
--- a/src/test/ui/regions/regions-outlives-projection-container-hrtb.rs
+++ b/src/test/ui/regions/regions-outlives-projection-container-hrtb.rs
@@ -4,6 +4,11 @@
// revisions: migrate nll
//[nll]compile-flags: -Z borrowck=mir
+// Since we are testing nll (and migration) explicitly as a separate
+// revisions, don't worry about the --compare-mode=nll on this test.
+
+// ignore-compare-mode-nll
+
#![allow(dead_code)]
pub trait TheTrait<'b> {
diff --git a/src/test/ui/regions/regions-outlives-projection-container-wc.migrate.nll.stderr b/src/test/ui/regions/regions-outlives-projection-container-wc.migrate.nll.stderr
deleted file mode 100644
index 70351443024..00000000000
--- a/src/test/ui/regions/regions-outlives-projection-container-wc.migrate.nll.stderr
+++ /dev/null
@@ -1,15 +0,0 @@
-error: lifetime may not live long enough
- --> $DIR/regions-outlives-projection-container-wc.rs:33:12
- |
-LL | fn with_assoc<'a,'b>() {
- | -- -- lifetime `'b` defined here
- | |
- | lifetime `'a` defined here
-...
-LL | let _: &'a WithAssoc<TheType<'b>> = loop { };
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^ type annotation requires that `'b` must outlive `'a`
- |
- = help: consider adding the following bound: `'b: 'a`
-
-error: aborting due to previous error
-
diff --git a/src/test/ui/regions/regions-outlives-projection-container-wc.migrate.stderr b/src/test/ui/regions/regions-outlives-projection-container-wc.migrate.stderr
index 8430b69f998..bda2896fca4 100644
--- a/src/test/ui/regions/regions-outlives-projection-container-wc.migrate.stderr
+++ b/src/test/ui/regions/regions-outlives-projection-container-wc.migrate.stderr
@@ -1,16 +1,16 @@
error[E0491]: in type `&'a WithAssoc<TheType<'b>>`, reference has a longer lifetime than the data it references
- --> $DIR/regions-outlives-projection-container-wc.rs:33:12
+ --> $DIR/regions-outlives-projection-container-wc.rs:38:12
|
LL | let _: &'a WithAssoc<TheType<'b>> = loop { };
| ^^^^^^^^^^^^^^^^^^^^^^^^^^
|
note: the pointer is valid for the lifetime `'a` as defined here
- --> $DIR/regions-outlives-projection-container-wc.rs:27:15
+ --> $DIR/regions-outlives-projection-container-wc.rs:32:15
|
LL | fn with_assoc<'a,'b>() {
| ^^
note: but the referenced data is only valid for the lifetime `'b` as defined here
- --> $DIR/regions-outlives-projection-container-wc.rs:27:18
+ --> $DIR/regions-outlives-projection-container-wc.rs:32:18
|
LL | fn with_assoc<'a,'b>() {
| ^^
diff --git a/src/test/ui/regions/regions-outlives-projection-container-wc.nll.stderr b/src/test/ui/regions/regions-outlives-projection-container-wc.nll.stderr
index 70351443024..fc32a72d508 100644
--- a/src/test/ui/regions/regions-outlives-projection-container-wc.nll.stderr
+++ b/src/test/ui/regions/regions-outlives-projection-container-wc.nll.stderr
@@ -1,5 +1,5 @@
error: lifetime may not live long enough
- --> $DIR/regions-outlives-projection-container-wc.rs:33:12
+ --> $DIR/regions-outlives-projection-container-wc.rs:38:12
|
LL | fn with_assoc<'a,'b>() {
| -- -- lifetime `'b` defined here
diff --git a/src/test/ui/regions/regions-outlives-projection-container-wc.rs b/src/test/ui/regions/regions-outlives-projection-container-wc.rs
index 99965f33390..c9b714cffb6 100644
--- a/src/test/ui/regions/regions-outlives-projection-container-wc.rs
+++ b/src/test/ui/regions/regions-outlives-projection-container-wc.rs
@@ -6,6 +6,11 @@
// revisions: migrate nll
//[nll]compile-flags: -Z borrowck=mir
+// Since we are testing nll (and migration) explicitly as a separate
+// revisions, don't worry about the --compare-mode=nll on this test.
+
+// ignore-compare-mode-nll
+
#![allow(dead_code)]
pub trait TheTrait {
diff --git a/src/test/ui/regions/regions-proc-bound-capture.stderr b/src/test/ui/regions/regions-proc-bound-capture.stderr
index 50b3748bf40..2ebe874da93 100644
--- a/src/test/ui/regions/regions-proc-bound-capture.stderr
+++ b/src/test/ui/regions/regions-proc-bound-capture.stderr
@@ -5,8 +5,16 @@ LL | fn static_proc(x: &isize) -> Box<dyn FnMut() -> (isize) + 'static> {
| ------ this data with an anonymous lifetime `'_`...
LL | // This is illegal, because the region bound on `proc` is 'static.
LL | Box::new(move || { *x })
- | ^^^^^^^^^^^^^^ ...is captured here, requiring it to live as long as `'static`
+ | ^^^^^^^^^^^^^^ ...is used and required to live as long as `'static` here
|
+note: `'static` lifetime requirement introduced by the return type
+ --> $DIR/regions-proc-bound-capture.rs:7:59
+ |
+LL | fn static_proc(x: &isize) -> Box<dyn FnMut() -> (isize) + 'static> {
+ | ^^^^^^^ `'static` requirement introduced here
+LL | // This is illegal, because the region bound on `proc` is 'static.
+LL | Box::new(move || { *x })
+ | ------------------------ because of this returned expression
help: consider changing the trait object's explicit `'static` bound to the lifetime of argument `x`
|
LL | fn static_proc(x: &isize) -> Box<dyn FnMut() -> (isize) + '_> {
diff --git a/src/test/ui/regions/regions-static-bound.stderr b/src/test/ui/regions/regions-static-bound.stderr
index 51fe16ca9da..b8e69e02609 100644
--- a/src/test/ui/regions/regions-static-bound.stderr
+++ b/src/test/ui/regions/regions-static-bound.stderr
@@ -17,7 +17,7 @@ error[E0759]: `u` has an anonymous lifetime `'_` but it needs to satisfy a `'sta
LL | fn error(u: &(), v: &()) {
| --- this data with an anonymous lifetime `'_`...
LL | static_id(&u);
- | ^^^^^^^^^ -- ...is captured here...
+ | ^^^^^^^^^ -- ...is used here...
|
note: ...and is required to live as long as `'static` here
--> $DIR/regions-static-bound.rs:10:5
@@ -32,7 +32,7 @@ LL | fn error(u: &(), v: &()) {
| --- this data with an anonymous lifetime `'_`...
LL | static_id(&u);
LL | static_id_indirect(&v);
- | ^^^^^^^^^^^^^^^^^^ -- ...is captured here...
+ | ^^^^^^^^^^^^^^^^^^ -- ...is used here...
|
note: ...and is required to live as long as `'static` here
--> $DIR/regions-static-bound.rs:11:5
diff --git a/src/test/ui/repr/issue-83921-pretty.pretty.stdout b/src/test/ui/repr/issue-83921-pretty.pretty.stdout
index dad3641f0f5..aaf3993538a 100644
--- a/src/test/ui/repr/issue-83921-pretty.pretty.stdout
+++ b/src/test/ui/repr/issue-83921-pretty.pretty.stdout
@@ -13,7 +13,6 @@ extern crate std;
// [pretty]compile-flags: -Zunpretty=everybody_loops
// [pretty]check-pass
#[repr("C")]
-struct A {
-}
+struct A {}
-fn main() { loop { } }
+fn main() { loop {} }
diff --git a/src/test/ui/resolve/issue-70736-async-fn-no-body-def-collector.stderr b/src/test/ui/resolve/issue-70736-async-fn-no-body-def-collector.stderr
index 50446bb659b..d3214458eac 100644
--- a/src/test/ui/resolve/issue-70736-async-fn-no-body-def-collector.stderr
+++ b/src/test/ui/resolve/issue-70736-async-fn-no-body-def-collector.stderr
@@ -48,15 +48,17 @@ error[E0053]: method `associated` has an incompatible type for trait
--> $DIR/issue-70736-async-fn-no-body-def-collector.rs:15:26
|
LL | async fn associated();
- | - type in trait
-...
-LL | async fn associated();
| ^
| |
| checked the `Output` of this `async fn`, found opaque type
| expected `()`, found opaque type
|
= note: while checking the return type of the `async fn`
+note: type in trait
+ --> $DIR/issue-70736-async-fn-no-body-def-collector.rs:11:26
+ |
+LL | async fn associated();
+ | ^
= note: expected fn pointer `fn()`
found fn pointer `fn() -> impl Future<Output = ()>`
diff --git a/src/test/ui/return/return-type.stderr b/src/test/ui/return/return-type.stderr
index 5af136e6011..f86209a651d 100644
--- a/src/test/ui/return/return-type.stderr
+++ b/src/test/ui/return/return-type.stderr
@@ -1,19 +1,15 @@
error[E0308]: mismatched types
--> $DIR/return-type.rs:10:5
|
+LL | fn bar() {
+ | - possibly return type missing here?
LL | foo(4 as usize)
- | ^^^^^^^^^^^^^^^ expected `()`, found struct `S`
+ | ^^^^^^^^^^^^^^^- help: consider using a semicolon here: `;`
+ | |
+ | expected `()`, found struct `S`
|
= note: expected unit type `()`
found struct `S<usize>`
-help: consider using a semicolon here
- |
-LL | foo(4 as usize);
- | +
-help: try adding a return type
- |
-LL | fn bar() -> S<usize> {
- | +++++++++++
error: aborting due to previous error
diff --git a/src/test/ui/rfc-1937-termination-trait/termination-trait-in-test.rs b/src/test/ui/rfc-1937-termination-trait/termination-trait-in-test.rs
index 0bd7bf3d51a..cd57d9bca94 100644
--- a/src/test/ui/rfc-1937-termination-trait/termination-trait-in-test.rs
+++ b/src/test/ui/rfc-1937-termination-trait/termination-trait-in-test.rs
@@ -1,5 +1,6 @@
// compile-flags: --test
// run-pass
+// needs-unwind
// ignore-wasm32-bare compiled with panic=abort by default
diff --git a/src/test/ui/rfc-2008-non-exhaustive/auxiliary/enums.rs b/src/test/ui/rfc-2008-non-exhaustive/auxiliary/enums.rs
index 0098f087d10..cb2b585ab96 100644
--- a/src/test/ui/rfc-2008-non-exhaustive/auxiliary/enums.rs
+++ b/src/test/ui/rfc-2008-non-exhaustive/auxiliary/enums.rs
@@ -30,3 +30,15 @@ pub enum VariantNonExhaustive {
pub enum NonExhaustiveSingleVariant {
A(bool),
}
+
+#[repr(u8)]
+pub enum FieldLessWithNonExhaustiveVariant {
+ A,
+ B,
+ #[non_exhaustive]
+ C,
+}
+
+impl Default for FieldLessWithNonExhaustiveVariant {
+ fn default() -> Self { Self::A }
+}
diff --git a/src/test/ui/rfc-2008-non-exhaustive/enum-as-cast.rs b/src/test/ui/rfc-2008-non-exhaustive/enum-as-cast.rs
new file mode 100644
index 00000000000..d9657bac776
--- /dev/null
+++ b/src/test/ui/rfc-2008-non-exhaustive/enum-as-cast.rs
@@ -0,0 +1,17 @@
+// aux-build:enums.rs
+// run-pass
+
+extern crate enums;
+
+use enums::FieldLessWithNonExhaustiveVariant;
+
+fn main() {
+ let e = FieldLessWithNonExhaustiveVariant::default();
+ // FIXME: https://github.com/rust-lang/rust/issues/91161
+ // This `as` cast *should* be an error, since it would fail
+ // if the non-exhaustive variant got fields. But today it
+ // doesn't. The fix for that will update this test to
+ // show an error (and not be run-pass any more).
+ let d = e as u8;
+ assert_eq!(d, 0);
+}
diff --git a/src/test/ui/rfc-2091-track-caller/error-with-naked.rs b/src/test/ui/rfc-2091-track-caller/error-with-naked.rs
index 9464ffe8722..0045d608133 100644
--- a/src/test/ui/rfc-2091-track-caller/error-with-naked.rs
+++ b/src/test/ui/rfc-2091-track-caller/error-with-naked.rs
@@ -1,5 +1,7 @@
// needs-asm-support
-#![feature(asm, naked_functions)]
+#![feature(naked_functions)]
+
+use std::arch::asm;
#[track_caller] //~ ERROR cannot use `#[track_caller]` with `#[naked]`
#[naked]
diff --git a/src/test/ui/rfc-2091-track-caller/error-with-naked.stderr b/src/test/ui/rfc-2091-track-caller/error-with-naked.stderr
index 5f17d6b2b51..d33aecc0f97 100644
--- a/src/test/ui/rfc-2091-track-caller/error-with-naked.stderr
+++ b/src/test/ui/rfc-2091-track-caller/error-with-naked.stderr
@@ -1,11 +1,11 @@
error[E0736]: cannot use `#[track_caller]` with `#[naked]`
- --> $DIR/error-with-naked.rs:4:1
+ --> $DIR/error-with-naked.rs:6:1
|
LL | #[track_caller]
| ^^^^^^^^^^^^^^^
error[E0736]: cannot use `#[track_caller]` with `#[naked]`
- --> $DIR/error-with-naked.rs:13:5
+ --> $DIR/error-with-naked.rs:15:5
|
LL | #[track_caller]
| ^^^^^^^^^^^^^^^
diff --git a/src/test/ui/rfc-2091-track-caller/std-panic-locations.rs b/src/test/ui/rfc-2091-track-caller/std-panic-locations.rs
index f0850d5c1f1..b067994a5c6 100644
--- a/src/test/ui/rfc-2091-track-caller/std-panic-locations.rs
+++ b/src/test/ui/rfc-2091-track-caller/std-panic-locations.rs
@@ -1,4 +1,5 @@
// run-pass
+// needs-unwind
// ignore-wasm32-bare compiled with panic=abort by default
// revisions: default mir-opt
//[mir-opt] compile-flags: -Zmir-opt-level=4
diff --git a/src/test/ui/rfc-2497-if-let-chains/ast-pretty-check.stdout b/src/test/ui/rfc-2497-if-let-chains/ast-pretty-check.stdout
index aeee43b01cc..6052ea95d0f 100644
--- a/src/test/ui/rfc-2497-if-let-chains/ast-pretty-check.stdout
+++ b/src/test/ui/rfc-2497-if-let-chains/ast-pretty-check.stdout
@@ -7,4 +7,4 @@ extern crate std;
// build-pass (FIXME(62277): could be check-pass?)
// compile-flags: -Z unpretty=expanded
-fn main() { if let 0 = 1 { } }
+fn main() { if let 0 = 1 {} }
diff --git a/src/test/ui/rfc-2497-if-let-chains/disallowed-positions.stderr b/src/test/ui/rfc-2497-if-let-chains/disallowed-positions.stderr
index 3fc5cb1b079..1433a16d727 100644
--- a/src/test/ui/rfc-2497-if-let-chains/disallowed-positions.stderr
+++ b/src/test/ui/rfc-2497-if-let-chains/disallowed-positions.stderr
@@ -644,7 +644,9 @@ error[E0308]: mismatched types
--> $DIR/disallowed-positions.rs:76:12
|
LL | if let Range { start: F, end } = F..|| true {}
- | ^^^^^^^^^^^^^^^^^^^^^^^ expected fn pointer, found struct `std::ops::Range`
+ | ^^^^^^^^^^^^^^^^^^^^^^^ - this expression has type `fn() -> bool`
+ | |
+ | expected fn pointer, found struct `std::ops::Range`
|
= note: expected fn pointer `fn() -> bool`
found struct `std::ops::Range<_>`
@@ -832,7 +834,9 @@ error[E0308]: mismatched types
--> $DIR/disallowed-positions.rs:140:15
|
LL | while let Range { start: F, end } = F..|| true {}
- | ^^^^^^^^^^^^^^^^^^^^^^^ expected fn pointer, found struct `std::ops::Range`
+ | ^^^^^^^^^^^^^^^^^^^^^^^ - this expression has type `fn() -> bool`
+ | |
+ | expected fn pointer, found struct `std::ops::Range`
|
= note: expected fn pointer `fn() -> bool`
found struct `std::ops::Range<_>`
diff --git a/src/test/ui/rfc-2565-param-attrs/auxiliary/param-attrs.rs b/src/test/ui/rfc-2565-param-attrs/auxiliary/param-attrs.rs
index 2a172c8458d..8800d3e66f9 100644
--- a/src/test/ui/rfc-2565-param-attrs/auxiliary/param-attrs.rs
+++ b/src/test/ui/rfc-2565-param-attrs/auxiliary/param-attrs.rs
@@ -18,14 +18,14 @@ macro_rules! checker {
}
checker!(attr_extern, r#"extern "C" { fn ffi(#[a1] arg1 : i32, #[a2] ...) ; }"#);
-checker!(attr_extern_cvar, r#"unsafe extern "C" fn cvar(arg1 : i32, #[a1] mut args : ...) { }"#);
+checker!(attr_extern_cvar, r#"unsafe extern "C" fn cvar(arg1 : i32, #[a1] mut args : ...) {}"#);
checker!(attr_alias, "type Alias = fn(#[a1] u8, #[a2] ...) ;");
checker!(attr_free, "fn free(#[a1] arg1 : u8) { let lam = | #[a2] W(x), #[a3] y | () ; }");
-checker!(attr_inherent_1, "fn inherent1(#[a1] self, #[a2] arg1 : u8) { }");
-checker!(attr_inherent_2, "fn inherent2(#[a1] & self, #[a2] arg1 : u8) { }");
-checker!(attr_inherent_3, "fn inherent3 < 'a > (#[a1] & 'a mut self, #[a2] arg1 : u8) { }");
-checker!(attr_inherent_4, "fn inherent4 < 'a > (#[a1] self : Box < Self >, #[a2] arg1 : u8) { }");
-checker!(attr_inherent_issue_64682, "fn inherent5(#[a1] #[a2] arg1 : u8, #[a3] arg2 : u8) { }");
+checker!(attr_inherent_1, "fn inherent1(#[a1] self, #[a2] arg1 : u8) {}");
+checker!(attr_inherent_2, "fn inherent2(#[a1] & self, #[a2] arg1 : u8) {}");
+checker!(attr_inherent_3, "fn inherent3 < 'a > (#[a1] & 'a mut self, #[a2] arg1 : u8) {}");
+checker!(attr_inherent_4, "fn inherent4 < 'a > (#[a1] self : Box < Self >, #[a2] arg1 : u8) {}");
+checker!(attr_inherent_issue_64682, "fn inherent5(#[a1] #[a2] arg1 : u8, #[a3] arg2 : u8) {}");
checker!(attr_trait_1, "fn trait1(#[a1] self, #[a2] arg1 : u8) ;");
checker!(attr_trait_2, "fn trait2(#[a1] & self, #[a2] arg1 : u8) ;");
checker!(attr_trait_3, "fn trait3 < 'a > (#[a1] & 'a mut self, #[a2] arg1 : u8) ;");
@@ -35,9 +35,9 @@ checker!(attr_trait_issue_64682, "fn trait5(#[a1] #[a2] arg1 : u8, #[a3] arg2 :
checker!(rename_params, r#"impl Foo
{
fn hello(#[angery(true)] a : i32, #[a2] b : i32, #[what = "how"] c : u32)
- { } fn
+ {} fn
hello2(#[a1] #[a2] a : i32, #[what = "how"] b : i32, #[angery(true)] c :
- u32) { } fn
+ u32) {} fn
hello_self(#[a1] #[a2] & self, #[a1] #[a2] a : i32, #[what = "how"] b :
- i32, #[angery(true)] c : u32) { }
+ i32, #[angery(true)] c : u32) {}
}"#);
diff --git a/src/test/ui/rfc-2632-const-trait-impl/assoc-type.rs b/src/test/ui/rfc-2632-const-trait-impl/assoc-type.rs
index 228b5ed71e8..7b012083c5a 100644
--- a/src/test/ui/rfc-2632-const-trait-impl/assoc-type.rs
+++ b/src/test/ui/rfc-2632-const-trait-impl/assoc-type.rs
@@ -1,6 +1,5 @@
// FIXME(fee1-dead): this should have a better error message
#![feature(const_trait_impl)]
-
struct NonConstAdd(i32);
impl std::ops::Add for NonConstAdd {
diff --git a/src/test/ui/rfc-2632-const-trait-impl/assoc-type.stderr b/src/test/ui/rfc-2632-const-trait-impl/assoc-type.stderr
index b894092205e..4a4b4de4758 100644
--- a/src/test/ui/rfc-2632-const-trait-impl/assoc-type.stderr
+++ b/src/test/ui/rfc-2632-const-trait-impl/assoc-type.stderr
@@ -1,12 +1,12 @@
error[E0277]: cannot add `NonConstAdd` to `NonConstAdd`
- --> $DIR/assoc-type.rs:19:5
+ --> $DIR/assoc-type.rs:18:16
|
LL | type Bar = NonConstAdd;
- | ^^^^^^^^^^^^^^^^^^^^^^^ no implementation for `NonConstAdd + NonConstAdd`
+ | ^^^^^^^^^^^ no implementation for `NonConstAdd + NonConstAdd`
|
= help: the trait `Add` is not implemented for `NonConstAdd`
note: required by a bound in `Foo::Bar`
- --> $DIR/assoc-type.rs:15:15
+ --> $DIR/assoc-type.rs:14:15
|
LL | type Bar: ~const std::ops::Add;
| ^^^^^^^^^^^^^^^^^^^^ required by this bound in `Foo::Bar`
diff --git a/src/test/ui/rfc-2632-const-trait-impl/auxiliary/cross-crate.rs b/src/test/ui/rfc-2632-const-trait-impl/auxiliary/cross-crate.rs
index d8fd7ef3c1f..2d049277d7f 100644
--- a/src/test/ui/rfc-2632-const-trait-impl/auxiliary/cross-crate.rs
+++ b/src/test/ui/rfc-2632-const-trait-impl/auxiliary/cross-crate.rs
@@ -1,6 +1,9 @@
+#![feature(const_fn_trait_bound)]
#![feature(const_trait_impl)]
pub trait MyTrait {
+ #[default_method_body_is_const]
+ fn defaulted_func(&self) {}
fn func(self);
}
diff --git a/src/test/ui/rfc-2632-const-trait-impl/const-drop-bound.rs b/src/test/ui/rfc-2632-const-trait-impl/const-drop-bound.rs
new file mode 100644
index 00000000000..83fa32bf092
--- /dev/null
+++ b/src/test/ui/rfc-2632-const-trait-impl/const-drop-bound.rs
@@ -0,0 +1,20 @@
+// check-pass
+
+#![feature(const_trait_impl)]
+#![feature(const_fn_trait_bound)]
+#![feature(const_precise_live_drops)]
+
+const fn foo<T, E>(res: Result<T, E>) -> Option<T> where E: ~const Drop {
+ match res {
+ Ok(t) => Some(t),
+ Err(_e) => None,
+ }
+}
+
+pub struct Foo<T>(T);
+
+const fn baz<T: ~const Drop, E: ~const Drop>(res: Result<Foo<T>, Foo<E>>) -> Option<Foo<T>> {
+ foo(res)
+}
+
+fn main() {}
diff --git a/src/test/ui/rfc-2632-const-trait-impl/cross-crate-default-method-body-is-const.rs b/src/test/ui/rfc-2632-const-trait-impl/cross-crate-default-method-body-is-const.rs
new file mode 100644
index 00000000000..c0f90c116e4
--- /dev/null
+++ b/src/test/ui/rfc-2632-const-trait-impl/cross-crate-default-method-body-is-const.rs
@@ -0,0 +1,18 @@
+// This tests that `default_method_body_is_const` methods can
+// be called from a const context when used across crates.
+//
+// check-pass
+
+#![feature(const_trait_impl)]
+
+// aux-build: cross-crate.rs
+extern crate cross_crate;
+
+use cross_crate::*;
+
+const _: () = {
+ Const.func();
+ Const.defaulted_func();
+};
+
+fn main() {}
diff --git a/src/test/ui/rfc-2632-const-trait-impl/default-method-body-is-const-body-checking.rs b/src/test/ui/rfc-2632-const-trait-impl/default-method-body-is-const-body-checking.rs
new file mode 100644
index 00000000000..7db04fe1ac3
--- /dev/null
+++ b/src/test/ui/rfc-2632-const-trait-impl/default-method-body-is-const-body-checking.rs
@@ -0,0 +1,17 @@
+#![feature(const_fn_trait_bound)]
+#![feature(const_trait_impl)]
+
+trait Tr {}
+impl Tr for () {}
+
+const fn foo<T>() where T: ~const Tr {}
+
+pub trait Foo {
+ #[default_method_body_is_const]
+ fn foo() {
+ foo::<()>();
+ //~^ ERROR the trait bound `(): Tr` is not satisfied
+ }
+}
+
+fn main() {}
diff --git a/src/test/ui/rfc-2632-const-trait-impl/default-method-body-is-const-body-checking.stderr b/src/test/ui/rfc-2632-const-trait-impl/default-method-body-is-const-body-checking.stderr
new file mode 100644
index 00000000000..6e7e4b3a472
--- /dev/null
+++ b/src/test/ui/rfc-2632-const-trait-impl/default-method-body-is-const-body-checking.stderr
@@ -0,0 +1,19 @@
+error[E0277]: the trait bound `(): Tr` is not satisfied
+ --> $DIR/default-method-body-is-const-body-checking.rs:12:15
+ |
+LL | foo::<()>();
+ | ^^ the trait `Tr` is not implemented for `()`
+ |
+note: required by a bound in `foo`
+ --> $DIR/default-method-body-is-const-body-checking.rs:7:28
+ |
+LL | const fn foo<T>() where T: ~const Tr {}
+ | ^^^^^^^^^ required by this bound in `foo`
+help: consider introducing a `where` bound, but there might be an alternative better way to express this requirement
+ |
+LL | pub trait Foo where (): Tr {
+ | ++++++++++++
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0277`.
diff --git a/src/test/ui/rfc-2632-const-trait-impl/non-const-op-in-closure-in-const.rs b/src/test/ui/rfc-2632-const-trait-impl/non-const-op-in-closure-in-const.rs
new file mode 100644
index 00000000000..ef74ef8e426
--- /dev/null
+++ b/src/test/ui/rfc-2632-const-trait-impl/non-const-op-in-closure-in-const.rs
@@ -0,0 +1,18 @@
+// check-pass
+
+#![feature(const_trait_impl)]
+#![feature(const_fn_trait_bound)]
+
+trait Convert<T> {
+ fn to(self) -> T;
+}
+
+impl<A, B> const Convert<B> for A where B: ~const From<A> {
+ fn to(self) -> B {
+ B::from(self)
+ }
+}
+
+const FOO: fn() -> String = || "foo".to();
+
+fn main() {}
diff --git a/src/test/ui/rfc-2632-const-trait-impl/trait-default-body-stability.rs b/src/test/ui/rfc-2632-const-trait-impl/trait-default-body-stability.rs
new file mode 100644
index 00000000000..cbfdf89b7bd
--- /dev/null
+++ b/src/test/ui/rfc-2632-const-trait-impl/trait-default-body-stability.rs
@@ -0,0 +1,51 @@
+// check-pass
+
+#![feature(staged_api)]
+#![feature(const_trait_impl)]
+#![feature(const_fn_trait_bound)]
+#![feature(const_t_try)]
+#![feature(const_try)]
+#![feature(try_trait_v2)]
+
+#![stable(feature = "foo", since = "1.0")]
+
+use std::ops::{ControlFlow, FromResidual, Try};
+
+#[stable(feature = "foo", since = "1.0")]
+pub struct T;
+
+#[stable(feature = "foo", since = "1.0")]
+#[rustc_const_unstable(feature = "const_t_try", issue = "none")]
+impl const Try for T {
+ type Output = T;
+ type Residual = T;
+
+ fn from_output(t: T) -> T {
+ t
+ }
+
+ fn branch(self) -> ControlFlow<T, T> {
+ ControlFlow::Continue(self)
+ }
+}
+
+#[stable(feature = "foo", since = "1.0")]
+#[rustc_const_unstable(feature = "const_t_try", issue = "none")]
+impl const FromResidual for T {
+ fn from_residual(t: T) -> T {
+ t
+ }
+}
+
+#[stable(feature = "foo", since = "1.0")]
+pub trait Tr {
+ #[default_method_body_is_const]
+ #[stable(feature = "foo", since = "1.0")]
+ fn bar() -> T {
+ T?
+ // Should be allowed.
+ // Must enable unstable features to call this trait fn in const contexts.
+ }
+}
+
+fn main() {}
diff --git a/src/test/ui/rfc1623.nll.stderr b/src/test/ui/rfc1623.nll.stderr
index 7f15c1c1f57..86513b6064d 100644
--- a/src/test/ui/rfc1623.nll.stderr
+++ b/src/test/ui/rfc1623.nll.stderr
@@ -1,26 +1,5 @@
-error[E0277]: `dyn for<'a, 'b> Fn(&'a Foo<'b>) -> &'a Foo<'b>` cannot be shared between threads safely
- --> $DIR/rfc1623.rs:21:1
- |
-LL | / static SOME_STRUCT: &SomeStruct = &SomeStruct {
-LL | | foo: &Foo { bools: &[false, true] },
-LL | | bar: &Bar { bools: &[true, true] },
-LL | | f: &id,
-LL | |
-LL | | };
- | |__^ `dyn for<'a, 'b> Fn(&'a Foo<'b>) -> &'a Foo<'b>` cannot be shared between threads safely
- |
- = help: within `&SomeStruct`, the trait `Sync` is not implemented for `dyn for<'a, 'b> Fn(&'a Foo<'b>) -> &'a Foo<'b>`
- = note: required because it appears within the type `&dyn for<'a, 'b> Fn(&'a Foo<'b>) -> &'a Foo<'b>`
-note: required because it appears within the type `SomeStruct`
- --> $DIR/rfc1623.rs:11:8
- |
-LL | struct SomeStruct<'x, 'y, 'z: 'x> {
- | ^^^^^^^^^^
- = note: required because it appears within the type `&SomeStruct`
- = note: shared static variables must have a type that implements `Sync`
-
error[E0308]: mismatched types
- --> $DIR/rfc1623.rs:21:35
+ --> $DIR/rfc1623.rs:25:35
|
LL | static SOME_STRUCT: &SomeStruct = &SomeStruct {
| ___________________________________^
@@ -35,7 +14,7 @@ LL | | };
found type `Fn<(&Foo<'_>,)>`
error[E0308]: mismatched types
- --> $DIR/rfc1623.rs:21:35
+ --> $DIR/rfc1623.rs:25:35
|
LL | static SOME_STRUCT: &SomeStruct = &SomeStruct {
| ___________________________________^
@@ -50,7 +29,7 @@ LL | | };
found type `Fn<(&Foo<'_>,)>`
error: implementation of `FnOnce` is not general enough
- --> $DIR/rfc1623.rs:21:35
+ --> $DIR/rfc1623.rs:25:35
|
LL | static SOME_STRUCT: &SomeStruct = &SomeStruct {
| ___________________________________^
@@ -65,7 +44,7 @@ LL | | };
= note: ...but it actually implements `FnOnce<(&'2 Foo<'_>,)>`, for some specific lifetime `'2`
error: implementation of `FnOnce` is not general enough
- --> $DIR/rfc1623.rs:21:35
+ --> $DIR/rfc1623.rs:25:35
|
LL | static SOME_STRUCT: &SomeStruct = &SomeStruct {
| ___________________________________^
@@ -79,7 +58,6 @@ LL | | };
= note: `fn(&Foo<'2>) -> &Foo<'2> {id::<&Foo<'2>>}` must implement `FnOnce<(&'a Foo<'1>,)>`, for any lifetime `'1`...
= note: ...but it actually implements `FnOnce<(&Foo<'2>,)>`, for some specific lifetime `'2`
-error: aborting due to 5 previous errors
+error: aborting due to 4 previous errors
-Some errors have detailed explanations: E0277, E0308.
-For more information about an error, try `rustc --explain E0277`.
+For more information about this error, try `rustc --explain E0308`.
diff --git a/src/test/ui/rfc1623.rs b/src/test/ui/rfc1623.rs
index 9ff4813d112..32e00f9cb76 100644
--- a/src/test/ui/rfc1623.rs
+++ b/src/test/ui/rfc1623.rs
@@ -14,6 +14,10 @@ struct SomeStruct<'x, 'y, 'z: 'x> {
f: &'y dyn for<'a, 'b> Fn(&'a Foo<'b>) -> &'a Foo<'b>,
}
+// Without this, the wf-check will fail early so we'll never see the
+// error in SOME_STRUCT's body.
+unsafe impl<'x, 'y, 'z: 'x> Sync for SomeStruct<'x, 'y, 'z> {}
+
fn id<T>(t: T) -> T {
t
}
diff --git a/src/test/ui/rfc1623.stderr b/src/test/ui/rfc1623.stderr
index e95e68c8e6d..16829b5caa0 100644
--- a/src/test/ui/rfc1623.stderr
+++ b/src/test/ui/rfc1623.stderr
@@ -1,5 +1,5 @@
error: implementation of `FnOnce` is not general enough
- --> $DIR/rfc1623.rs:24:8
+ --> $DIR/rfc1623.rs:28:8
|
LL | f: &id,
| ^^^ implementation of `FnOnce` is not general enough
diff --git a/src/test/ui/rfcs/rfc1857-drop-order.rs b/src/test/ui/rfcs/rfc1857-drop-order.rs
index 7923aa7c0e2..243b7fb6fad 100644
--- a/src/test/ui/rfcs/rfc1857-drop-order.rs
+++ b/src/test/ui/rfcs/rfc1857-drop-order.rs
@@ -1,4 +1,5 @@
// run-pass
+// needs-unwind
// ignore-wasm32-bare compiled with panic=abort by default
#![allow(dead_code, unreachable_code)]
diff --git a/src/test/ui/runtime/rt-explody-panic-payloads.rs b/src/test/ui/runtime/rt-explody-panic-payloads.rs
index dc193582c6a..eb5bf8f67a8 100644
--- a/src/test/ui/runtime/rt-explody-panic-payloads.rs
+++ b/src/test/ui/runtime/rt-explody-panic-payloads.rs
@@ -1,4 +1,5 @@
// run-pass
+// needs-unwind
// ignore-emscripten no processes
// ignore-sgx no processes
// ignore-wasm32-bare no unwinding panic
diff --git a/src/test/ui/rust-2018/uniform-paths/deadlock.rs b/src/test/ui/rust-2018/uniform-paths/deadlock.rs
index 83ed70a0459..2427bde6d18 100644
--- a/src/test/ui/rust-2018/uniform-paths/deadlock.rs
+++ b/src/test/ui/rust-2018/uniform-paths/deadlock.rs
@@ -1,7 +1,8 @@
// edition:2018
// compile-flags:--extern foo --extern bar
+use bar::foo; //~ ERROR can't find crate for `bar`
use foo::bar; //~ ERROR can't find crate for `foo`
-use bar::foo;
+//~^^ ERROR unresolved imports `bar::foo`, `foo::bar`
fn main() {}
diff --git a/src/test/ui/rust-2018/uniform-paths/deadlock.stderr b/src/test/ui/rust-2018/uniform-paths/deadlock.stderr
index 9336e90afb7..8b9863948bd 100644
--- a/src/test/ui/rust-2018/uniform-paths/deadlock.stderr
+++ b/src/test/ui/rust-2018/uniform-paths/deadlock.stderr
@@ -1,9 +1,24 @@
-error[E0463]: can't find crate for `foo`
+error[E0463]: can't find crate for `bar`
--> $DIR/deadlock.rs:4:5
|
+LL | use bar::foo;
+ | ^^^ can't find crate
+
+error[E0463]: can't find crate for `foo`
+ --> $DIR/deadlock.rs:5:5
+ |
LL | use foo::bar;
| ^^^ can't find crate
-error: aborting due to previous error
+error[E0432]: unresolved imports `bar::foo`, `foo::bar`
+ --> $DIR/deadlock.rs:4:5
+ |
+LL | use bar::foo;
+ | ^^^^^^^^
+LL | use foo::bar;
+ | ^^^^^^^^
+
+error: aborting due to 3 previous errors
-For more information about this error, try `rustc --explain E0463`.
+Some errors have detailed explanations: E0432, E0463.
+For more information about an error, try `rustc --explain E0432`.
diff --git a/src/test/ui/rustdoc/doc_keyword.rs b/src/test/ui/rustdoc/doc_keyword.rs
index 4518f77ef93..43b84e5018c 100644
--- a/src/test/ui/rustdoc/doc_keyword.rs
+++ b/src/test/ui/rustdoc/doc_keyword.rs
@@ -1,5 +1,5 @@
#![crate_type = "lib"]
-#![feature(doc_keyword)]
+#![feature(rustdoc_internals)]
#![doc(keyword = "hello")] //~ ERROR
diff --git a/src/test/ui/rustdoc/renamed-features-rustdoc_internals.rs b/src/test/ui/rustdoc/renamed-features-rustdoc_internals.rs
new file mode 100644
index 00000000000..739c624d0c6
--- /dev/null
+++ b/src/test/ui/rustdoc/renamed-features-rustdoc_internals.rs
@@ -0,0 +1,5 @@
+#![feature(doc_keyword)] //~ ERROR
+#![feature(doc_primitive)] //~ ERROR
+#![crate_type = "lib"]
+
+pub fn foo() {}
diff --git a/src/test/ui/rustdoc/renamed-features-rustdoc_internals.stderr b/src/test/ui/rustdoc/renamed-features-rustdoc_internals.stderr
new file mode 100644
index 00000000000..d0979ce97ac
--- /dev/null
+++ b/src/test/ui/rustdoc/renamed-features-rustdoc_internals.stderr
@@ -0,0 +1,19 @@
+error[E0557]: feature has been removed
+ --> $DIR/renamed-features-rustdoc_internals.rs:1:12
+ |
+LL | #![feature(doc_keyword)]
+ | ^^^^^^^^^^^ feature has been removed
+ |
+ = note: merged into `#![feature(rustdoc_internals)]`
+
+error[E0557]: feature has been removed
+ --> $DIR/renamed-features-rustdoc_internals.rs:2:12
+ |
+LL | #![feature(doc_primitive)]
+ | ^^^^^^^^^^^^^ feature has been removed
+ |
+ = note: merged into `#![feature(rustdoc_internals)]`
+
+error: aborting due to 2 previous errors
+
+For more information about this error, try `rustc --explain E0557`.
diff --git a/src/test/ui/self/arbitrary_self_types_pin_lifetime_impl_trait-async.stderr b/src/test/ui/self/arbitrary_self_types_pin_lifetime_impl_trait-async.stderr
index 953d7cd6a07..61ac7731777 100644
--- a/src/test/ui/self/arbitrary_self_types_pin_lifetime_impl_trait-async.stderr
+++ b/src/test/ui/self/arbitrary_self_types_pin_lifetime_impl_trait-async.stderr
@@ -6,7 +6,7 @@ LL | async fn f(self: Pin<&Self>) -> impl Clone { self }
| |
| hidden type `Pin<&Foo>` captures the lifetime `'_` as defined here
|
-help: to declare that the `impl Trait` captures '_, you can add an explicit `'_` lifetime bound
+help: to declare that the `impl Trait` captures `'_`, you can add an explicit `'_` lifetime bound
|
LL | async fn f(self: Pin<&Self>) -> impl Clone + '_ { self }
| ++++
diff --git a/src/test/ui/self/arbitrary_self_types_pin_lifetime_impl_trait.stderr b/src/test/ui/self/arbitrary_self_types_pin_lifetime_impl_trait.stderr
index faa1233ffde..6f8200739b9 100644
--- a/src/test/ui/self/arbitrary_self_types_pin_lifetime_impl_trait.stderr
+++ b/src/test/ui/self/arbitrary_self_types_pin_lifetime_impl_trait.stderr
@@ -6,7 +6,7 @@ LL | fn f(self: Pin<&Self>) -> impl Clone { self }
| |
| hidden type `Pin<&Foo>` captures the anonymous lifetime defined here
|
-help: to declare that the `impl Trait` captures '_, you can add an explicit `'_` lifetime bound
+help: to declare that the `impl Trait` captures `'_`, you can add an explicit `'_` lifetime bound
|
LL | fn f(self: Pin<&Self>) -> impl Clone + '_ { self }
| ++++
diff --git a/src/test/ui/sepcomp/sepcomp-unwind.rs b/src/test/ui/sepcomp/sepcomp-unwind.rs
index 50a4e043943..a59e25a273e 100644
--- a/src/test/ui/sepcomp/sepcomp-unwind.rs
+++ b/src/test/ui/sepcomp/sepcomp-unwind.rs
@@ -1,4 +1,5 @@
// run-pass
+// needs-unwind
#![allow(dead_code)]
// compile-flags: -C codegen-units=3
// ignore-emscripten no threads support
diff --git a/src/test/ui/simd/intrinsic/generic-elements-pass.rs b/src/test/ui/simd/intrinsic/generic-elements-pass.rs
index 08544bce45d..3c913c0adfa 100644
--- a/src/test/ui/simd/intrinsic/generic-elements-pass.rs
+++ b/src/test/ui/simd/intrinsic/generic-elements-pass.rs
@@ -2,7 +2,6 @@
// ignore-emscripten FIXME(#45351) hits an LLVM assert
#![feature(repr_simd, platform_intrinsics)]
-#![allow(incomplete_features)]
#![feature(inline_const)]
#[repr(simd)]
diff --git a/src/test/ui/simple_global_asm.rs b/src/test/ui/simple_global_asm.rs
index 75b4788b56f..3c69379ff14 100644
--- a/src/test/ui/simple_global_asm.rs
+++ b/src/test/ui/simple_global_asm.rs
@@ -1,11 +1,10 @@
// run-pass
-#![feature(global_asm)]
#![feature(naked_functions)]
#![allow(dead_code)]
#[cfg(any(target_arch = "x86_64", target_arch = "x86"))]
-global_asm!(
+core::arch::global_asm!(
r#"
.global foo
.global _foo
diff --git a/src/test/ui/slightly-nice-generic-literal-messages.stderr b/src/test/ui/slightly-nice-generic-literal-messages.stderr
index 14f01f0ebdf..61eabed9504 100644
--- a/src/test/ui/slightly-nice-generic-literal-messages.stderr
+++ b/src/test/ui/slightly-nice-generic-literal-messages.stderr
@@ -1,8 +1,6 @@
error[E0308]: mismatched types
--> $DIR/slightly-nice-generic-literal-messages.rs:7:9
|
-LL | match Foo(1.1, marker::PhantomData) {
- | ----------------------------- this expression has type `Foo<{float}, _>`
LL | 1 => {}
| ^ expected struct `Foo`, found integer
|
diff --git a/src/test/ui/span/issue-43927-non-ADT-derive.rs b/src/test/ui/span/issue-43927-non-ADT-derive.rs
index 840c12e16e1..935bfa001bf 100644
--- a/src/test/ui/span/issue-43927-non-ADT-derive.rs
+++ b/src/test/ui/span/issue-43927-non-ADT-derive.rs
@@ -1,5 +1,6 @@
#![derive(Debug, PartialEq, Eq)] // should be an outer attribute!
//~^ ERROR cannot determine resolution for the attribute macro `derive`
+//~^^ ERROR `derive` attribute cannot be used at crate level
struct DerivedOn;
fn main() {}
diff --git a/src/test/ui/span/issue-43927-non-ADT-derive.stderr b/src/test/ui/span/issue-43927-non-ADT-derive.stderr
index 9ef81c5150a..e3ae37e3689 100644
--- a/src/test/ui/span/issue-43927-non-ADT-derive.stderr
+++ b/src/test/ui/span/issue-43927-non-ADT-derive.stderr
@@ -6,5 +6,16 @@ LL | #![derive(Debug, PartialEq, Eq)] // should be an outer attribute!
|
= note: import resolution is stuck, try simplifying macro imports
-error: aborting due to previous error
+error: `derive` attribute cannot be used at crate level
+ --> $DIR/issue-43927-non-ADT-derive.rs:1:1
+ |
+LL | #![derive(Debug, PartialEq, Eq)] // should be an outer attribute!
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ |
+help: perhaps you meant to use an outer attribute
+ |
+LL | #[derive(Debug, PartialEq, Eq)] // should be an outer attribute!
+ | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+error: aborting due to 2 previous errors
diff --git a/src/test/ui/specialization/deafult-associated-type-bound-1.stderr b/src/test/ui/specialization/deafult-associated-type-bound-1.stderr
index b3dba0d552a..9e400f87024 100644
--- a/src/test/ui/specialization/deafult-associated-type-bound-1.stderr
+++ b/src/test/ui/specialization/deafult-associated-type-bound-1.stderr
@@ -9,10 +9,10 @@ LL | #![feature(specialization)]
= help: consider using `min_specialization` instead, which is more stable and complete
error[E0277]: the trait bound `str: Clone` is not satisfied
- --> $DIR/deafult-associated-type-bound-1.rs:19:5
+ --> $DIR/deafult-associated-type-bound-1.rs:19:22
|
LL | default type U = str;
- | ^^^^^^^^^^^^^^^^^^^^^ the trait `Clone` is not implemented for `str`
+ | ^^^ the trait `Clone` is not implemented for `str`
|
note: required by a bound in `X::U`
--> $DIR/deafult-associated-type-bound-1.rs:9:13
diff --git a/src/test/ui/specialization/deafult-associated-type-bound-2.stderr b/src/test/ui/specialization/deafult-associated-type-bound-2.stderr
index d425fae6dc3..47ea69d40bb 100644
--- a/src/test/ui/specialization/deafult-associated-type-bound-2.stderr
+++ b/src/test/ui/specialization/deafult-associated-type-bound-2.stderr
@@ -9,10 +9,10 @@ LL | #![feature(specialization)]
= help: consider using `min_specialization` instead, which is more stable and complete
error[E0277]: can't compare `&'static B` with `B`
- --> $DIR/deafult-associated-type-bound-2.rs:16:5
+ --> $DIR/deafult-associated-type-bound-2.rs:16:22
|
LL | default type U = &'static B;
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ no implementation for `&'static B == B`
+ | ^^^^^^^^^^ no implementation for `&'static B == B`
|
= help: the trait `PartialEq<B>` is not implemented for `&'static B`
note: required by a bound in `X::U`
diff --git a/src/test/ui/specialization/deafult-generic-associated-type-bound.stderr b/src/test/ui/specialization/deafult-generic-associated-type-bound.stderr
index 8cfce7feffc..da5fe97cf1b 100644
--- a/src/test/ui/specialization/deafult-generic-associated-type-bound.stderr
+++ b/src/test/ui/specialization/deafult-generic-associated-type-bound.stderr
@@ -9,10 +9,10 @@ LL | #![feature(specialization)]
= help: consider using `min_specialization` instead, which is more stable and complete
error[E0277]: can't compare `T` with `T`
- --> $DIR/deafult-generic-associated-type-bound.rs:18:5
+ --> $DIR/deafult-generic-associated-type-bound.rs:18:26
|
LL | default type U<'a> = &'a T;
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ no implementation for `T == T`
+ | ^^^^^ no implementation for `T == T`
|
= note: required because of the requirements on the impl of `PartialEq` for `&'a T`
note: required by a bound in `X::U`
diff --git a/src/test/ui/specialization/issue-33017.stderr b/src/test/ui/specialization/issue-33017.stderr
index 44e7581f5ca..78e94cec2c0 100644
--- a/src/test/ui/specialization/issue-33017.stderr
+++ b/src/test/ui/specialization/issue-33017.stderr
@@ -1,8 +1,8 @@
error[E0277]: the trait bound `T: Copy` is not satisfied
- --> $DIR/issue-33017.rs:12:5
+ --> $DIR/issue-33017.rs:12:27
|
LL | default type Output = Self;
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `Copy` is not implemented for `T`
+ | ^^^^ the trait `Copy` is not implemented for `T`
|
note: required by a bound in `UncheckedCopy::Output`
--> $DIR/issue-33017.rs:8:31
diff --git a/src/test/ui/specialization/issue-38091.stderr b/src/test/ui/specialization/issue-38091.stderr
index d5452e1d513..cc5536c9e9a 100644
--- a/src/test/ui/specialization/issue-38091.stderr
+++ b/src/test/ui/specialization/issue-38091.stderr
@@ -9,10 +9,10 @@ LL | #![feature(specialization)]
= help: consider using `min_specialization` instead, which is more stable and complete
error[E0277]: the trait bound `(): Valid` is not satisfied
- --> $DIR/issue-38091.rs:12:5
+ --> $DIR/issue-38091.rs:12:23
|
LL | default type Ty = ();
- | ^^^^^^^^^^^^^^^^^^^^^ the trait `Valid` is not implemented for `()`
+ | ^^ the trait `Valid` is not implemented for `()`
|
note: required by a bound in `Iterate::Ty`
--> $DIR/issue-38091.rs:5:14
diff --git a/src/test/ui/specialization/issue-44861.stderr b/src/test/ui/specialization/issue-44861.stderr
index 114504b0439..1941d40fee8 100644
--- a/src/test/ui/specialization/issue-44861.stderr
+++ b/src/test/ui/specialization/issue-44861.stderr
@@ -1,8 +1,8 @@
error[E0277]: the trait bound `(): CoerceUnsized<*const [u8]>` is not satisfied
- --> $DIR/issue-44861.rs:21:5
+ --> $DIR/issue-44861.rs:21:26
|
LL | default type Data2 = ();
- | ^^^^^^^^^^^^^^^^^^^^^^^^ the trait `CoerceUnsized<*const [u8]>` is not implemented for `()`
+ | ^^ the trait `CoerceUnsized<*const [u8]>` is not implemented for `()`
|
note: required by a bound in `Smartass::Data2`
--> $DIR/issue-44861.rs:12:17
diff --git a/src/test/ui/specialization/issue-59435.stderr b/src/test/ui/specialization/issue-59435.stderr
index 606d22ed07b..bb5d90f001e 100644
--- a/src/test/ui/specialization/issue-59435.stderr
+++ b/src/test/ui/specialization/issue-59435.stderr
@@ -1,8 +1,8 @@
error[E0277]: the trait bound `MyStruct: Default` is not satisfied
- --> $DIR/issue-59435.rs:11:5
+ --> $DIR/issue-59435.rs:11:27
|
LL | default type MyType = MyStruct;
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `Default` is not implemented for `MyStruct`
+ | ^^^^^^^^ the trait `Default` is not implemented for `MyStruct`
|
note: required by a bound in `MyTrait::MyType`
--> $DIR/issue-59435.rs:7:18
diff --git a/src/test/ui/specialization/min_specialization/repeated_projection_type.stderr b/src/test/ui/specialization/min_specialization/repeated_projection_type.stderr
index d2eea15f398..07d194476a5 100644
--- a/src/test/ui/specialization/min_specialization/repeated_projection_type.stderr
+++ b/src/test/ui/specialization/min_specialization/repeated_projection_type.stderr
@@ -1,4 +1,4 @@
-error: cannot specialize on `Binder(ProjectionPredicate(ProjectionTy { substs: [V], item_def_id: DefId(0:6 ~ repeated_projection_type[b09c]::Id::This) }, (I,)), [])`
+error: cannot specialize on `Binder(ProjectionPredicate(ProjectionTy { substs: [V], item_def_id: DefId(0:6 ~ repeated_projection_type[HASH]::Id::This) }, (I,)), [])`
--> $DIR/repeated_projection_type.rs:19:1
|
LL | / impl<I, V: Id<This = (I,)>> X for V {
diff --git a/src/test/ui/stability-attribute/suggest-vec-allocator-api.rs b/src/test/ui/stability-attribute/suggest-vec-allocator-api.rs
new file mode 100644
index 00000000000..fac52ab77c6
--- /dev/null
+++ b/src/test/ui/stability-attribute/suggest-vec-allocator-api.rs
@@ -0,0 +1,9 @@
+fn main() {
+ let _: Vec<u8, _> = vec![]; //~ ERROR use of unstable library feature 'allocator_api'
+ #[rustfmt::skip]
+ let _: Vec<
+ String,
+ _> = vec![]; //~ ERROR use of unstable library feature 'allocator_api'
+ let _ = Vec::<u16, _>::new(); //~ ERROR use of unstable library feature 'allocator_api'
+ let _boxed: Box<u32, _> = Box::new(10); //~ ERROR use of unstable library feature 'allocator_api'
+}
diff --git a/src/test/ui/stability-attribute/suggest-vec-allocator-api.stderr b/src/test/ui/stability-attribute/suggest-vec-allocator-api.stderr
new file mode 100644
index 00000000000..41e5787b8c2
--- /dev/null
+++ b/src/test/ui/stability-attribute/suggest-vec-allocator-api.stderr
@@ -0,0 +1,49 @@
+error[E0658]: use of unstable library feature 'allocator_api'
+ --> $DIR/suggest-vec-allocator-api.rs:2:20
+ |
+LL | let _: Vec<u8, _> = vec![];
+ | ----^
+ | |
+ | help: consider wrapping the inner types in tuple: `(u8, _)`
+ |
+ = note: see issue #32838 <https://github.com/rust-lang/rust/issues/32838> for more information
+ = help: add `#![feature(allocator_api)]` to the crate attributes to enable
+
+error[E0658]: use of unstable library feature 'allocator_api'
+ --> $DIR/suggest-vec-allocator-api.rs:6:9
+ |
+LL | _> = vec![];
+ | ^
+ |
+ = note: see issue #32838 <https://github.com/rust-lang/rust/issues/32838> for more information
+ = help: add `#![feature(allocator_api)]` to the crate attributes to enable
+help: consider wrapping the inner types in tuple
+ |
+LL ~ let _: Vec<(
+LL + String,
+LL ~ _)> = vec![];
+ |
+
+error[E0658]: use of unstable library feature 'allocator_api'
+ --> $DIR/suggest-vec-allocator-api.rs:8:26
+ |
+LL | let _boxed: Box<u32, _> = Box::new(10);
+ | ^
+ |
+ = note: see issue #32838 <https://github.com/rust-lang/rust/issues/32838> for more information
+ = help: add `#![feature(allocator_api)]` to the crate attributes to enable
+
+error[E0658]: use of unstable library feature 'allocator_api'
+ --> $DIR/suggest-vec-allocator-api.rs:7:24
+ |
+LL | let _ = Vec::<u16, _>::new();
+ | -----^
+ | |
+ | help: consider wrapping the inner types in tuple: `(u16, _)`
+ |
+ = note: see issue #32838 <https://github.com/rust-lang/rust/issues/32838> for more information
+ = help: add `#![feature(allocator_api)]` to the crate attributes to enable
+
+error: aborting due to 4 previous errors
+
+For more information about this error, try `rustc --explain E0658`.
diff --git a/src/test/ui/stack-protector/warn-stack-protector-unsupported.all.stderr b/src/test/ui/stack-protector/warn-stack-protector-unsupported.all.stderr
new file mode 100644
index 00000000000..54887715523
--- /dev/null
+++ b/src/test/ui/stack-protector/warn-stack-protector-unsupported.all.stderr
@@ -0,0 +1,4 @@
+warning: `-Z stack-protector=all` is not supported for target nvptx64-nvidia-cuda and will be ignored
+
+warning: 1 warning emitted
+
diff --git a/src/test/ui/stack-protector/warn-stack-protector-unsupported.basic.stderr b/src/test/ui/stack-protector/warn-stack-protector-unsupported.basic.stderr
new file mode 100644
index 00000000000..f7a1ee39fb9
--- /dev/null
+++ b/src/test/ui/stack-protector/warn-stack-protector-unsupported.basic.stderr
@@ -0,0 +1,4 @@
+warning: `-Z stack-protector=basic` is not supported for target nvptx64-nvidia-cuda and will be ignored
+
+warning: 1 warning emitted
+
diff --git a/src/test/ui/stack-protector/warn-stack-protector-unsupported.rs b/src/test/ui/stack-protector/warn-stack-protector-unsupported.rs
new file mode 100644
index 00000000000..6df5d3cd5ae
--- /dev/null
+++ b/src/test/ui/stack-protector/warn-stack-protector-unsupported.rs
@@ -0,0 +1,19 @@
+// build-pass
+// revisions: all strong basic
+// compile-flags: --target nvptx64-nvidia-cuda
+// needs-llvm-components: nvptx
+// [all] compile-flags: -Z stack-protector=all
+// [strong] compile-flags: -Z stack-protector=strong
+// [basic] compile-flags: -Z stack-protector=basic
+
+#![crate_type = "lib"]
+#![feature(no_core, lang_items)]
+#![no_std]
+#![no_core]
+
+#[lang = "sized"]
+trait Sized {}
+#[lang = "copy"]
+trait Copy {}
+
+pub fn main(){}
diff --git a/src/test/ui/stack-protector/warn-stack-protector-unsupported.strong.stderr b/src/test/ui/stack-protector/warn-stack-protector-unsupported.strong.stderr
new file mode 100644
index 00000000000..ccc2f9f2cc5
--- /dev/null
+++ b/src/test/ui/stack-protector/warn-stack-protector-unsupported.strong.stderr
@@ -0,0 +1,4 @@
+warning: `-Z stack-protector=strong` is not supported for target nvptx64-nvidia-cuda and will be ignored
+
+warning: 1 warning emitted
+
diff --git a/src/test/ui/static/static-mut-bad-types.stderr b/src/test/ui/static/static-mut-bad-types.stderr
index ddd98ff4079..983e1026f91 100644
--- a/src/test/ui/static/static-mut-bad-types.stderr
+++ b/src/test/ui/static/static-mut-bad-types.stderr
@@ -1,6 +1,9 @@
error[E0308]: mismatched types
--> $DIR/static-mut-bad-types.rs:5:13
|
+LL | static mut a: isize = 3;
+ | ----- expected due to this type
+...
LL | a = true;
| ^^^^ expected `isize`, found `bool`
diff --git a/src/test/ui/structs-enums/unit-like-struct-drop-run.rs b/src/test/ui/structs-enums/unit-like-struct-drop-run.rs
index 980fd97e2c6..1e9c269a4d3 100644
--- a/src/test/ui/structs-enums/unit-like-struct-drop-run.rs
+++ b/src/test/ui/structs-enums/unit-like-struct-drop-run.rs
@@ -1,4 +1,5 @@
// run-pass
+// needs-unwind
// ignore-emscripten no threads support
// Make sure the destructor is run for unit-like structs.
diff --git a/src/test/ui/structs/structure-constructor-type-mismatch.stderr b/src/test/ui/structs/structure-constructor-type-mismatch.stderr
index 3d64fc601df..98972a12159 100644
--- a/src/test/ui/structs/structure-constructor-type-mismatch.stderr
+++ b/src/test/ui/structs/structure-constructor-type-mismatch.stderr
@@ -101,8 +101,6 @@ LL | type PointF = Point<f32>;
error[E0308]: mismatched types
--> $DIR/structure-constructor-type-mismatch.rs:54:9
|
-LL | match (Point { x: 1, y: 2 }) {
- | ---------------------- this expression has type `Point<{integer}>`
LL | PointF::<u32> { .. } => {}
| ^^^^^^^^^^^^^^^^^^^^ expected integer, found `f32`
|
@@ -112,8 +110,6 @@ LL | PointF::<u32> { .. } => {}
error[E0308]: mismatched types
--> $DIR/structure-constructor-type-mismatch.rs:59:9
|
-LL | match (Point { x: 1, y: 2 }) {
- | ---------------------- this expression has type `Point<{integer}>`
LL | PointF { .. } => {}
| ^^^^^^^^^^^^^ expected integer, found `f32`
|
@@ -123,8 +119,6 @@ LL | PointF { .. } => {}
error[E0308]: mismatched types
--> $DIR/structure-constructor-type-mismatch.rs:67:9
|
-LL | match (Pair { x: 1, y: 2 }) {
- | --------------------- this expression has type `Pair<{integer}, {integer}>`
LL | PairF::<u32> { .. } => {}
| ^^^^^^^^^^^^^^^^^^^ expected integer, found `f32`
|
diff --git a/src/test/ui/suggestions/as-ref-2.stderr b/src/test/ui/suggestions/as-ref-2.stderr
index 86a175098c6..3c9d0f72abe 100644
--- a/src/test/ui/suggestions/as-ref-2.stderr
+++ b/src/test/ui/suggestions/as-ref-2.stderr
@@ -11,8 +11,8 @@ LL | let _y = foo;
note: this function takes ownership of the receiver `self`, which moves `foo`
--> $SRC_DIR/core/src/option.rs:LL:COL
|
-LL | pub fn map<U, F: FnOnce(T) -> U>(self, f: F) -> Option<U> {
- | ^^^^
+LL | pub const fn map<U, F>(self, f: F) -> Option<U>
+ | ^^^^
help: consider calling `.as_ref()` to borrow the type's contents
|
LL | let _x: Option<Struct> = foo.as_ref().map(|s| bar(&s));
diff --git a/src/test/ui/suggestions/async-fn-ctor-passed-as-arg-where-it-should-have-been-called.stderr b/src/test/ui/suggestions/async-fn-ctor-passed-as-arg-where-it-should-have-been-called.stderr
index 4759ebea0e9..766db2a8356 100644
--- a/src/test/ui/suggestions/async-fn-ctor-passed-as-arg-where-it-should-have-been-called.stderr
+++ b/src/test/ui/suggestions/async-fn-ctor-passed-as-arg-where-it-should-have-been-called.stderr
@@ -10,6 +10,7 @@ LL | bar(foo);
| required by a bound introduced by this call
|
= help: the trait `Future` is not implemented for `fn() -> impl Future<Output = ()> {foo}`
+ = note: fn() -> impl Future<Output = ()> {foo} must be a future or must implement `IntoFuture` to be awaited
note: required by a bound in `bar`
--> $DIR/async-fn-ctor-passed-as-arg-where-it-should-have-been-called.rs:7:16
|
@@ -31,6 +32,7 @@ LL | bar(async_closure);
| required by a bound introduced by this call
|
= help: the trait `Future` is not implemented for `[closure@$DIR/async-fn-ctor-passed-as-arg-where-it-should-have-been-called.rs:11:25: 11:36]`
+ = note: [closure@$DIR/async-fn-ctor-passed-as-arg-where-it-should-have-been-called.rs:11:25: 11:36] must be a future or must implement `IntoFuture` to be awaited
note: required by a bound in `bar`
--> $DIR/async-fn-ctor-passed-as-arg-where-it-should-have-been-called.rs:7:16
|
diff --git a/src/test/ui/suggestions/count2len.rs b/src/test/ui/suggestions/count2len.rs
new file mode 100644
index 00000000000..f11a789efbc
--- /dev/null
+++ b/src/test/ui/suggestions/count2len.rs
@@ -0,0 +1,8 @@
+fn main() {
+ let slice = [1,2,3,4];
+ let vec = vec![1,2,3,4];
+
+ slice.count(); //~ERROR: E0599
+ vec.count(); //~ERROR: E0599
+ vec.as_slice().count(); //~ERROR: E0599
+}
diff --git a/src/test/ui/suggestions/count2len.stderr b/src/test/ui/suggestions/count2len.stderr
new file mode 100644
index 00000000000..6394a84dd47
--- /dev/null
+++ b/src/test/ui/suggestions/count2len.stderr
@@ -0,0 +1,36 @@
+error[E0599]: no method named `count` found for array `[{integer}; 4]` in the current scope
+ --> $DIR/count2len.rs:5:11
+ |
+LL | slice.count();
+ | ^^^^^
+ | |
+ | method cannot be called on `[{integer}; 4]` due to unsatisfied trait bounds
+ | help: consider using `len` instead
+ |
+ = note: `count` is defined on `Iterator`, which `[{integer}; 4]` does not implement
+
+error[E0599]: no method named `count` found for struct `Vec<{integer}>` in the current scope
+ --> $DIR/count2len.rs:6:9
+ |
+LL | vec.count();
+ | ^^^^^
+ | |
+ | method cannot be called on `Vec<{integer}>` due to unsatisfied trait bounds
+ | help: consider using `len` instead
+ |
+ = note: `count` is defined on `Iterator`, which `Vec<{integer}>` does not implement
+
+error[E0599]: no method named `count` found for reference `&[{integer}]` in the current scope
+ --> $DIR/count2len.rs:7:20
+ |
+LL | vec.as_slice().count();
+ | ^^^^^
+ | |
+ | method cannot be called on `&[{integer}]` due to unsatisfied trait bounds
+ | help: consider using `len` instead
+ |
+ = note: `count` is defined on `Iterator`, which `&[{integer}]` does not implement
+
+error: aborting due to 3 previous errors
+
+For more information about this error, try `rustc --explain E0599`.
diff --git a/src/test/ui/suggestions/derive-macro-missing-bounds.rs b/src/test/ui/suggestions/derive-macro-missing-bounds.rs
new file mode 100644
index 00000000000..56c218f97eb
--- /dev/null
+++ b/src/test/ui/suggestions/derive-macro-missing-bounds.rs
@@ -0,0 +1,89 @@
+mod a {
+ use std::fmt::{Debug, Formatter, Result};
+ struct Inner<T>(T);
+
+ impl Debug for Inner<()> {
+ fn fmt(&self, f: &mut Formatter<'_>) -> Result {
+ todo!()
+ }
+ }
+
+ #[derive(Debug)]
+ struct Outer<T>(Inner<T>); //~ ERROR `a::Inner<T>` doesn't implement `Debug`
+}
+
+mod b {
+ use std::fmt::{Debug, Formatter, Result};
+ struct Inner<T>(T);
+
+ impl<T: Debug> Debug for Inner<T> {
+ fn fmt(&self, f: &mut Formatter<'_>) -> Result {
+ todo!()
+ }
+ }
+
+ #[derive(Debug)]
+ struct Outer<T>(Inner<T>);
+}
+
+mod c {
+ use std::fmt::{Debug, Formatter, Result};
+ struct Inner<T>(T);
+ trait Trait {}
+
+ impl<T: Debug + Trait> Debug for Inner<T> {
+ fn fmt(&self, f: &mut Formatter<'_>) -> Result {
+ todo!()
+ }
+ }
+
+ #[derive(Debug)]
+ struct Outer<T>(Inner<T>); //~ ERROR the trait bound `T: c::Trait` is not satisfied
+}
+
+mod d {
+ use std::fmt::{Debug, Formatter, Result};
+ struct Inner<T>(T);
+ trait Trait {}
+
+ impl<T> Debug for Inner<T> where T: Debug, T: Trait {
+ fn fmt(&self, f: &mut Formatter<'_>) -> Result {
+ todo!()
+ }
+ }
+
+ #[derive(Debug)]
+ struct Outer<T>(Inner<T>); //~ ERROR the trait bound `T: d::Trait` is not satisfied
+}
+
+mod e {
+ use std::fmt::{Debug, Formatter, Result};
+ struct Inner<T>(T);
+ trait Trait {}
+
+ impl<T> Debug for Inner<T> where T: Debug + Trait {
+ fn fmt(&self, f: &mut Formatter<'_>) -> Result {
+ todo!()
+ }
+ }
+
+ #[derive(Debug)]
+ struct Outer<T>(Inner<T>); //~ ERROR the trait bound `T: e::Trait` is not satisfied
+}
+
+mod f {
+ use std::fmt::{Debug, Formatter, Result};
+ struct Inner<T>(T);
+ trait Trait {}
+
+ impl<T: Debug> Debug for Inner<T> where T: Trait {
+ fn fmt(&self, f: &mut Formatter<'_>) -> Result {
+ todo!()
+ }
+ }
+
+ #[derive(Debug)]
+ struct Outer<T>(Inner<T>); //~ ERROR the trait bound `T: f::Trait` is not satisfied
+}
+
+fn main() {}
diff --git a/src/test/ui/suggestions/derive-macro-missing-bounds.stderr b/src/test/ui/suggestions/derive-macro-missing-bounds.stderr
new file mode 100644
index 00000000000..7a4f7e209c1
--- /dev/null
+++ b/src/test/ui/suggestions/derive-macro-missing-bounds.stderr
@@ -0,0 +1,107 @@
+error[E0277]: `a::Inner<T>` doesn't implement `Debug`
+ --> $DIR/derive-macro-missing-bounds.rs:12:21
+ |
+LL | #[derive(Debug)]
+ | ----- in this derive macro expansion
+LL | struct Outer<T>(Inner<T>);
+ | ^^^^^^^^ `a::Inner<T>` cannot be formatted using `{:?}`
+ |
+ = help: the trait `Debug` is not implemented for `a::Inner<T>`
+ = note: add `#[derive(Debug)]` to `a::Inner<T>` or manually `impl Debug for a::Inner<T>`
+ = note: this error originates in the derive macro `Debug` (in Nightly builds, run with -Z macro-backtrace for more info)
+help: consider introducing a `where` bound, but there might be an alternative better way to express this requirement
+ |
+LL | struct Outer<T>(Inner<T>) where a::Inner<T>: Debug;
+ | ++++++++++++++++++++++++
+
+error[E0277]: the trait bound `T: c::Trait` is not satisfied
+ --> $DIR/derive-macro-missing-bounds.rs:41:21
+ |
+LL | #[derive(Debug)]
+ | ----- in this derive macro expansion
+LL | struct Outer<T>(Inner<T>);
+ | ^^^^^^^^ the trait `c::Trait` is not implemented for `T`
+ |
+note: required because of the requirements on the impl of `Debug` for `c::Inner<T>`
+ --> $DIR/derive-macro-missing-bounds.rs:34:28
+ |
+LL | impl<T: Debug + Trait> Debug for Inner<T> {
+ | ^^^^^ ^^^^^^^^
+ = note: 1 redundant requirement hidden
+ = note: required because of the requirements on the impl of `Debug` for `&c::Inner<T>`
+ = note: required for the cast to the object type `dyn Debug`
+ = note: this error originates in the derive macro `Debug` (in Nightly builds, run with -Z macro-backtrace for more info)
+help: consider restricting type parameter `T`
+ |
+LL | struct Outer<T: c::Trait>(Inner<T>);
+ | ++++++++++
+
+error[E0277]: the trait bound `T: d::Trait` is not satisfied
+ --> $DIR/derive-macro-missing-bounds.rs:56:21
+ |
+LL | #[derive(Debug)]
+ | ----- in this derive macro expansion
+LL | struct Outer<T>(Inner<T>);
+ | ^^^^^^^^ the trait `d::Trait` is not implemented for `T`
+ |
+note: required because of the requirements on the impl of `Debug` for `d::Inner<T>`
+ --> $DIR/derive-macro-missing-bounds.rs:49:13
+ |
+LL | impl<T> Debug for Inner<T> where T: Debug, T: Trait {
+ | ^^^^^ ^^^^^^^^
+ = note: 1 redundant requirement hidden
+ = note: required because of the requirements on the impl of `Debug` for `&d::Inner<T>`
+ = note: required for the cast to the object type `dyn Debug`
+ = note: this error originates in the derive macro `Debug` (in Nightly builds, run with -Z macro-backtrace for more info)
+help: consider restricting type parameter `T`
+ |
+LL | struct Outer<T: d::Trait>(Inner<T>);
+ | ++++++++++
+
+error[E0277]: the trait bound `T: e::Trait` is not satisfied
+ --> $DIR/derive-macro-missing-bounds.rs:71:21
+ |
+LL | #[derive(Debug)]
+ | ----- in this derive macro expansion
+LL | struct Outer<T>(Inner<T>);
+ | ^^^^^^^^ the trait `e::Trait` is not implemented for `T`
+ |
+note: required because of the requirements on the impl of `Debug` for `e::Inner<T>`
+ --> $DIR/derive-macro-missing-bounds.rs:64:13
+ |
+LL | impl<T> Debug for Inner<T> where T: Debug + Trait {
+ | ^^^^^ ^^^^^^^^
+ = note: 1 redundant requirement hidden
+ = note: required because of the requirements on the impl of `Debug` for `&e::Inner<T>`
+ = note: required for the cast to the object type `dyn Debug`
+ = note: this error originates in the derive macro `Debug` (in Nightly builds, run with -Z macro-backtrace for more info)
+help: consider restricting type parameter `T`
+ |
+LL | struct Outer<T: e::Trait>(Inner<T>);
+ | ++++++++++
+
+error[E0277]: the trait bound `T: f::Trait` is not satisfied
+ --> $DIR/derive-macro-missing-bounds.rs:86:21
+ |
+LL | #[derive(Debug)]
+ | ----- in this derive macro expansion
+LL | struct Outer<T>(Inner<T>);
+ | ^^^^^^^^ the trait `f::Trait` is not implemented for `T`
+ |
+note: required because of the requirements on the impl of `Debug` for `f::Inner<T>`
+ --> $DIR/derive-macro-missing-bounds.rs:79:20
+ |
+LL | impl<T: Debug> Debug for Inner<T> where T: Trait {
+ | ^^^^^ ^^^^^^^^
+ = note: 1 redundant requirement hidden
+ = note: required because of the requirements on the impl of `Debug` for `&f::Inner<T>`
+ = note: required for the cast to the object type `dyn Debug`
+ = note: this error originates in the derive macro `Debug` (in Nightly builds, run with -Z macro-backtrace for more info)
+help: consider restricting type parameter `T`
+ |
+LL | struct Outer<T: f::Trait>(Inner<T>);
+ | ++++++++++
+
+error: aborting due to 5 previous errors
+
+For more information about this error, try `rustc --explain E0277`.
diff --git a/src/test/ui/suggestions/expected-boxed-future-isnt-pinned.stderr b/src/test/ui/suggestions/expected-boxed-future-isnt-pinned.stderr
index 7ef4895249c..550ed4b03b0 100644
--- a/src/test/ui/suggestions/expected-boxed-future-isnt-pinned.stderr
+++ b/src/test/ui/suggestions/expected-boxed-future-isnt-pinned.stderr
@@ -81,7 +81,7 @@ LL | pub const fn from_generator<T>(gen: T) -> impl Future<Output = T::Return>
| ------------------------------- the found opaque type
|
= note: expected struct `Pin<Box<(dyn Future<Output = i32> + Send + 'static)>>`
- found opaque type `impl Future`
+ found opaque type `impl Future<Output = [async output]>`
help: you need to pin and box this expression
|
LL ~ Box::pin(async {
diff --git a/src/test/ui/suggestions/fn-ctor-passed-as-arg-where-it-should-have-been-called.stderr b/src/test/ui/suggestions/fn-ctor-passed-as-arg-where-it-should-have-been-called.stderr
index b111df49f6e..101e7aecc02 100644
--- a/src/test/ui/suggestions/fn-ctor-passed-as-arg-where-it-should-have-been-called.stderr
+++ b/src/test/ui/suggestions/fn-ctor-passed-as-arg-where-it-should-have-been-called.stderr
@@ -1,11 +1,11 @@
-error[E0277]: the trait bound `fn() -> impl T {foo}: T` is not satisfied
+error[E0277]: the trait bound `fn() -> impl T<O = ()> {foo}: T` is not satisfied
--> $DIR/fn-ctor-passed-as-arg-where-it-should-have-been-called.rs:17:9
|
LL | fn foo() -> impl T<O=()> { S }
| --- consider calling this function
...
LL | bar(foo);
- | --- ^^^ the trait `T` is not implemented for `fn() -> impl T {foo}`
+ | --- ^^^ the trait `T` is not implemented for `fn() -> impl T<O = ()> {foo}`
| |
| required by a bound introduced by this call
|
diff --git a/src/test/ui/suggestions/fn-or-tuple-struct-with-underscore-args.rs b/src/test/ui/suggestions/fn-or-tuple-struct-with-underscore-args.rs
index 00638e04f5d..ae1dbfeea93 100644
--- a/src/test/ui/suggestions/fn-or-tuple-struct-with-underscore-args.rs
+++ b/src/test/ui/suggestions/fn-or-tuple-struct-with-underscore-args.rs
@@ -10,16 +10,10 @@ fn main() {
let _: usize = foo(_, _);
//~^ ERROR `_` can only be used on the left-hand side of an assignment
//~| ERROR `_` can only be used on the left-hand side of an assignment
- //~| ERROR destructuring assignments are unstable
- //~| ERROR destructuring assignments are unstable
let _: S = S(_, _);
//~^ ERROR `_` can only be used on the left-hand side of an assignment
//~| ERROR `_` can only be used on the left-hand side of an assignment
- //~| ERROR destructuring assignments are unstable
- //~| ERROR destructuring assignments are unstable
let _: usize = T::baz(_, _);
//~^ ERROR `_` can only be used on the left-hand side of an assignment
//~| ERROR `_` can only be used on the left-hand side of an assignment
- //~| ERROR destructuring assignments are unstable
- //~| ERROR destructuring assignments are unstable
}
diff --git a/src/test/ui/suggestions/fn-or-tuple-struct-with-underscore-args.stderr b/src/test/ui/suggestions/fn-or-tuple-struct-with-underscore-args.stderr
index 248fa6b9c9c..aa562030619 100644
--- a/src/test/ui/suggestions/fn-or-tuple-struct-with-underscore-args.stderr
+++ b/src/test/ui/suggestions/fn-or-tuple-struct-with-underscore-args.stderr
@@ -1,57 +1,3 @@
-error[E0658]: destructuring assignments are unstable
- --> $DIR/fn-or-tuple-struct-with-underscore-args.rs:10:24
- |
-LL | let _: usize = foo(_, _);
- | ^
- |
- = note: see issue #71126 <https://github.com/rust-lang/rust/issues/71126> for more information
- = help: add `#![feature(destructuring_assignment)]` to the crate attributes to enable
-
-error[E0658]: destructuring assignments are unstable
- --> $DIR/fn-or-tuple-struct-with-underscore-args.rs:10:27
- |
-LL | let _: usize = foo(_, _);
- | ^
- |
- = note: see issue #71126 <https://github.com/rust-lang/rust/issues/71126> for more information
- = help: add `#![feature(destructuring_assignment)]` to the crate attributes to enable
-
-error[E0658]: destructuring assignments are unstable
- --> $DIR/fn-or-tuple-struct-with-underscore-args.rs:15:18
- |
-LL | let _: S = S(_, _);
- | ^
- |
- = note: see issue #71126 <https://github.com/rust-lang/rust/issues/71126> for more information
- = help: add `#![feature(destructuring_assignment)]` to the crate attributes to enable
-
-error[E0658]: destructuring assignments are unstable
- --> $DIR/fn-or-tuple-struct-with-underscore-args.rs:15:21
- |
-LL | let _: S = S(_, _);
- | ^
- |
- = note: see issue #71126 <https://github.com/rust-lang/rust/issues/71126> for more information
- = help: add `#![feature(destructuring_assignment)]` to the crate attributes to enable
-
-error[E0658]: destructuring assignments are unstable
- --> $DIR/fn-or-tuple-struct-with-underscore-args.rs:20:27
- |
-LL | let _: usize = T::baz(_, _);
- | ^
- |
- = note: see issue #71126 <https://github.com/rust-lang/rust/issues/71126> for more information
- = help: add `#![feature(destructuring_assignment)]` to the crate attributes to enable
-
-error[E0658]: destructuring assignments are unstable
- --> $DIR/fn-or-tuple-struct-with-underscore-args.rs:20:30
- |
-LL | let _: usize = T::baz(_, _);
- | ^
- |
- = note: see issue #71126 <https://github.com/rust-lang/rust/issues/71126> for more information
- = help: add `#![feature(destructuring_assignment)]` to the crate attributes to enable
-
error: in expressions, `_` can only be used on the left-hand side of an assignment
--> $DIR/fn-or-tuple-struct-with-underscore-args.rs:10:24
|
@@ -65,29 +11,28 @@ LL | let _: usize = foo(_, _);
| ^ `_` not allowed here
error: in expressions, `_` can only be used on the left-hand side of an assignment
- --> $DIR/fn-or-tuple-struct-with-underscore-args.rs:15:18
+ --> $DIR/fn-or-tuple-struct-with-underscore-args.rs:13:18
|
LL | let _: S = S(_, _);
| ^ `_` not allowed here
error: in expressions, `_` can only be used on the left-hand side of an assignment
- --> $DIR/fn-or-tuple-struct-with-underscore-args.rs:15:21
+ --> $DIR/fn-or-tuple-struct-with-underscore-args.rs:13:21
|
LL | let _: S = S(_, _);
| ^ `_` not allowed here
error: in expressions, `_` can only be used on the left-hand side of an assignment
- --> $DIR/fn-or-tuple-struct-with-underscore-args.rs:20:27
+ --> $DIR/fn-or-tuple-struct-with-underscore-args.rs:16:27
|
LL | let _: usize = T::baz(_, _);
| ^ `_` not allowed here
error: in expressions, `_` can only be used on the left-hand side of an assignment
- --> $DIR/fn-or-tuple-struct-with-underscore-args.rs:20:30
+ --> $DIR/fn-or-tuple-struct-with-underscore-args.rs:16:30
|
LL | let _: usize = T::baz(_, _);
| ^ `_` not allowed here
-error: aborting due to 12 previous errors
+error: aborting due to 6 previous errors
-For more information about this error, try `rustc --explain E0658`.
diff --git a/src/test/ui/suggestions/if-let-typo.rs b/src/test/ui/suggestions/if-let-typo.rs
index b9714b67e58..375bd3f03c9 100644
--- a/src/test/ui/suggestions/if-let-typo.rs
+++ b/src/test/ui/suggestions/if-let-typo.rs
@@ -3,12 +3,9 @@ fn main() {
let bar = None;
if Some(x) = foo {} //~ ERROR cannot find value `x` in this scope
//~^ ERROR mismatched types
- //~^^ ERROR destructuring assignments are unstable
if Some(foo) = bar {} //~ ERROR mismatched types
- //~^ ERROR destructuring assignments are unstable
if 3 = foo {} //~ ERROR mismatched types
if Some(3) = foo {} //~ ERROR mismatched types
- //~^ ERROR destructuring assignments are unstable
- //~^^ ERROR invalid left-hand side of assignment
+ //~^ ERROR invalid left-hand side of assignment
if x = 5 {} //~ ERROR cannot find value `x` in this scope
}
diff --git a/src/test/ui/suggestions/if-let-typo.stderr b/src/test/ui/suggestions/if-let-typo.stderr
index 7f71cb48581..3d9ac40ec36 100644
--- a/src/test/ui/suggestions/if-let-typo.stderr
+++ b/src/test/ui/suggestions/if-let-typo.stderr
@@ -10,7 +10,7 @@ LL | if let Some(x) = foo {}
| +++
error[E0425]: cannot find value `x` in this scope
- --> $DIR/if-let-typo.rs:13:8
+ --> $DIR/if-let-typo.rs:10:8
|
LL | if x = 5 {}
| ^ not found in this scope
@@ -20,39 +20,6 @@ help: you might have meant to use pattern matching
LL | if let x = 5 {}
| +++
-error[E0658]: destructuring assignments are unstable
- --> $DIR/if-let-typo.rs:4:16
- |
-LL | if Some(x) = foo {}
- | ------- ^
- | |
- | cannot assign to this expression
- |
- = note: see issue #71126 <https://github.com/rust-lang/rust/issues/71126> for more information
- = help: add `#![feature(destructuring_assignment)]` to the crate attributes to enable
-
-error[E0658]: destructuring assignments are unstable
- --> $DIR/if-let-typo.rs:7:18
- |
-LL | if Some(foo) = bar {}
- | --------- ^
- | |
- | cannot assign to this expression
- |
- = note: see issue #71126 <https://github.com/rust-lang/rust/issues/71126> for more information
- = help: add `#![feature(destructuring_assignment)]` to the crate attributes to enable
-
-error[E0658]: destructuring assignments are unstable
- --> $DIR/if-let-typo.rs:10:16
- |
-LL | if Some(3) = foo {}
- | ------- ^
- | |
- | cannot assign to this expression
- |
- = note: see issue #71126 <https://github.com/rust-lang/rust/issues/71126> for more information
- = help: add `#![feature(destructuring_assignment)]` to the crate attributes to enable
-
error[E0308]: mismatched types
--> $DIR/if-let-typo.rs:4:8
|
@@ -60,24 +27,19 @@ LL | if Some(x) = foo {}
| ^^^^^^^^^^^^^ expected `bool`, found `()`
error[E0308]: mismatched types
- --> $DIR/if-let-typo.rs:7:8
+ --> $DIR/if-let-typo.rs:6:8
|
LL | if Some(foo) = bar {}
| ^^^^^^^^^^^^^^^ expected `bool`, found `()`
error[E0308]: mismatched types
- --> $DIR/if-let-typo.rs:9:8
+ --> $DIR/if-let-typo.rs:7:8
|
LL | if 3 = foo {}
| ^^^^^^^ expected `bool`, found `()`
- |
-help: you might have meant to use pattern matching
- |
-LL | if let 3 = foo {}
- | +++
error[E0070]: invalid left-hand side of assignment
- --> $DIR/if-let-typo.rs:10:16
+ --> $DIR/if-let-typo.rs:8:16
|
LL | if Some(3) = foo {}
| - ^
@@ -85,12 +47,12 @@ LL | if Some(3) = foo {}
| cannot assign to this expression
error[E0308]: mismatched types
- --> $DIR/if-let-typo.rs:10:8
+ --> $DIR/if-let-typo.rs:8:8
|
LL | if Some(3) = foo {}
| ^^^^^^^^^^^^^ expected `bool`, found `()`
-error: aborting due to 10 previous errors
+error: aborting due to 7 previous errors
-Some errors have detailed explanations: E0070, E0308, E0425, E0658.
+Some errors have detailed explanations: E0070, E0308, E0425.
For more information about an error, try `rustc --explain E0070`.
diff --git a/src/test/ui/suggestions/impl-on-dyn-trait-with-implicit-static-bound-needing-more-suggestions.stderr b/src/test/ui/suggestions/impl-on-dyn-trait-with-implicit-static-bound-needing-more-suggestions.stderr
index 2961d8d7eac..63d291ed7cd 100644
--- a/src/test/ui/suggestions/impl-on-dyn-trait-with-implicit-static-bound-needing-more-suggestions.stderr
+++ b/src/test/ui/suggestions/impl-on-dyn-trait-with-implicit-static-bound-needing-more-suggestions.stderr
@@ -22,7 +22,7 @@ error[E0772]: `val` has lifetime `'a` but calling `use_self` introduces an impli
LL | fn use_it<'a>(val: Box<dyn ObjectTrait<Assoc = i32> + 'a>) -> &'a () {
| -------------------------------------- this data with lifetime `'a`...
LL | val.use_self()
- | ^^^^^^^^ ...is captured and required to live as long as `'static` here
+ | ^^^^^^^^ ...is used and required to live as long as `'static` here
|
note: the used `impl` has a `'static` requirement
--> $DIR/impl-on-dyn-trait-with-implicit-static-bound-needing-more-suggestions.rs:60:30
diff --git a/src/test/ui/suggestions/impl-on-dyn-trait-with-implicit-static-bound.stderr b/src/test/ui/suggestions/impl-on-dyn-trait-with-implicit-static-bound.stderr
index 6d9f0811b27..55a1bbf18ab 100644
--- a/src/test/ui/suggestions/impl-on-dyn-trait-with-implicit-static-bound.stderr
+++ b/src/test/ui/suggestions/impl-on-dyn-trait-with-implicit-static-bound.stderr
@@ -4,7 +4,7 @@ error[E0759]: `val` has lifetime `'a` but it needs to satisfy a `'static` lifeti
LL | fn use_it<'a, T>(val: &'a dyn ObjectTrait<T>) -> impl OtherTrait<'a> + 'a {
| ---------------------- this data with lifetime `'a`...
LL | val.use_self::<T>()
- | ^^^^^^^^ ...is captured and required to live as long as `'static` here
+ | ^^^^^^^^ ...is used and required to live as long as `'static` here
|
note: the used `impl` has a `'static` requirement
--> $DIR/impl-on-dyn-trait-with-implicit-static-bound.rs:14:32
@@ -24,7 +24,7 @@ error[E0772]: `val` has lifetime `'a` but calling `use_self` introduces an impli
LL | fn use_it<'a>(val: &'a dyn ObjectTrait) -> impl OtherTrait<'a> + 'a {
| ------------------- this data with lifetime `'a`...
LL | val.use_self()
- | ^^^^^^^^ ...is captured and required to live as long as `'static` here because of an implicit lifetime bound on the inherent `impl`
+ | ^^^^^^^^ ...is used and required to live as long as `'static` here because of an implicit lifetime bound on the inherent `impl`
|
note: the used `impl` has a `'static` requirement
--> $DIR/impl-on-dyn-trait-with-implicit-static-bound.rs:64:14
@@ -44,7 +44,7 @@ error[E0759]: `val` has lifetime `'a` but it needs to satisfy a `'static` lifeti
LL | fn use_it<'a>(val: &'a dyn ObjectTrait) -> impl OtherTrait<'a> {
| ------------------- this data with lifetime `'a`...
LL | val.use_self()
- | ^^^^^^^^ ...is captured and required to live as long as `'static` here
+ | ^^^^^^^^ ...is used and required to live as long as `'static` here
|
note: the used `impl` has a `'static` requirement
--> $DIR/impl-on-dyn-trait-with-implicit-static-bound.rs:85:26
@@ -69,7 +69,7 @@ error[E0759]: `val` has lifetime `'a` but it needs to satisfy a `'static` lifeti
LL | fn use_it<'a>(val: &'a dyn ObjectTrait) -> impl OtherTrait<'a> + 'a {
| ------------------- this data with lifetime `'a`...
LL | MyTrait::use_self(val)
- | ^^^ ...is captured here...
+ | ^^^ ...is used here...
|
note: ...and is required to live as long as `'static` here
--> $DIR/impl-on-dyn-trait-with-implicit-static-bound.rs:108:9
@@ -95,7 +95,7 @@ error[E0772]: `val` has lifetime `'a` but calling `use_self` introduces an impli
LL | fn use_it<'a>(val: &'a dyn ObjectTrait) -> &'a () {
| ------------------- this data with lifetime `'a`...
LL | val.use_self()
- | ^^^^^^^^ ...is captured and required to live as long as `'static` here
+ | ^^^^^^^^ ...is used and required to live as long as `'static` here
|
note: the used `impl` has a `'static` requirement
--> $DIR/impl-on-dyn-trait-with-implicit-static-bound.rs:31:26
@@ -115,7 +115,7 @@ error[E0772]: `val` has lifetime `'a` but calling `use_self` introduces an impli
LL | fn use_it<'a>(val: &'a Box<dyn ObjectTrait + 'a>) -> &'a () {
| ----------------------------- this data with lifetime `'a`...
LL | val.use_self()
- | ^^^^^^^^ ...is captured and required to live as long as `'static` here
+ | ^^^^^^^^ ...is used and required to live as long as `'static` here
|
note: the used `impl` has a `'static` requirement
--> $DIR/impl-on-dyn-trait-with-implicit-static-bound.rs:48:30
diff --git a/src/test/ui/suggestions/issue-61963.rs b/src/test/ui/suggestions/issue-61963.rs
index d31ed01b191..a27c3845253 100644
--- a/src/test/ui/suggestions/issue-61963.rs
+++ b/src/test/ui/suggestions/issue-61963.rs
@@ -18,10 +18,20 @@ pub struct Qux<T>(T);
pub struct Foo {
//~^ ERROR trait objects without an explicit `dyn` are deprecated [bare_trait_objects]
//~| WARN this is accepted in the current edition
+ //~| ERROR trait objects without an explicit `dyn` are deprecated [bare_trait_objects]
+ //~| WARN this is accepted in the current edition
+ //~| ERROR trait objects without an explicit `dyn` are deprecated [bare_trait_objects]
+ //~| WARN this is accepted in the current edition
+ //~| ERROR trait objects without an explicit `dyn` are deprecated [bare_trait_objects]
+ //~| WARN this is accepted in the current edition
qux: Qux<Qux<Baz>>,
bar: Box<Bar>,
//~^ ERROR trait objects without an explicit `dyn` are deprecated [bare_trait_objects]
//~| WARN this is accepted in the current edition
+ //~| ERROR trait objects without an explicit `dyn` are deprecated [bare_trait_objects]
+ //~| WARN this is accepted in the current edition
+ //~| ERROR trait objects without an explicit `dyn` are deprecated [bare_trait_objects]
+ //~| WARN this is accepted in the current edition
}
fn main() {}
diff --git a/src/test/ui/suggestions/issue-61963.stderr b/src/test/ui/suggestions/issue-61963.stderr
index bb487920e3b..1eebd8d60ca 100644
--- a/src/test/ui/suggestions/issue-61963.stderr
+++ b/src/test/ui/suggestions/issue-61963.stderr
@@ -1,8 +1,8 @@
error: trait objects without an explicit `dyn` are deprecated
- --> $DIR/issue-61963.rs:22:14
+ --> $DIR/issue-61963.rs:28:14
|
LL | bar: Box<Bar>,
- | ^^^ help: use `dyn`: `dyn Bar`
+ | ^^^
|
note: the lint level is defined here
--> $DIR/issue-61963.rs:3:9
@@ -11,15 +11,95 @@ LL | #![deny(bare_trait_objects)]
| ^^^^^^^^^^^^^^^^^^
= warning: this is accepted in the current edition (Rust 2015) but is a hard error in Rust 2021!
= note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2021/warnings-promoted-to-error.html>
+help: use `dyn`
+ |
+LL - bar: Box<Bar>,
+LL + bar: Box<dyn Bar>,
+ |
error: trait objects without an explicit `dyn` are deprecated
--> $DIR/issue-61963.rs:18:1
|
LL | pub struct Foo {
- | ^^^ help: use `dyn`: `dyn pub`
+ | ^^^
+ |
+ = warning: this is accepted in the current edition (Rust 2015) but is a hard error in Rust 2021!
+ = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2021/warnings-promoted-to-error.html>
+help: use `dyn`
+ |
+LL - pub struct Foo {
+LL + dyn pub struct Foo {
+ |
+
+error: trait objects without an explicit `dyn` are deprecated
+ --> $DIR/issue-61963.rs:28:14
+ |
+LL | bar: Box<Bar>,
+ | ^^^
|
= warning: this is accepted in the current edition (Rust 2015) but is a hard error in Rust 2021!
= note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2021/warnings-promoted-to-error.html>
+help: use `dyn`
+ |
+LL - bar: Box<Bar>,
+LL + bar: Box<dyn Bar>,
+ |
+
+error: trait objects without an explicit `dyn` are deprecated
+ --> $DIR/issue-61963.rs:28:14
+ |
+LL | bar: Box<Bar>,
+ | ^^^
+ |
+ = warning: this is accepted in the current edition (Rust 2015) but is a hard error in Rust 2021!
+ = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2021/warnings-promoted-to-error.html>
+help: use `dyn`
+ |
+LL - bar: Box<Bar>,
+LL + bar: Box<dyn Bar>,
+ |
+
+error: trait objects without an explicit `dyn` are deprecated
+ --> $DIR/issue-61963.rs:18:1
+ |
+LL | pub struct Foo {
+ | ^^^
+ |
+ = warning: this is accepted in the current edition (Rust 2015) but is a hard error in Rust 2021!
+ = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2021/warnings-promoted-to-error.html>
+help: use `dyn`
+ |
+LL - pub struct Foo {
+LL + dyn pub struct Foo {
+ |
+
+error: trait objects without an explicit `dyn` are deprecated
+ --> $DIR/issue-61963.rs:18:1
+ |
+LL | pub struct Foo {
+ | ^^^
+ |
+ = warning: this is accepted in the current edition (Rust 2015) but is a hard error in Rust 2021!
+ = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2021/warnings-promoted-to-error.html>
+help: use `dyn`
+ |
+LL - pub struct Foo {
+LL + dyn pub struct Foo {
+ |
+
+error: trait objects without an explicit `dyn` are deprecated
+ --> $DIR/issue-61963.rs:18:1
+ |
+LL | pub struct Foo {
+ | ^^^
+ |
+ = warning: this is accepted in the current edition (Rust 2015) but is a hard error in Rust 2021!
+ = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2021/warnings-promoted-to-error.html>
+help: use `dyn`
+ |
+LL - pub struct Foo {
+LL + dyn pub struct Foo {
+ |
-error: aborting due to 2 previous errors
+error: aborting due to 7 previous errors
diff --git a/src/test/ui/suggestions/issue-71394-no-from-impl.stderr b/src/test/ui/suggestions/issue-71394-no-from-impl.stderr
index 79724377713..355f2038df8 100644
--- a/src/test/ui/suggestions/issue-71394-no-from-impl.stderr
+++ b/src/test/ui/suggestions/issue-71394-no-from-impl.stderr
@@ -4,9 +4,6 @@ error[E0277]: the trait bound `&[i8]: From<&[u8]>` is not satisfied
LL | let _: &[i8] = data.into();
| ^^^^ the trait `From<&[u8]>` is not implemented for `&[i8]`
|
- = help: the following implementations were found:
- <[T; LANES] as From<Simd<T, LANES>>>
- <[bool; LANES] as From<Mask<T, LANES>>>
= note: required because of the requirements on the impl of `Into<&[i8]>` for `&[u8]`
error: aborting due to previous error
diff --git a/src/test/ui/suggestions/issue-85945-check-where-clause-before-suggesting-unsized.rs b/src/test/ui/suggestions/issue-85945-check-where-clause-before-suggesting-unsized.rs
index 5cfaf4be96a..1a36f6e8e7f 100644
--- a/src/test/ui/suggestions/issue-85945-check-where-clause-before-suggesting-unsized.rs
+++ b/src/test/ui/suggestions/issue-85945-check-where-clause-before-suggesting-unsized.rs
@@ -2,7 +2,7 @@
// `Sized` bound is already in a `where` clause.
fn foo<T>(_: &T) where T: Sized {}
fn bar() { foo(""); }
-//~^ERROR the size for values of type
+//~^ ERROR the size for values of type
pub fn main() {
}
diff --git a/src/test/ui/suggestions/lifetimes/trait-object-nested-in-impl-trait.stderr b/src/test/ui/suggestions/lifetimes/trait-object-nested-in-impl-trait.stderr
index 1ca22ebeef4..a5b50634c71 100644
--- a/src/test/ui/suggestions/lifetimes/trait-object-nested-in-impl-trait.stderr
+++ b/src/test/ui/suggestions/lifetimes/trait-object-nested-in-impl-trait.stderr
@@ -7,7 +7,7 @@ LL | fn iter(&self) -> impl Iterator<Item = Box<dyn Foo>> {
LL | remaining: self.0.iter(),
| ------ ^^^^
| |
- | ...is captured here...
+ | ...is used here...
|
note: ...and is required to live as long as `'static` here
--> $DIR/trait-object-nested-in-impl-trait.rs:27:23
@@ -32,7 +32,7 @@ LL | fn iter(&self) -> impl Iterator<Item = Box<dyn Foo>> + '_ {
LL | remaining: self.0.iter(),
| ------ ^^^^
| |
- | ...is captured here...
+ | ...is used here...
|
note: ...and is required to live as long as `'static` here
--> $DIR/trait-object-nested-in-impl-trait.rs:38:23
@@ -53,7 +53,7 @@ LL | fn iter<'a>(&'a self) -> impl Iterator<Item = Box<dyn Foo>> + 'a {
LL | remaining: self.0.iter(),
| ------ ^^^^
| |
- | ...is captured here...
+ | ...is used here...
|
note: ...and is required to live as long as `'static` here
--> $DIR/trait-object-nested-in-impl-trait.rs:49:30
@@ -74,7 +74,7 @@ LL | fn iter<'a>(&'a self) -> impl Iterator<Item = Box<dyn Foo>> {
LL | remaining: self.0.iter(),
| ------ ^^^^
| |
- | ...is captured here...
+ | ...is used here...
|
note: ...and is required to live as long as `'static` here
--> $DIR/trait-object-nested-in-impl-trait.rs:60:30
diff --git a/src/test/ui/suggestions/mut-ref-reassignment.stderr b/src/test/ui/suggestions/mut-ref-reassignment.stderr
index fd5677898e6..3bd98c76307 100644
--- a/src/test/ui/suggestions/mut-ref-reassignment.stderr
+++ b/src/test/ui/suggestions/mut-ref-reassignment.stderr
@@ -1,6 +1,8 @@
error[E0308]: mismatched types
--> $DIR/mut-ref-reassignment.rs:2:11
|
+LL | fn suggestion(opt: &mut Option<String>) {
+ | ------------------- expected due to this parameter type
LL | opt = None;
| ^^^^ expected mutable reference, found enum `Option`
|
@@ -14,6 +16,8 @@ LL | *opt = None;
error[E0308]: mismatched types
--> $DIR/mut-ref-reassignment.rs:6:11
|
+LL | fn no_suggestion(opt: &mut Result<String, ()>) {
+ | ----------------------- expected due to this parameter type
LL | opt = None
| ^^^^ expected mutable reference, found enum `Option`
|
@@ -23,6 +27,8 @@ LL | opt = None
error[E0308]: mismatched types
--> $DIR/mut-ref-reassignment.rs:10:11
|
+LL | fn suggestion2(opt: &mut Option<String>) {
+ | ------------------- expected due to this parameter type
LL | opt = Some(String::new())
| ^^^^^^^^^^^^^^^^^^^ expected mutable reference, found enum `Option`
|
@@ -36,6 +42,8 @@ LL | *opt = Some(String::new())
error[E0308]: mismatched types
--> $DIR/mut-ref-reassignment.rs:14:11
|
+LL | fn no_suggestion2(opt: &mut Option<String>) {
+ | ------------------- expected due to this parameter type
LL | opt = Some(42)
| ^^^^^^^^ expected mutable reference, found enum `Option`
|
diff --git a/src/test/ui/suggestions/suggest-add-self.rs b/src/test/ui/suggestions/suggest-add-self.rs
new file mode 100644
index 00000000000..40692c8df20
--- /dev/null
+++ b/src/test/ui/suggestions/suggest-add-self.rs
@@ -0,0 +1,15 @@
+struct X(i32);
+
+impl X {
+ pub(crate) fn f() {
+ self.0
+ //~^ ERROR expected value, found module `self`
+ }
+
+ pub fn g() {
+ self.0
+ //~^ ERROR expected value, found module `self`
+ }
+}
+
+fn main() {}
diff --git a/src/test/ui/suggestions/suggest-add-self.stderr b/src/test/ui/suggestions/suggest-add-self.stderr
new file mode 100644
index 00000000000..a5e8f93deb6
--- /dev/null
+++ b/src/test/ui/suggestions/suggest-add-self.stderr
@@ -0,0 +1,29 @@
+error[E0424]: expected value, found module `self`
+ --> $DIR/suggest-add-self.rs:5:9
+ |
+LL | pub(crate) fn f() {
+ | - this function doesn't have a `self` parameter
+LL | self.0
+ | ^^^^ `self` value is a keyword only available in methods with a `self` parameter
+ |
+help: add a `self` receiver parameter to make the associated `fn` a method
+ |
+LL | pub(crate) fn f(&self) {
+ | +++++
+
+error[E0424]: expected value, found module `self`
+ --> $DIR/suggest-add-self.rs:10:9
+ |
+LL | pub fn g() {
+ | - this function doesn't have a `self` parameter
+LL | self.0
+ | ^^^^ `self` value is a keyword only available in methods with a `self` parameter
+ |
+help: add a `self` receiver parameter to make the associated `fn` a method
+ |
+LL | pub fn g(&self) {
+ | +++++
+
+error: aborting due to 2 previous errors
+
+For more information about this error, try `rustc --explain E0424`.
diff --git a/src/test/ui/suggestions/suggest-move-lifetimes.stderr b/src/test/ui/suggestions/suggest-move-lifetimes.stderr
index 657914d1c8c..f52631caed1 100644
--- a/src/test/ui/suggestions/suggest-move-lifetimes.stderr
+++ b/src/test/ui/suggestions/suggest-move-lifetimes.stderr
@@ -2,25 +2,25 @@ error: lifetime parameters must be declared prior to type parameters
--> $DIR/suggest-move-lifetimes.rs:1:13
|
LL | struct A<T, 'a> {
- | ----^^- help: reorder the parameters: lifetimes, then types, then consts: `<'a, T>`
+ | ----^^- help: reorder the parameters: lifetimes, then consts and types: `<'a, T>`
error: lifetime parameters must be declared prior to type parameters
--> $DIR/suggest-move-lifetimes.rs:5:13
|
LL | struct B<T, 'a, U> {
- | ----^^---- help: reorder the parameters: lifetimes, then types, then consts: `<'a, T, U>`
+ | ----^^---- help: reorder the parameters: lifetimes, then consts and types: `<'a, T, U>`
error: lifetime parameters must be declared prior to type parameters
--> $DIR/suggest-move-lifetimes.rs:10:16
|
LL | struct C<T, U, 'a> {
- | -------^^- help: reorder the parameters: lifetimes, then types, then consts: `<'a, T, U>`
+ | -------^^- help: reorder the parameters: lifetimes, then consts and types: `<'a, T, U>`
error: lifetime parameters must be declared prior to type parameters
--> $DIR/suggest-move-lifetimes.rs:15:16
|
LL | struct D<T, U, 'a, 'b, V, 'c> {
- | -------^^--^^-----^^- help: reorder the parameters: lifetimes, then types, then consts: `<'a, 'b, 'c, T, U, V>`
+ | -------^^--^^-----^^- help: reorder the parameters: lifetimes, then consts and types: `<'a, 'b, 'c, T, U, V>`
error: aborting due to 4 previous errors
diff --git a/src/test/ui/suggestions/suggest-semicolon-for-fn-in-extern-block.fixed b/src/test/ui/suggestions/suggest-semicolon-for-fn-in-extern-block.fixed
new file mode 100644
index 00000000000..5c55566ffe9
--- /dev/null
+++ b/src/test/ui/suggestions/suggest-semicolon-for-fn-in-extern-block.fixed
@@ -0,0 +1,9 @@
+// run-rustfix
+
+#[allow(dead_code)]
+
+extern "C" {
+ fn foo(); //~ERROR expected `;`
+}
+
+fn main() {}
diff --git a/src/test/ui/suggestions/suggest-semicolon-for-fn-in-extern-block.rs b/src/test/ui/suggestions/suggest-semicolon-for-fn-in-extern-block.rs
new file mode 100644
index 00000000000..91971cba3e8
--- /dev/null
+++ b/src/test/ui/suggestions/suggest-semicolon-for-fn-in-extern-block.rs
@@ -0,0 +1,9 @@
+// run-rustfix
+
+#[allow(dead_code)]
+
+extern "C" {
+ fn foo() //~ERROR expected `;`
+}
+
+fn main() {}
diff --git a/src/test/ui/suggestions/suggest-semicolon-for-fn-in-extern-block.stderr b/src/test/ui/suggestions/suggest-semicolon-for-fn-in-extern-block.stderr
new file mode 100644
index 00000000000..c5df72c4a47
--- /dev/null
+++ b/src/test/ui/suggestions/suggest-semicolon-for-fn-in-extern-block.stderr
@@ -0,0 +1,10 @@
+error: expected `;`, found `}`
+ --> $DIR/suggest-semicolon-for-fn-in-extern-block.rs:6:11
+ |
+LL | fn foo()
+ | ^ help: add `;` here
+LL | }
+ | - unexpected token
+
+error: aborting due to previous error
+
diff --git a/src/test/ui/svh/changing-crates.rs b/src/test/ui/svh/changing-crates.rs
index 60c043bc43f..66298e06ed6 100644
--- a/src/test/ui/svh/changing-crates.rs
+++ b/src/test/ui/svh/changing-crates.rs
@@ -1,5 +1,3 @@
-// ignore-msvc FIXME #31306
-
// note that these aux-build directives must be in this order
// aux-build:changing-crates-a1.rs
// aux-build:changing-crates-b.rs
diff --git a/src/test/ui/svh/changing-crates.stderr b/src/test/ui/svh/changing-crates.stderr
index cc62a4d4d9d..7244919e86d 100644
--- a/src/test/ui/svh/changing-crates.stderr
+++ b/src/test/ui/svh/changing-crates.stderr
@@ -1,5 +1,5 @@
error[E0460]: found possibly newer version of crate `a` which `b` depends on
- --> $DIR/changing-crates.rs:10:1
+ --> $DIR/changing-crates.rs:8:1
|
LL | extern crate b;
| ^^^^^^^^^^^^^^^
diff --git a/src/test/ui/svh/svh-change-lit.rs b/src/test/ui/svh/svh-change-lit.rs
index 7d991cc9971..ea500711bb7 100644
--- a/src/test/ui/svh/svh-change-lit.rs
+++ b/src/test/ui/svh/svh-change-lit.rs
@@ -1,5 +1,3 @@
-// ignore-msvc FIXME #31306
-
// note that these aux-build directives must be in this order
// aux-build:svh-a-base.rs
// aux-build:svh-b.rs
diff --git a/src/test/ui/svh/svh-change-lit.stderr b/src/test/ui/svh/svh-change-lit.stderr
index bf51e31bfd6..1e97e9d0557 100644
--- a/src/test/ui/svh/svh-change-lit.stderr
+++ b/src/test/ui/svh/svh-change-lit.stderr
@@ -1,5 +1,5 @@
error[E0460]: found possibly newer version of crate `a` which `b` depends on
- --> $DIR/svh-change-lit.rs:10:1
+ --> $DIR/svh-change-lit.rs:8:1
|
LL | extern crate b;
| ^^^^^^^^^^^^^^^
diff --git a/src/test/ui/svh/svh-change-significant-cfg.rs b/src/test/ui/svh/svh-change-significant-cfg.rs
index 8cf0d9ccaf1..ff919ea83d5 100644
--- a/src/test/ui/svh/svh-change-significant-cfg.rs
+++ b/src/test/ui/svh/svh-change-significant-cfg.rs
@@ -1,5 +1,3 @@
-// ignore-msvc FIXME #31306
-
// note that these aux-build directives must be in this order
// aux-build:svh-a-base.rs
// aux-build:svh-b.rs
diff --git a/src/test/ui/svh/svh-change-significant-cfg.stderr b/src/test/ui/svh/svh-change-significant-cfg.stderr
index c747464db75..f04046f4c87 100644
--- a/src/test/ui/svh/svh-change-significant-cfg.stderr
+++ b/src/test/ui/svh/svh-change-significant-cfg.stderr
@@ -1,5 +1,5 @@
error[E0460]: found possibly newer version of crate `a` which `b` depends on
- --> $DIR/svh-change-significant-cfg.rs:10:1
+ --> $DIR/svh-change-significant-cfg.rs:8:1
|
LL | extern crate b;
| ^^^^^^^^^^^^^^^
diff --git a/src/test/ui/svh/svh-change-trait-bound.rs b/src/test/ui/svh/svh-change-trait-bound.rs
index ddd10ac068d..a4ba06eaf2e 100644
--- a/src/test/ui/svh/svh-change-trait-bound.rs
+++ b/src/test/ui/svh/svh-change-trait-bound.rs
@@ -1,5 +1,3 @@
-// ignore-msvc FIXME #31306
-
// note that these aux-build directives must be in this order
// aux-build:svh-a-base.rs
// aux-build:svh-b.rs
diff --git a/src/test/ui/svh/svh-change-trait-bound.stderr b/src/test/ui/svh/svh-change-trait-bound.stderr
index b144b3b70da..a778c61806a 100644
--- a/src/test/ui/svh/svh-change-trait-bound.stderr
+++ b/src/test/ui/svh/svh-change-trait-bound.stderr
@@ -1,5 +1,5 @@
error[E0460]: found possibly newer version of crate `a` which `b` depends on
- --> $DIR/svh-change-trait-bound.rs:10:1
+ --> $DIR/svh-change-trait-bound.rs:8:1
|
LL | extern crate b;
| ^^^^^^^^^^^^^^^
diff --git a/src/test/ui/svh/svh-change-type-arg.rs b/src/test/ui/svh/svh-change-type-arg.rs
index f845ab5bc6a..d1651814bf6 100644
--- a/src/test/ui/svh/svh-change-type-arg.rs
+++ b/src/test/ui/svh/svh-change-type-arg.rs
@@ -1,5 +1,3 @@
-// ignore-msvc FIXME #31306
-
// note that these aux-build directives must be in this order
// aux-build:svh-a-base.rs
// aux-build:svh-b.rs
diff --git a/src/test/ui/svh/svh-change-type-arg.stderr b/src/test/ui/svh/svh-change-type-arg.stderr
index 473e4000d2d..f09babf93fd 100644
--- a/src/test/ui/svh/svh-change-type-arg.stderr
+++ b/src/test/ui/svh/svh-change-type-arg.stderr
@@ -1,5 +1,5 @@
error[E0460]: found possibly newer version of crate `a` which `b` depends on
- --> $DIR/svh-change-type-arg.rs:10:1
+ --> $DIR/svh-change-type-arg.rs:8:1
|
LL | extern crate b;
| ^^^^^^^^^^^^^^^
diff --git a/src/test/ui/svh/svh-change-type-ret.rs b/src/test/ui/svh/svh-change-type-ret.rs
index fb3e996c5fd..a4be50a6433 100644
--- a/src/test/ui/svh/svh-change-type-ret.rs
+++ b/src/test/ui/svh/svh-change-type-ret.rs
@@ -1,5 +1,3 @@
-// ignore-msvc FIXME #31306
-
// note that these aux-build directives must be in this order
// aux-build:svh-a-base.rs
// aux-build:svh-b.rs
diff --git a/src/test/ui/svh/svh-change-type-ret.stderr b/src/test/ui/svh/svh-change-type-ret.stderr
index ecb332fc5b5..0998cd4b549 100644
--- a/src/test/ui/svh/svh-change-type-ret.stderr
+++ b/src/test/ui/svh/svh-change-type-ret.stderr
@@ -1,5 +1,5 @@
error[E0460]: found possibly newer version of crate `a` which `b` depends on
- --> $DIR/svh-change-type-ret.rs:10:1
+ --> $DIR/svh-change-type-ret.rs:8:1
|
LL | extern crate b;
| ^^^^^^^^^^^^^^^
diff --git a/src/test/ui/svh/svh-change-type-static.rs b/src/test/ui/svh/svh-change-type-static.rs
index 0dfcaa0003b..c470761be19 100644
--- a/src/test/ui/svh/svh-change-type-static.rs
+++ b/src/test/ui/svh/svh-change-type-static.rs
@@ -1,5 +1,3 @@
-// ignore-msvc FIXME #31306
-
// note that these aux-build directives must be in this order
// aux-build:svh-a-base.rs
// aux-build:svh-b.rs
diff --git a/src/test/ui/svh/svh-change-type-static.stderr b/src/test/ui/svh/svh-change-type-static.stderr
index 33f7e3c485a..9c48cbd30a5 100644
--- a/src/test/ui/svh/svh-change-type-static.stderr
+++ b/src/test/ui/svh/svh-change-type-static.stderr
@@ -1,5 +1,5 @@
error[E0460]: found possibly newer version of crate `a` which `b` depends on
- --> $DIR/svh-change-type-static.rs:10:1
+ --> $DIR/svh-change-type-static.rs:8:1
|
LL | extern crate b;
| ^^^^^^^^^^^^^^^
diff --git a/src/test/ui/svh/svh-use-trait.rs b/src/test/ui/svh/svh-use-trait.rs
index e5c427e096a..e144fdffb52 100644
--- a/src/test/ui/svh/svh-use-trait.rs
+++ b/src/test/ui/svh/svh-use-trait.rs
@@ -1,5 +1,3 @@
-// ignore-msvc FIXME #31306
-
// note that these aux-build directives must be in this order
// aux-build:svh-uta-base.rs
// aux-build:svh-utb.rs
diff --git a/src/test/ui/svh/svh-use-trait.stderr b/src/test/ui/svh/svh-use-trait.stderr
index 3230bb5c384..5780cfef357 100644
--- a/src/test/ui/svh/svh-use-trait.stderr
+++ b/src/test/ui/svh/svh-use-trait.stderr
@@ -1,5 +1,5 @@
error[E0460]: found possibly newer version of crate `uta` which `utb` depends on
- --> $DIR/svh-use-trait.rs:15:1
+ --> $DIR/svh-use-trait.rs:13:1
|
LL | extern crate utb;
| ^^^^^^^^^^^^^^^^^
diff --git a/src/test/ui/symbol-names/basic.legacy.stderr b/src/test/ui/symbol-names/basic.legacy.stderr
index de4d35e261c..e0e798dac40 100644
--- a/src/test/ui/symbol-names/basic.legacy.stderr
+++ b/src/test/ui/symbol-names/basic.legacy.stderr
@@ -1,10 +1,10 @@
-error: symbol-name(_ZN5basic4main17hd75b915511563828E)
+error: symbol-name(_ZN5basic4main17h<SYMBOL_HASH>)
--> $DIR/basic.rs:8:1
|
LL | #[rustc_symbol_name]
| ^^^^^^^^^^^^^^^^^^^^
-error: demangling(basic::main::hd75b915511563828)
+error: demangling(basic::main::h<SYMBOL_HASH>)
--> $DIR/basic.rs:8:1
|
LL | #[rustc_symbol_name]
diff --git a/src/test/ui/symbol-names/basic.rs b/src/test/ui/symbol-names/basic.rs
index d871a4ee829..a6fbe98e6ed 100644
--- a/src/test/ui/symbol-names/basic.rs
+++ b/src/test/ui/symbol-names/basic.rs
@@ -9,8 +9,8 @@
//[legacy]~^ ERROR symbol-name(_ZN5basic4main
//[legacy]~| ERROR demangling(basic::main
//[legacy]~| ERROR demangling-alt(basic::main)
- //[v0]~^^^^ ERROR symbol-name(_RNvCsj6j3mjPNGKx_5basic4main)
- //[v0]~| ERROR demangling(basic[de7d5b6b69c71f37]::main)
+ //[v0]~^^^^ ERROR symbol-name(_RNv
+ //[v0]~| ERROR demangling(basic[
//[v0]~| ERROR demangling-alt(basic::main)
#[rustc_def_path]
//[legacy]~^ ERROR def-path(main)
diff --git a/src/test/ui/symbol-names/basic.v0.stderr b/src/test/ui/symbol-names/basic.v0.stderr
index e30fa6f66d5..27308fc5ec3 100644
--- a/src/test/ui/symbol-names/basic.v0.stderr
+++ b/src/test/ui/symbol-names/basic.v0.stderr
@@ -1,10 +1,10 @@
-error: symbol-name(_RNvCsj6j3mjPNGKx_5basic4main)
+error: symbol-name(_RNvCsCRATE_HASH_5basic4main)
--> $DIR/basic.rs:8:1
|
LL | #[rustc_symbol_name]
| ^^^^^^^^^^^^^^^^^^^^
-error: demangling(basic[de7d5b6b69c71f37]::main)
+error: demangling(basic[HASH]::main)
--> $DIR/basic.rs:8:1
|
LL | #[rustc_symbol_name]
diff --git a/src/test/ui/symbol-names/const-generics-demangling.rs b/src/test/ui/symbol-names/const-generics-demangling.rs
index 38b07acbdb2..d44c8f0abae 100644
--- a/src/test/ui/symbol-names/const-generics-demangling.rs
+++ b/src/test/ui/symbol-names/const-generics-demangling.rs
@@ -1,36 +1,37 @@
// build-fail
// compile-flags: -Z symbol-mangling-version=v0 --crate-name=c
+// normalize-stderr-test: "c\[.*?\]" -> "c[HASH]"
#![feature(rustc_attrs)]
pub struct Unsigned<const F: u8>;
#[rustc_symbol_name]
-//~^ ERROR symbol-name(_RMCsno73SFvQKx_1cINtB0_8UnsignedKhb_E)
-//~| ERROR demangling(<c[464da6a86cb672f]::Unsigned<11u8>>)
+//~^ ERROR symbol-name(_RMCs
+//~| ERROR demangling(<c[
//~| ERROR demangling-alt(<c::Unsigned<11>>)
impl Unsigned<11> {}
pub struct Signed<const F: i16>;
#[rustc_symbol_name]
-//~^ ERROR symbol-name(_RMs_Csno73SFvQKx_1cINtB2_6SignedKsn98_E)
-//~| ERROR demangling(<c[464da6a86cb672f]::Signed<-152i16>>)
+//~^ ERROR symbol-name(_RMs_Cs
+//~| ERROR demangling(<c[
//~| ERROR demangling-alt(<c::Signed<-152>>)
impl Signed<-152> {}
pub struct Bool<const F: bool>;
#[rustc_symbol_name]
-//~^ ERROR symbol-name(_RMs0_Csno73SFvQKx_1cINtB3_4BoolKb1_E)
-//~| ERROR demangling(<c[464da6a86cb672f]::Bool<true>>)
+//~^ ERROR symbol-name(_RMs0_Cs
+//~| ERROR demangling(<c[
//~| ERROR demangling-alt(<c::Bool<true>>)
impl Bool<true> {}
pub struct Char<const F: char>;
#[rustc_symbol_name]
-//~^ ERROR symbol-name(_RMs1_Csno73SFvQKx_1cINtB3_4CharKc2202_E)
-//~| ERROR demangling(<c[464da6a86cb672f]::Char<'∂'>>)
+//~^ ERROR symbol-name(_RMs1_Cs
+//~| ERROR demangling(<c[
//~| ERROR demangling-alt(<c::Char<'∂'>>)
impl Char<'∂'> {}
diff --git a/src/test/ui/symbol-names/const-generics-demangling.stderr b/src/test/ui/symbol-names/const-generics-demangling.stderr
index 2abf293071f..8aa08b8a22c 100644
--- a/src/test/ui/symbol-names/const-generics-demangling.stderr
+++ b/src/test/ui/symbol-names/const-generics-demangling.stderr
@@ -1,71 +1,71 @@
-error: symbol-name(_RMCsno73SFvQKx_1cINtB0_8UnsignedKhb_E)
- --> $DIR/const-generics-demangling.rs:7:1
+error: symbol-name(_RMCsCRATE_HASH_1cINtB<REF>_8UnsignedKhb_E)
+ --> $DIR/const-generics-demangling.rs:8:1
|
LL | #[rustc_symbol_name]
| ^^^^^^^^^^^^^^^^^^^^
-error: demangling(<c[464da6a86cb672f]::Unsigned<11u8>>)
- --> $DIR/const-generics-demangling.rs:7:1
+error: demangling(<c[HASH]::Unsigned<11u8>>)
+ --> $DIR/const-generics-demangling.rs:8:1
|
LL | #[rustc_symbol_name]
| ^^^^^^^^^^^^^^^^^^^^
error: demangling-alt(<c::Unsigned<11>>)
- --> $DIR/const-generics-demangling.rs:7:1
+ --> $DIR/const-generics-demangling.rs:8:1
|
LL | #[rustc_symbol_name]
| ^^^^^^^^^^^^^^^^^^^^
-error: symbol-name(_RMs_Csno73SFvQKx_1cINtB2_6SignedKsn98_E)
- --> $DIR/const-generics-demangling.rs:15:1
+error: symbol-name(_RMs_CsCRATE_HASH_1cINtB<REF>_6SignedKsn98_E)
+ --> $DIR/const-generics-demangling.rs:16:1
|
LL | #[rustc_symbol_name]
| ^^^^^^^^^^^^^^^^^^^^
-error: demangling(<c[464da6a86cb672f]::Signed<-152i16>>)
- --> $DIR/const-generics-demangling.rs:15:1
+error: demangling(<c[HASH]::Signed<-152i16>>)
+ --> $DIR/const-generics-demangling.rs:16:1
|
LL | #[rustc_symbol_name]
| ^^^^^^^^^^^^^^^^^^^^
error: demangling-alt(<c::Signed<-152>>)
- --> $DIR/const-generics-demangling.rs:15:1
+ --> $DIR/const-generics-demangling.rs:16:1
|
LL | #[rustc_symbol_name]
| ^^^^^^^^^^^^^^^^^^^^
-error: symbol-name(_RMs0_Csno73SFvQKx_1cINtB3_4BoolKb1_E)
- --> $DIR/const-generics-demangling.rs:23:1
+error: symbol-name(_RMs0_CsCRATE_HASH_1cINtB<REF>_4BoolKb1_E)
+ --> $DIR/const-generics-demangling.rs:24:1
|
LL | #[rustc_symbol_name]
| ^^^^^^^^^^^^^^^^^^^^
-error: demangling(<c[464da6a86cb672f]::Bool<true>>)
- --> $DIR/const-generics-demangling.rs:23:1
+error: demangling(<c[HASH]::Bool<true>>)
+ --> $DIR/const-generics-demangling.rs:24:1
|
LL | #[rustc_symbol_name]
| ^^^^^^^^^^^^^^^^^^^^
error: demangling-alt(<c::Bool<true>>)
- --> $DIR/const-generics-demangling.rs:23:1
+ --> $DIR/const-generics-demangling.rs:24:1
|
LL | #[rustc_symbol_name]
| ^^^^^^^^^^^^^^^^^^^^
-error: symbol-name(_RMs1_Csno73SFvQKx_1cINtB3_4CharKc2202_E)
- --> $DIR/const-generics-demangling.rs:31:1
+error: symbol-name(_RMs1_CsCRATE_HASH_1cINtB<REF>_4CharKc2202_E)
+ --> $DIR/const-generics-demangling.rs:32:1
|
LL | #[rustc_symbol_name]
| ^^^^^^^^^^^^^^^^^^^^
-error: demangling(<c[464da6a86cb672f]::Char<'∂'>>)
- --> $DIR/const-generics-demangling.rs:31:1
+error: demangling(<c[HASH]::Char<'∂'>>)
+ --> $DIR/const-generics-demangling.rs:32:1
|
LL | #[rustc_symbol_name]
| ^^^^^^^^^^^^^^^^^^^^
error: demangling-alt(<c::Char<'∂'>>)
- --> $DIR/const-generics-demangling.rs:31:1
+ --> $DIR/const-generics-demangling.rs:32:1
|
LL | #[rustc_symbol_name]
| ^^^^^^^^^^^^^^^^^^^^
diff --git a/src/test/ui/symbol-names/const-generics-str-demangling.rs b/src/test/ui/symbol-names/const-generics-str-demangling.rs
index f450dfef575..300f6510380 100644
--- a/src/test/ui/symbol-names/const-generics-str-demangling.rs
+++ b/src/test/ui/symbol-names/const-generics-str-demangling.rs
@@ -1,43 +1,44 @@
// build-fail
// compile-flags: -Z symbol-mangling-version=v0 --crate-name=c
+// normalize-stderr-test: "c\[.*?\]" -> "c[HASH]"
#![feature(adt_const_params, rustc_attrs)]
#![allow(incomplete_features)]
pub struct Str<const S: &'static str>;
#[rustc_symbol_name]
-//~^ ERROR symbol-name(_RMCsno73SFvQKx_1cINtB0_3StrKRe616263_E)
-//~| ERROR demangling(<c[464da6a86cb672f]::Str<"abc">>)
+//~^ ERROR symbol-name
+//~| ERROR demangling
//~| ERROR demangling-alt(<c::Str<"abc">>)
impl Str<"abc"> {}
#[rustc_symbol_name]
-//~^ ERROR symbol-name(_RMs_Csno73SFvQKx_1cINtB2_3StrKRe27_E)
-//~| ERROR demangling(<c[464da6a86cb672f]::Str<"'">>)
+//~^ ERROR symbol-name
+//~| ERROR demangling
//~| ERROR demangling-alt(<c::Str<"'">>)
impl Str<"'"> {}
#[rustc_symbol_name]
-//~^ ERROR symbol-name(_RMs0_Csno73SFvQKx_1cINtB3_3StrKRe090a_E)
-//~| ERROR demangling(<c[464da6a86cb672f]::Str<"\t\n">>)
+//~^ ERROR symbol-name
+//~| ERROR demangling
//~| ERROR demangling-alt(<c::Str<"\t\n">>)
impl Str<"\t\n"> {}
#[rustc_symbol_name]
-//~^ ERROR symbol-name(_RMs1_Csno73SFvQKx_1cINtB3_3StrKRee28882c3bc_E)
-//~| ERROR demangling(<c[464da6a86cb672f]::Str<"∂ü">>)
+//~^ ERROR symbol-name
+//~| ERROR demangling
//~| ERROR demangling-alt(<c::Str<"∂ü">>)
impl Str<"∂ü"> {}
#[rustc_symbol_name]
-//~^ ERROR symbol-name(_RMs2_Csno73SFvQKx_1cINtB3_3StrKRee183a1e18390e183ade1839be18394e1839ae18390e183935fe18392e18394e1839be183a0e18398e18394e1839ae183985fe183a1e18390e18393e18398e1839ae18398_E)
-//~| ERROR demangling(<c[464da6a86cb672f]::Str<"საჭმელად_გემრიელი_სადილი">>)
+//~^ ERROR symbol-name
+//~| ERROR demangling
//~| ERROR demangling-alt(<c::Str<"საჭმელად_გემრიელი_სადილი">>)
impl Str<"საჭმელად_გემრიელი_სადილი"> {}
#[rustc_symbol_name]
-//~^ ERROR symbol-name(_RMs3_Csno73SFvQKx_1cINtB3_3StrKRef09f908af09fa688f09fa686f09f90ae20c2a720f09f90b6f09f9192e29895f09f94a520c2a720f09fa7a1f09f929bf09f929af09f9299f09f929c_E)
-//~| ERROR demangling(<c[464da6a86cb672f]::Str<"🐊🦈🦆🐮 § 🐶👒☕🔥 § 🧡💛💚💙💜">>)
+//~^ ERROR symbol-name
+//~| ERROR demangling
//~| ERROR demangling-alt(<c::Str<"🐊🦈🦆🐮 § 🐶👒☕🔥 § 🧡💛💚💙💜">>)
impl Str<"🐊🦈🦆🐮 § 🐶👒☕🔥 § 🧡💛💚💙💜"> {}
diff --git a/src/test/ui/symbol-names/const-generics-str-demangling.stderr b/src/test/ui/symbol-names/const-generics-str-demangling.stderr
index f401997017f..06d3cdda2f8 100644
--- a/src/test/ui/symbol-names/const-generics-str-demangling.stderr
+++ b/src/test/ui/symbol-names/const-generics-str-demangling.stderr
@@ -1,107 +1,107 @@
-error: symbol-name(_RMCsno73SFvQKx_1cINtB0_3StrKRe616263_E)
- --> $DIR/const-generics-str-demangling.rs:8:1
+error: symbol-name(_RMCsCRATE_HASH_1cINtB<REF>_3StrKRe616263_E)
+ --> $DIR/const-generics-str-demangling.rs:9:1
|
LL | #[rustc_symbol_name]
| ^^^^^^^^^^^^^^^^^^^^
-error: demangling(<c[464da6a86cb672f]::Str<"abc">>)
- --> $DIR/const-generics-str-demangling.rs:8:1
+error: demangling(<c[HASH]::Str<"abc">>)
+ --> $DIR/const-generics-str-demangling.rs:9:1
|
LL | #[rustc_symbol_name]
| ^^^^^^^^^^^^^^^^^^^^
error: demangling-alt(<c::Str<"abc">>)
- --> $DIR/const-generics-str-demangling.rs:8:1
+ --> $DIR/const-generics-str-demangling.rs:9:1
|
LL | #[rustc_symbol_name]
| ^^^^^^^^^^^^^^^^^^^^
-error: symbol-name(_RMs_Csno73SFvQKx_1cINtB2_3StrKRe27_E)
- --> $DIR/const-generics-str-demangling.rs:14:1
+error: symbol-name(_RMs_CsCRATE_HASH_1cINtB<REF>_3StrKRe27_E)
+ --> $DIR/const-generics-str-demangling.rs:15:1
|
LL | #[rustc_symbol_name]
| ^^^^^^^^^^^^^^^^^^^^
-error: demangling(<c[464da6a86cb672f]::Str<"'">>)
- --> $DIR/const-generics-str-demangling.rs:14:1
+error: demangling(<c[HASH]::Str<"'">>)
+ --> $DIR/const-generics-str-demangling.rs:15:1
|
LL | #[rustc_symbol_name]
| ^^^^^^^^^^^^^^^^^^^^
error: demangling-alt(<c::Str<"'">>)
- --> $DIR/const-generics-str-demangling.rs:14:1
+ --> $DIR/const-generics-str-demangling.rs:15:1
|
LL | #[rustc_symbol_name]
| ^^^^^^^^^^^^^^^^^^^^
-error: symbol-name(_RMs0_Csno73SFvQKx_1cINtB3_3StrKRe090a_E)
- --> $DIR/const-generics-str-demangling.rs:20:1
+error: symbol-name(_RMs0_CsCRATE_HASH_1cINtB<REF>_3StrKRe090a_E)
+ --> $DIR/const-generics-str-demangling.rs:21:1
|
LL | #[rustc_symbol_name]
| ^^^^^^^^^^^^^^^^^^^^
-error: demangling(<c[464da6a86cb672f]::Str<"\t\n">>)
- --> $DIR/const-generics-str-demangling.rs:20:1
+error: demangling(<c[HASH]::Str<"\t\n">>)
+ --> $DIR/const-generics-str-demangling.rs:21:1
|
LL | #[rustc_symbol_name]
| ^^^^^^^^^^^^^^^^^^^^
error: demangling-alt(<c::Str<"\t\n">>)
- --> $DIR/const-generics-str-demangling.rs:20:1
+ --> $DIR/const-generics-str-demangling.rs:21:1
|
LL | #[rustc_symbol_name]
| ^^^^^^^^^^^^^^^^^^^^
-error: symbol-name(_RMs1_Csno73SFvQKx_1cINtB3_3StrKRee28882c3bc_E)
- --> $DIR/const-generics-str-demangling.rs:26:1
+error: symbol-name(_RMs1_CsCRATE_HASH_1cINtB<REF>_3StrKRee28882c3bc_E)
+ --> $DIR/const-generics-str-demangling.rs:27:1
|
LL | #[rustc_symbol_name]
| ^^^^^^^^^^^^^^^^^^^^
-error: demangling(<c[464da6a86cb672f]::Str<"∂ü">>)
- --> $DIR/const-generics-str-demangling.rs:26:1
+error: demangling(<c[HASH]::Str<"∂ü">>)
+ --> $DIR/const-generics-str-demangling.rs:27:1
|
LL | #[rustc_symbol_name]
| ^^^^^^^^^^^^^^^^^^^^
error: demangling-alt(<c::Str<"∂ü">>)
- --> $DIR/const-generics-str-demangling.rs:26:1
+ --> $DIR/const-generics-str-demangling.rs:27:1
|
LL | #[rustc_symbol_name]
| ^^^^^^^^^^^^^^^^^^^^
-error: symbol-name(_RMs2_Csno73SFvQKx_1cINtB3_3StrKRee183a1e18390e183ade1839be18394e1839ae18390e183935fe18392e18394e1839be183a0e18398e18394e1839ae183985fe183a1e18390e18393e18398e1839ae18398_E)
- --> $DIR/const-generics-str-demangling.rs:32:1
+error: symbol-name(_RMs2_CsCRATE_HASH_1cINtB<REF>_3StrKRee183a1e18390e183ade1839be18394e1839ae18390e183935fe18392e18394e1839be183a0e18398e18394e1839ae183985fe183a1e18390e18393e18398e1839ae18398_E)
+ --> $DIR/const-generics-str-demangling.rs:33:1
|
LL | #[rustc_symbol_name]
| ^^^^^^^^^^^^^^^^^^^^
-error: demangling(<c[464da6a86cb672f]::Str<"საჭმელად_გემრიელი_სადილი">>)
- --> $DIR/const-generics-str-demangling.rs:32:1
+error: demangling(<c[HASH]::Str<"საჭმელად_გემრიელი_სადილი">>)
+ --> $DIR/const-generics-str-demangling.rs:33:1
|
LL | #[rustc_symbol_name]
| ^^^^^^^^^^^^^^^^^^^^
error: demangling-alt(<c::Str<"საჭმელად_გემრიელი_სადილი">>)
- --> $DIR/const-generics-str-demangling.rs:32:1
+ --> $DIR/const-generics-str-demangling.rs:33:1
|
LL | #[rustc_symbol_name]
| ^^^^^^^^^^^^^^^^^^^^
-error: symbol-name(_RMs3_Csno73SFvQKx_1cINtB3_3StrKRef09f908af09fa688f09fa686f09f90ae20c2a720f09f90b6f09f9192e29895f09f94a520c2a720f09fa7a1f09f929bf09f929af09f9299f09f929c_E)
- --> $DIR/const-generics-str-demangling.rs:38:1
+error: symbol-name(_RMs3_CsCRATE_HASH_1cINtB<REF>_3StrKRef09f908af09fa688f09fa686f09f90ae20c2a720f09f90b6f09f9192e29895f09f94a520c2a720f09fa7a1f09f929bf09f929af09f9299f09f929c_E)
+ --> $DIR/const-generics-str-demangling.rs:39:1
|
LL | #[rustc_symbol_name]
| ^^^^^^^^^^^^^^^^^^^^
-error: demangling(<c[464da6a86cb672f]::Str<"🐊🦈🦆🐮 § 🐶👒☕🔥 § 🧡💛💚💙💜">>)
- --> $DIR/const-generics-str-demangling.rs:38:1
+error: demangling(<c[HASH]::Str<"🐊🦈🦆🐮 § 🐶👒☕🔥 § 🧡💛💚💙💜">>)
+ --> $DIR/const-generics-str-demangling.rs:39:1
|
LL | #[rustc_symbol_name]
| ^^^^^^^^^^^^^^^^^^^^
error: demangling-alt(<c::Str<"🐊🦈🦆🐮 § 🐶👒☕🔥 § 🧡💛💚💙💜">>)
- --> $DIR/const-generics-str-demangling.rs:38:1
+ --> $DIR/const-generics-str-demangling.rs:39:1
|
LL | #[rustc_symbol_name]
| ^^^^^^^^^^^^^^^^^^^^
diff --git a/src/test/ui/symbol-names/const-generics-structural-demangling.rs b/src/test/ui/symbol-names/const-generics-structural-demangling.rs
index fa3884860c3..73de48fed6c 100644
--- a/src/test/ui/symbol-names/const-generics-structural-demangling.rs
+++ b/src/test/ui/symbol-names/const-generics-structural-demangling.rs
@@ -3,8 +3,8 @@
// NOTE(eddyb) we need `core` for `core::option::Option`, normalize away its
// disambiguator hash, which can/should change (including between stage{1,2}).
-// normalize-stderr-test: "Cs[0-9a-zA-Z]+_4core" -> "Cs$$HASH_4core"
-// normalize-stderr-test: "core\[[0-9a-f]+\]" -> "core[$$HASH_HEX]"
+// normalize-stderr-test: "core\[[0-9a-f]+\]" -> "core[HASH]"
+// normalize-stderr-test: "c\[[0-9a-f]+\]" -> "c[HASH]"
#![feature(adt_const_params, decl_macro, rustc_attrs)]
#![allow(incomplete_features)]
@@ -12,8 +12,8 @@
pub struct RefByte<const RB: &'static u8>;
#[rustc_symbol_name]
-//~^ ERROR symbol-name(_RMCsno73SFvQKx_1cINtB0_7RefByteKRh7b_E)
-//~| ERROR demangling(<c[464da6a86cb672f]::RefByte<{&123u8}>>)
+//~^ ERROR symbol-name
+//~| ERROR demangling
//~| ERROR demangling-alt(<c::RefByte<{&123}>>)
impl RefByte<{&123}> {}
@@ -22,24 +22,24 @@ impl RefByte<{&123}> {}
pub struct RefZst<const RMZ: &'static [u8; 0]>;
#[rustc_symbol_name]
-//~^ ERROR symbol-name(_RMs_Csno73SFvQKx_1cINtB2_6RefZstKRAEE)
-//~| ERROR demangling(<c[464da6a86cb672f]::RefZst<{&[]}>>)
+//~^ ERROR symbol-name
+//~| ERROR demangling
//~| ERROR demangling-alt(<c::RefZst<{&[]}>>)
impl RefZst<{&[]}> {}
pub struct Array3Bytes<const A3B: [u8; 3]>;
#[rustc_symbol_name]
-//~^ ERROR symbol-name(_RMs0_Csno73SFvQKx_1cINtB3_11Array3BytesKAh1_h2_h3_EE)
-//~| ERROR demangling(<c[464da6a86cb672f]::Array3Bytes<{[1u8, 2u8, 3u8]}>>)
+//~^ ERROR symbol-name
+//~| ERROR demangling
//~| ERROR demangling-alt(<c::Array3Bytes<{[1, 2, 3]}>>)
impl Array3Bytes<{[1, 2, 3]}> {}
pub struct TupleByteBool<const TBB: (u8, bool)>;
#[rustc_symbol_name]
-//~^ ERROR symbol-name(_RMs1_Csno73SFvQKx_1cINtB3_13TupleByteBoolKTh1_b0_EE)
-//~| ERROR demangling(<c[464da6a86cb672f]::TupleByteBool<{(1u8, false)}>>)
+//~^ ERROR symbol-name
+//~| ERROR demangling
//~| ERROR demangling-alt(<c::TupleByteBool<{(1, false)}>>)
impl TupleByteBool<{(1, false)}> {}
@@ -48,16 +48,16 @@ pub struct OptionUsize<const OU: Option<usize>>;
// HACK(eddyb) the full mangling is only in `.stderr` because we can normalize
// the `core` disambiguator hash away there, but not here.
#[rustc_symbol_name]
-//~^ ERROR symbol-name(_RMs2_Csno73SFvQKx_1cINtB3_11OptionUsizeKVNtINtNtCs
-//~| ERROR demangling(<c[464da6a86cb672f]::OptionUsize<{core[
+//~^ ERROR symbol-name
+//~| ERROR demangling
//~| ERROR demangling-alt(<c::OptionUsize<{core::option::Option::<usize>::None}>>)
impl OptionUsize<{None}> {}
// HACK(eddyb) the full mangling is only in `.stderr` because we can normalize
// the `core` disambiguator hash away there, but not here.
#[rustc_symbol_name]
-//~^ ERROR symbol-name(_RMs3_Csno73SFvQKx_1cINtB3_11OptionUsizeKVNtINtNtCs
-//~| ERROR demangling(<c[464da6a86cb672f]::OptionUsize<{core[
+//~^ ERROR symbol-name
+//~| ERROR demangling
//~| ERROR demangling-alt(<c::OptionUsize<{core::option::Option::<usize>::Some(0)}>>)
impl OptionUsize<{Some(0)}> {}
@@ -70,8 +70,8 @@ pub struct Foo {
pub struct Foo_<const F: Foo>;
#[rustc_symbol_name]
-//~^ ERROR symbol-name(_RMs4_Csno73SFvQKx_1cINtB3_4Foo_KVNtB3_3FooS1sRe616263_2chc78_5sliceRAh1_h2_h3_EEE)
-//~| ERROR demangling(<c[464da6a86cb672f]::Foo_<{c[464da6a86cb672f]::Foo { s: "abc", ch: 'x', slice: &[1u8, 2u8, 3u8] }}>>)
+//~^ ERROR symbol-name
+//~| ERROR demangling
//~| ERROR demangling-alt(<c::Foo_<{c::Foo { s: "abc", ch: 'x', slice: &[1, 2, 3] }}>>)
impl Foo_<{Foo { s: "abc", ch: 'x', slice: &[1, 2, 3] }}> {}
@@ -86,8 +86,8 @@ macro duplicate_field_name_test($x:ident) {
pub struct Bar_<const B: Bar>;
#[rustc_symbol_name]
- //~^ ERROR symbol-name(_RMs9_Csno73SFvQKx_1cINtB3_4Bar_KVNtB3_3BarS1xh7b_s_1xt1000_EE)
- //~| ERROR demangling(<c[464da6a86cb672f]::Bar_<{c[464da6a86cb672f]::Bar { x: 123u8, x: 4096u16 }}>>)
+ //~^ ERROR symbol-name
+ //~| ERROR demangling
//~| ERROR demangling-alt(<c::Bar_<{c::Bar { x: 123, x: 4096 }}>>)
impl Bar_<{Bar { $x: 123, x: 4096 }}> {}
}
diff --git a/src/test/ui/symbol-names/const-generics-structural-demangling.stderr b/src/test/ui/symbol-names/const-generics-structural-demangling.stderr
index 45cbcecacab..a4c997477ee 100644
--- a/src/test/ui/symbol-names/const-generics-structural-demangling.stderr
+++ b/src/test/ui/symbol-names/const-generics-structural-demangling.stderr
@@ -1,10 +1,10 @@
-error: symbol-name(_RMCsno73SFvQKx_1cINtB0_7RefByteKRh7b_E)
+error: symbol-name(_RMCsCRATE_HASH_1cINtB<REF>_7RefByteKRh7b_E)
--> $DIR/const-generics-structural-demangling.rs:14:1
|
LL | #[rustc_symbol_name]
| ^^^^^^^^^^^^^^^^^^^^
-error: demangling(<c[464da6a86cb672f]::RefByte<{&123u8}>>)
+error: demangling(<c[HASH]::RefByte<{&123u8}>>)
--> $DIR/const-generics-structural-demangling.rs:14:1
|
LL | #[rustc_symbol_name]
@@ -16,13 +16,13 @@ error: demangling-alt(<c::RefByte<{&123}>>)
LL | #[rustc_symbol_name]
| ^^^^^^^^^^^^^^^^^^^^
-error: symbol-name(_RMs_Csno73SFvQKx_1cINtB2_6RefZstKRAEE)
+error: symbol-name(_RMs_CsCRATE_HASH_1cINtB<REF>_6RefZstKRAEE)
--> $DIR/const-generics-structural-demangling.rs:24:1
|
LL | #[rustc_symbol_name]
| ^^^^^^^^^^^^^^^^^^^^
-error: demangling(<c[464da6a86cb672f]::RefZst<{&[]}>>)
+error: demangling(<c[HASH]::RefZst<{&[]}>>)
--> $DIR/const-generics-structural-demangling.rs:24:1
|
LL | #[rustc_symbol_name]
@@ -34,13 +34,13 @@ error: demangling-alt(<c::RefZst<{&[]}>>)
LL | #[rustc_symbol_name]
| ^^^^^^^^^^^^^^^^^^^^
-error: symbol-name(_RMs0_Csno73SFvQKx_1cINtB3_11Array3BytesKAh1_h2_h3_EE)
+error: symbol-name(_RMs0_CsCRATE_HASH_1cINtB<REF>_11Array3BytesKAh1_h2_h3_EE)
--> $DIR/const-generics-structural-demangling.rs:32:1
|
LL | #[rustc_symbol_name]
| ^^^^^^^^^^^^^^^^^^^^
-error: demangling(<c[464da6a86cb672f]::Array3Bytes<{[1u8, 2u8, 3u8]}>>)
+error: demangling(<c[HASH]::Array3Bytes<{[1u8, 2u8, 3u8]}>>)
--> $DIR/const-generics-structural-demangling.rs:32:1
|
LL | #[rustc_symbol_name]
@@ -52,13 +52,13 @@ error: demangling-alt(<c::Array3Bytes<{[1, 2, 3]}>>)
LL | #[rustc_symbol_name]
| ^^^^^^^^^^^^^^^^^^^^
-error: symbol-name(_RMs1_Csno73SFvQKx_1cINtB3_13TupleByteBoolKTh1_b0_EE)
+error: symbol-name(_RMs1_CsCRATE_HASH_1cINtB<REF>_13TupleByteBoolKTh1_b0_EE)
--> $DIR/const-generics-structural-demangling.rs:40:1
|
LL | #[rustc_symbol_name]
| ^^^^^^^^^^^^^^^^^^^^
-error: demangling(<c[464da6a86cb672f]::TupleByteBool<{(1u8, false)}>>)
+error: demangling(<c[HASH]::TupleByteBool<{(1u8, false)}>>)
--> $DIR/const-generics-structural-demangling.rs:40:1
|
LL | #[rustc_symbol_name]
@@ -70,13 +70,13 @@ error: demangling-alt(<c::TupleByteBool<{(1, false)}>>)
LL | #[rustc_symbol_name]
| ^^^^^^^^^^^^^^^^^^^^
-error: symbol-name(_RMs2_Csno73SFvQKx_1cINtB3_11OptionUsizeKVNtINtNtCs$HASH_4core6option6OptionjE4NoneUE)
+error: symbol-name(_RMs2_CsCRATE_HASH_1cINtB<REF>_11OptionUsizeKVNtINtNtCsCRATE_HASH_4core6option6OptionjE4NoneUE)
--> $DIR/const-generics-structural-demangling.rs:50:1
|
LL | #[rustc_symbol_name]
| ^^^^^^^^^^^^^^^^^^^^
-error: demangling(<c[464da6a86cb672f]::OptionUsize<{core[$HASH_HEX]::option::Option::<usize>::None}>>)
+error: demangling(<c[HASH]::OptionUsize<{core[HASH]::option::Option::<usize>::None}>>)
--> $DIR/const-generics-structural-demangling.rs:50:1
|
LL | #[rustc_symbol_name]
@@ -88,13 +88,13 @@ error: demangling-alt(<c::OptionUsize<{core::option::Option::<usize>::None}>>)
LL | #[rustc_symbol_name]
| ^^^^^^^^^^^^^^^^^^^^
-error: symbol-name(_RMs3_Csno73SFvQKx_1cINtB3_11OptionUsizeKVNtINtNtCs$HASH_4core6option6OptionjE4SomeTj0_EE)
+error: symbol-name(_RMs3_CsCRATE_HASH_1cINtB<REF>_11OptionUsizeKVNtINtNtCsCRATE_HASH_4core6option6OptionjE4SomeTj0_EE)
--> $DIR/const-generics-structural-demangling.rs:58:1
|
LL | #[rustc_symbol_name]
| ^^^^^^^^^^^^^^^^^^^^
-error: demangling(<c[464da6a86cb672f]::OptionUsize<{core[$HASH_HEX]::option::Option::<usize>::Some(0usize)}>>)
+error: demangling(<c[HASH]::OptionUsize<{core[HASH]::option::Option::<usize>::Some(0usize)}>>)
--> $DIR/const-generics-structural-demangling.rs:58:1
|
LL | #[rustc_symbol_name]
@@ -106,13 +106,13 @@ error: demangling-alt(<c::OptionUsize<{core::option::Option::<usize>::Some(0)}>>
LL | #[rustc_symbol_name]
| ^^^^^^^^^^^^^^^^^^^^
-error: symbol-name(_RMs4_Csno73SFvQKx_1cINtB3_4Foo_KVNtB3_3FooS1sRe616263_2chc78_5sliceRAh1_h2_h3_EEE)
+error: symbol-name(_RMs4_CsCRATE_HASH_1cINtB<REF>_4Foo_KVNtB<REF>_3FooS1sRe616263_2chc78_5sliceRAh1_h2_h3_EEE)
--> $DIR/const-generics-structural-demangling.rs:72:1
|
LL | #[rustc_symbol_name]
| ^^^^^^^^^^^^^^^^^^^^
-error: demangling(<c[464da6a86cb672f]::Foo_<{c[464da6a86cb672f]::Foo { s: "abc", ch: 'x', slice: &[1u8, 2u8, 3u8] }}>>)
+error: demangling(<c[HASH]::Foo_<{c[HASH]::Foo { s: "abc", ch: 'x', slice: &[1u8, 2u8, 3u8] }}>>)
--> $DIR/const-generics-structural-demangling.rs:72:1
|
LL | #[rustc_symbol_name]
@@ -124,7 +124,7 @@ error: demangling-alt(<c::Foo_<{c::Foo { s: "abc", ch: 'x', slice: &[1, 2, 3] }}
LL | #[rustc_symbol_name]
| ^^^^^^^^^^^^^^^^^^^^
-error: symbol-name(_RMs9_Csno73SFvQKx_1cINtB3_4Bar_KVNtB3_3BarS1xh7b_s_1xt1000_EE)
+error: symbol-name(_RMs9_CsCRATE_HASH_1cINtB<REF>_4Bar_KVNtB<REF>_3BarS1xh7b_s_1xt1000_EE)
--> $DIR/const-generics-structural-demangling.rs:88:5
|
LL | #[rustc_symbol_name]
@@ -135,7 +135,7 @@ LL | duplicate_field_name_test!(x);
|
= note: this error originates in the macro `duplicate_field_name_test` (in Nightly builds, run with -Z macro-backtrace for more info)
-error: demangling(<c[464da6a86cb672f]::Bar_<{c[464da6a86cb672f]::Bar { x: 123u8, x: 4096u16 }}>>)
+error: demangling(<c[HASH]::Bar_<{c[HASH]::Bar { x: 123u8, x: 4096u16 }}>>)
--> $DIR/const-generics-structural-demangling.rs:88:5
|
LL | #[rustc_symbol_name]
diff --git a/src/test/ui/symbol-names/impl1.legacy.stderr b/src/test/ui/symbol-names/impl1.legacy.stderr
index b6012e41594..b17a073ee49 100644
--- a/src/test/ui/symbol-names/impl1.legacy.stderr
+++ b/src/test/ui/symbol-names/impl1.legacy.stderr
@@ -1,10 +1,10 @@
-error: symbol-name(_ZN5impl13foo3Foo3bar17<SYMBOL_HASH>)
+error: symbol-name(_ZN5impl13foo3Foo3bar17h<SYMBOL_HASH>)
--> $DIR/impl1.rs:14:9
|
LL | #[rustc_symbol_name]
| ^^^^^^^^^^^^^^^^^^^^
-error: demangling(impl1::foo::Foo::bar::<SYMBOL_HASH>)
+error: demangling(impl1::foo::Foo::bar::h<SYMBOL_HASH>)
--> $DIR/impl1.rs:14:9
|
LL | #[rustc_symbol_name]
@@ -22,13 +22,13 @@ error: def-path(foo::Foo::bar)
LL | #[rustc_def_path]
| ^^^^^^^^^^^^^^^^^
-error: symbol-name(_ZN5impl13bar33_$LT$impl$u20$impl1..foo..Foo$GT$3baz17<SYMBOL_HASH>)
+error: symbol-name(_ZN5impl13bar33_$LT$impl$u20$impl1..foo..Foo$GT$3baz17h<SYMBOL_HASH>)
--> $DIR/impl1.rs:32:9
|
LL | #[rustc_symbol_name]
| ^^^^^^^^^^^^^^^^^^^^
-error: demangling(impl1::bar::<impl impl1::foo::Foo>::baz::<SYMBOL_HASH>)
+error: demangling(impl1::bar::<impl impl1::foo::Foo>::baz::h<SYMBOL_HASH>)
--> $DIR/impl1.rs:32:9
|
LL | #[rustc_symbol_name]
@@ -46,13 +46,13 @@ error: def-path(bar::<impl foo::Foo>::baz)
LL | #[rustc_def_path]
| ^^^^^^^^^^^^^^^^^
-error: symbol-name(_ZN209_$LT$$u5b$$RF$dyn$u20$impl1..Foo$u2b$Assoc$u20$$u3d$$u20$extern$u20$$u22$C$u22$$u20$fn$LP$$RF$u8$C$$u20$...$RP$$u2b$impl1..AutoTrait$u3b$$u20$3$u5d$$u20$as$u20$impl1..main..$u7b$$u7b$closure$u7d$$u7d$..Bar$GT$6method17<SYMBOL_HASH>)
+error: symbol-name(_ZN209_$LT$$u5b$$RF$dyn$u20$impl1..Foo$u2b$Assoc$u20$$u3d$$u20$extern$u20$$u22$C$u22$$u20$fn$LP$$RF$u8$C$$u20$...$RP$$u2b$impl1..AutoTrait$u3b$$u20$3$u5d$$u20$as$u20$impl1..main..$u7b$$u7b$closure$u7d$$u7d$..Bar$GT$6method17h<SYMBOL_HASH>)
--> $DIR/impl1.rs:62:13
|
LL | #[rustc_symbol_name]
| ^^^^^^^^^^^^^^^^^^^^
-error: demangling(<[&dyn impl1::Foo+Assoc = extern "C" fn(&u8, ::.)+impl1::AutoTrait; 3] as impl1::main::{{closure}}::Bar>::method::<SYMBOL_HASH>)
+error: demangling(<[&dyn impl1::Foo+Assoc = extern "C" fn(&u8, ::.)+impl1::AutoTrait; 3] as impl1::main::{{closure}}::Bar>::method::h<SYMBOL_HASH>)
--> $DIR/impl1.rs:62:13
|
LL | #[rustc_symbol_name]
diff --git a/src/test/ui/symbol-names/impl1.rs b/src/test/ui/symbol-names/impl1.rs
index 60f19266ba9..f20cb1c01fd 100644
--- a/src/test/ui/symbol-names/impl1.rs
+++ b/src/test/ui/symbol-names/impl1.rs
@@ -15,8 +15,8 @@ mod foo {
//[legacy]~^ ERROR symbol-name(_ZN5impl13foo3Foo3bar
//[legacy]~| ERROR demangling(impl1::foo::Foo::bar
//[legacy]~| ERROR demangling-alt(impl1::foo::Foo::bar)
- //[v0]~^^^^ ERROR symbol-name(_RNvMNtCs2qSCrjELJET_5impl13fooNtB2_3Foo3bar)
- //[v0]~| ERROR demangling(<impl1[1c5860ab79c9e305]::foo::Foo>::bar)
+ //[v0]~^^^^ ERROR symbol-name(_RNvMNtCs
+ //[v0]~| ERROR demangling(<impl1[
//[v0]~| ERROR demangling-alt(<impl1::foo::Foo>::bar)
#[rustc_def_path]
//[legacy]~^ ERROR def-path(foo::Foo::bar)
@@ -33,8 +33,8 @@ mod bar {
//[legacy]~^ ERROR symbol-name(_ZN5impl13bar33_$LT$impl$u20$impl1..foo..Foo$GT$3baz
//[legacy]~| ERROR demangling(impl1::bar::<impl impl1::foo::Foo>::baz
//[legacy]~| ERROR demangling-alt(impl1::bar::<impl impl1::foo::Foo>::baz)
- //[v0]~^^^^ ERROR symbol-name(_RNvMNtCs2qSCrjELJET_5impl13barNtNtB4_3foo3Foo3baz)
- //[v0]~| ERROR demangling(<impl1[1c5860ab79c9e305]::foo::Foo>::baz)
+ //[v0]~^^^^ ERROR symbol-name(_RNvMNtCs
+ //[v0]~| ERROR demangling(<impl1[
//[v0]~| ERROR demangling-alt(<impl1::foo::Foo>::baz)
#[rustc_def_path]
//[legacy]~^ ERROR def-path(bar::<impl foo::Foo>::baz)
@@ -63,8 +63,8 @@ fn main() {
//[legacy]~^ ERROR symbol-name(_ZN209_$LT$$u5b$$RF$dyn$u20$impl1..Foo$u2b$Assoc$u20$$u3d$$u20$extern$u20$$u22$C$u22$$u20$fn$LP$$RF$u8$C$$u20$...$RP$$u2b$impl1..AutoTrait$u3b$$u20$3$u5d$$u20$as$u20$impl1..main..$u7b$$u7b$closure$u7d$$u7d$..Bar$GT$6method
//[legacy]~| ERROR demangling(<[&dyn impl1::Foo+Assoc = extern "C" fn(&u8, ::.)+impl1::AutoTrait; 3] as impl1::main::{{closure}}::Bar>::method
//[legacy]~| ERROR demangling-alt(<[&dyn impl1::Foo+Assoc = extern "C" fn(&u8, ::.)+impl1::AutoTrait; 3] as impl1::main::{{closure}}::Bar>::method)
- //[v0]~^^^^ ERROR symbol-name(_RNvXNCNvCs2qSCrjELJET_5impl14mains_0ARDNtB6_3Foop5AssocFG_KCRL0_hvEuNtB6_9AutoTraitEL_j3_NtB2_3Bar6method)
- //[v0]~| ERROR demangling(<[&dyn impl1[1c5860ab79c9e305]::Foo<Assoc = for<'a> extern "C" fn(&'a u8, ...)> + impl1[1c5860ab79c9e305]::AutoTrait; 3usize] as impl1[1c5860ab79c9e305]::main::{closure#1}::Bar>::method)
+ //[v0]~^^^^ ERROR symbol-name(_RNvXNCNvCs
+ //[v0]~| ERROR demangling(<[&dyn
//[v0]~| ERROR demangling-alt(<[&dyn impl1::Foo<Assoc = for<'a> extern "C" fn(&'a u8, ...)> + impl1::AutoTrait; 3] as impl1::main::{closure#1}::Bar>::method)
#[rustc_def_path]
//[legacy]~^ ERROR def-path(<[&dyn Foo<Assoc = for<'r> extern "C" fn(&'r u8, ...)> + AutoTrait; 3] as main::{closure#1}::Bar>::method)
diff --git a/src/test/ui/symbol-names/impl1.v0.stderr b/src/test/ui/symbol-names/impl1.v0.stderr
index 926e750e3cd..06778e57fb1 100644
--- a/src/test/ui/symbol-names/impl1.v0.stderr
+++ b/src/test/ui/symbol-names/impl1.v0.stderr
@@ -1,10 +1,10 @@
-error: symbol-name(_RNvMNtCs2qSCrjELJET_5impl13fooNtB2_3Foo3bar)
+error: symbol-name(_RNvMNtCsCRATE_HASH_5impl13fooNtB<REF>_3Foo3bar)
--> $DIR/impl1.rs:14:9
|
LL | #[rustc_symbol_name]
| ^^^^^^^^^^^^^^^^^^^^
-error: demangling(<impl1[1c5860ab79c9e305]::foo::Foo>::bar)
+error: demangling(<impl1[HASH]::foo::Foo>::bar)
--> $DIR/impl1.rs:14:9
|
LL | #[rustc_symbol_name]
@@ -22,13 +22,13 @@ error: def-path(foo::Foo::bar)
LL | #[rustc_def_path]
| ^^^^^^^^^^^^^^^^^
-error: symbol-name(_RNvMNtCs2qSCrjELJET_5impl13barNtNtB4_3foo3Foo3baz)
+error: symbol-name(_RNvMNtCsCRATE_HASH_5impl13barNtNtB<REF>_3foo3Foo3baz)
--> $DIR/impl1.rs:32:9
|
LL | #[rustc_symbol_name]
| ^^^^^^^^^^^^^^^^^^^^
-error: demangling(<impl1[1c5860ab79c9e305]::foo::Foo>::baz)
+error: demangling(<impl1[HASH]::foo::Foo>::baz)
--> $DIR/impl1.rs:32:9
|
LL | #[rustc_symbol_name]
@@ -46,13 +46,13 @@ error: def-path(bar::<impl foo::Foo>::baz)
LL | #[rustc_def_path]
| ^^^^^^^^^^^^^^^^^
-error: symbol-name(_RNvXNCNvCs2qSCrjELJET_5impl14mains_0ARDNtB6_3Foop5AssocFG_KCRL0_hvEuNtB6_9AutoTraitEL_j3_NtB2_3Bar6method)
+error: symbol-name(_RNvXNCNvCsCRATE_HASH_5impl14mains_0ARDNtB<REF>_3Foop5AssocFG_KCRL0_hvEuNtB<REF>_9AutoTraitEL_j3_NtB<REF>_3Bar6method)
--> $DIR/impl1.rs:62:13
|
LL | #[rustc_symbol_name]
| ^^^^^^^^^^^^^^^^^^^^
-error: demangling(<[&dyn impl1[1c5860ab79c9e305]::Foo<Assoc = for<'a> extern "C" fn(&'a u8, ...)> + impl1[1c5860ab79c9e305]::AutoTrait; 3usize] as impl1[1c5860ab79c9e305]::main::{closure#1}::Bar>::method)
+error: demangling(<[&dyn impl1[HASH]::Foo<Assoc = for<'a> extern "C" fn(&'a u8, ...)> + impl1[HASH]::AutoTrait; 3usize] as impl1[HASH]::main::{closure#1}::Bar>::method)
--> $DIR/impl1.rs:62:13
|
LL | #[rustc_symbol_name]
diff --git a/src/test/ui/symbol-names/issue-60925.legacy.stderr b/src/test/ui/symbol-names/issue-60925.legacy.stderr
index 52d0c666398..46cb84e57bf 100644
--- a/src/test/ui/symbol-names/issue-60925.legacy.stderr
+++ b/src/test/ui/symbol-names/issue-60925.legacy.stderr
@@ -1,10 +1,10 @@
-error: symbol-name(_ZN11issue_609253foo37Foo$LT$issue_60925..llv$u6d$..Foo$GT$3foo17h18eaa05e22e59176E)
+error: symbol-name(_ZN11issue_609253foo37Foo$LT$issue_60925..llv$u6d$..Foo$GT$3foo17h<SYMBOL_HASH>)
--> $DIR/issue-60925.rs:21:9
|
LL | #[rustc_symbol_name]
| ^^^^^^^^^^^^^^^^^^^^
-error: demangling(issue_60925::foo::Foo<issue_60925::llvm::Foo>::foo::h18eaa05e22e59176)
+error: demangling(issue_60925::foo::Foo<issue_60925::llvm::Foo>::foo::h<SYMBOL_HASH>)
--> $DIR/issue-60925.rs:21:9
|
LL | #[rustc_symbol_name]
diff --git a/src/test/ui/symbol-names/issue-60925.rs b/src/test/ui/symbol-names/issue-60925.rs
index a313c1ef383..57114ca1f15 100644
--- a/src/test/ui/symbol-names/issue-60925.rs
+++ b/src/test/ui/symbol-names/issue-60925.rs
@@ -22,8 +22,8 @@ mod foo {
//[legacy]~^ ERROR symbol-name(_ZN11issue_609253foo37Foo$LT$issue_60925..llv$u6d$..Foo$GT$3foo
//[legacy]~| ERROR demangling(issue_60925::foo::Foo<issue_60925::llvm::Foo>::foo
//[legacy]~| ERROR demangling-alt(issue_60925::foo::Foo<issue_60925::llvm::Foo>::foo)
- //[v0]~^^^^ ERROR symbol-name(_RNvMNtCs8dUWfuENynB_11issue_609253fooINtB2_3FooNtNtB4_4llvm3FooE3foo)
- //[v0]~| ERROR demangling(<issue_60925[5fcbb46c6fac4139]::foo::Foo<issue_60925[5fcbb46c6fac4139]::llvm::Foo>>::foo)
+ //[v0]~^^^^ ERROR symbol-name
+ //[v0]~| ERROR demangling
//[v0]~| ERROR demangling-alt(<issue_60925::foo::Foo<issue_60925::llvm::Foo>>::foo)
pub(crate) fn foo() {
for _ in 0..0 {
diff --git a/src/test/ui/symbol-names/issue-60925.v0.stderr b/src/test/ui/symbol-names/issue-60925.v0.stderr
index 5d99abff59a..1cddba92085 100644
--- a/src/test/ui/symbol-names/issue-60925.v0.stderr
+++ b/src/test/ui/symbol-names/issue-60925.v0.stderr
@@ -1,10 +1,10 @@
-error: symbol-name(_RNvMNtCs8dUWfuENynB_11issue_609253fooINtB2_3FooNtNtB4_4llvm3FooE3foo)
+error: symbol-name(_RNvMNtCsCRATE_HASH_11issue_609253fooINtB<REF>_3FooNtNtB<REF>_4llvm3FooE3foo)
--> $DIR/issue-60925.rs:21:9
|
LL | #[rustc_symbol_name]
| ^^^^^^^^^^^^^^^^^^^^
-error: demangling(<issue_60925[5fcbb46c6fac4139]::foo::Foo<issue_60925[5fcbb46c6fac4139]::llvm::Foo>>::foo)
+error: demangling(<issue_60925[HASH]::foo::Foo<issue_60925[HASH]::llvm::Foo>>::foo)
--> $DIR/issue-60925.rs:21:9
|
LL | #[rustc_symbol_name]
diff --git a/src/test/ui/symbol-names/issue-75326.legacy.stderr b/src/test/ui/symbol-names/issue-75326.legacy.stderr
index aadc0cf43a2..74e481badb0 100644
--- a/src/test/ui/symbol-names/issue-75326.legacy.stderr
+++ b/src/test/ui/symbol-names/issue-75326.legacy.stderr
@@ -1,10 +1,10 @@
-error: symbol-name(_ZN72_$LT$issue_75326..Foo$LT$I$C$E$GT$$u20$as$u20$issue_75326..Iterator2$GT$4next17SYMBOL_HASH)
+error: symbol-name(_ZN72_$LT$issue_75326..Foo$LT$I$C$E$GT$$u20$as$u20$issue_75326..Iterator2$GT$4next17h<SYMBOL_HASH>)
--> $DIR/issue-75326.rs:41:5
|
LL | #[rustc_symbol_name]
| ^^^^^^^^^^^^^^^^^^^^
-error: demangling(<issue_75326::Foo<I,E> as issue_75326::Iterator2>::next::SYMBOL_HASH)
+error: demangling(<issue_75326::Foo<I,E> as issue_75326::Iterator2>::next::h<SYMBOL_HASH>)
--> $DIR/issue-75326.rs:41:5
|
LL | #[rustc_symbol_name]
diff --git a/src/test/ui/symbol-names/issue-75326.rs b/src/test/ui/symbol-names/issue-75326.rs
index 0f721fc1f89..d1bc152af5c 100644
--- a/src/test/ui/symbol-names/issue-75326.rs
+++ b/src/test/ui/symbol-names/issue-75326.rs
@@ -42,8 +42,8 @@ where
//[legacy]~^ ERROR symbol-name(_ZN72_$LT$issue_75326..Foo$LT$I$C$E$GT$$u20$as$u20$issue_75326..Iterator2$GT$4next
//[legacy]~| ERROR demangling(<issue_75326::Foo<I,E> as issue_75326::Iterator2>::next
//[legacy]~| ERROR demangling-alt(<issue_75326::Foo<I,E> as issue_75326::Iterator2>::next)
- //[v0]~^^^^ ERROR symbol-name(_RNvXINICsiMBouZZ1iuD_11issue_75326s_0pppEINtB5_3FooppENtB5_9Iterator24nextB5_)
- //[v0]~| ERROR demangling(<issue_75326[dac9b7624645f95d]::Foo<_, _> as issue_75326[dac9b7624645f95d]::Iterator2>::next)
+ //[v0]~^^^^ ERROR symbol-name
+ //[v0]~| ERROR demangling
//[v0]~| ERROR demangling-alt(<issue_75326::Foo<_, _> as issue_75326::Iterator2>::next)
fn next(&mut self) -> Option<Self::Item> {
self.find(|_| true)
diff --git a/src/test/ui/symbol-names/issue-75326.v0.stderr b/src/test/ui/symbol-names/issue-75326.v0.stderr
index 093ba8c8576..446fb8d6cf6 100644
--- a/src/test/ui/symbol-names/issue-75326.v0.stderr
+++ b/src/test/ui/symbol-names/issue-75326.v0.stderr
@@ -1,10 +1,10 @@
-error: symbol-name(_RNvXINICsiMBouZZ1iuD_11issue_75326s_0pppEINtB5_3FooppENtB5_9Iterator24nextB5_)
+error: symbol-name(_RNvXINICsCRATE_HASH_11issue_75326s_0pppEINtB<REF>_3FooppENtB<REF>_9Iterator24nextB<REF>_)
--> $DIR/issue-75326.rs:41:5
|
LL | #[rustc_symbol_name]
| ^^^^^^^^^^^^^^^^^^^^
-error: demangling(<issue_75326[dac9b7624645f95d]::Foo<_, _> as issue_75326[dac9b7624645f95d]::Iterator2>::next)
+error: demangling(<issue_75326[HASH]::Foo<_, _> as issue_75326[HASH]::Iterator2>::next)
--> $DIR/issue-75326.rs:41:5
|
LL | #[rustc_symbol_name]
diff --git a/src/test/ui/symbol-names/trait-objects.rs b/src/test/ui/symbol-names/trait-objects.rs
index cea1a89d757..502afebcb5a 100644
--- a/src/test/ui/symbol-names/trait-objects.rs
+++ b/src/test/ui/symbol-names/trait-objects.rs
@@ -3,7 +3,6 @@
// build-fail
// revisions: v0
//[v0]compile-flags: -Z symbol-mangling-version=v0
-//[v0]normalize-stderr-test: "Cs.*?_" -> "CRATE_HASH"
//[v0]normalize-stderr-test: "core\[.*?\]" -> "core[HASH]"
#![feature(rustc_attrs)]
diff --git a/src/test/ui/symbol-names/trait-objects.v0.stderr b/src/test/ui/symbol-names/trait-objects.v0.stderr
index 5ada82dfb2d..6c5e55ed2ae 100644
--- a/src/test/ui/symbol-names/trait-objects.v0.stderr
+++ b/src/test/ui/symbol-names/trait-objects.v0.stderr
@@ -1,53 +1,53 @@
-error: symbol-name(_RNvXCRATE_HASH13trait_objectsRDG_INtNtNtCRATE_HASH4core3ops8function5FnMutTRL0_hEEp6OutputuEL_NtB2_3Bar6method)
- --> $DIR/trait-objects.rs:16:5
+error: symbol-name(_RNvXCsCRATE_HASH_13trait_objectsRDG_INtNtNtCsCRATE_HASH_4core3ops8function5FnMutTRL0_hEEp6OutputuEL_NtB<REF>_3Bar6method)
+ --> $DIR/trait-objects.rs:15:5
|
LL | #[rustc_symbol_name]
| ^^^^^^^^^^^^^^^^^^^^
-error: demangling(<&dyn for<'a> core[HASH]::ops::function::FnMut<(&'a u8,), Output = ()> as trait_objects[3f8b57f879016e18]::Bar>::method)
- --> $DIR/trait-objects.rs:16:5
+error: demangling(<&dyn for<'a> core[HASH]::ops::function::FnMut<(&'a u8,), Output = ()> as trait_objects[HASH]::Bar>::method)
+ --> $DIR/trait-objects.rs:15:5
|
LL | #[rustc_symbol_name]
| ^^^^^^^^^^^^^^^^^^^^
error: demangling-alt(<&dyn for<'a> core::ops::function::FnMut<(&'a u8,), Output = ()> as trait_objects::Bar>::method)
- --> $DIR/trait-objects.rs:16:5
+ --> $DIR/trait-objects.rs:15:5
|
LL | #[rustc_symbol_name]
| ^^^^^^^^^^^^^^^^^^^^
-error: symbol-name(_RNvXs_CRATE_HASH13trait_objectsRDG_INtNtNtCRATE_HASH4core3ops8function5FnMutTRL0_hEEp6OutputuNtNtBI_6marker4SendEL_NtB4_3Foo6method)
- --> $DIR/trait-objects.rs:28:5
+error: symbol-name(_RNvXs_CsCRATE_HASH_13trait_objectsRDG_INtNtNtCsCRATE_HASH_4core3ops8function5FnMutTRL0_hEEp6OutputuNtNtB<REF>_6marker4SendEL_NtB<REF>_3Foo6method)
+ --> $DIR/trait-objects.rs:27:5
|
LL | #[rustc_symbol_name]
| ^^^^^^^^^^^^^^^^^^^^
-error: demangling(<&dyn for<'a> core[HASH]::ops::function::FnMut<(&'a u8,), Output = ()> + core[HASH]::marker::Send as trait_objects[3f8b57f879016e18]::Foo>::method)
- --> $DIR/trait-objects.rs:28:5
+error: demangling(<&dyn for<'a> core[HASH]::ops::function::FnMut<(&'a u8,), Output = ()> + core[HASH]::marker::Send as trait_objects[HASH]::Foo>::method)
+ --> $DIR/trait-objects.rs:27:5
|
LL | #[rustc_symbol_name]
| ^^^^^^^^^^^^^^^^^^^^
error: demangling-alt(<&dyn for<'a> core::ops::function::FnMut<(&'a u8,), Output = ()> + core::marker::Send as trait_objects::Foo>::method)
- --> $DIR/trait-objects.rs:28:5
+ --> $DIR/trait-objects.rs:27:5
|
LL | #[rustc_symbol_name]
| ^^^^^^^^^^^^^^^^^^^^
-error: symbol-name(_RNvXs0_CRATE_HASH13trait_objectsRDG_INtNtNtCRATE_HASH4core3ops8function5FnMutTRL0_hEEp6OutputuNtNtBJ_6marker4SendEL_NtB5_3Baz6method)
- --> $DIR/trait-objects.rs:40:5
+error: symbol-name(_RNvXs0_CsCRATE_HASH_13trait_objectsRDG_INtNtNtCsCRATE_HASH_4core3ops8function5FnMutTRL0_hEEp6OutputuNtNtB<REF>_6marker4SendEL_NtB<REF>_3Baz6method)
+ --> $DIR/trait-objects.rs:39:5
|
LL | #[rustc_symbol_name]
| ^^^^^^^^^^^^^^^^^^^^
-error: demangling(<&dyn for<'a> core[HASH]::ops::function::FnMut<(&'a u8,), Output = ()> + core[HASH]::marker::Send as trait_objects[3f8b57f879016e18]::Baz>::method)
- --> $DIR/trait-objects.rs:40:5
+error: demangling(<&dyn for<'a> core[HASH]::ops::function::FnMut<(&'a u8,), Output = ()> + core[HASH]::marker::Send as trait_objects[HASH]::Baz>::method)
+ --> $DIR/trait-objects.rs:39:5
|
LL | #[rustc_symbol_name]
| ^^^^^^^^^^^^^^^^^^^^
error: demangling-alt(<&dyn for<'a> core::ops::function::FnMut<(&'a u8,), Output = ()> + core::marker::Send as trait_objects::Baz>::method)
- --> $DIR/trait-objects.rs:40:5
+ --> $DIR/trait-objects.rs:39:5
|
LL | #[rustc_symbol_name]
| ^^^^^^^^^^^^^^^^^^^^
diff --git a/src/test/ui/test-attrs/test-should-fail-good-message.rs b/src/test/ui/test-attrs/test-should-fail-good-message.rs
index 9fa759f9eb4..3260b6938f0 100644
--- a/src/test/ui/test-attrs/test-should-fail-good-message.rs
+++ b/src/test/ui/test-attrs/test-should-fail-good-message.rs
@@ -1,4 +1,5 @@
// run-pass
+// needs-unwind
// ignore-wasm32-bare compiled with panic=abort by default
// compile-flags: --test
#[test]
diff --git a/src/test/ui/thir-tree.stdout b/src/test/ui/thir-tree.stdout
index 389eaf5e715..a732eb68a2b 100644
--- a/src/test/ui/thir-tree.stdout
+++ b/src/test/ui/thir-tree.stdout
@@ -1,4 +1,4 @@
-DefId(0:3 ~ thir_tree[348d]::main):
+DefId(0:3 ~ thir_tree[HASH]::main):
Thir {
arms: [],
exprs: [
@@ -30,7 +30,7 @@ Thir {
region_scope: Node(2),
lint_level: Explicit(
HirId {
- owner: DefId(0:3 ~ thir_tree[348d]::main),
+ owner: DefId(0:3 ~ thir_tree[HASH]::main),
local_id: 2,
},
),
diff --git a/src/test/ui/threads-sendsync/task-stderr.rs b/src/test/ui/threads-sendsync/task-stderr.rs
index 78145e337da..68d226ffbae 100644
--- a/src/test/ui/threads-sendsync/task-stderr.rs
+++ b/src/test/ui/threads-sendsync/task-stderr.rs
@@ -1,5 +1,6 @@
// run-pass
// ignore-emscripten no threads support
+// needs-unwind
#![feature(internal_output_capture)]
diff --git a/src/test/ui/threads-sendsync/unwind-resource.rs b/src/test/ui/threads-sendsync/unwind-resource.rs
index a063bef0822..6950a9c40d2 100644
--- a/src/test/ui/threads-sendsync/unwind-resource.rs
+++ b/src/test/ui/threads-sendsync/unwind-resource.rs
@@ -1,4 +1,5 @@
// run-pass
+// needs-unwind
#![allow(non_camel_case_types)]
// ignore-emscripten no threads support
diff --git a/src/test/ui/traits/associated_type_bound/check-trait-object-bounds-5.stderr b/src/test/ui/traits/associated_type_bound/check-trait-object-bounds-5.stderr
index c97408ff91e..4251c1a1ed6 100644
--- a/src/test/ui/traits/associated_type_bound/check-trait-object-bounds-5.stderr
+++ b/src/test/ui/traits/associated_type_bound/check-trait-object-bounds-5.stderr
@@ -2,8 +2,13 @@ error[E0271]: type mismatch resolving `<i32 as Is>::T == i64`
--> $DIR/check-trait-object-bounds-5.rs:23:5
|
LL | is_obj(x)
- | ^^^^^^ expected `i64`, found `i32`
+ | ^^^^^^ type mismatch resolving `<i32 as Is>::T == i64`
|
+note: expected this to be `i64`
+ --> $DIR/check-trait-object-bounds-5.rs:9:14
+ |
+LL | type T = U;
+ | ^
note: required by a bound in `is_obj`
--> $DIR/check-trait-object-bounds-5.rs:20:23
|
diff --git a/src/test/ui/traits/associated_type_bound/check-trait-object-bounds-6.stderr b/src/test/ui/traits/associated_type_bound/check-trait-object-bounds-6.stderr
index 89356449437..5b23a513eea 100644
--- a/src/test/ui/traits/associated_type_bound/check-trait-object-bounds-6.stderr
+++ b/src/test/ui/traits/associated_type_bound/check-trait-object-bounds-6.stderr
@@ -2,8 +2,13 @@ error[E0271]: type mismatch resolving `<i32 as Is>::T == i64`
--> $DIR/check-trait-object-bounds-6.rs:20:5
|
LL | is_obj(x)
- | ^^^^^^ expected `i64`, found `i32`
+ | ^^^^^^ type mismatch resolving `<i32 as Is>::T == i64`
|
+note: expected this to be `i64`
+ --> $DIR/check-trait-object-bounds-6.rs:9:14
+ |
+LL | type T = U;
+ | ^
note: required by a bound in `is_obj`
--> $DIR/check-trait-object-bounds-6.rs:17:23
|
diff --git a/src/test/ui/traits/bound/not-on-bare-trait.stderr b/src/test/ui/traits/bound/not-on-bare-trait.stderr
index 0bbf1bffda5..08f6d166d22 100644
--- a/src/test/ui/traits/bound/not-on-bare-trait.stderr
+++ b/src/test/ui/traits/bound/not-on-bare-trait.stderr
@@ -2,11 +2,16 @@ warning: trait objects without an explicit `dyn` are deprecated
--> $DIR/not-on-bare-trait.rs:7:12
|
LL | fn foo(_x: Foo + Send) {
- | ^^^^^^^^^^ help: use `dyn`: `dyn Foo + Send`
+ | ^^^^^^^^^^
|
= note: `#[warn(bare_trait_objects)]` on by default
= warning: this is accepted in the current edition (Rust 2015) but is a hard error in Rust 2021!
= note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2021/warnings-promoted-to-error.html>
+help: use `dyn`
+ |
+LL - fn foo(_x: Foo + Send) {
+LL + fn foo(_x: dyn Foo + Send) {
+ |
error[E0277]: the size for values of type `(dyn Foo + Send + 'static)` cannot be known at compilation time
--> $DIR/not-on-bare-trait.rs:7:8
diff --git a/src/test/ui/traits/impl-method-mismatch.stderr b/src/test/ui/traits/impl-method-mismatch.stderr
index c909446d9dc..30aa97d2934 100644
--- a/src/test/ui/traits/impl-method-mismatch.stderr
+++ b/src/test/ui/traits/impl-method-mismatch.stderr
@@ -1,12 +1,14 @@
error[E0053]: method `jumbo` has an incompatible type for trait
--> $DIR/impl-method-mismatch.rs:7:5
|
-LL | fn jumbo(&self, x: &usize) -> usize;
- | ------------------------------------ type in trait
-...
LL | unsafe fn jumbo(&self, x: &usize) { *self + *x; }
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected normal fn, found unsafe fn
|
+note: type in trait
+ --> $DIR/impl-method-mismatch.rs:2:5
+ |
+LL | fn jumbo(&self, x: &usize) -> usize;
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
= note: expected fn pointer `fn(&usize, &usize) -> usize`
found fn pointer `unsafe fn(&usize, &usize)`
diff --git a/src/test/ui/traits/inductive-overflow/lifetime.rs b/src/test/ui/traits/inductive-overflow/lifetime.rs
index 8be42fc4ad0..c36c17d3d24 100644
--- a/src/test/ui/traits/inductive-overflow/lifetime.rs
+++ b/src/test/ui/traits/inductive-overflow/lifetime.rs
@@ -22,6 +22,7 @@ impl<'a> NotAuto for C<'a> {}
fn is_send<S: NotAuto>() {}
//~^ NOTE: required
//~| NOTE: required
+
fn main() {
// Should only be a few notes.
is_send::<X<C<'static>>>();
diff --git a/src/test/ui/traits/inductive-overflow/lifetime.stderr b/src/test/ui/traits/inductive-overflow/lifetime.stderr
index 2ffcdb0e1c6..9ca615aacee 100644
--- a/src/test/ui/traits/inductive-overflow/lifetime.stderr
+++ b/src/test/ui/traits/inductive-overflow/lifetime.stderr
@@ -1,5 +1,5 @@
error[E0275]: overflow evaluating the requirement `X<C<'_>>: NotAuto`
- --> $DIR/lifetime.rs:27:5
+ --> $DIR/lifetime.rs:28:5
|
LL | is_send::<X<C<'static>>>();
| ^^^^^^^^^^^^^^^^^^^^^^^^
diff --git a/src/test/ui/traits/inductive-overflow/two-traits.stderr b/src/test/ui/traits/inductive-overflow/two-traits.stderr
index 28610c94181..0d0bf88616c 100644
--- a/src/test/ui/traits/inductive-overflow/two-traits.stderr
+++ b/src/test/ui/traits/inductive-overflow/two-traits.stderr
@@ -1,8 +1,8 @@
error[E0277]: `T` cannot be shared between threads safely
- --> $DIR/two-traits.rs:11:5
+ --> $DIR/two-traits.rs:11:14
|
LL | type X = Self;
- | ^^^^^^^^^^^^^^ `T` cannot be shared between threads safely
+ | ^^^^ `T` cannot be shared between threads safely
|
note: required by a bound in `Magic::X`
--> $DIR/two-traits.rs:8:13
diff --git a/src/test/ui/traits/issue-65673.stderr b/src/test/ui/traits/issue-65673.stderr
index fba24d683a6..245c4ee525e 100644
--- a/src/test/ui/traits/issue-65673.stderr
+++ b/src/test/ui/traits/issue-65673.stderr
@@ -1,8 +1,8 @@
error[E0277]: the size for values of type `(dyn Trait + 'static)` cannot be known at compilation time
- --> $DIR/issue-65673.rs:9:5
+ --> $DIR/issue-65673.rs:9:16
|
LL | type Ctx = dyn Alias<T>;
- | ^^^^^^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time
+ | ^^^^^^^^^^^^ doesn't have a size known at compile-time
|
= help: the trait `Sized` is not implemented for `(dyn Trait + 'static)`
note: required by a bound in `WithType::Ctx`
diff --git a/src/test/ui/traits/issue-85360-eval-obligation-ice.rs b/src/test/ui/traits/issue-85360-eval-obligation-ice.rs
new file mode 100644
index 00000000000..19131684a48
--- /dev/null
+++ b/src/test/ui/traits/issue-85360-eval-obligation-ice.rs
@@ -0,0 +1,143 @@
+// compile-flags: --edition=2021
+
+#![feature(rustc_attrs)]
+
+use core::any::Any;
+use core::marker::PhantomData;
+
+fn main() {
+ test::<MaskedStorage<GenericComp<Pos>>>(make());
+ //~^ ERROR evaluate(Binder(TraitPredicate(<MaskedStorage<GenericComp<Pos>> as std::marker::Sized>, polarity:Positive), [])) = Ok(EvaluatedToOk)
+ //~| ERROR evaluate(Binder(TraitPredicate(<MaskedStorage<GenericComp<Pos>> as std::marker::Sized>, polarity:Positive), [])) = Ok(EvaluatedToOk)
+
+ test::<MaskedStorage<GenericComp2<Pos>>>(make());
+ //~^ ERROR evaluate(Binder(TraitPredicate(<MaskedStorage<GenericComp2<Pos>> as std::marker::Sized>, polarity:Positive), [])) = Ok(EvaluatedToOkModuloRegions)
+ //~| ERROR evaluate(Binder(TraitPredicate(<MaskedStorage<GenericComp2<Pos>> as std::marker::Sized>, polarity:Positive), [])) = Ok(EvaluatedToOkModuloRegions)
+}
+
+#[rustc_evaluate_where_clauses]
+fn test<T: Sized>(_: T) {}
+
+fn make<T>() -> T {
+ todo!()
+}
+
+struct DerefWrap<T>(T);
+
+impl<T> core::ops::Deref for DerefWrap<T> {
+ type Target = T;
+ fn deref(&self) -> &Self::Target {
+ &self.0
+ }
+}
+
+struct Storage<T, D> {
+ phantom: PhantomData<(T, D)>,
+}
+
+type ReadStorage<T> = Storage<T, DerefWrap<MaskedStorage<T>>>;
+
+pub trait Component {
+ type Storage;
+}
+
+struct VecStorage;
+
+struct Pos;
+
+impl Component for Pos {
+ type Storage = VecStorage;
+}
+
+struct GenericComp<T> {
+ _t: T,
+}
+
+impl<T: 'static> Component for GenericComp<T> {
+ type Storage = VecStorage;
+}
+
+struct GenericComp2<T> {
+ _t: T,
+}
+
+impl<T: 'static> Component for GenericComp2<T> where for<'a> &'a bool: 'a {
+ type Storage = VecStorage;
+}
+
+struct ReadData {
+ pos_interpdata: ReadStorage<GenericComp<Pos>>,
+}
+
+trait System {
+ type SystemData;
+
+ fn run(data: Self::SystemData, any: Box<dyn Any>);
+}
+
+struct Sys;
+
+impl System for Sys {
+ type SystemData = (ReadData, ReadStorage<Pos>);
+
+ fn run((data, pos): Self::SystemData, any: Box<dyn Any>) {
+ <ReadStorage<GenericComp<Pos>> as SystemData>::setup(any);
+
+ ParJoin::par_join((&pos, &data.pos_interpdata));
+ }
+}
+
+trait ParJoin {
+ fn par_join(self)
+ where
+ Self: Sized,
+ {
+ }
+}
+
+impl<'a, T, D> ParJoin for &'a Storage<T, D>
+where
+ T: Component,
+ D: core::ops::Deref<Target = MaskedStorage<T>>,
+ T::Storage: Sync,
+{
+}
+
+impl<A, B> ParJoin for (A, B)
+where
+ A: ParJoin,
+ B: ParJoin,
+{
+}
+
+pub trait SystemData {
+ fn setup(any: Box<dyn Any>);
+}
+
+impl<T: 'static> SystemData for ReadStorage<T>
+where
+ T: Component,
+{
+ fn setup(any: Box<dyn Any>) {
+ let storage: &MaskedStorage<T> = any.downcast_ref().unwrap();
+
+ <dyn Any as CastFrom<MaskedStorage<T>>>::cast(&storage);
+ }
+}
+
+pub struct MaskedStorage<T: Component> {
+ _inner: T::Storage,
+}
+
+pub unsafe trait CastFrom<T> {
+ fn cast(t: &T) -> &Self;
+}
+
+unsafe impl<T> CastFrom<T> for dyn Any
+where
+ T: Any + 'static,
+{
+ fn cast(t: &T) -> &Self {
+ t
+ }
+}
diff --git a/src/test/ui/traits/issue-85360-eval-obligation-ice.stderr b/src/test/ui/traits/issue-85360-eval-obligation-ice.stderr
new file mode 100644
index 00000000000..ebf977dd680
--- /dev/null
+++ b/src/test/ui/traits/issue-85360-eval-obligation-ice.stderr
@@ -0,0 +1,38 @@
+error: evaluate(Binder(TraitPredicate(<MaskedStorage<GenericComp<Pos>> as std::marker::Sized>, polarity:Positive), [])) = Ok(EvaluatedToOk)
+ --> $DIR/issue-85360-eval-obligation-ice.rs:9:5
+ |
+LL | test::<MaskedStorage<GenericComp<Pos>>>(make());
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+...
+LL | fn test<T: Sized>(_: T) {}
+ | - predicate
+
+error: evaluate(Binder(TraitPredicate(<MaskedStorage<GenericComp<Pos>> as std::marker::Sized>, polarity:Positive), [])) = Ok(EvaluatedToOk)
+ --> $DIR/issue-85360-eval-obligation-ice.rs:9:5
+ |
+LL | test::<MaskedStorage<GenericComp<Pos>>>(make());
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+...
+LL | fn test<T: Sized>(_: T) {}
+ | ----- predicate
+
+error: evaluate(Binder(TraitPredicate(<MaskedStorage<GenericComp2<Pos>> as std::marker::Sized>, polarity:Positive), [])) = Ok(EvaluatedToOkModuloRegions)
+ --> $DIR/issue-85360-eval-obligation-ice.rs:13:5
+ |
+LL | test::<MaskedStorage<GenericComp2<Pos>>>(make());
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+...
+LL | fn test<T: Sized>(_: T) {}
+ | - predicate
+
+error: evaluate(Binder(TraitPredicate(<MaskedStorage<GenericComp2<Pos>> as std::marker::Sized>, polarity:Positive), [])) = Ok(EvaluatedToOkModuloRegions)
+ --> $DIR/issue-85360-eval-obligation-ice.rs:13:5
+ |
+LL | test::<MaskedStorage<GenericComp2<Pos>>>(make());
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+...
+LL | fn test<T: Sized>(_: T) {}
+ | ----- predicate
+
+error: aborting due to 4 previous errors
+
diff --git a/src/test/ui/traits/project-modulo-regions.rs b/src/test/ui/traits/project-modulo-regions.rs
new file mode 100644
index 00000000000..f0c0dd3ed95
--- /dev/null
+++ b/src/test/ui/traits/project-modulo-regions.rs
@@ -0,0 +1,55 @@
+// revisions: with_clause without_clause
+// Tests that `EvaluatedToOkModuloRegions` from a projection sub-obligation
+// is correctly propagated
+
+#![feature(rustc_attrs)]
+
+trait MyTrait {
+ type Assoc;
+}
+
+struct MyStruct;
+
+impl MyTrait for MyStruct {
+ // Evaluating this projection will result in `EvaluatedToOkModuloRegions`
+ // (when `with_clause` is enabled)
+ type Assoc = <Bar as MyTrait>::Assoc;
+}
+
+struct Bar;
+
+// The `where` clause on this impl will cause us to produce `EvaluatedToOkModuloRegions`
+// when evaluating a projection involving this impl
+#[cfg(with_clause)]
+impl MyTrait for Bar where for<'b> &'b (): 'b {
+ type Assoc = bool;
+}
+
+// This impl tests that the `EvaluatedToOkModuoRegions` result that we get
+// is really due to the `where` clause on the `with_clause` impl
+#[cfg(without_clause)]
+impl MyTrait for Bar {
+ type Assoc = bool;
+}
+
+// The implementation of `#[rustc_evaluate_where_clauses]` doesn't perform
+// normalization, so we need to place the projection predicate behind a normal
+// trait predicate
+struct Helper {}
+trait HelperTrait {}
+impl HelperTrait for Helper where <MyStruct as MyTrait>::Assoc: Sized {}
+
+// Evaluating this 'where' clause will (recursively) end up evaluating
+// `for<'b> &'b (): 'b`, which will produce `EvaluatedToOkModuloRegions`
+#[rustc_evaluate_where_clauses]
+fn test(val: MyStruct) where Helper: HelperTrait {
+ panic!()
+}
+
+fn foo(val: MyStruct) {
+ test(val);
+ //[with_clause]~^ ERROR evaluate(Binder(TraitPredicate(<Helper as HelperTrait>, polarity:Positive), [])) = Ok(EvaluatedToOkModuloRegions)
+ //[without_clause]~^^ ERROR evaluate(Binder(TraitPredicate(<Helper as HelperTrait>, polarity:Positive), [])) = Ok(EvaluatedToOk)
+}
+
+fn main() {}
diff --git a/src/test/ui/traits/project-modulo-regions.with_clause.stderr b/src/test/ui/traits/project-modulo-regions.with_clause.stderr
new file mode 100644
index 00000000000..2434c32c818
--- /dev/null
+++ b/src/test/ui/traits/project-modulo-regions.with_clause.stderr
@@ -0,0 +1,11 @@
+error: evaluate(Binder(TraitPredicate(<Helper as HelperTrait>, polarity:Positive), [])) = Ok(EvaluatedToOkModuloRegions)
+ --> $DIR/project-modulo-regions.rs:50:5
+ |
+LL | fn test(val: MyStruct) where Helper: HelperTrait {
+ | ----------- predicate
+...
+LL | test(val);
+ | ^^^^
+
+error: aborting due to previous error
+
diff --git a/src/test/ui/traits/project-modulo-regions.without_clause.stderr b/src/test/ui/traits/project-modulo-regions.without_clause.stderr
new file mode 100644
index 00000000000..9d35690d5f0
--- /dev/null
+++ b/src/test/ui/traits/project-modulo-regions.without_clause.stderr
@@ -0,0 +1,11 @@
+error: evaluate(Binder(TraitPredicate(<Helper as HelperTrait>, polarity:Positive), [])) = Ok(EvaluatedToOk)
+ --> $DIR/project-modulo-regions.rs:50:5
+ |
+LL | fn test(val: MyStruct) where Helper: HelperTrait {
+ | ----------- predicate
+...
+LL | test(val);
+ | ^^^^
+
+error: aborting due to previous error
+
diff --git a/src/test/ui/traits/trait-upcasting/type-checking-test-4.rs b/src/test/ui/traits/trait-upcasting/type-checking-test-4.rs
index 9b27fd46f7a..95698fd1e1a 100644
--- a/src/test/ui/traits/trait-upcasting/type-checking-test-4.rs
+++ b/src/test/ui/traits/trait-upcasting/type-checking-test-4.rs
@@ -29,4 +29,22 @@ fn test_wrong3<'a>(x: &dyn Foo<'a>) -> Option<&'static u32> {
y.get_b() // ERROR
}
+fn test_wrong4<'a>(x: &dyn Foo<'a>) -> Option<&'static u32> {
+ <_ as Bar>::get_b(x) // ERROR
+ //~^ ERROR `x` has lifetime `'a` but it needs to satisfy a `'static` lifetime requirement
+}
+
+fn test_wrong5<'a>(x: &dyn Foo<'a>) -> Option<&'static u32> {
+ <_ as Bar<'_, '_>>::get_b(x) // ERROR
+ //~^ ERROR `x` has lifetime `'a` but it needs to satisfy a `'static` lifetime requirement
+}
+
+fn test_wrong6<'a>(x: &dyn Foo<'a>) -> Option<&'static u32> {
+ let y = x as &dyn Bar<'_, '_>;
+ //~^ ERROR `x` has lifetime `'a` but it needs to satisfy a `'static` lifetime requirement
+ y.get_b(); // ERROR
+ let z = y;
+ z.get_b() // ERROR
+}
+
fn main() {}
diff --git a/src/test/ui/traits/trait-upcasting/type-checking-test-4.stderr b/src/test/ui/traits/trait-upcasting/type-checking-test-4.stderr
index 4967f3dc2c8..d4bb9350b0b 100644
--- a/src/test/ui/traits/trait-upcasting/type-checking-test-4.stderr
+++ b/src/test/ui/traits/trait-upcasting/type-checking-test-4.stderr
@@ -36,12 +36,88 @@ LL | fn test_wrong3<'a>(x: &dyn Foo<'a>) -> Option<&'static u32> {
LL | let y = x as &dyn Bar<'_, '_>;
| - ^^
| |
- | ...is captured here...
+ | ...is used here...
LL |
LL | y.get_b() // ERROR
- | --------- ...and is required to live as long as `'static` here
+ | - ...is used here...
+ |
+note: ...and is required to live as long as `'static` here
+ --> $DIR/type-checking-test-4.rs:29:5
+ |
+LL | y.get_b() // ERROR
+ | ^^^^^^^^^
+note: `'static` lifetime requirement introduced by the return type
+ --> $DIR/type-checking-test-4.rs:26:48
+ |
+LL | fn test_wrong3<'a>(x: &dyn Foo<'a>) -> Option<&'static u32> {
+ | ^^^^^^^ `'static` requirement introduced here
+...
+LL | y.get_b() // ERROR
+ | --------- because of this returned expression
+
+error[E0759]: `x` has lifetime `'a` but it needs to satisfy a `'static` lifetime requirement
+ --> $DIR/type-checking-test-4.rs:33:5
+ |
+LL | fn test_wrong4<'a>(x: &dyn Foo<'a>) -> Option<&'static u32> {
+ | ------------ this data with lifetime `'a`...
+LL | <_ as Bar>::get_b(x) // ERROR
+ | ^^^^^^^^^^^^^^^^^ ...is used and required to live as long as `'static` here
+ |
+note: `'static` lifetime requirement introduced by the return type
+ --> $DIR/type-checking-test-4.rs:32:48
+ |
+LL | fn test_wrong4<'a>(x: &dyn Foo<'a>) -> Option<&'static u32> {
+ | ^^^^^^^ `'static` requirement introduced here
+LL | <_ as Bar>::get_b(x) // ERROR
+ | -------------------- because of this returned expression
+
+error[E0759]: `x` has lifetime `'a` but it needs to satisfy a `'static` lifetime requirement
+ --> $DIR/type-checking-test-4.rs:38:15
+ |
+LL | fn test_wrong5<'a>(x: &dyn Foo<'a>) -> Option<&'static u32> {
+ | ------------ this data with lifetime `'a`...
+LL | <_ as Bar<'_, '_>>::get_b(x) // ERROR
+ | ----------^^------------- ...is used and required to live as long as `'static` here
+ |
+note: `'static` lifetime requirement introduced by the return type
+ --> $DIR/type-checking-test-4.rs:37:48
+ |
+LL | fn test_wrong5<'a>(x: &dyn Foo<'a>) -> Option<&'static u32> {
+ | ^^^^^^^ `'static` requirement introduced here
+LL | <_ as Bar<'_, '_>>::get_b(x) // ERROR
+ | ---------------------------- because of this returned expression
+
+error[E0759]: `x` has lifetime `'a` but it needs to satisfy a `'static` lifetime requirement
+ --> $DIR/type-checking-test-4.rs:43:27
+ |
+LL | fn test_wrong6<'a>(x: &dyn Foo<'a>) -> Option<&'static u32> {
+ | ------------ this data with lifetime `'a`...
+LL | let y = x as &dyn Bar<'_, '_>;
+ | - ^^
+ | |
+ | ...is used here...
+LL |
+LL | y.get_b(); // ERROR
+ | - ...is used here...
+LL | let z = y;
+LL | z.get_b() // ERROR
+ | - ...is used here...
+ |
+note: ...and is required to live as long as `'static` here
+ --> $DIR/type-checking-test-4.rs:47:5
+ |
+LL | z.get_b() // ERROR
+ | ^^^^^^^^^
+note: `'static` lifetime requirement introduced by the return type
+ --> $DIR/type-checking-test-4.rs:42:48
+ |
+LL | fn test_wrong6<'a>(x: &dyn Foo<'a>) -> Option<&'static u32> {
+ | ^^^^^^^ `'static` requirement introduced here
+...
+LL | z.get_b() // ERROR
+ | --------- because of this returned expression
-error: aborting due to 3 previous errors
+error: aborting due to 6 previous errors
Some errors have detailed explanations: E0308, E0759.
For more information about an error, try `rustc --explain E0308`.
diff --git a/src/test/ui/traits/vtable/issue-91807.rs b/src/test/ui/traits/vtable/issue-91807.rs
new file mode 100644
index 00000000000..f435ff09dc3
--- /dev/null
+++ b/src/test/ui/traits/vtable/issue-91807.rs
@@ -0,0 +1,17 @@
+// check-pass
+// incremental
+
+struct Struct<T>(T);
+
+impl<T> std::ops::Deref for Struct<T> {
+ type Target = dyn Fn(T);
+ fn deref(&self) -> &Self::Target {
+ unimplemented!()
+ }
+}
+
+fn main() {
+ let f = Struct(Default::default());
+ f(0);
+ f(0);
+}
diff --git a/src/test/ui/try-block/try-block-maybe-bad-lifetime.stderr b/src/test/ui/try-block/try-block-maybe-bad-lifetime.stderr
index c092aa26946..d6822d94ca8 100644
--- a/src/test/ui/try-block/try-block-maybe-bad-lifetime.stderr
+++ b/src/test/ui/try-block/try-block-maybe-bad-lifetime.stderr
@@ -21,6 +21,8 @@ LL | ::std::mem::drop(x);
LL | };
LL | println!("{}", x);
| ^ value borrowed here after move
+ |
+ = note: this error originates in the macro `$crate::format_args_nl` (in Nightly builds, run with -Z macro-backtrace for more info)
error[E0506]: cannot assign to `i` because it is borrowed
--> $DIR/try-block-maybe-bad-lifetime.rs:40:9
diff --git a/src/test/ui/type-alias-impl-trait/argument-types.stderr b/src/test/ui/type-alias-impl-trait/argument-types.stderr
index 1cbf9c95d31..a87e44a048b 100644
--- a/src/test/ui/type-alias-impl-trait/argument-types.stderr
+++ b/src/test/ui/type-alias-impl-trait/argument-types.stderr
@@ -4,6 +4,8 @@ error[E0308]: mismatched types
LL | type Foo = impl Debug;
| ---------- the expected opaque type
...
+LL | fn foo1(mut x: Foo) {
+ | --- expected due to this parameter type
LL | x = 22_u32;
| ^^^^^^ expected opaque type, found `u32`
|
diff --git a/src/test/ui/type-alias-impl-trait/issue-63355.stderr b/src/test/ui/type-alias-impl-trait/issue-63355.stderr
index dc5370a2666..6fc6b4bfe1f 100644
--- a/src/test/ui/type-alias-impl-trait/issue-63355.stderr
+++ b/src/test/ui/type-alias-impl-trait/issue-63355.stderr
@@ -4,8 +4,13 @@ error[E0271]: type mismatch resolving `<() as Bar>::Foo == ()`
LL | pub type FooImpl = impl Foo;
| -------- the found opaque type
LL | pub type BarImpl = impl Bar<Foo = FooImpl>;
- | ^^^^^^^^^^^^^^^^^^^^^^^ expected `()`, found opaque type
+ | ^^^^^^^^^^^^^^^^^^^^^^^ type mismatch resolving `<() as Bar>::Foo == ()`
|
+note: expected this to be `()`
+ --> $DIR/issue-63355.rs:24:16
+ |
+LL | type Foo = FooImpl;
+ | ^^^^^^^
= note: expected unit type `()`
found opaque type `impl Foo`
diff --git a/src/test/ui/type-alias-impl-trait/issue-89686.rs b/src/test/ui/type-alias-impl-trait/issue-89686.rs
index 2b6ce49e7e2..5878b26fddb 100644
--- a/src/test/ui/type-alias-impl-trait/issue-89686.rs
+++ b/src/test/ui/type-alias-impl-trait/issue-89686.rs
@@ -5,7 +5,7 @@
use std::future::Future;
type G<'a, T> = impl Future<Output = ()>;
-//~^ ERROR: type mismatch resolving `<impl Future as Future>::Output == ()`
+//~^ ERROR: type mismatch resolving `<impl Future<Output = [async output]> as Future>::Output == ()`
//~| ERROR: the trait bound `T: Trait` is not satisfied
trait Trait {
diff --git a/src/test/ui/type-alias-impl-trait/issue-89686.stderr b/src/test/ui/type-alias-impl-trait/issue-89686.stderr
index accc84d30a7..19ed9a7476c 100644
--- a/src/test/ui/type-alias-impl-trait/issue-89686.stderr
+++ b/src/test/ui/type-alias-impl-trait/issue-89686.stderr
@@ -1,4 +1,4 @@
-error[E0271]: type mismatch resolving `<impl Future as Future>::Output == ()`
+error[E0271]: type mismatch resolving `<impl Future<Output = [async output]> as Future>::Output == ()`
--> $DIR/issue-89686.rs:7:17
|
LL | type G<'a, T> = impl Future<Output = ()>;
@@ -13,8 +13,8 @@ LL | pub const fn from_generator<T>(gen: T) -> impl Future<Output = T::Return>
| ------------------------------- the found opaque type
|
= note: expected unit type `()`
- found associated type `<impl Future as Future>::Output`
- = help: consider constraining the associated type `<impl Future as Future>::Output` to `()`
+ found associated type `<impl Future<Output = [async output]> as Future>::Output`
+ = help: consider constraining the associated type `<impl Future<Output = [async output]> as Future>::Output` to `()`
= note: for more information, visit https://doc.rust-lang.org/book/ch19-03-advanced-traits.html
error[E0277]: the trait bound `T: Trait` is not satisfied
diff --git a/src/test/ui/type-alias-impl-trait/static-const-types.rs b/src/test/ui/type-alias-impl-trait/static-const-types.rs
index f630d278335..86b685022b2 100644
--- a/src/test/ui/type-alias-impl-trait/static-const-types.rs
+++ b/src/test/ui/type-alias-impl-trait/static-const-types.rs
@@ -5,12 +5,9 @@
use std::fmt::Debug;
-type Foo = impl Debug;
-//~^ ERROR: could not find defining uses
+type Foo = impl Debug; //~ ERROR could not find defining uses
-static FOO1: Foo = 22_u32;
-//~^ ERROR: mismatched types [E0308]
-const FOO2: Foo = 22_u32;
-//~^ ERROR: mismatched types [E0308]
+static FOO1: Foo = 22_u32; //~ ERROR mismatched types
+const FOO2: Foo = 22_u32; //~ ERROR mismatched types
fn main() {}
diff --git a/src/test/ui/type-alias-impl-trait/static-const-types.stderr b/src/test/ui/type-alias-impl-trait/static-const-types.stderr
index 72083d014fe..6f4c2944f72 100644
--- a/src/test/ui/type-alias-impl-trait/static-const-types.stderr
+++ b/src/test/ui/type-alias-impl-trait/static-const-types.stderr
@@ -1,9 +1,9 @@
error[E0308]: mismatched types
- --> $DIR/static-const-types.rs:11:20
+ --> $DIR/static-const-types.rs:10:20
|
LL | type Foo = impl Debug;
| ---------- the expected opaque type
-...
+LL |
LL | static FOO1: Foo = 22_u32;
| ^^^^^^ expected opaque type, found `u32`
|
@@ -11,7 +11,7 @@ LL | static FOO1: Foo = 22_u32;
found type `u32`
error[E0308]: mismatched types
- --> $DIR/static-const-types.rs:13:19
+ --> $DIR/static-const-types.rs:11:19
|
LL | type Foo = impl Debug;
| ---------- the expected opaque type
diff --git a/src/test/ui/type/issue-91268.rs b/src/test/ui/type/issue-91268.rs
new file mode 100644
index 00000000000..fd2733c1c54
--- /dev/null
+++ b/src/test/ui/type/issue-91268.rs
@@ -0,0 +1,9 @@
+// error-pattern: this file contains an unclosed delimiter
+// error-pattern: cannot find type `ţ` in this scope
+// error-pattern: parenthesized type parameters may only be used with a `Fn` trait
+// error-pattern: type arguments are not allowed for this type
+// error-pattern: mismatched types
+// ignore-tidy-trailing-newlines
+// `ţ` must be the last character in this file, it cannot be followed by a newline
+fn main() {
+ 0: u8(ţ \ No newline at end of file
diff --git a/src/test/ui/type/issue-91268.stderr b/src/test/ui/type/issue-91268.stderr
new file mode 100644
index 00000000000..2fe6ba6248c
--- /dev/null
+++ b/src/test/ui/type/issue-91268.stderr
@@ -0,0 +1,50 @@
+error: this file contains an unclosed delimiter
+ --> $DIR/issue-91268.rs:9:12
+ |
+LL | fn main() {
+ | - unclosed delimiter
+LL | 0: u8(ţ
+ | - ^
+ | |
+ | unclosed delimiter
+
+error: this file contains an unclosed delimiter
+ --> $DIR/issue-91268.rs:9:12
+ |
+LL | fn main() {
+ | - unclosed delimiter
+LL | 0: u8(ţ
+ | - ^
+ | |
+ | unclosed delimiter
+
+error[E0412]: cannot find type `ţ` in this scope
+ --> $DIR/issue-91268.rs:9:11
+ |
+LL | 0: u8(ţ
+ | ^ expecting a type here because of type ascription
+
+error[E0214]: parenthesized type parameters may only be used with a `Fn` trait
+ --> $DIR/issue-91268.rs:9:8
+ |
+LL | 0: u8(ţ
+ | ^^^^ only `Fn` traits may use parentheses
+
+error[E0109]: type arguments are not allowed for this type
+ --> $DIR/issue-91268.rs:9:11
+ |
+LL | 0: u8(ţ
+ | ^ type argument not allowed
+
+error[E0308]: mismatched types
+ --> $DIR/issue-91268.rs:9:5
+ |
+LL | fn main() {
+ | - expected `()` because of default return type
+LL | 0: u8(ţ
+ | ^^^^^^^ expected `()`, found `u8`
+
+error: aborting due to 6 previous errors
+
+Some errors have detailed explanations: E0109, E0214, E0308, E0412.
+For more information about an error, try `rustc --explain E0109`.
diff --git a/src/test/ui/type/type-annotation-needed.rs b/src/test/ui/type/type-annotation-needed.rs
index 999486018a3..347887f4bcf 100644
--- a/src/test/ui/type/type-annotation-needed.rs
+++ b/src/test/ui/type/type-annotation-needed.rs
@@ -1,6 +1,7 @@
fn foo<T: Into<String>>(x: i32) {}
//~^ NOTE required by
//~| NOTE required by
+
fn main() {
foo(42);
//~^ ERROR type annotations needed
diff --git a/src/test/ui/type/type-annotation-needed.stderr b/src/test/ui/type/type-annotation-needed.stderr
index 20cae3eb24c..f7dfb845238 100644
--- a/src/test/ui/type/type-annotation-needed.stderr
+++ b/src/test/ui/type/type-annotation-needed.stderr
@@ -1,5 +1,5 @@
error[E0283]: type annotations needed
- --> $DIR/type-annotation-needed.rs:5:5
+ --> $DIR/type-annotation-needed.rs:6:5
|
LL | foo(42);
| ^^^ cannot infer type for type parameter `T` declared on the function `foo`
diff --git a/src/test/ui/type/type-check/assignment-expected-bool.stderr b/src/test/ui/type/type-check/assignment-expected-bool.stderr
index 862ac65bc24..e2b821f7b05 100644
--- a/src/test/ui/type/type-check/assignment-expected-bool.stderr
+++ b/src/test/ui/type/type-check/assignment-expected-bool.stderr
@@ -48,10 +48,6 @@ error[E0308]: mismatched types
LL | if 0 = 0 {}
| ^^^^^ expected `bool`, found `()`
|
-help: you might have meant to use pattern matching
- |
-LL | if let 0 = 0 {}
- | +++
help: you might have meant to compare for equality
|
LL | if 0 == 0 {}
diff --git a/src/test/ui/type/type-check/assignment-in-if.stderr b/src/test/ui/type/type-check/assignment-in-if.stderr
index 710be9d6a04..f4ef44e2444 100644
--- a/src/test/ui/type/type-check/assignment-in-if.stderr
+++ b/src/test/ui/type/type-check/assignment-in-if.stderr
@@ -37,10 +37,6 @@ error[E0308]: mismatched types
LL | if 3 = x {
| ^^^^^ expected `bool`, found `()`
|
-help: you might have meant to use pattern matching
- |
-LL | if let 3 = x {
- | +++
help: you might have meant to compare for equality
|
LL | if 3 == x {
diff --git a/src/test/ui/typeck/issue-57673-ice-on-deref-of-boxed-trait.stderr b/src/test/ui/typeck/issue-57673-ice-on-deref-of-boxed-trait.stderr
index b4d7dfe06be..b92a6f2ec2b 100644
--- a/src/test/ui/typeck/issue-57673-ice-on-deref-of-boxed-trait.stderr
+++ b/src/test/ui/typeck/issue-57673-ice-on-deref-of-boxed-trait.stderr
@@ -2,7 +2,7 @@ error[E0308]: mismatched types
--> $DIR/issue-57673-ice-on-deref-of-boxed-trait.rs:5:5
|
LL | fn ice(x: Box<dyn Iterator<Item=()>>) {
- | - possibly return type missing here?
+ | - help: try adding a return type: `-> (dyn Iterator<Item = ()> + 'static)`
LL | *x
| ^^ expected `()`, found trait object `dyn Iterator`
|
diff --git a/src/test/ui/typeck/issue-81293.stderr b/src/test/ui/typeck/issue-81293.stderr
index 1e6ff3b5f9e..c545a563b0d 100644
--- a/src/test/ui/typeck/issue-81293.stderr
+++ b/src/test/ui/typeck/issue-81293.stderr
@@ -7,6 +7,9 @@ LL | a = c + b * 5;
error[E0308]: mismatched types
--> $DIR/issue-81293.rs:6:9
|
+LL | let a: u16;
+ | --- expected due to this type
+...
LL | a = c + b * 5;
| ^^^^^^^^^ expected `u16`, found `usize`
diff --git a/src/test/ui/typeck/issue-87771-ice-assign-assign-to-bool.stderr b/src/test/ui/typeck/issue-87771-ice-assign-assign-to-bool.stderr
index fe10fa733d2..56817ee2ca9 100644
--- a/src/test/ui/typeck/issue-87771-ice-assign-assign-to-bool.stderr
+++ b/src/test/ui/typeck/issue-87771-ice-assign-assign-to-bool.stderr
@@ -1,6 +1,8 @@
error[E0308]: mismatched types
--> $DIR/issue-87771-ice-assign-assign-to-bool.rs:3:9
|
+LL | let mut a;
+ | ----- expected due to the type of this binding
LL | a = a = true;
| ^^^^^^^^ expected `bool`, found `()`
diff --git a/src/test/ui/typeck/issue-91210-ptr-method.fixed b/src/test/ui/typeck/issue-91210-ptr-method.fixed
new file mode 100644
index 00000000000..94200cce73e
--- /dev/null
+++ b/src/test/ui/typeck/issue-91210-ptr-method.fixed
@@ -0,0 +1,15 @@
+// Regression test for issue #91210.
+
+// run-rustfix
+
+#![allow(unused)]
+
+struct Foo { read: i32 }
+
+unsafe fn blah(x: *mut Foo) {
+ (*x).read = 4;
+ //~^ ERROR: attempted to take value of method
+ //~| HELP: to access the field, dereference first
+}
+
+fn main() {}
diff --git a/src/test/ui/typeck/issue-91210-ptr-method.rs b/src/test/ui/typeck/issue-91210-ptr-method.rs
new file mode 100644
index 00000000000..ed0ce6effe7
--- /dev/null
+++ b/src/test/ui/typeck/issue-91210-ptr-method.rs
@@ -0,0 +1,15 @@
+// Regression test for issue #91210.
+
+// run-rustfix
+
+#![allow(unused)]
+
+struct Foo { read: i32 }
+
+unsafe fn blah(x: *mut Foo) {
+ x.read = 4;
+ //~^ ERROR: attempted to take value of method
+ //~| HELP: to access the field, dereference first
+}
+
+fn main() {}
diff --git a/src/test/ui/typeck/issue-91210-ptr-method.stderr b/src/test/ui/typeck/issue-91210-ptr-method.stderr
new file mode 100644
index 00000000000..503a32373d5
--- /dev/null
+++ b/src/test/ui/typeck/issue-91210-ptr-method.stderr
@@ -0,0 +1,11 @@
+error[E0615]: attempted to take value of method `read` on type `*mut Foo`
+ --> $DIR/issue-91210-ptr-method.rs:10:7
+ |
+LL | x.read = 4;
+ | - ^^^^ method, not a field
+ | |
+ | help: to access the field, dereference first: `(*x)`
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0615`.
diff --git a/src/test/ui/typeck/issue-91267.rs b/src/test/ui/typeck/issue-91267.rs
new file mode 100644
index 00000000000..f5a37e9cb86
--- /dev/null
+++ b/src/test/ui/typeck/issue-91267.rs
@@ -0,0 +1,6 @@
+fn main() {
+ 0: u8<e<5>=e>
+ //~^ ERROR: cannot find type `e` in this scope [E0412]
+ //~| ERROR: associated type bindings are not allowed here [E0229]
+ //~| ERROR: mismatched types [E0308]
+}
diff --git a/src/test/ui/typeck/issue-91267.stderr b/src/test/ui/typeck/issue-91267.stderr
new file mode 100644
index 00000000000..aac00b9b6a9
--- /dev/null
+++ b/src/test/ui/typeck/issue-91267.stderr
@@ -0,0 +1,27 @@
+error[E0412]: cannot find type `e` in this scope
+ --> $DIR/issue-91267.rs:2:16
+ |
+LL | 0: u8<e<5>=e>
+ | ^
+ | |
+ | not found in this scope
+ | help: maybe you meant to write an assignment here: `let e`
+
+error[E0229]: associated type bindings are not allowed here
+ --> $DIR/issue-91267.rs:2:11
+ |
+LL | 0: u8<e<5>=e>
+ | ^^^^^^ associated type not allowed here
+
+error[E0308]: mismatched types
+ --> $DIR/issue-91267.rs:2:5
+ |
+LL | fn main() {
+ | - expected `()` because of default return type
+LL | 0: u8<e<5>=e>
+ | ^^^^^^^^^^^^^ expected `()`, found `u8`
+
+error: aborting due to 3 previous errors
+
+Some errors have detailed explanations: E0229, E0308, E0412.
+For more information about an error, try `rustc --explain E0229`.
diff --git a/src/test/ui/typeck/issue-91334.rs b/src/test/ui/typeck/issue-91334.rs
new file mode 100644
index 00000000000..bf9a5a62620
--- /dev/null
+++ b/src/test/ui/typeck/issue-91334.rs
@@ -0,0 +1,10 @@
+// Regression test for the ICE described in issue #91334.
+
+// error-pattern: this file contains an unclosed delimiter
+// error-pattern: expected one of
+// error-pattern: mismatched closing delimiter
+// error-pattern: mismatched types
+
+#![feature(generators)]
+
+fn f(){||yield(((){),
diff --git a/src/test/ui/typeck/issue-91334.stderr b/src/test/ui/typeck/issue-91334.stderr
new file mode 100644
index 00000000000..0872e83ea2e
--- /dev/null
+++ b/src/test/ui/typeck/issue-91334.stderr
@@ -0,0 +1,50 @@
+error: this file contains an unclosed delimiter
+ --> $DIR/issue-91334.rs:10:23
+ |
+LL | fn f(){||yield(((){),
+ | - - ^
+ | | |
+ | | unclosed delimiter
+ | unclosed delimiter
+
+error: this file contains an unclosed delimiter
+ --> $DIR/issue-91334.rs:10:23
+ |
+LL | fn f(){||yield(((){),
+ | - - ^
+ | | |
+ | | unclosed delimiter
+ | unclosed delimiter
+
+error: expected one of `)`, `,`, `.`, `?`, or an operator, found `{`
+ --> $DIR/issue-91334.rs:10:19
+ |
+LL | fn f(){||yield(((){),
+ | ^
+ | |
+ | expected one of `)`, `,`, `.`, `?`, or an operator
+ | help: missing `,`
+
+error: mismatched closing delimiter: `)`
+ --> $DIR/issue-91334.rs:10:19
+ |
+LL | fn f(){||yield(((){),
+ | - ^^ mismatched closing delimiter
+ | | |
+ | | unclosed delimiter
+ | closing delimiter possibly meant for this
+
+error[E0308]: mismatched types
+ --> $DIR/issue-91334.rs:10:8
+ |
+LL | fn f(){||yield(((){),
+ | -^^^^^^^^^^^^^^^ expected `()`, found generator
+ | |
+ | possibly return type missing here?
+ |
+ = note: expected unit type `()`
+ found generator `[generator@$DIR/issue-91334.rs:10:8: 10:23]`
+
+error: aborting due to 5 previous errors
+
+For more information about this error, try `rustc --explain E0308`.
diff --git a/src/test/ui/typeck/issue-91450-inner-ty-error.rs b/src/test/ui/typeck/issue-91450-inner-ty-error.rs
new file mode 100644
index 00000000000..0b942d6d94f
--- /dev/null
+++ b/src/test/ui/typeck/issue-91450-inner-ty-error.rs
@@ -0,0 +1,7 @@
+// Regression test for #91450.
+// This test ensures that the compiler does not suggest `Foo<[type error]>` in diagnostic messages.
+
+fn foo() -> Option<_> {} //~ ERROR: [E0308]
+//~^ ERROR: the type placeholder `_` is not allowed
+
+fn main() {}
diff --git a/src/test/ui/typeck/issue-91450-inner-ty-error.stderr b/src/test/ui/typeck/issue-91450-inner-ty-error.stderr
new file mode 100644
index 00000000000..314fe561803
--- /dev/null
+++ b/src/test/ui/typeck/issue-91450-inner-ty-error.stderr
@@ -0,0 +1,21 @@
+error[E0308]: mismatched types
+ --> $DIR/issue-91450-inner-ty-error.rs:4:13
+ |
+LL | fn foo() -> Option<_> {}
+ | --- ^^^^^^^^^ expected enum `Option`, found `()`
+ | |
+ | implicitly returns `()` as its body has no tail or `return` expression
+ |
+ = note: expected enum `Option<_>`
+ found unit type `()`
+
+error[E0121]: the type placeholder `_` is not allowed within types on item signatures for return types
+ --> $DIR/issue-91450-inner-ty-error.rs:4:20
+ |
+LL | fn foo() -> Option<_> {}
+ | ^ not allowed in type signatures
+
+error: aborting due to 2 previous errors
+
+Some errors have detailed explanations: E0121, E0308.
+For more information about an error, try `rustc --explain E0121`.
diff --git a/src/test/ui/typeck/return_type_containing_closure.rs b/src/test/ui/typeck/return_type_containing_closure.rs
new file mode 100644
index 00000000000..aee9769b280
--- /dev/null
+++ b/src/test/ui/typeck/return_type_containing_closure.rs
@@ -0,0 +1,10 @@
+#[allow(unused)]
+fn foo() {
+ //~^ NOTE possibly return type missing here?
+ vec!['a'].iter().map(|c| c)
+ //~^ ERROR mismatched types [E0308]
+ //~| NOTE expected `()`, found struct `Map`
+ //~| NOTE expected unit type `()`
+}
+
+fn main() {}
diff --git a/src/test/ui/typeck/return_type_containing_closure.stderr b/src/test/ui/typeck/return_type_containing_closure.stderr
new file mode 100644
index 00000000000..b08152d6331
--- /dev/null
+++ b/src/test/ui/typeck/return_type_containing_closure.stderr
@@ -0,0 +1,17 @@
+error[E0308]: mismatched types
+ --> $DIR/return_type_containing_closure.rs:4:5
+ |
+LL | fn foo() {
+ | - possibly return type missing here?
+LL |
+LL | vec!['a'].iter().map(|c| c)
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^- help: consider using a semicolon here: `;`
+ | |
+ | expected `()`, found struct `Map`
+ |
+ = note: expected unit type `()`
+ found struct `Map<std::slice::Iter<'_, char>, [closure@$DIR/return_type_containing_closure.rs:4:26: 4:31]>`
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0308`.
diff --git a/src/test/ui/underscore-lifetime/dyn-trait-underscore.stderr b/src/test/ui/underscore-lifetime/dyn-trait-underscore.stderr
index de3a6bbae17..f4285a0f98e 100644
--- a/src/test/ui/underscore-lifetime/dyn-trait-underscore.stderr
+++ b/src/test/ui/underscore-lifetime/dyn-trait-underscore.stderr
@@ -5,8 +5,18 @@ LL | fn a<T>(items: &[T]) -> Box<dyn Iterator<Item=&T>> {
| ---- this data with an anonymous lifetime `'_`...
LL | // ^^^^^^^^^^^^^^^^^^^^^ bound *here* defaults to `'static`
LL | Box::new(items.iter())
- | ---------------^^^^--- ...is captured and required to live as long as `'static` here
+ | ----- ^^^^
+ | |
+ | ...is used and required to live as long as `'static` here
|
+note: `'static` lifetime requirement introduced by the return type
+ --> $DIR/dyn-trait-underscore.rs:6:29
+ |
+LL | fn a<T>(items: &[T]) -> Box<dyn Iterator<Item=&T>> {
+ | ^^^^^^^^^^^^^^^^^^^^^ `'static` requirement introduced here
+LL | // ^^^^^^^^^^^^^^^^^^^^^ bound *here* defaults to `'static`
+LL | Box::new(items.iter())
+ | ---------------------- because of this returned expression
help: to declare that the trait object captures data from argument `items`, you can add an explicit `'_` lifetime bound
|
LL | fn a<T>(items: &[T]) -> Box<dyn Iterator<Item=&T> + '_> {
diff --git a/src/test/ui/union/issue-81199.rs b/src/test/ui/union/issue-81199.rs
new file mode 100644
index 00000000000..628e7c6ed5d
--- /dev/null
+++ b/src/test/ui/union/issue-81199.rs
@@ -0,0 +1,21 @@
+#[repr(C)]
+union PtrRepr<T: ?Sized> {
+ const_ptr: *const T,
+ mut_ptr: *mut T,
+ components: PtrComponents<T>,
+ //~^ ERROR the trait bound
+}
+
+#[repr(C)]
+struct PtrComponents<T: Pointee + ?Sized> {
+ data_address: *const (),
+ metadata: <T as Pointee>::Metadata,
+}
+
+
+
+pub trait Pointee {
+ type Metadata;
+}
+
+fn main() {}
diff --git a/src/test/ui/union/issue-81199.stderr b/src/test/ui/union/issue-81199.stderr
new file mode 100644
index 00000000000..f26bfe3a0b0
--- /dev/null
+++ b/src/test/ui/union/issue-81199.stderr
@@ -0,0 +1,29 @@
+error[E0277]: the trait bound `T: Pointee` is not satisfied in `PtrComponents<T>`
+ --> $DIR/issue-81199.rs:5:17
+ |
+LL | components: PtrComponents<T>,
+ | ^^^^^^^^^^^^^^^^ within `PtrComponents<T>`, the trait `Pointee` is not implemented for `T`
+ |
+note: required because it appears within the type `PtrComponents<T>`
+ --> $DIR/issue-81199.rs:10:8
+ |
+LL | struct PtrComponents<T: Pointee + ?Sized> {
+ | ^^^^^^^^^^^^^
+ = note: no field of a union may have a dynamically sized type
+ = help: change the field's type to have a statically known size
+help: consider further restricting this bound
+ |
+LL | union PtrRepr<T: ?Sized + Pointee> {
+ | +++++++++
+help: borrowed types always have a statically known size
+ |
+LL | components: &PtrComponents<T>,
+ | +
+help: the `Box` type always has a statically known size and allocates its contents in the heap
+ |
+LL | components: Box<PtrComponents<T>>,
+ | ++++ +
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0277`.
diff --git a/src/test/ui/unsafe/inline_asm.mir.stderr b/src/test/ui/unsafe/inline_asm.mir.stderr
index 865d5cc61ca..fee93dc070d 100644
--- a/src/test/ui/unsafe/inline_asm.mir.stderr
+++ b/src/test/ui/unsafe/inline_asm.mir.stderr
@@ -1,5 +1,5 @@
error[E0133]: use of inline assembly is unsafe and requires unsafe function or block
- --> $DIR/inline_asm.rs:10:5
+ --> $DIR/inline_asm.rs:11:5
|
LL | asm!("nop");
| ^^^^^^^^^^^ use of inline assembly
@@ -7,7 +7,7 @@ LL | asm!("nop");
= note: inline assembly is entirely unchecked and can cause undefined behavior
error[E0133]: use of inline assembly is unsafe and requires unsafe function or block
- --> $DIR/inline_asm.rs:11:5
+ --> $DIR/inline_asm.rs:12:5
|
LL | llvm_asm!("nop");
| ^^^^^^^^^^^^^^^^ use of inline assembly
diff --git a/src/test/ui/unsafe/inline_asm.rs b/src/test/ui/unsafe/inline_asm.rs
index 8e1325bc0a8..7c1f86ac0e0 100644
--- a/src/test/ui/unsafe/inline_asm.rs
+++ b/src/test/ui/unsafe/inline_asm.rs
@@ -3,9 +3,10 @@
// needs-asm-support
#![feature(llvm_asm)]
-#![feature(asm)]
#![allow(deprecated)] // llvm_asm!
+use std::arch::asm;
+
fn main() {
asm!("nop"); //~ ERROR use of inline assembly is unsafe and requires unsafe function or block
llvm_asm!("nop"); //~ ERROR use of inline assembly is unsafe and requires unsafe function or block
diff --git a/src/test/ui/unsafe/inline_asm.thir.stderr b/src/test/ui/unsafe/inline_asm.thir.stderr
index 865d5cc61ca..fee93dc070d 100644
--- a/src/test/ui/unsafe/inline_asm.thir.stderr
+++ b/src/test/ui/unsafe/inline_asm.thir.stderr
@@ -1,5 +1,5 @@
error[E0133]: use of inline assembly is unsafe and requires unsafe function or block
- --> $DIR/inline_asm.rs:10:5
+ --> $DIR/inline_asm.rs:11:5
|
LL | asm!("nop");
| ^^^^^^^^^^^ use of inline assembly
@@ -7,7 +7,7 @@ LL | asm!("nop");
= note: inline assembly is entirely unchecked and can cause undefined behavior
error[E0133]: use of inline assembly is unsafe and requires unsafe function or block
- --> $DIR/inline_asm.rs:11:5
+ --> $DIR/inline_asm.rs:12:5
|
LL | llvm_asm!("nop");
| ^^^^^^^^^^^^^^^^ use of inline assembly
diff --git a/src/test/ui/unsafe/unsafe-trait-impl.stderr b/src/test/ui/unsafe/unsafe-trait-impl.stderr
index 1c3d057cbc9..8a0cba1fac5 100644
--- a/src/test/ui/unsafe/unsafe-trait-impl.stderr
+++ b/src/test/ui/unsafe/unsafe-trait-impl.stderr
@@ -1,12 +1,14 @@
error[E0053]: method `len` has an incompatible type for trait
--> $DIR/unsafe-trait-impl.rs:8:5
|
-LL | unsafe fn len(&self) -> u32;
- | ---------------------------- type in trait
-...
LL | fn len(&self) -> u32 { *self }
| ^^^^^^^^^^^^^^^^^^^^ expected unsafe fn, found normal fn
|
+note: type in trait
+ --> $DIR/unsafe-trait-impl.rs:4:5
+ |
+LL | unsafe fn len(&self) -> u32;
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
= note: expected fn pointer `unsafe fn(&u32) -> _`
found fn pointer `fn(&u32) -> _`
diff --git a/src/test/ui/unspecified-self-in-trait-ref.rs b/src/test/ui/unspecified-self-in-trait-ref.rs
index 74a9af84cae..158b5a98557 100644
--- a/src/test/ui/unspecified-self-in-trait-ref.rs
+++ b/src/test/ui/unspecified-self-in-trait-ref.rs
@@ -9,12 +9,22 @@ pub trait Bar<X=usize, A=Self> {
fn main() {
let a = Foo::lol();
//~^ ERROR no function or associated item named
+ //~| WARN trait objects without an explicit `dyn` are deprecated
+ //~| WARN this is accepted in the current edition
let b = Foo::<_>::lol();
//~^ ERROR no function or associated item named
+ //~| WARN trait objects without an explicit `dyn` are deprecated
+ //~| WARN this is accepted in the current edition
let c = Bar::lol();
//~^ ERROR no function or associated item named
+ //~| WARN trait objects without an explicit `dyn` are deprecated
+ //~| WARN this is accepted in the current edition
let d = Bar::<usize, _>::lol();
//~^ ERROR no function or associated item named
+ //~| WARN trait objects without an explicit `dyn` are deprecated
+ //~| WARN this is accepted in the current edition
let e = Bar::<usize>::lol();
//~^ ERROR must be explicitly specified
+ //~| WARN trait objects without an explicit `dyn` are deprecated
+ //~| WARN this is accepted in the current edition
}
diff --git a/src/test/ui/unspecified-self-in-trait-ref.stderr b/src/test/ui/unspecified-self-in-trait-ref.stderr
index c9518170222..2ba92187157 100644
--- a/src/test/ui/unspecified-self-in-trait-ref.stderr
+++ b/src/test/ui/unspecified-self-in-trait-ref.stderr
@@ -1,29 +1,95 @@
+warning: trait objects without an explicit `dyn` are deprecated
+ --> $DIR/unspecified-self-in-trait-ref.rs:10:13
+ |
+LL | let a = Foo::lol();
+ | ^^^
+ |
+ = note: `#[warn(bare_trait_objects)]` on by default
+ = warning: this is accepted in the current edition (Rust 2015) but is a hard error in Rust 2021!
+ = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2021/warnings-promoted-to-error.html>
+help: use `dyn`
+ |
+LL | let a = <dyn Foo>::lol();
+ | ++++ +
+
error[E0599]: no function or associated item named `lol` found for trait object `dyn Foo<_>` in the current scope
--> $DIR/unspecified-self-in-trait-ref.rs:10:18
|
LL | let a = Foo::lol();
| ^^^ function or associated item not found in `dyn Foo<_>`
+warning: trait objects without an explicit `dyn` are deprecated
+ --> $DIR/unspecified-self-in-trait-ref.rs:14:13
+ |
+LL | let b = Foo::<_>::lol();
+ | ^^^^^^^^
+ |
+ = warning: this is accepted in the current edition (Rust 2015) but is a hard error in Rust 2021!
+ = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2021/warnings-promoted-to-error.html>
+help: use `dyn`
+ |
+LL | let b = <dyn Foo::<_>>::lol();
+ | ++++ +
+
error[E0599]: no function or associated item named `lol` found for trait object `dyn Foo<_>` in the current scope
- --> $DIR/unspecified-self-in-trait-ref.rs:12:23
+ --> $DIR/unspecified-self-in-trait-ref.rs:14:23
|
LL | let b = Foo::<_>::lol();
| ^^^ function or associated item not found in `dyn Foo<_>`
+warning: trait objects without an explicit `dyn` are deprecated
+ --> $DIR/unspecified-self-in-trait-ref.rs:18:13
+ |
+LL | let c = Bar::lol();
+ | ^^^
+ |
+ = warning: this is accepted in the current edition (Rust 2015) but is a hard error in Rust 2021!
+ = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2021/warnings-promoted-to-error.html>
+help: use `dyn`
+ |
+LL | let c = <dyn Bar>::lol();
+ | ++++ +
+
error[E0599]: no function or associated item named `lol` found for trait object `dyn Bar<_, _>` in the current scope
- --> $DIR/unspecified-self-in-trait-ref.rs:14:18
+ --> $DIR/unspecified-self-in-trait-ref.rs:18:18
|
LL | let c = Bar::lol();
| ^^^ function or associated item not found in `dyn Bar<_, _>`
+warning: trait objects without an explicit `dyn` are deprecated
+ --> $DIR/unspecified-self-in-trait-ref.rs:22:13
+ |
+LL | let d = Bar::<usize, _>::lol();
+ | ^^^^^^^^^^^^^^^
+ |
+ = warning: this is accepted in the current edition (Rust 2015) but is a hard error in Rust 2021!
+ = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2021/warnings-promoted-to-error.html>
+help: use `dyn`
+ |
+LL | let d = <dyn Bar::<usize, _>>::lol();
+ | ++++ +
+
error[E0599]: no function or associated item named `lol` found for trait object `dyn Bar<usize, _>` in the current scope
- --> $DIR/unspecified-self-in-trait-ref.rs:16:30
+ --> $DIR/unspecified-self-in-trait-ref.rs:22:30
|
LL | let d = Bar::<usize, _>::lol();
| ^^^ function or associated item not found in `dyn Bar<usize, _>`
+warning: trait objects without an explicit `dyn` are deprecated
+ --> $DIR/unspecified-self-in-trait-ref.rs:26:13
+ |
+LL | let e = Bar::<usize>::lol();
+ | ^^^^^^^^^^^^
+ |
+ = warning: this is accepted in the current edition (Rust 2015) but is a hard error in Rust 2021!
+ = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2021/warnings-promoted-to-error.html>
+help: use `dyn`
+ |
+LL | let e = <dyn Bar::<usize>>::lol();
+ | ++++ +
+
error[E0393]: the type parameter `A` must be explicitly specified
- --> $DIR/unspecified-self-in-trait-ref.rs:18:13
+ --> $DIR/unspecified-self-in-trait-ref.rs:26:13
|
LL | / pub trait Bar<X=usize, A=Self> {
LL | | fn foo(&self);
@@ -35,7 +101,7 @@ LL | let e = Bar::<usize>::lol();
|
= note: because of the default `Self` reference, type parameters must be specified on object types
-error: aborting due to 5 previous errors
+error: aborting due to 5 previous errors; 5 warnings emitted
Some errors have detailed explanations: E0393, E0599.
For more information about an error, try `rustc --explain E0393`.
diff --git a/src/test/ui/unwind-unique.rs b/src/test/ui/unwind-unique.rs
index 7ca53b664ac..50ecf751a86 100644
--- a/src/test/ui/unwind-unique.rs
+++ b/src/test/ui/unwind-unique.rs
@@ -1,4 +1,5 @@
// run-pass
+// needs-unwind
// ignore-emscripten no threads support
use std::thread;
diff --git a/src/test/ui/use/use-after-move-based-on-type.stderr b/src/test/ui/use/use-after-move-based-on-type.stderr
index 11ce005bb45..361a6e2d8c2 100644
--- a/src/test/ui/use/use-after-move-based-on-type.stderr
+++ b/src/test/ui/use/use-after-move-based-on-type.stderr
@@ -7,6 +7,8 @@ LL | let _y = x;
| - value moved here
LL | println!("{}", x);
| ^ value borrowed here after move
+ |
+ = note: this error originates in the macro `$crate::format_args_nl` (in Nightly builds, run with -Z macro-backtrace for more info)
error: aborting due to previous error
diff --git a/src/test/ui/walk-struct-literal-with.stderr b/src/test/ui/walk-struct-literal-with.stderr
index cda08b0f4e0..377a8074458 100644
--- a/src/test/ui/walk-struct-literal-with.stderr
+++ b/src/test/ui/walk-struct-literal-with.stderr
@@ -13,6 +13,7 @@ note: this function takes ownership of the receiver `self`, which moves `start`
|
LL | fn make_string_bar(mut self) -> Mine{
| ^^^^
+ = note: this error originates in the macro `$crate::format_args_nl` (in Nightly builds, run with -Z macro-backtrace for more info)
error: aborting due to previous error
diff --git a/src/test/ui/weird-exprs.rs b/src/test/ui/weird-exprs.rs
index 2d7ebbf1d5b..a02b3230689 100644
--- a/src/test/ui/weird-exprs.rs
+++ b/src/test/ui/weird-exprs.rs
@@ -1,7 +1,6 @@
// run-pass
#![feature(generators)]
-#![feature(destructuring_assignment)]
#![allow(non_camel_case_types)]
#![allow(dead_code)]
diff --git a/src/test/ui/wf/hir-wf-check-erase-regions.stderr b/src/test/ui/wf/hir-wf-check-erase-regions.stderr
index 0d9b9627562..aef6db0a40b 100644
--- a/src/test/ui/wf/hir-wf-check-erase-regions.stderr
+++ b/src/test/ui/wf/hir-wf-check-erase-regions.stderr
@@ -5,7 +5,11 @@ LL | type IntoIter = std::iter::Flatten<std::slice::Iter<'a, T>>;
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `&T` is not an iterator
|
= help: the trait `Iterator` is not implemented for `&T`
- = note: required because of the requirements on the impl of `IntoIterator` for `&T`
+note: required because of the requirements on the impl of `IntoIterator` for `&T`
+ --> $DIR/hir-wf-check-erase-regions.rs:6:29
+ |
+LL | impl<'a, T, const N: usize> IntoIterator for &'a Table<T, N> {
+ | ^^^^^^^^^^^^ ^^^^^^^^^^^^^^^
note: required by a bound in `Flatten`
--> $SRC_DIR/core/src/iter/adapters/flatten.rs:LL:COL
|
@@ -19,7 +23,11 @@ LL | fn into_iter(self) -> Self::IntoIter {
| ^^^^^^^^^^^^^^ `&T` is not an iterator
|
= help: the trait `Iterator` is not implemented for `&T`
- = note: required because of the requirements on the impl of `IntoIterator` for `&T`
+note: required because of the requirements on the impl of `IntoIterator` for `&T`
+ --> $DIR/hir-wf-check-erase-regions.rs:6:29
+ |
+LL | impl<'a, T, const N: usize> IntoIterator for &'a Table<T, N> {
+ | ^^^^^^^^^^^^ ^^^^^^^^^^^^^^^
note: required by a bound in `Flatten`
--> $SRC_DIR/core/src/iter/adapters/flatten.rs:LL:COL
|
diff --git a/src/tools/cargo b/src/tools/cargo
-Subproject ad50d0d266213e0cc4f6e526a39d96faae9a384
+Subproject fcef61230c3b6213b6b0d233a36ba4ebd1649ec
diff --git a/src/tools/clippy/.github/ISSUE_TEMPLATE/blank_issue.md b/src/tools/clippy/.github/ISSUE_TEMPLATE/blank_issue.md
deleted file mode 100644
index 866303a1f9f..00000000000
--- a/src/tools/clippy/.github/ISSUE_TEMPLATE/blank_issue.md
+++ /dev/null
@@ -1,18 +0,0 @@
----
-name: Blank Issue
-about: Create a blank issue.
----
-
-
-<!--
-Additional labels can be added to this issue by including the following command
-(without the space after the @ symbol):
-
-@ rustbot label +<label>
-
-Common labels for this issue type are:
-* C-an-interesting-project
-* C-enhancement
-* C-question
-* C-tracking-issue
--->
diff --git a/src/tools/clippy/.github/ISSUE_TEMPLATE/blank_issue.yml b/src/tools/clippy/.github/ISSUE_TEMPLATE/blank_issue.yml
new file mode 100644
index 00000000000..d610e8c7bc4
--- /dev/null
+++ b/src/tools/clippy/.github/ISSUE_TEMPLATE/blank_issue.yml
@@ -0,0 +1,44 @@
+name: Blank Issue
+description: Create a blank issue.
+body:
+ - type: markdown
+ attributes:
+ value: Thank you for filing an issue!
+ - type: textarea
+ id: problem
+ attributes:
+ label: Description
+ description: >
+ Please provide a discription of the issue, along with any information
+ you feel relevant to replicate it.
+ validations:
+ required: true
+ - type: textarea
+ id: version
+ attributes:
+ label: Version
+ description: "Rust version (`rustc -Vv`)"
+ placeholder: |
+ rustc 1.46.0-nightly (f455e46ea 2020-06-20)
+ binary: rustc
+ commit-hash: f455e46eae1a227d735091091144601b467e1565
+ commit-date: 2020-06-20
+ host: x86_64-unknown-linux-gnu
+ release: 1.46.0-nightly
+ LLVM version: 10.0
+ render: text
+ - type: textarea
+ id: labels
+ attributes:
+ label: Additional Labels
+ description: >
+ Additional labels can be added to this issue by including the following
+ command
+ placeholder: |
+ @rustbot label +<label>
+
+ Common labels for this issue type are:
+ * C-an-interesting-project
+ * C-enhancement
+ * C-question
+ * C-tracking-issue
diff --git a/src/tools/clippy/.github/ISSUE_TEMPLATE/bug_report.md b/src/tools/clippy/.github/ISSUE_TEMPLATE/bug_report.md
deleted file mode 100644
index 119a498fb99..00000000000
--- a/src/tools/clippy/.github/ISSUE_TEMPLATE/bug_report.md
+++ /dev/null
@@ -1,43 +0,0 @@
----
-name: Bug Report
-about: Create a bug report for Clippy
-labels: C-bug
----
-<!--
-Thank you for filing a bug report! 🐛 Please provide a short summary of the bug,
-along with any information you feel relevant to replicating the bug.
--->
-
-I tried this code:
-
-```rust
-<code>
-```
-
-I expected to see this happen: *explanation*
-
-Instead, this happened: *explanation*
-
-### Meta
-
-**Rust version (`rustc -Vv`):**
-
-```
-rustc 1.46.0-nightly (f455e46ea 2020-06-20)
-binary: rustc
-commit-hash: f455e46eae1a227d735091091144601b467e1565
-commit-date: 2020-06-20
-host: x86_64-unknown-linux-gnu
-release: 1.46.0-nightly
-LLVM version: 10.0
-```
-
-<!--
-Additional labels can be added to this issue by including the following command
-(without the space after the @ symbol):
-
-@ rustbot label +<label>
-
-Common labels for this issue type are:
-* `I-suggestion-causes-error`
--->
diff --git a/src/tools/clippy/.github/ISSUE_TEMPLATE/bug_report.yml b/src/tools/clippy/.github/ISSUE_TEMPLATE/bug_report.yml
new file mode 100644
index 00000000000..68877efc9e1
--- /dev/null
+++ b/src/tools/clippy/.github/ISSUE_TEMPLATE/bug_report.yml
@@ -0,0 +1,57 @@
+name: Bug Report
+description: Create a bug report for Clippy
+labels: ["C-bug"]
+body:
+ - type: markdown
+ attributes:
+ value: Thank you for filing a bug report! 🐛
+ - type: textarea
+ id: problem
+ attributes:
+ label: Summary
+ description: >
+ Please provide a short summary of the bug, along with any information
+ you feel relevant to replicate the bug.
+ validations:
+ required: true
+ - type: textarea
+ id: reproducer
+ attributes:
+ label: Reproducer
+ description: Please provide the code and steps to repoduce the bug
+ value: |
+ I tried this code:
+
+ ```rust
+ <code>
+ ```
+
+ I expected to see this happen:
+
+ Instead, this happened:
+ - type: textarea
+ id: version
+ attributes:
+ label: Version
+ description: "Rust version (`rustc -Vv`)"
+ placeholder: |
+ rustc 1.46.0-nightly (f455e46ea 2020-06-20)
+ binary: rustc
+ commit-hash: f455e46eae1a227d735091091144601b467e1565
+ commit-date: 2020-06-20
+ host: x86_64-unknown-linux-gnu
+ release: 1.46.0-nightly
+ LLVM version: 10.0
+ render: text
+ - type: textarea
+ id: labels
+ attributes:
+ label: Additional Labels
+ description: >
+ Additional labels can be added to this issue by including the following
+ command
+ placeholder: |
+ @rustbot label +<label>
+
+ Common labels for this issue type are:
+ * `I-suggestion-causes-error`
diff --git a/src/tools/clippy/.github/ISSUE_TEMPLATE/false_negative.md b/src/tools/clippy/.github/ISSUE_TEMPLATE/false_negative.md
deleted file mode 100644
index d9ea2db34ed..00000000000
--- a/src/tools/clippy/.github/ISSUE_TEMPLATE/false_negative.md
+++ /dev/null
@@ -1,35 +0,0 @@
----
-name: Bug Report (False Negative)
-about: Create a bug report about missing warnings from a lint
-labels: C-bug, I-false-negative
----
-<!--
-Thank you for filing a bug report! 🐛 Please provide a short summary of the bug,
-along with any information you feel relevant to replicating the bug.
--->
-Lint name:
-
-
-I tried this code:
-
-```rust
-<code>
-```
-
-I expected to see this happen: *explanation*
-
-Instead, this happened: *explanation*
-
-### Meta
-
-**Rust version (`rustc -Vv`):**
-
-```
-rustc 1.46.0-nightly (f455e46ea 2020-06-20)
-binary: rustc
-commit-hash: f455e46eae1a227d735091091144601b467e1565
-commit-date: 2020-06-20
-host: x86_64-unknown-linux-gnu
-release: 1.46.0-nightly
-LLVM version: 10.0
-```
diff --git a/src/tools/clippy/.github/ISSUE_TEMPLATE/false_negative.yml b/src/tools/clippy/.github/ISSUE_TEMPLATE/false_negative.yml
new file mode 100644
index 00000000000..9357ccc4f4e
--- /dev/null
+++ b/src/tools/clippy/.github/ISSUE_TEMPLATE/false_negative.yml
@@ -0,0 +1,50 @@
+name: Bug Report (False Negative)
+description: Create a bug report about missing warnings from a lint
+labels: ["C-bug", "I-false-negative"]
+body:
+ - type: markdown
+ attributes:
+ value: Thank you for filing a bug report! 🐛
+ - type: textarea
+ id: problem
+ attributes:
+ label: Summary
+ description: >
+ Please provide a short summary of the bug, along with any information
+ you feel relevant to replicate the bug.
+ validations:
+ required: true
+ - type: input
+ id: lint-name
+ attributes:
+ label: Lint Name
+ description: Please provide the lint name.
+ - type: textarea
+ id: reproducer
+ attributes:
+ label: Reproducer
+ description: Please provide the code and steps to repoduce the bug
+ value: |
+ I tried this code:
+
+ ```rust
+ <code>
+ ```
+
+ I expected to see this happen:
+
+ Instead, this happened:
+ - type: textarea
+ id: version
+ attributes:
+ label: Version
+ description: "Rust version (`rustc -Vv`)"
+ placeholder: |
+ rustc 1.46.0-nightly (f455e46ea 2020-06-20)
+ binary: rustc
+ commit-hash: f455e46eae1a227d735091091144601b467e1565
+ commit-date: 2020-06-20
+ host: x86_64-unknown-linux-gnu
+ release: 1.46.0-nightly
+ LLVM version: 10.0
+ render: text
diff --git a/src/tools/clippy/.github/ISSUE_TEMPLATE/false_positive.md b/src/tools/clippy/.github/ISSUE_TEMPLATE/false_positive.md
deleted file mode 100644
index 82158e02f08..00000000000
--- a/src/tools/clippy/.github/ISSUE_TEMPLATE/false_positive.md
+++ /dev/null
@@ -1,44 +0,0 @@
----
-name: Bug Report (False Positive)
-about: Create a bug report about a wrongly emitted lint warning
-labels: C-bug, I-false-positive
----
-<!--
-Thank you for filing a bug report! 🐛 Please provide a short summary of the bug,
-along with any information you feel relevant to replicating the bug.
--->
-Lint name:
-
-
-I tried this code:
-
-```rust
-<code>
-```
-
-I expected to see this happen: *explanation*
-
-Instead, this happened: *explanation*
-
-### Meta
-
-**Rust version (`rustc -Vv`):**
-```
-rustc 1.46.0-nightly (f455e46ea 2020-06-20)
-binary: rustc
-commit-hash: f455e46eae1a227d735091091144601b467e1565
-commit-date: 2020-06-20
-host: x86_64-unknown-linux-gnu
-release: 1.46.0-nightly
-LLVM version: 10.0
-```
-
-<!--
-Additional labels can be added to this issue by including the following command
-(without the space after the @ symbol):
-
-@ rustbot label +<label>
-
-Common labels for this issue type are:
-* I-suggestion-causes-error
--->
diff --git a/src/tools/clippy/.github/ISSUE_TEMPLATE/false_positive.yml b/src/tools/clippy/.github/ISSUE_TEMPLATE/false_positive.yml
new file mode 100644
index 00000000000..b7dd400ee73
--- /dev/null
+++ b/src/tools/clippy/.github/ISSUE_TEMPLATE/false_positive.yml
@@ -0,0 +1,68 @@
+name: Bug Report (False Positive)
+description: Create a bug report about a wrongly emitted lint warning
+labels: ["C-bug", "I-false-positive"]
+body:
+ - type: markdown
+ attributes:
+ value: Thank you for filing a bug report! 🐛
+ - type: textarea
+ id: problem
+ attributes:
+ label: Summary
+ description: >
+ Please provide a short summary of the bug, along with any information
+ you feel relevant to replicate the bug.
+ validations:
+ required: true
+ - type: input
+ id: lint-name
+ attributes:
+ label: Lint Name
+ description: Please provide the lint name.
+ - type: textarea
+ id: reproducer
+ attributes:
+ label: Reproducer
+ description: >
+ Please provide the code and steps to repoduce the bug together with the
+ output from Clippy.
+ value: |
+ I tried this code:
+
+ ```rust
+ <code>
+ ```
+
+ I saw this happen:
+
+ ```
+ <output>
+ ```
+
+ I expected to see this happen:
+ - type: textarea
+ id: version
+ attributes:
+ label: Version
+ description: "Rust version (`rustc -Vv`)"
+ placeholder: |
+ rustc 1.46.0-nightly (f455e46ea 2020-06-20)
+ binary: rustc
+ commit-hash: f455e46eae1a227d735091091144601b467e1565
+ commit-date: 2020-06-20
+ host: x86_64-unknown-linux-gnu
+ release: 1.46.0-nightly
+ LLVM version: 10.0
+ render: text
+ - type: textarea
+ id: labels
+ attributes:
+ label: Additional Labels
+ description: >
+ Additional labels can be added to this issue by including the following
+ command
+ placeholder: |
+ @rustbot label +<label>
+
+ Common labels for this issue type are:
+ * `I-suggestion-causes-error`
diff --git a/src/tools/clippy/.github/ISSUE_TEMPLATE/ice.md b/src/tools/clippy/.github/ISSUE_TEMPLATE/ice.md
deleted file mode 100644
index 6c1bed663c6..00000000000
--- a/src/tools/clippy/.github/ISSUE_TEMPLATE/ice.md
+++ /dev/null
@@ -1,52 +0,0 @@
----
-name: Internal Compiler Error
-about: Create a report for an internal compiler error in Clippy.
-labels: C-bug, I-ICE
----
-<!--
-Thank you for finding an Internal Compiler Error! 🧊 If possible, try to provide
-a minimal verifiable example. You can read "Rust Bug Minimization Patterns" for
-how to create smaller examples.
-
-http://blog.pnkfx.org/blog/2019/11/18/rust-bug-minimization-patterns/
-
--->
-
-### Code
-
-```rust
-<code>
-```
-
-### Meta
-
-**Rust version (`rustc -Vv`):**
-```
-rustc 1.46.0-nightly (f455e46ea 2020-06-20)
-binary: rustc
-commit-hash: f455e46eae1a227d735091091144601b467e1565
-commit-date: 2020-06-20
-host: x86_64-unknown-linux-gnu
-release: 1.46.0-nightly
-LLVM version: 10.0
-```
-
-### Error output
-
-```
-<output>
-```
-
-<!--
-Include a backtrace in the code block by setting `RUST_BACKTRACE=1` in your
-environment. E.g. `RUST_BACKTRACE=1 cargo clippy`.
--->
-<details><summary>Backtrace</summary>
- <p>
-
- ```
- <backtrace>
- ```
-
- </p>
-</details>
diff --git a/src/tools/clippy/.github/ISSUE_TEMPLATE/ice.yml b/src/tools/clippy/.github/ISSUE_TEMPLATE/ice.yml
new file mode 100644
index 00000000000..2a5b8b3c891
--- /dev/null
+++ b/src/tools/clippy/.github/ISSUE_TEMPLATE/ice.yml
@@ -0,0 +1,48 @@
+name: Internal Compiler Error
+description: Create a report for an internal compiler error (ICE) in Clippy.
+labels: ["C-bug", "I-ICE"]
+body:
+ - type: markdown
+ attributes:
+ value: Thank you for finding an Internal Compiler Error! 🧊
+ - type: textarea
+ id: problem
+ attributes:
+ label: Summary
+ description: |
+ If possible, try to provide a minimal verifiable example. You can read ["Rust Bug Minimization Patterns"][mve] for how to create smaller examples. Otherwise, provide the crate where the ICE occured.
+
+ [mve]: http://blog.pnkfx.org/blog/2019/11/18/rust-bug-minimization-patterns/
+ validations:
+ required: true
+ - type: textarea
+ id: version
+ attributes:
+ label: Version
+ description: "Rust version (`rustc -Vv`)"
+ placeholder: |
+ rustc 1.46.0-nightly (f455e46ea 2020-06-20)
+ binary: rustc
+ commit-hash: f455e46eae1a227d735091091144601b467e1565
+ commit-date: 2020-06-20
+ host: x86_64-unknown-linux-gnu
+ release: 1.46.0-nightly
+ LLVM version: 10.0
+ render: text
+ - type: textarea
+ id: error
+ attributes:
+ label: Error output
+ description: >
+ Include a backtrace in the code block by setting `RUST_BACKTRACE=1` in
+ your environment. E.g. `RUST_BACKTRACE=1 cargo clippy`.
+ value: |
+ <details><summary>Backtrace</summary>
+ <p>
+
+ ```
+ <backtrace>
+ ```
+
+ </p>
+ </details>
diff --git a/src/tools/clippy/.github/ISSUE_TEMPLATE/new_lint.md b/src/tools/clippy/.github/ISSUE_TEMPLATE/new_lint.md
deleted file mode 100644
index 2216bb9f293..00000000000
--- a/src/tools/clippy/.github/ISSUE_TEMPLATE/new_lint.md
+++ /dev/null
@@ -1,36 +0,0 @@
----
-name: New lint suggestion
-about: Suggest a new Clippy lint.
-labels: A-lint
----
-
-### What it does
-
-*What does this lint do?*
-
-### Categories (optional)
-
-- Kind: *See <https://github.com/rust-lang/rust-clippy/blob/master/README.md#clippy> for list of lint kinds*
-
-*What is the advantage of the recommended code over the original code*
-
-For example:
-- Remove bounds check inserted by ...
-- Remove the need to duplicate/store ...
-- Remove typo ...
-
-### Drawbacks
-
-None.
-
-### Example
-
-```rust
-<code>
-```
-
-Could be written as:
-
-```rust
-<code>
-```
diff --git a/src/tools/clippy/.github/ISSUE_TEMPLATE/new_lint.yml b/src/tools/clippy/.github/ISSUE_TEMPLATE/new_lint.yml
new file mode 100644
index 00000000000..0b43d8d70c0
--- /dev/null
+++ b/src/tools/clippy/.github/ISSUE_TEMPLATE/new_lint.yml
@@ -0,0 +1,71 @@
+name: New lint suggestion
+description: Suggest a new Clippy lint.
+labels: ["A-lint"]
+body:
+ - type: markdown
+ attributes:
+ value: Thank you for your lint idea!
+ - type: textarea
+ id: what
+ attributes:
+ label: What it does
+ description: What does this lint do?
+ validations:
+ required: true
+ - type: input
+ id: lint-name
+ attributes:
+ label: Lint Name
+ description: Please provide the lint name.
+ - type: dropdown
+ id: category
+ attributes:
+ label: Category
+ description: >
+ What category should this lint go into? If you're unsure you can select
+ multiple categories. You can find a category description in the
+ `README`.
+ multiple: true
+ options:
+ - correctness
+ - suspicious
+ - style
+ - complexity
+ - perf
+ - pedantic
+ - restriction
+ - cargo
+ - type: textarea
+ id: advantage
+ attributes:
+ label: Advantage
+ description: >
+ What is the advantage of the recommended code over the original code?
+ placeholder: |
+ - Remove bounds check inserted by ...
+ - Remove the need to duplicate/store ...
+ - Remove typo ...
+ - type: textarea
+ id: drawbacks
+ attributes:
+ label: Drawbacks
+ description: What might be possible drawbacks of such a lint?
+ - type: textarea
+ id: example
+ attributes:
+ label: Example
+ description: >
+ Include a short example showing when the lint should trigger together
+ with the improved code.
+ value: |
+ ```rust
+ <code>
+ ```
+
+ Could be written as:
+
+ ```rust
+ <code>
+ ```
+ validations:
+ required: true
diff --git a/src/tools/clippy/.github/workflows/clippy_dev.yml b/src/tools/clippy/.github/workflows/clippy_dev.yml
index 9a5416153ab..fe8bce00fa8 100644
--- a/src/tools/clippy/.github/workflows/clippy_dev.yml
+++ b/src/tools/clippy/.github/workflows/clippy_dev.yml
@@ -25,18 +25,6 @@ jobs:
- name: Checkout
uses: actions/checkout@v2.3.3
- - name: remove toolchain file
- run: rm rust-toolchain
-
- - name: rust-toolchain
- uses: actions-rs/toolchain@v1.0.6
- with:
- toolchain: nightly
- target: x86_64-unknown-linux-gnu
- profile: minimal
- components: rustfmt
- default: true
-
# Run
- name: Build
run: cargo build --features deny-warnings
diff --git a/src/tools/clippy/.gitignore b/src/tools/clippy/.gitignore
index 523bab18828..e82a0ec4765 100644
--- a/src/tools/clippy/.gitignore
+++ b/src/tools/clippy/.gitignore
@@ -27,9 +27,11 @@ out
# Generated by dogfood
/target_recur/
+# Generated by lintcheck
+/lintcheck-logs
+
# gh pages docs
util/gh-pages/lints.json
-**/metadata_collection.json
# rustfmt backups
*.rs.bk
diff --git a/src/tools/clippy/CHANGELOG.md b/src/tools/clippy/CHANGELOG.md
index 85a6a6be8b7..7b5279cda6e 100644
--- a/src/tools/clippy/CHANGELOG.md
+++ b/src/tools/clippy/CHANGELOG.md
@@ -70,7 +70,7 @@ Current beta, release 2021-12-02
[#7560](https://github.com/rust-lang/rust-clippy/pull/7560)
* [`unnecessary_unwrap`]: Now also checks for `expect`s
[#7584](https://github.com/rust-lang/rust-clippy/pull/7584)
-* [`disallowed_method`]: Allow adding a reason that will be displayed with the
+* [`disallowed_methods`]: Allow adding a reason that will be displayed with the
lint message
[#7621](https://github.com/rust-lang/rust-clippy/pull/7621)
* [`approx_constant`]: Now checks the MSRV for `LOG10_2` and `LOG2_10`
@@ -174,7 +174,7 @@ Current stable, released 2021-10-21
* [`needless_continue`]: Now also lints in `loop { continue; }` case
[#7477](https://github.com/rust-lang/rust-clippy/pull/7477)
-* [`disallowed_type`]: Now also primitive types can be disallowed
+* [`disallowed_types`]: Now also primitive types can be disallowed
[#7488](https://github.com/rust-lang/rust-clippy/pull/7488)
* [`manual_swap`]: Now also lints on xor swaps
[#7506](https://github.com/rust-lang/rust-clippy/pull/7506)
@@ -248,7 +248,7 @@ Released 2021-09-09
[#7403](https://github.com/rust-lang/rust-clippy/pull/7403)
* [`disallowed_script_idents`]
[#7400](https://github.com/rust-lang/rust-clippy/pull/7400)
-* [`disallowed_type`]
+* [`disallowed_types`]
[#7315](https://github.com/rust-lang/rust-clippy/pull/7315)
* [`missing_enforced_import_renames`]
[#7300](https://github.com/rust-lang/rust-clippy/pull/7300)
@@ -294,7 +294,7 @@ Released 2021-09-09
[#7379](https://github.com/rust-lang/rust-clippy/pull/7379)
* [`redundant_closure`]: Suggests `&mut` for `FnMut`
[#7437](https://github.com/rust-lang/rust-clippy/pull/7437)
-* [`disallowed_method`], [`disallowed_type`]: The configuration values `disallowed-method` and `disallowed-type`
+* [`disallowed_methods`], [`disallowed_types`]: The configuration values `disallowed-method` and `disallowed-type`
no longer require fully qualified paths
[#7345](https://github.com/rust-lang/rust-clippy/pull/7345)
* [`zst_offset`]: Fixed lint invocation after it was accidentally suppressed
@@ -703,7 +703,7 @@ Released 2021-05-06
### Enhancements
-* [`disallowed_method`]: Now supports functions in addition to methods
+* [`disallowed_methods`]: Now supports functions in addition to methods
[#6674](https://github.com/rust-lang/rust-clippy/pull/6674)
* [`upper_case_acronyms`]: Added a new configuration `upper-case-acronyms-aggressive` to
trigger the lint if there is more than one uppercase character next to each other
@@ -1044,7 +1044,7 @@ Released 2020-12-31
* [`field_reassign_with_default`] [#5911](https://github.com/rust-lang/rust-clippy/pull/5911)
* [`await_holding_refcell_ref`] [#6029](https://github.com/rust-lang/rust-clippy/pull/6029)
-* [`disallowed_method`] [#6081](https://github.com/rust-lang/rust-clippy/pull/6081)
+* [`disallowed_methods`] [#6081](https://github.com/rust-lang/rust-clippy/pull/6081)
* [`inline_asm_x86_att_syntax`] [#6092](https://github.com/rust-lang/rust-clippy/pull/6092)
* [`inline_asm_x86_intel_syntax`] [#6092](https://github.com/rust-lang/rust-clippy/pull/6092)
* [`from_iter_instead_of_collect`] [#6101](https://github.com/rust-lang/rust-clippy/pull/6101)
@@ -2821,9 +2821,9 @@ Released 2018-09-13
[`derivable_impls`]: https://rust-lang.github.io/rust-clippy/master/index.html#derivable_impls
[`derive_hash_xor_eq`]: https://rust-lang.github.io/rust-clippy/master/index.html#derive_hash_xor_eq
[`derive_ord_xor_partial_ord`]: https://rust-lang.github.io/rust-clippy/master/index.html#derive_ord_xor_partial_ord
-[`disallowed_method`]: https://rust-lang.github.io/rust-clippy/master/index.html#disallowed_method
+[`disallowed_methods`]: https://rust-lang.github.io/rust-clippy/master/index.html#disallowed_methods
[`disallowed_script_idents`]: https://rust-lang.github.io/rust-clippy/master/index.html#disallowed_script_idents
-[`disallowed_type`]: https://rust-lang.github.io/rust-clippy/master/index.html#disallowed_type
+[`disallowed_types`]: https://rust-lang.github.io/rust-clippy/master/index.html#disallowed_types
[`diverging_sub_expression`]: https://rust-lang.github.io/rust-clippy/master/index.html#diverging_sub_expression
[`doc_markdown`]: https://rust-lang.github.io/rust-clippy/master/index.html#doc_markdown
[`double_comparisons`]: https://rust-lang.github.io/rust-clippy/master/index.html#double_comparisons
@@ -2904,6 +2904,7 @@ Released 2018-09-13
[`imprecise_flops`]: https://rust-lang.github.io/rust-clippy/master/index.html#imprecise_flops
[`inconsistent_digit_grouping`]: https://rust-lang.github.io/rust-clippy/master/index.html#inconsistent_digit_grouping
[`inconsistent_struct_constructor`]: https://rust-lang.github.io/rust-clippy/master/index.html#inconsistent_struct_constructor
+[`index_refutable_slice`]: https://rust-lang.github.io/rust-clippy/master/index.html#index_refutable_slice
[`indexing_slicing`]: https://rust-lang.github.io/rust-clippy/master/index.html#indexing_slicing
[`ineffective_bit_mask`]: https://rust-lang.github.io/rust-clippy/master/index.html#ineffective_bit_mask
[`inefficient_to_string`]: https://rust-lang.github.io/rust-clippy/master/index.html#inefficient_to_string
@@ -3032,12 +3033,14 @@ Released 2018-09-13
[`needless_continue`]: https://rust-lang.github.io/rust-clippy/master/index.html#needless_continue
[`needless_doctest_main`]: https://rust-lang.github.io/rust-clippy/master/index.html#needless_doctest_main
[`needless_for_each`]: https://rust-lang.github.io/rust-clippy/master/index.html#needless_for_each
+[`needless_late_init`]: https://rust-lang.github.io/rust-clippy/master/index.html#needless_late_init
[`needless_lifetimes`]: https://rust-lang.github.io/rust-clippy/master/index.html#needless_lifetimes
[`needless_option_as_deref`]: https://rust-lang.github.io/rust-clippy/master/index.html#needless_option_as_deref
[`needless_pass_by_value`]: https://rust-lang.github.io/rust-clippy/master/index.html#needless_pass_by_value
[`needless_question_mark`]: https://rust-lang.github.io/rust-clippy/master/index.html#needless_question_mark
[`needless_range_loop`]: https://rust-lang.github.io/rust-clippy/master/index.html#needless_range_loop
[`needless_return`]: https://rust-lang.github.io/rust-clippy/master/index.html#needless_return
+[`needless_splitn`]: https://rust-lang.github.io/rust-clippy/master/index.html#needless_splitn
[`needless_update`]: https://rust-lang.github.io/rust-clippy/master/index.html#needless_update
[`neg_cmp_op_on_partial_ord`]: https://rust-lang.github.io/rust-clippy/master/index.html#neg_cmp_op_on_partial_ord
[`neg_multiply`]: https://rust-lang.github.io/rust-clippy/master/index.html#neg_multiply
@@ -3054,6 +3057,7 @@ Released 2018-09-13
[`nonsensical_open_options`]: https://rust-lang.github.io/rust-clippy/master/index.html#nonsensical_open_options
[`nonstandard_macro_braces`]: https://rust-lang.github.io/rust-clippy/master/index.html#nonstandard_macro_braces
[`not_unsafe_ptr_arg_deref`]: https://rust-lang.github.io/rust-clippy/master/index.html#not_unsafe_ptr_arg_deref
+[`octal_escapes`]: https://rust-lang.github.io/rust-clippy/master/index.html#octal_escapes
[`ok_expect`]: https://rust-lang.github.io/rust-clippy/master/index.html#ok_expect
[`op_ref`]: https://rust-lang.github.io/rust-clippy/master/index.html#op_ref
[`option_as_ref_deref`]: https://rust-lang.github.io/rust-clippy/master/index.html#option_as_ref_deref
@@ -3114,6 +3118,7 @@ Released 2018-09-13
[`result_map_or_into_option`]: https://rust-lang.github.io/rust-clippy/master/index.html#result_map_or_into_option
[`result_map_unit_fn`]: https://rust-lang.github.io/rust-clippy/master/index.html#result_map_unit_fn
[`result_unit_err`]: https://rust-lang.github.io/rust-clippy/master/index.html#result_unit_err
+[`return_self_not_must_use`]: https://rust-lang.github.io/rust-clippy/master/index.html#return_self_not_must_use
[`reversed_empty_ranges`]: https://rust-lang.github.io/rust-clippy/master/index.html#reversed_empty_ranges
[`same_functions_in_if_condition`]: https://rust-lang.github.io/rust-clippy/master/index.html#same_functions_in_if_condition
[`same_item_push`]: https://rust-lang.github.io/rust-clippy/master/index.html#same_item_push
@@ -3205,6 +3210,7 @@ Released 2018-09-13
[`unnecessary_operation`]: https://rust-lang.github.io/rust-clippy/master/index.html#unnecessary_operation
[`unnecessary_self_imports`]: https://rust-lang.github.io/rust-clippy/master/index.html#unnecessary_self_imports
[`unnecessary_sort_by`]: https://rust-lang.github.io/rust-clippy/master/index.html#unnecessary_sort_by
+[`unnecessary_to_owned`]: https://rust-lang.github.io/rust-clippy/master/index.html#unnecessary_to_owned
[`unnecessary_unwrap`]: https://rust-lang.github.io/rust-clippy/master/index.html#unnecessary_unwrap
[`unnecessary_wraps`]: https://rust-lang.github.io/rust-clippy/master/index.html#unnecessary_wraps
[`unneeded_field_pattern`]: https://rust-lang.github.io/rust-clippy/master/index.html#unneeded_field_pattern
diff --git a/src/tools/clippy/Cargo.toml b/src/tools/clippy/Cargo.toml
index 602877bb9d6..8661a867758 100644
--- a/src/tools/clippy/Cargo.toml
+++ b/src/tools/clippy/Cargo.toml
@@ -1,6 +1,6 @@
[package]
name = "clippy"
-version = "0.1.58"
+version = "0.1.59"
description = "A bunch of helpful lints to avoid common pitfalls in Rust"
repository = "https://github.com/rust-lang/rust-clippy"
readme = "README.md"
@@ -47,6 +47,7 @@ itertools = "0.10"
quote = "1.0"
serde = { version = "1.0", features = ["derive"] }
syn = { version = "1.0", features = ["full"] }
+parking_lot = "0.11.2"
[build-dependencies]
rustc_tools_util = { version = "0.2", path = "rustc_tools_util" }
diff --git a/src/tools/clippy/README.md b/src/tools/clippy/README.md
index 822335fc65f..73b0167d363 100644
--- a/src/tools/clippy/README.md
+++ b/src/tools/clippy/README.md
@@ -162,7 +162,8 @@ define the `CLIPPY_DISABLE_DOCS_LINKS` environment variable.
You can add options to your code to `allow`/`warn`/`deny` Clippy lints:
-* the whole set of `Warn` lints using the `clippy` lint group (`#![deny(clippy::all)]`)
+* the whole set of `Warn` lints using the `clippy` lint group (`#![deny(clippy::all)]`).
+ Note that `rustc` has additional [lint groups](https://doc.rust-lang.org/rustc/lints/groups.html).
* all lints using both the `clippy` and `clippy::pedantic` lint groups (`#![deny(clippy::all)]`,
`#![deny(clippy::pedantic)]`). Note that `clippy::pedantic` contains some very aggressive
diff --git a/src/tools/clippy/clippy_dev/Cargo.toml b/src/tools/clippy/clippy_dev/Cargo.toml
index affb283017c..d350d9a0018 100644
--- a/src/tools/clippy/clippy_dev/Cargo.toml
+++ b/src/tools/clippy/clippy_dev/Cargo.toml
@@ -12,6 +12,7 @@ opener = "0.5"
regex = "1.5"
shell-escape = "0.1"
walkdir = "2.3"
+cargo_metadata = "0.14"
[features]
deny-warnings = []
diff --git a/src/tools/clippy/clippy_dev/src/fmt.rs b/src/tools/clippy/clippy_dev/src/fmt.rs
index c81eb40d52f..9ceadee58ea 100644
--- a/src/tools/clippy/clippy_dev/src/fmt.rs
+++ b/src/tools/clippy/clippy_dev/src/fmt.rs
@@ -1,6 +1,7 @@
use crate::clippy_project_root;
+use itertools::Itertools;
use shell_escape::escape;
-use std::ffi::OsStr;
+use std::ffi::{OsStr, OsString};
use std::path::Path;
use std::process::{self, Command};
use std::{fs, io};
@@ -56,15 +57,22 @@ pub fn run(check: bool, verbose: bool) {
success &= cargo_fmt(context, &project_root.join("rustc_tools_util"))?;
success &= cargo_fmt(context, &project_root.join("lintcheck"))?;
- for entry in WalkDir::new(project_root.join("tests")) {
- let entry = entry?;
- let path = entry.path();
-
- if path.extension() != Some("rs".as_ref()) || entry.file_name() == "ice-3891.rs" {
- continue;
- }
-
- success &= rustfmt(context, path)?;
+ let chunks = WalkDir::new(project_root.join("tests"))
+ .into_iter()
+ .filter_map(|entry| {
+ let entry = entry.expect("failed to find tests");
+ let path = entry.path();
+
+ if path.extension() != Some("rs".as_ref()) || entry.file_name() == "ice-3891.rs" {
+ None
+ } else {
+ Some(entry.into_path().into_os_string())
+ }
+ })
+ .chunks(250);
+
+ for chunk in &chunks {
+ success &= rustfmt(context, chunk)?;
}
Ok(success)
@@ -149,7 +157,7 @@ fn exec(
}
fn cargo_fmt(context: &FmtContext, path: &Path) -> Result<bool, CliError> {
- let mut args = vec!["+nightly", "fmt", "--all"];
+ let mut args = vec!["fmt", "--all"];
if context.check {
args.push("--");
args.push("--check");
@@ -162,7 +170,7 @@ fn cargo_fmt(context: &FmtContext, path: &Path) -> Result<bool, CliError> {
fn rustfmt_test(context: &FmtContext) -> Result<(), CliError> {
let program = "rustfmt";
let dir = std::env::current_dir()?;
- let args = &["+nightly", "--version"];
+ let args = &["--version"];
if context.verbose {
println!("{}", format_command(&program, &dir, args));
@@ -185,14 +193,14 @@ fn rustfmt_test(context: &FmtContext) -> Result<(), CliError> {
}
}
-fn rustfmt(context: &FmtContext, path: &Path) -> Result<bool, CliError> {
- let mut args = vec!["+nightly".as_ref(), path.as_os_str()];
+fn rustfmt(context: &FmtContext, paths: impl Iterator<Item = OsString>) -> Result<bool, CliError> {
+ let mut args = Vec::new();
if context.check {
- args.push("--check".as_ref());
+ args.push(OsString::from("--check"));
}
+ args.extend(paths);
+
let success = exec(context, "rustfmt", std::env::current_dir()?, &args)?;
- if !success {
- eprintln!("rustfmt failed on {}", path.display());
- }
+
Ok(success)
}
diff --git a/src/tools/clippy/clippy_dev/src/lib.rs b/src/tools/clippy/clippy_dev/src/lib.rs
index 5538f62c8e7..59fde447547 100644
--- a/src/tools/clippy/clippy_dev/src/lib.rs
+++ b/src/tools/clippy/clippy_dev/src/lib.rs
@@ -7,6 +7,7 @@ use std::path::PathBuf;
pub mod bless;
pub mod fmt;
+pub mod lint;
pub mod new_lint;
pub mod serve;
pub mod setup;
diff --git a/src/tools/clippy/clippy_dev/src/lint.rs b/src/tools/clippy/clippy_dev/src/lint.rs
new file mode 100644
index 00000000000..dfd16f71054
--- /dev/null
+++ b/src/tools/clippy/clippy_dev/src/lint.rs
@@ -0,0 +1,20 @@
+use std::process::{self, Command};
+
+pub fn run(filename: &str) {
+ let code = Command::new("cargo")
+ .args(["run", "--bin", "clippy-driver", "--"])
+ .args(["-L", "./target/debug"])
+ .args(["-Z", "no-codegen"])
+ .args(["--edition", "2021"])
+ .arg(filename)
+ .env("__CLIPPY_INTERNAL_TESTS", "true")
+ .status()
+ .expect("failed to run cargo")
+ .code();
+
+ if code.is_none() {
+ eprintln!("Killed by signal");
+ }
+
+ process::exit(code.unwrap_or(1));
+}
diff --git a/src/tools/clippy/clippy_dev/src/main.rs b/src/tools/clippy/clippy_dev/src/main.rs
index b5c04efce3b..30a241c8ba1 100644
--- a/src/tools/clippy/clippy_dev/src/main.rs
+++ b/src/tools/clippy/clippy_dev/src/main.rs
@@ -3,7 +3,7 @@
#![warn(rust_2018_idioms, unused_lifetimes)]
use clap::{App, AppSettings, Arg, ArgMatches, SubCommand};
-use clippy_dev::{bless, fmt, new_lint, serve, setup, update_lints};
+use clippy_dev::{bless, fmt, lint, new_lint, serve, setup, update_lints};
fn main() {
let matches = get_clap_config();
@@ -55,6 +55,10 @@ fn main() {
let lint = matches.value_of("lint");
serve::run(port, lint);
},
+ ("lint", Some(matches)) => {
+ let filename = matches.value_of("filename").unwrap();
+ lint::run(filename);
+ },
_ => {},
}
}
@@ -219,5 +223,14 @@ fn get_clap_config<'a>() -> ArgMatches<'a> {
)
.arg(Arg::with_name("lint").help("Which lint's page to load initially (optional)")),
)
+ .subcommand(
+ SubCommand::with_name("lint")
+ .about("Manually run clippy on a file")
+ .arg(
+ Arg::with_name("filename")
+ .required(true)
+ .help("The path to a file to lint"),
+ ),
+ )
.get_matches()
}
diff --git a/src/tools/clippy/clippy_dev/src/new_lint.rs b/src/tools/clippy/clippy_dev/src/new_lint.rs
index 43a478ee77d..59658b42c79 100644
--- a/src/tools/clippy/clippy_dev/src/new_lint.rs
+++ b/src/tools/clippy/clippy_dev/src/new_lint.rs
@@ -132,6 +132,18 @@ fn to_camel_case(name: &str) -> String {
.collect()
}
+fn get_stabilisation_version() -> String {
+ let mut command = cargo_metadata::MetadataCommand::new();
+ command.no_deps();
+ if let Ok(metadata) = command.exec() {
+ if let Some(pkg) = metadata.packages.iter().find(|pkg| pkg.name == "clippy") {
+ return format!("{}.{}.0", pkg.version.minor, pkg.version.patch);
+ }
+ }
+
+ String::from("<TODO set version(see doc/adding_lints.md)>")
+}
+
fn get_test_file_contents(lint_name: &str, header_commands: Option<&str>) -> String {
let mut contents = format!(
indoc! {"
@@ -178,6 +190,7 @@ fn get_lint_file_contents(lint: &LintData<'_>, enable_msrv: bool) -> String {
},
};
+ let version = get_stabilisation_version();
let lint_name = lint.name;
let category = lint.category;
let name_camel = to_camel_case(lint.name);
@@ -212,7 +225,7 @@ fn get_lint_file_contents(lint: &LintData<'_>, enable_msrv: bool) -> String {
});
result.push_str(&format!(
- indoc! {"
+ indoc! {r#"
declare_clippy_lint! {{
/// ### What it does
///
@@ -226,11 +239,13 @@ fn get_lint_file_contents(lint: &LintData<'_>, enable_msrv: bool) -> String {
/// ```rust
/// // example code which does not raise clippy warning
/// ```
+ #[clippy::version = "{version}"]
pub {name_upper},
{category},
- \"default lint description\"
+ "default lint description"
}}
- "},
+ "#},
+ version = version,
name_upper = name_upper,
category = category,
));
diff --git a/src/tools/clippy/clippy_dev/src/update_lints.rs b/src/tools/clippy/clippy_dev/src/update_lints.rs
index 23f58bc4915..8dd073ef405 100644
--- a/src/tools/clippy/clippy_dev/src/update_lints.rs
+++ b/src/tools/clippy/clippy_dev/src/update_lints.rs
@@ -18,6 +18,7 @@ static DEC_CLIPPY_LINT_RE: SyncLazy<Regex> = SyncLazy::new(|| {
r#"(?x)
declare_clippy_lint!\s*[\{(]
(?:\s+///.*)*
+ (?:\s*\#\[clippy::version\s*=\s*"[^"]*"\])?
\s+pub\s+(?P<name>[A-Z_][A-Z_0-9]*)\s*,\s*
(?P<cat>[a-z_]+)\s*,\s*
"(?P<desc>(?:[^"\\]+|\\(?s).(?-s))*)"\s*[})]
@@ -31,6 +32,7 @@ static DEC_DEPRECATED_LINT_RE: SyncLazy<Regex> = SyncLazy::new(|| {
r#"(?x)
declare_deprecated_lint!\s*[{(]\s*
(?:\s+///.*)*
+ (?:\s*\#\[clippy::version\s*=\s*"[^"]*"\])?
\s+pub\s+(?P<name>[A-Z_][A-Z_0-9]*)\s*,\s*
"(?P<desc>(?:[^"\\]+|\\(?s).(?-s))*)"\s*[})]
"#,
@@ -495,6 +497,7 @@ fn test_parse_contents() {
let result: Vec<Lint> = parse_contents(
r#"
declare_clippy_lint! {
+ #[clippy::version = "Hello Clippy!"]
pub PTR_ARG,
style,
"really long \
@@ -502,6 +505,7 @@ declare_clippy_lint! {
}
declare_clippy_lint!{
+ #[clippy::version = "Test version"]
pub DOC_MARKDOWN,
pedantic,
"single line"
@@ -509,6 +513,7 @@ declare_clippy_lint!{
/// some doc comment
declare_deprecated_lint! {
+ #[clippy::version = "I'm a version"]
pub SHOULD_ASSERT_EQ,
"`assert!()` will be more flexible with RFC 2011"
}
diff --git a/src/tools/clippy/clippy_lints/Cargo.toml b/src/tools/clippy/clippy_lints/Cargo.toml
index 281480b8d94..0661c280386 100644
--- a/src/tools/clippy/clippy_lints/Cargo.toml
+++ b/src/tools/clippy/clippy_lints/Cargo.toml
@@ -1,6 +1,6 @@
[package]
name = "clippy_lints"
-version = "0.1.58"
+version = "0.1.59"
description = "A bunch of helpful lints to avoid common pitfalls in Rust"
repository = "https://github.com/rust-lang/rust-clippy"
readme = "README.md"
diff --git a/src/tools/clippy/clippy_lints/src/absurd_extreme_comparisons.rs b/src/tools/clippy/clippy_lints/src/absurd_extreme_comparisons.rs
index 1483f3f9185..7665aa8380b 100644
--- a/src/tools/clippy/clippy_lints/src/absurd_extreme_comparisons.rs
+++ b/src/tools/clippy/clippy_lints/src/absurd_extreme_comparisons.rs
@@ -36,6 +36,7 @@ declare_clippy_lint! {
/// if vec.len() <= 0 {}
/// if 100 > i32::MAX {}
/// ```
+ #[clippy::version = "pre 1.29.0"]
pub ABSURD_EXTREME_COMPARISONS,
correctness,
"a comparison with a maximum or minimum value that is always true or false"
diff --git a/src/tools/clippy/clippy_lints/src/approx_const.rs b/src/tools/clippy/clippy_lints/src/approx_const.rs
index fb54ac1ec51..12435eefbc4 100644
--- a/src/tools/clippy/clippy_lints/src/approx_const.rs
+++ b/src/tools/clippy/clippy_lints/src/approx_const.rs
@@ -33,6 +33,7 @@ declare_clippy_lint! {
/// let x = std::f32::consts::PI;
/// let y = std::f64::consts::FRAC_1_PI;
/// ```
+ #[clippy::version = "pre 1.29.0"]
pub APPROX_CONSTANT,
correctness,
"the approximate of a known float constant (in `std::fXX::consts`)"
diff --git a/src/tools/clippy/clippy_lints/src/arithmetic.rs b/src/tools/clippy/clippy_lints/src/arithmetic.rs
index 36fe7b7a867..e0c1d6ab6e1 100644
--- a/src/tools/clippy/clippy_lints/src/arithmetic.rs
+++ b/src/tools/clippy/clippy_lints/src/arithmetic.rs
@@ -25,6 +25,7 @@ declare_clippy_lint! {
/// # let a = 0;
/// a + 1;
/// ```
+ #[clippy::version = "pre 1.29.0"]
pub INTEGER_ARITHMETIC,
restriction,
"any integer arithmetic expression which could overflow or panic"
@@ -43,6 +44,7 @@ declare_clippy_lint! {
/// # let a = 0.0;
/// a + 1.0;
/// ```
+ #[clippy::version = "pre 1.29.0"]
pub FLOAT_ARITHMETIC,
restriction,
"any floating-point arithmetic statement"
diff --git a/src/tools/clippy/clippy_lints/src/as_conversions.rs b/src/tools/clippy/clippy_lints/src/as_conversions.rs
index 0be460d67a7..53704da1046 100644
--- a/src/tools/clippy/clippy_lints/src/as_conversions.rs
+++ b/src/tools/clippy/clippy_lints/src/as_conversions.rs
@@ -38,6 +38,7 @@ declare_clippy_lint! {
/// f(a.try_into().expect("Unexpected u16 overflow in f"));
/// ```
///
+ #[clippy::version = "1.41.0"]
pub AS_CONVERSIONS,
restriction,
"using a potentially dangerous silent `as` conversion"
diff --git a/src/tools/clippy/clippy_lints/src/asm_syntax.rs b/src/tools/clippy/clippy_lints/src/asm_syntax.rs
index 825832eb79d..f419781dbc8 100644
--- a/src/tools/clippy/clippy_lints/src/asm_syntax.rs
+++ b/src/tools/clippy/clippy_lints/src/asm_syntax.rs
@@ -65,6 +65,7 @@ declare_clippy_lint! {
/// ```rust,no_run
/// # #![feature(asm)]
/// # unsafe { let ptr = "".as_ptr();
+ /// # use std::arch::asm;
/// asm!("lea {}, [{}]", lateout(reg) _, in(reg) ptr);
/// # }
/// ```
@@ -72,9 +73,11 @@ declare_clippy_lint! {
/// ```rust,no_run
/// # #![feature(asm)]
/// # unsafe { let ptr = "".as_ptr();
+ /// # use std::arch::asm;
/// asm!("lea ({}), {}", in(reg) ptr, lateout(reg) _, options(att_syntax));
/// # }
/// ```
+ #[clippy::version = "1.49.0"]
pub INLINE_ASM_X86_INTEL_SYNTAX,
restriction,
"prefer AT&T x86 assembly syntax"
@@ -101,6 +104,7 @@ declare_clippy_lint! {
/// ```rust,no_run
/// # #![feature(asm)]
/// # unsafe { let ptr = "".as_ptr();
+ /// # use std::arch::asm;
/// asm!("lea ({}), {}", in(reg) ptr, lateout(reg) _, options(att_syntax));
/// # }
/// ```
@@ -108,9 +112,11 @@ declare_clippy_lint! {
/// ```rust,no_run
/// # #![feature(asm)]
/// # unsafe { let ptr = "".as_ptr();
+ /// # use std::arch::asm;
/// asm!("lea {}, [{}]", lateout(reg) _, in(reg) ptr);
/// # }
/// ```
+ #[clippy::version = "1.49.0"]
pub INLINE_ASM_X86_ATT_SYNTAX,
restriction,
"prefer Intel x86 assembly syntax"
diff --git a/src/tools/clippy/clippy_lints/src/assertions_on_constants.rs b/src/tools/clippy/clippy_lints/src/assertions_on_constants.rs
index d834a1d317a..b7f414742f1 100644
--- a/src/tools/clippy/clippy_lints/src/assertions_on_constants.rs
+++ b/src/tools/clippy/clippy_lints/src/assertions_on_constants.rs
@@ -2,7 +2,7 @@ use clippy_utils::consts::{constant, Constant};
use clippy_utils::diagnostics::span_lint_and_help;
use clippy_utils::higher;
use clippy_utils::source::snippet_opt;
-use clippy_utils::{is_direct_expn_of, is_expn_of, match_panic_call};
+use clippy_utils::{is_direct_expn_of, is_expn_of, match_panic_call, peel_blocks};
use if_chain::if_chain;
use rustc_hir::{Expr, ExprKind, UnOp};
use rustc_lint::{LateContext, LateLintPass};
@@ -26,6 +26,7 @@ declare_clippy_lint! {
/// const B: bool = false;
/// assert!(B)
/// ```
+ #[clippy::version = "1.34.0"]
pub ASSERTIONS_ON_CONSTANTS,
style,
"`assert!(true)` / `assert!(false)` will be optimized out by the compiler, and should probably be replaced by a `panic!()` or `unreachable!()`"
@@ -121,15 +122,7 @@ fn match_assert_with_message<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>)
if let ExprKind::Unary(UnOp::Not, expr) = cond.kind;
// bind the first argument of the `assert!` macro
if let Some((Constant::Bool(is_true), _)) = constant(cx, cx.typeck_results(), expr);
- // block
- if let ExprKind::Block(block, _) = then.kind;
- if block.stmts.is_empty();
- if let Some(block_expr) = &block.expr;
- // inner block is optional. unwrap it if it exists, or use the expression as is otherwise.
- if let Some(begin_panic_call) = match block_expr.kind {
- ExprKind::Block(inner_block, _) => &inner_block.expr,
- _ => &block.expr,
- };
+ let begin_panic_call = peel_blocks(then);
// function call
if let Some(arg) = match_panic_call(cx, begin_panic_call);
// bind the second argument of the `assert!` macro if it exists
diff --git a/src/tools/clippy/clippy_lints/src/assign_ops.rs b/src/tools/clippy/clippy_lints/src/assign_ops.rs
index 2097a1feff9..e16f4369da9 100644
--- a/src/tools/clippy/clippy_lints/src/assign_ops.rs
+++ b/src/tools/clippy/clippy_lints/src/assign_ops.rs
@@ -34,6 +34,7 @@ declare_clippy_lint! {
/// // Good
/// a += b;
/// ```
+ #[clippy::version = "pre 1.29.0"]
pub ASSIGN_OP_PATTERN,
style,
"assigning the result of an operation on a variable to that same variable"
@@ -60,6 +61,7 @@ declare_clippy_lint! {
/// // ...
/// a += a + b;
/// ```
+ #[clippy::version = "pre 1.29.0"]
pub MISREFACTORED_ASSIGN_OP,
suspicious,
"having a variable on both sides of an assign op"
diff --git a/src/tools/clippy/clippy_lints/src/async_yields_async.rs b/src/tools/clippy/clippy_lints/src/async_yields_async.rs
index 182736a5a20..0619490e73c 100644
--- a/src/tools/clippy/clippy_lints/src/async_yields_async.rs
+++ b/src/tools/clippy/clippy_lints/src/async_yields_async.rs
@@ -34,6 +34,7 @@ declare_clippy_lint! {
/// };
/// }
/// ```
+ #[clippy::version = "1.48.0"]
pub ASYNC_YIELDS_ASYNC,
correctness,
"async blocks that return a type that can be awaited"
diff --git a/src/tools/clippy/clippy_lints/src/attrs.rs b/src/tools/clippy/clippy_lints/src/attrs.rs
index 6f8b645dd70..1edb7c950e7 100644
--- a/src/tools/clippy/clippy_lints/src/attrs.rs
+++ b/src/tools/clippy/clippy_lints/src/attrs.rs
@@ -1,8 +1,9 @@
//! checks for attributes
use clippy_utils::diagnostics::{span_lint, span_lint_and_help, span_lint_and_sugg, span_lint_and_then};
-use clippy_utils::match_panic_def_id;
+use clippy_utils::msrvs;
use clippy_utils::source::{first_line_of_span, is_present_in_source, snippet_opt, without_block_comments};
+use clippy_utils::{extract_msrv_attr, match_panic_def_id, meets_msrv};
use if_chain::if_chain;
use rustc_ast::{AttrKind, AttrStyle, Attribute, Lit, LitKind, MetaItemKind, NestedMetaItem};
use rustc_errors::Applicability;
@@ -12,7 +13,8 @@ use rustc_hir::{
use rustc_lint::{EarlyContext, EarlyLintPass, LateContext, LateLintPass, LintContext};
use rustc_middle::lint::in_external_macro;
use rustc_middle::ty;
-use rustc_session::{declare_lint_pass, declare_tool_lint};
+use rustc_semver::RustcVersion;
+use rustc_session::{declare_lint_pass, declare_tool_lint, impl_lint_pass};
use rustc_span::source_map::Span;
use rustc_span::sym;
use rustc_span::symbol::{Symbol, SymbolStr};
@@ -64,6 +66,7 @@ declare_clippy_lint! {
/// #[inline(always)]
/// fn not_quite_hot_code(..) { ... }
/// ```
+ #[clippy::version = "pre 1.29.0"]
pub INLINE_ALWAYS,
pedantic,
"use of `#[inline(always)]`"
@@ -98,6 +101,7 @@ declare_clippy_lint! {
/// #[macro_use]
/// extern crate baz;
/// ```
+ #[clippy::version = "pre 1.29.0"]
pub USELESS_ATTRIBUTE,
correctness,
"use of lint attributes on `extern crate` items"
@@ -117,6 +121,7 @@ declare_clippy_lint! {
/// #[deprecated(since = "forever")]
/// fn something_else() { /* ... */ }
/// ```
+ #[clippy::version = "pre 1.29.0"]
pub DEPRECATED_SEMVER,
correctness,
"use of `#[deprecated(since = \"x\")]` where x is not semver"
@@ -154,6 +159,7 @@ declare_clippy_lint! {
/// #[allow(dead_code)]
/// fn this_is_fine_too() { }
/// ```
+ #[clippy::version = "pre 1.29.0"]
pub EMPTY_LINE_AFTER_OUTER_ATTR,
nursery,
"empty line after outer attribute"
@@ -177,6 +183,7 @@ declare_clippy_lint! {
/// ```rust
/// #![deny(clippy::as_conversions)]
/// ```
+ #[clippy::version = "1.47.0"]
pub BLANKET_CLIPPY_RESTRICTION_LINTS,
suspicious,
"enabling the complete restriction group"
@@ -208,6 +215,7 @@ declare_clippy_lint! {
/// #[rustfmt::skip]
/// fn main() { }
/// ```
+ #[clippy::version = "1.32.0"]
pub DEPRECATED_CFG_ATTR,
complexity,
"usage of `cfg_attr(rustfmt)` instead of tool attributes"
@@ -240,6 +248,7 @@ declare_clippy_lint! {
/// fn conditional() { }
/// ```
/// Check the [Rust Reference](https://doc.rust-lang.org/reference/conditional-compilation.html#target_os) for more details.
+ #[clippy::version = "1.45.0"]
pub MISMATCHED_TARGET_OS,
correctness,
"usage of `cfg(operating_system)` instead of `cfg(target_os = \"operating_system\")`"
@@ -497,7 +506,11 @@ fn is_word(nmi: &NestedMetaItem, expected: Symbol) -> bool {
}
}
-declare_lint_pass!(EarlyAttributes => [
+pub struct EarlyAttributes {
+ pub msrv: Option<RustcVersion>,
+}
+
+impl_lint_pass!(EarlyAttributes => [
DEPRECATED_CFG_ATTR,
MISMATCHED_TARGET_OS,
EMPTY_LINE_AFTER_OUTER_ATTR,
@@ -509,9 +522,11 @@ impl EarlyLintPass for EarlyAttributes {
}
fn check_attribute(&mut self, cx: &EarlyContext<'_>, attr: &Attribute) {
- check_deprecated_cfg_attr(cx, attr);
+ check_deprecated_cfg_attr(cx, attr, self.msrv);
check_mismatched_target_os(cx, attr);
}
+
+ extract_msrv_attr!(EarlyContext);
}
fn check_empty_line_after_outer_attr(cx: &EarlyContext<'_>, item: &rustc_ast::Item) {
@@ -548,8 +563,9 @@ fn check_empty_line_after_outer_attr(cx: &EarlyContext<'_>, item: &rustc_ast::It
}
}
-fn check_deprecated_cfg_attr(cx: &EarlyContext<'_>, attr: &Attribute) {
+fn check_deprecated_cfg_attr(cx: &EarlyContext<'_>, attr: &Attribute, msrv: Option<RustcVersion>) {
if_chain! {
+ if meets_msrv(msrv.as_ref(), &msrvs::TOOL_ATTRIBUTES);
// check cfg_attr
if attr.has_name(sym::cfg_attr);
if let Some(items) = attr.meta_item_list();
diff --git a/src/tools/clippy/clippy_lints/src/await_holding_invalid.rs b/src/tools/clippy/clippy_lints/src/await_holding_invalid.rs
index 28615b9217c..1cc3418d474 100644
--- a/src/tools/clippy/clippy_lints/src/await_holding_invalid.rs
+++ b/src/tools/clippy/clippy_lints/src/await_holding_invalid.rs
@@ -47,6 +47,7 @@ declare_clippy_lint! {
/// bar.await;
/// }
/// ```
+ #[clippy::version = "1.45.0"]
pub AWAIT_HOLDING_LOCK,
pedantic,
"Inside an async function, holding a MutexGuard while calling await"
@@ -88,6 +89,7 @@ declare_clippy_lint! {
/// bar.await;
/// }
/// ```
+ #[clippy::version = "1.49.0"]
pub AWAIT_HOLDING_REFCELL_REF,
pedantic,
"Inside an async function, holding a RefCell ref while calling await"
diff --git a/src/tools/clippy/clippy_lints/src/bit_mask.rs b/src/tools/clippy/clippy_lints/src/bit_mask.rs
index 11346e7c96a..0977cf22b2c 100644
--- a/src/tools/clippy/clippy_lints/src/bit_mask.rs
+++ b/src/tools/clippy/clippy_lints/src/bit_mask.rs
@@ -41,6 +41,7 @@ declare_clippy_lint! {
/// # let x = 1;
/// if (x & 1 == 2) { }
/// ```
+ #[clippy::version = "pre 1.29.0"]
pub BAD_BIT_MASK,
correctness,
"expressions of the form `_ & mask == select` that will only ever return `true` or `false`"
@@ -73,6 +74,7 @@ declare_clippy_lint! {
/// # let x = 1;
/// if (x | 1 > 3) { }
/// ```
+ #[clippy::version = "pre 1.29.0"]
pub INEFFECTIVE_BIT_MASK,
correctness,
"expressions where a bit mask will be rendered useless by a comparison, e.g., `(x | 1) > 2`"
@@ -95,6 +97,7 @@ declare_clippy_lint! {
/// # let x = 1;
/// if x & 0b1111 == 0 { }
/// ```
+ #[clippy::version = "pre 1.29.0"]
pub VERBOSE_BIT_MASK,
pedantic,
"expressions where a bit mask is less readable than the corresponding method call"
diff --git a/src/tools/clippy/clippy_lints/src/blacklisted_name.rs b/src/tools/clippy/clippy_lints/src/blacklisted_name.rs
index 916c78c982a..1600fb25d89 100644
--- a/src/tools/clippy/clippy_lints/src/blacklisted_name.rs
+++ b/src/tools/clippy/clippy_lints/src/blacklisted_name.rs
@@ -17,6 +17,7 @@ declare_clippy_lint! {
/// ```rust
/// let foo = 3.14;
/// ```
+ #[clippy::version = "pre 1.29.0"]
pub BLACKLISTED_NAME,
style,
"usage of a blacklisted/placeholder name"
diff --git a/src/tools/clippy/clippy_lints/src/blocks_in_if_conditions.rs b/src/tools/clippy/clippy_lints/src/blocks_in_if_conditions.rs
index 47e5b0d583d..475fdb440d4 100644
--- a/src/tools/clippy/clippy_lints/src/blocks_in_if_conditions.rs
+++ b/src/tools/clippy/clippy_lints/src/blocks_in_if_conditions.rs
@@ -41,6 +41,7 @@ declare_clippy_lint! {
/// let res = { let x = somefunc(); x };
/// if res { /* ... */ }
/// ```
+ #[clippy::version = "1.45.0"]
pub BLOCKS_IN_IF_CONDITIONS,
style,
"useless or complex blocks that can be eliminated in conditions"
@@ -72,9 +73,11 @@ impl<'a, 'tcx> Visitor<'tcx> for ExVisitor<'a, 'tcx> {
let body = self.cx.tcx.hir().body(eid);
let ex = &body.value;
- if matches!(ex.kind, ExprKind::Block(_, _)) && !body.value.span.from_expansion() {
- self.found_block = Some(ex);
- return;
+ if let ExprKind::Block(block, _) = ex.kind {
+ if !body.value.span.from_expansion() && !block.stmts.is_empty() {
+ self.found_block = Some(ex);
+ return;
+ }
}
}
walk_expr(self, expr);
diff --git a/src/tools/clippy/clippy_lints/src/bool_assert_comparison.rs b/src/tools/clippy/clippy_lints/src/bool_assert_comparison.rs
index cdc192a47e4..d0b8c52a36a 100644
--- a/src/tools/clippy/clippy_lints/src/bool_assert_comparison.rs
+++ b/src/tools/clippy/clippy_lints/src/bool_assert_comparison.rs
@@ -23,6 +23,7 @@ declare_clippy_lint! {
/// // Good
/// assert!(!"a".is_empty());
/// ```
+ #[clippy::version = "1.53.0"]
pub BOOL_ASSERT_COMPARISON,
style,
"Using a boolean as comparison value in an assert_* macro when there is no need"
@@ -72,7 +73,7 @@ impl<'tcx> LateLintPass<'tcx> for BoolAssertComparison {
if let Some(span) = is_direct_expn_of(expr.span, mac) {
if let Some(args) = higher::extract_assert_macro_args(expr) {
if let [a, b, ..] = args[..] {
- let nb_bool_args = is_bool_lit(a) as usize + is_bool_lit(b) as usize;
+ let nb_bool_args = usize::from(is_bool_lit(a)) + usize::from(is_bool_lit(b));
if nb_bool_args != 1 {
// If there are two boolean arguments, we definitely don't understand
diff --git a/src/tools/clippy/clippy_lints/src/booleans.rs b/src/tools/clippy/clippy_lints/src/booleans.rs
index 8282800c819..51835ee7488 100644
--- a/src/tools/clippy/clippy_lints/src/booleans.rs
+++ b/src/tools/clippy/clippy_lints/src/booleans.rs
@@ -1,7 +1,7 @@
use clippy_utils::diagnostics::{span_lint_and_sugg, span_lint_and_then};
use clippy_utils::source::snippet_opt;
use clippy_utils::ty::{implements_trait, is_type_diagnostic_item};
-use clippy_utils::{eq_expr_value, get_trait_def_id, in_macro, paths};
+use clippy_utils::{eq_expr_value, get_trait_def_id, paths};
use if_chain::if_chain;
use rustc_ast::ast::LitKind;
use rustc_errors::Applicability;
@@ -31,6 +31,7 @@ declare_clippy_lint! {
/// if a && true // should be: if a
/// if !(a == b) // should be: if a != b
/// ```
+ #[clippy::version = "pre 1.29.0"]
pub NONMINIMAL_BOOL,
complexity,
"boolean expressions that can be written more concisely"
@@ -52,6 +53,7 @@ declare_clippy_lint! {
/// if a && b || a { ... }
/// ```
/// The `b` is unnecessary, the expression is equivalent to `if a`.
+ #[clippy::version = "pre 1.29.0"]
pub LOGIC_BUG,
correctness,
"boolean expressions that contain terminals which can be eliminated"
@@ -453,22 +455,20 @@ impl<'a, 'tcx> Visitor<'tcx> for NonminimalBoolVisitor<'a, 'tcx> {
type Map = Map<'tcx>;
fn visit_expr(&mut self, e: &'tcx Expr<'_>) {
- if in_macro(e.span) {
- return;
- }
- match &e.kind {
- ExprKind::Binary(binop, _, _) if binop.node == BinOpKind::Or || binop.node == BinOpKind::And => {
- self.bool_expr(e);
- },
- ExprKind::Unary(UnOp::Not, inner) => {
- if self.cx.typeck_results().node_types()[inner.hir_id].is_bool() {
+ if !e.span.from_expansion() {
+ match &e.kind {
+ ExprKind::Binary(binop, _, _) if binop.node == BinOpKind::Or || binop.node == BinOpKind::And => {
self.bool_expr(e);
- } else {
- walk_expr(self, e);
- }
- },
- _ => walk_expr(self, e),
+ },
+ ExprKind::Unary(UnOp::Not, inner) => {
+ if self.cx.typeck_results().node_types()[inner.hir_id].is_bool() {
+ self.bool_expr(e);
+ }
+ },
+ _ => {},
+ }
}
+ walk_expr(self, e);
}
fn nested_visit_map(&mut self) -> NestedVisitorMap<Self::Map> {
NestedVisitorMap::None
diff --git a/src/tools/clippy/clippy_lints/src/bytecount.rs b/src/tools/clippy/clippy_lints/src/bytecount.rs
index a07cd5e5f4e..92336a54e27 100644
--- a/src/tools/clippy/clippy_lints/src/bytecount.rs
+++ b/src/tools/clippy/clippy_lints/src/bytecount.rs
@@ -2,7 +2,7 @@ use clippy_utils::diagnostics::span_lint_and_sugg;
use clippy_utils::source::snippet_with_applicability;
use clippy_utils::ty::match_type;
use clippy_utils::visitors::is_local_used;
-use clippy_utils::{path_to_local_id, paths, peel_ref_operators, remove_blocks, strip_pat_refs};
+use clippy_utils::{path_to_local_id, paths, peel_blocks, peel_ref_operators, strip_pat_refs};
use if_chain::if_chain;
use rustc_errors::Applicability;
use rustc_hir::{BinOpKind, Expr, ExprKind, PatKind};
@@ -30,6 +30,7 @@ declare_clippy_lint! {
/// # let vec = vec![1_u8];
/// &vec.iter().filter(|x| **x == 0u8).count(); // use bytecount::count instead
/// ```
+ #[clippy::version = "pre 1.29.0"]
pub NAIVE_BYTECOUNT,
pedantic,
"use of naive `<slice>.filter(|&x| x == y).count()` to count byte values"
@@ -41,7 +42,7 @@ impl<'tcx> LateLintPass<'tcx> for ByteCount {
fn check_expr(&mut self, cx: &LateContext<'_>, expr: &Expr<'_>) {
if_chain! {
if let ExprKind::MethodCall(count, _, [count_recv], _) = expr.kind;
- if count.ident.name == sym!(count);
+ if count.ident.name == sym::count;
if let ExprKind::MethodCall(filter, _, [filter_recv, filter_arg], _) = count_recv.kind;
if filter.ident.name == sym!(filter);
if let ExprKind::Closure(_, _, body_id, _, _) = filter_arg.kind;
@@ -54,7 +55,7 @@ impl<'tcx> LateLintPass<'tcx> for ByteCount {
cx.typeck_results().expr_ty(filter_recv).peel_refs(),
&paths::SLICE_ITER);
let operand_is_arg = |expr| {
- let expr = peel_ref_operators(cx, remove_blocks(expr));
+ let expr = peel_ref_operators(cx, peel_blocks(expr));
path_to_local_id(expr, arg_id)
};
let needle = if operand_is_arg(l) {
@@ -73,10 +74,10 @@ impl<'tcx> LateLintPass<'tcx> for ByteCount {
if (p == sym::iter || p == sym!(iter_mut)) && args.len() == 1 {
&args[0]
} else {
- &filter_recv
+ filter_recv
}
} else {
- &filter_recv
+ filter_recv
};
let mut applicability = Applicability::MaybeIncorrect;
span_lint_and_sugg(
diff --git a/src/tools/clippy/clippy_lints/src/cargo_common_metadata.rs b/src/tools/clippy/clippy_lints/src/cargo_common_metadata.rs
index ff619c59b6e..23f79fdc682 100644
--- a/src/tools/clippy/clippy_lints/src/cargo_common_metadata.rs
+++ b/src/tools/clippy/clippy_lints/src/cargo_common_metadata.rs
@@ -42,6 +42,7 @@ declare_clippy_lint! {
/// keywords = ["clippy", "lint", "plugin"]
/// categories = ["development-tools", "development-tools::cargo-plugins"]
/// ```
+ #[clippy::version = "1.32.0"]
pub CARGO_COMMON_METADATA,
cargo,
"common metadata is defined in `Cargo.toml`"
diff --git a/src/tools/clippy/clippy_lints/src/case_sensitive_file_extension_comparisons.rs b/src/tools/clippy/clippy_lints/src/case_sensitive_file_extension_comparisons.rs
index c876553c165..3f286dd9e2f 100644
--- a/src/tools/clippy/clippy_lints/src/case_sensitive_file_extension_comparisons.rs
+++ b/src/tools/clippy/clippy_lints/src/case_sensitive_file_extension_comparisons.rs
@@ -27,6 +27,7 @@ declare_clippy_lint! {
/// filename.rsplit('.').next().map(|ext| ext.eq_ignore_ascii_case("rs")) == Some(true)
/// }
/// ```
+ #[clippy::version = "1.51.0"]
pub CASE_SENSITIVE_FILE_EXTENSION_COMPARISONS,
pedantic,
"Checks for calls to ends_with with case-sensitive file extensions"
diff --git a/src/tools/clippy/clippy_lints/src/casts/cast_lossless.rs b/src/tools/clippy/clippy_lints/src/casts/cast_lossless.rs
index 869deecfbd5..4a95bed1148 100644
--- a/src/tools/clippy/clippy_lints/src/casts/cast_lossless.rs
+++ b/src/tools/clippy/clippy_lints/src/casts/cast_lossless.rs
@@ -1,16 +1,24 @@
use clippy_utils::diagnostics::span_lint_and_sugg;
-use clippy_utils::in_constant;
use clippy_utils::source::snippet_opt;
use clippy_utils::ty::is_isize_or_usize;
+use clippy_utils::{in_constant, meets_msrv, msrvs};
use rustc_errors::Applicability;
use rustc_hir::{Expr, ExprKind};
use rustc_lint::LateContext;
use rustc_middle::ty::{self, FloatTy, Ty};
+use rustc_semver::RustcVersion;
use super::{utils, CAST_LOSSLESS};
-pub(super) fn check(cx: &LateContext<'_>, expr: &Expr<'_>, cast_op: &Expr<'_>, cast_from: Ty<'_>, cast_to: Ty<'_>) {
- if !should_lint(cx, expr, cast_from, cast_to) {
+pub(super) fn check(
+ cx: &LateContext<'_>,
+ expr: &Expr<'_>,
+ cast_op: &Expr<'_>,
+ cast_from: Ty<'_>,
+ cast_to: Ty<'_>,
+ msrv: &Option<RustcVersion>,
+) {
+ if !should_lint(cx, expr, cast_from, cast_to, msrv) {
return;
}
@@ -32,21 +40,36 @@ pub(super) fn check(cx: &LateContext<'_>, expr: &Expr<'_>, cast_op: &Expr<'_>, c
},
);
+ let message = if cast_from.is_bool() {
+ format!(
+ "casting `{0:}` to `{1:}` is more cleanly stated with `{1:}::from(_)`",
+ cast_from, cast_to
+ )
+ } else {
+ format!(
+ "casting `{}` to `{}` may become silently lossy if you later change the type",
+ cast_from, cast_to
+ )
+ };
+
span_lint_and_sugg(
cx,
CAST_LOSSLESS,
expr.span,
- &format!(
- "casting `{}` to `{}` may become silently lossy if you later change the type",
- cast_from, cast_to
- ),
+ &message,
"try",
format!("{}::from({})", cast_to, sugg),
applicability,
);
}
-fn should_lint(cx: &LateContext<'_>, expr: &Expr<'_>, cast_from: Ty<'_>, cast_to: Ty<'_>) -> bool {
+fn should_lint(
+ cx: &LateContext<'_>,
+ expr: &Expr<'_>,
+ cast_from: Ty<'_>,
+ cast_to: Ty<'_>,
+ msrv: &Option<RustcVersion>,
+) -> bool {
// Do not suggest using From in consts/statics until it is valid to do so (see #2267).
if in_constant(cx, expr.hir_id) {
return false;
@@ -72,7 +95,7 @@ fn should_lint(cx: &LateContext<'_>, expr: &Expr<'_>, cast_from: Ty<'_>, cast_to
};
from_nbits < to_nbits
},
-
+ (false, true) if matches!(cast_from.kind(), ty::Bool) && meets_msrv(msrv.as_ref(), &msrvs::FROM_BOOL) => true,
(_, _) => {
matches!(cast_from.kind(), ty::Float(FloatTy::F32)) && matches!(cast_to.kind(), ty::Float(FloatTy::F64))
},
diff --git a/src/tools/clippy/clippy_lints/src/casts/mod.rs b/src/tools/clippy/clippy_lints/src/casts/mod.rs
index 233abd17894..aee1e50b94a 100644
--- a/src/tools/clippy/clippy_lints/src/casts/mod.rs
+++ b/src/tools/clippy/clippy_lints/src/casts/mod.rs
@@ -40,6 +40,7 @@ declare_clippy_lint! {
/// let x = u64::MAX;
/// x as f64;
/// ```
+ #[clippy::version = "pre 1.29.0"]
pub CAST_PRECISION_LOSS,
pedantic,
"casts that cause loss of precision, e.g., `x as f32` where `x: u64`"
@@ -61,6 +62,7 @@ declare_clippy_lint! {
/// let y: i8 = -1;
/// y as u128; // will return 18446744073709551615
/// ```
+ #[clippy::version = "pre 1.29.0"]
pub CAST_SIGN_LOSS,
pedantic,
"casts from signed types to unsigned types, e.g., `x as u32` where `x: i32`"
@@ -83,6 +85,7 @@ declare_clippy_lint! {
/// x as u8
/// }
/// ```
+ #[clippy::version = "pre 1.29.0"]
pub CAST_POSSIBLE_TRUNCATION,
pedantic,
"casts that may cause truncation of the value, e.g., `x as u8` where `x: u32`, or `x as i32` where `x: f32`"
@@ -106,6 +109,7 @@ declare_clippy_lint! {
/// ```rust
/// u32::MAX as i32; // will yield a value of `-1`
/// ```
+ #[clippy::version = "pre 1.29.0"]
pub CAST_POSSIBLE_WRAP,
pedantic,
"casts that may cause wrapping around the value, e.g., `x as i32` where `x: u32` and `x > i32::MAX`"
@@ -138,6 +142,7 @@ declare_clippy_lint! {
/// u64::from(x)
/// }
/// ```
+ #[clippy::version = "pre 1.29.0"]
pub CAST_LOSSLESS,
pedantic,
"casts using `as` that are known to be lossless, e.g., `x as u64` where `x: u8`"
@@ -163,6 +168,7 @@ declare_clippy_lint! {
/// let _ = 2_i32;
/// let _ = 0.5_f32;
/// ```
+ #[clippy::version = "pre 1.29.0"]
pub UNNECESSARY_CAST,
complexity,
"cast to the same type, e.g., `x as i32` where `x: i32`"
@@ -190,6 +196,7 @@ declare_clippy_lint! {
/// (&1u8 as *const u8).cast::<u16>();
/// (&mut 1u8 as *mut u8).cast::<u16>();
/// ```
+ #[clippy::version = "pre 1.29.0"]
pub CAST_PTR_ALIGNMENT,
pedantic,
"cast from a pointer to a more-strictly-aligned pointer"
@@ -217,6 +224,7 @@ declare_clippy_lint! {
/// fn fun2() -> i32 { 1 }
/// let a = fun2 as usize;
/// ```
+ #[clippy::version = "pre 1.29.0"]
pub FN_TO_NUMERIC_CAST,
style,
"casting a function pointer to a numeric type other than usize"
@@ -247,6 +255,7 @@ declare_clippy_lint! {
/// let fn_ptr = fn2 as usize;
/// let fn_ptr_truncated = fn_ptr as i32;
/// ```
+ #[clippy::version = "pre 1.29.0"]
pub FN_TO_NUMERIC_CAST_WITH_TRUNCATION,
style,
"casting a function pointer to a numeric type not wide enough to store the address"
@@ -283,6 +292,7 @@ declare_clippy_lint! {
/// }
/// let _ = fn3 as fn() -> u16;
/// ```
+ #[clippy::version = "1.58.0"]
pub FN_TO_NUMERIC_CAST_ANY,
restriction,
"casting a function pointer to any integer type"
@@ -317,6 +327,7 @@ declare_clippy_lint! {
/// }
/// }
/// ```
+ #[clippy::version = "1.33.0"]
pub CAST_REF_TO_MUT,
correctness,
"a cast of reference to a mutable pointer"
@@ -344,6 +355,7 @@ declare_clippy_lint! {
/// ```rust,ignore
/// b'x'
/// ```
+ #[clippy::version = "pre 1.29.0"]
pub CHAR_LIT_AS_U8,
complexity,
"casting a character literal to `u8` truncates"
@@ -372,6 +384,7 @@ declare_clippy_lint! {
/// let _ = ptr.cast::<i32>();
/// let _ = mut_ptr.cast::<i32>();
/// ```
+ #[clippy::version = "1.51.0"]
pub PTR_AS_PTR,
pedantic,
"casting using `as` from and to raw pointers that doesn't change its mutability, where `pointer::cast` could take the place of `as`"
@@ -426,12 +439,16 @@ impl<'tcx> LateLintPass<'tcx> for Casts {
fn_to_numeric_cast_any::check(cx, expr, cast_expr, cast_from, cast_to);
fn_to_numeric_cast::check(cx, expr, cast_expr, cast_from, cast_to);
fn_to_numeric_cast_with_truncation::check(cx, expr, cast_expr, cast_from, cast_to);
- if cast_from.is_numeric() && cast_to.is_numeric() && !in_external_macro(cx.sess(), expr.span) {
- cast_possible_truncation::check(cx, expr, cast_expr, cast_from, cast_to);
- cast_possible_wrap::check(cx, expr, cast_from, cast_to);
- cast_precision_loss::check(cx, expr, cast_from, cast_to);
- cast_lossless::check(cx, expr, cast_expr, cast_from, cast_to);
- cast_sign_loss::check(cx, expr, cast_expr, cast_from, cast_to);
+
+ if cast_to.is_numeric() && !in_external_macro(cx.sess(), expr.span) {
+ if cast_from.is_numeric() {
+ cast_possible_truncation::check(cx, expr, cast_expr, cast_from, cast_to);
+ cast_possible_wrap::check(cx, expr, cast_from, cast_to);
+ cast_precision_loss::check(cx, expr, cast_from, cast_to);
+ cast_sign_loss::check(cx, expr, cast_expr, cast_from, cast_to);
+ }
+
+ cast_lossless::check(cx, expr, cast_expr, cast_from, cast_to, &self.msrv);
}
}
diff --git a/src/tools/clippy/clippy_lints/src/checked_conversions.rs b/src/tools/clippy/clippy_lints/src/checked_conversions.rs
index 842bbf006cc..ffe6340bd77 100644
--- a/src/tools/clippy/clippy_lints/src/checked_conversions.rs
+++ b/src/tools/clippy/clippy_lints/src/checked_conversions.rs
@@ -36,6 +36,7 @@ declare_clippy_lint! {
/// i32::try_from(foo).is_ok()
/// # ;
/// ```
+ #[clippy::version = "1.37.0"]
pub CHECKED_CONVERSIONS,
pedantic,
"`try_from` could replace manual bounds checking when casting"
diff --git a/src/tools/clippy/clippy_lints/src/cognitive_complexity.rs b/src/tools/clippy/clippy_lints/src/cognitive_complexity.rs
index 1ccb8c5d880..84a2373efe1 100644
--- a/src/tools/clippy/clippy_lints/src/cognitive_complexity.rs
+++ b/src/tools/clippy/clippy_lints/src/cognitive_complexity.rs
@@ -27,6 +27,7 @@ declare_clippy_lint! {
///
/// ### Example
/// No. You'll see it when you get the warning.
+ #[clippy::version = "1.35.0"]
pub COGNITIVE_COMPLEXITY,
nursery,
"functions that should be split up into multiple functions"
diff --git a/src/tools/clippy/clippy_lints/src/collapsible_if.rs b/src/tools/clippy/clippy_lints/src/collapsible_if.rs
index 4aa87980715..f03f34e5a4b 100644
--- a/src/tools/clippy/clippy_lints/src/collapsible_if.rs
+++ b/src/tools/clippy/clippy_lints/src/collapsible_if.rs
@@ -47,6 +47,7 @@ declare_clippy_lint! {
/// …
/// }
/// ```
+ #[clippy::version = "pre 1.29.0"]
pub COLLAPSIBLE_IF,
style,
"nested `if`s that can be collapsed (e.g., `if x { if y { ... } }`"
@@ -82,6 +83,7 @@ declare_clippy_lint! {
/// …
/// }
/// ```
+ #[clippy::version = "1.51.0"]
pub COLLAPSIBLE_ELSE_IF,
style,
"nested `else`-`if` expressions that can be collapsed (e.g., `else { if x { ... } }`)"
diff --git a/src/tools/clippy/clippy_lints/src/collapsible_match.rs b/src/tools/clippy/clippy_lints/src/collapsible_match.rs
index a4693fa213b..c71e9f10f79 100644
--- a/src/tools/clippy/clippy_lints/src/collapsible_match.rs
+++ b/src/tools/clippy/clippy_lints/src/collapsible_match.rs
@@ -1,10 +1,10 @@
use clippy_utils::diagnostics::span_lint_and_then;
use clippy_utils::higher::IfLetOrMatch;
use clippy_utils::visitors::is_local_used;
-use clippy_utils::{is_lang_ctor, is_unit_expr, path_to_local, peel_ref_operators, SpanlessEq};
+use clippy_utils::{is_lang_ctor, is_unit_expr, path_to_local, peel_blocks_with_stmt, peel_ref_operators, SpanlessEq};
use if_chain::if_chain;
use rustc_hir::LangItem::OptionNone;
-use rustc_hir::{Arm, Expr, ExprKind, Guard, HirId, Pat, PatKind, StmtKind};
+use rustc_hir::{Arm, Expr, Guard, HirId, Pat, PatKind};
use rustc_lint::{LateContext, LateLintPass};
use rustc_session::{declare_lint_pass, declare_tool_lint};
use rustc_span::{MultiSpan, Span};
@@ -41,6 +41,7 @@ declare_clippy_lint! {
/// };
/// }
/// ```
+ #[clippy::version = "1.50.0"]
pub COLLAPSIBLE_MATCH,
style,
"Nested `match` or `if let` expressions where the patterns may be \"collapsed\" together."
@@ -74,7 +75,7 @@ fn check_arm<'tcx>(
outer_guard: Option<&'tcx Guard<'tcx>>,
outer_else_body: Option<&'tcx Expr<'tcx>>,
) {
- let inner_expr = strip_singleton_blocks(outer_then_body);
+ let inner_expr = peel_blocks_with_stmt(outer_then_body);
if_chain! {
if let Some(inner) = IfLetOrMatch::parse(cx, inner_expr);
if let Some((inner_scrutinee, inner_then_pat, inner_else_body)) = match inner {
@@ -137,20 +138,6 @@ fn check_arm<'tcx>(
}
}
-fn strip_singleton_blocks<'hir>(mut expr: &'hir Expr<'hir>) -> &'hir Expr<'hir> {
- while let ExprKind::Block(block, _) = expr.kind {
- match (block.stmts, block.expr) {
- ([stmt], None) => match stmt.kind {
- StmtKind::Expr(e) | StmtKind::Semi(e) => expr = e,
- _ => break,
- },
- ([], Some(e)) => expr = e,
- _ => break,
- }
- }
- expr
-}
-
/// A "wild-like" arm has a wild (`_`) or `None` pattern and no guard. Such arms can be "collapsed"
/// into a single wild arm without any significant loss in semantics or readability.
fn arm_is_wild_like(cx: &LateContext<'_>, arm: &Arm<'_>) -> bool {
diff --git a/src/tools/clippy/clippy_lints/src/comparison_chain.rs b/src/tools/clippy/clippy_lints/src/comparison_chain.rs
index 597a3c67024..399d11472b0 100644
--- a/src/tools/clippy/clippy_lints/src/comparison_chain.rs
+++ b/src/tools/clippy/clippy_lints/src/comparison_chain.rs
@@ -49,6 +49,7 @@ declare_clippy_lint! {
/// }
/// }
/// ```
+ #[clippy::version = "1.40.0"]
pub COMPARISON_CHAIN,
style,
"`if`s that can be rewritten with `match` and `cmp`"
diff --git a/src/tools/clippy/clippy_lints/src/copies.rs b/src/tools/clippy/clippy_lints/src/copies.rs
index 8abf10c0d1c..d07bc23235b 100644
--- a/src/tools/clippy/clippy_lints/src/copies.rs
+++ b/src/tools/clippy/clippy_lints/src/copies.rs
@@ -1,8 +1,8 @@
use clippy_utils::diagnostics::{span_lint_and_note, span_lint_and_then};
use clippy_utils::source::{first_line_of_span, indent_of, reindent_multiline, snippet, snippet_opt};
use clippy_utils::{
- both, count_eq, eq_expr_value, get_enclosing_block, get_parent_expr, if_sequence, in_macro, is_else_clause,
- is_lint_allowed, search_same, ContainsName, SpanlessEq, SpanlessHash,
+ both, count_eq, eq_expr_value, get_enclosing_block, get_parent_expr, if_sequence, is_else_clause, is_lint_allowed,
+ search_same, ContainsName, SpanlessEq, SpanlessHash,
};
use if_chain::if_chain;
use rustc_data_structures::fx::FxHashSet;
@@ -41,6 +41,7 @@ declare_clippy_lint! {
/// …
/// }
/// ```
+ #[clippy::version = "pre 1.29.0"]
pub IFS_SAME_COND,
correctness,
"consecutive `if`s with the same condition"
@@ -88,6 +89,7 @@ declare_clippy_lint! {
/// }
/// }
/// ```
+ #[clippy::version = "1.41.0"]
pub SAME_FUNCTIONS_IN_IF_CONDITION,
pedantic,
"consecutive `if`s with the same function call"
@@ -109,6 +111,7 @@ declare_clippy_lint! {
/// 42
/// };
/// ```
+ #[clippy::version = "pre 1.29.0"]
pub IF_SAME_THEN_ELSE,
correctness,
"`if` with the same `then` and `else` blocks"
@@ -147,6 +150,7 @@ declare_clippy_lint! {
/// 42
/// };
/// ```
+ #[clippy::version = "1.53.0"]
pub BRANCHES_SHARING_CODE,
nursery,
"`if` statement with shared code in all blocks"
@@ -623,7 +627,7 @@ fn lint_same_fns_in_if_cond(cx: &LateContext<'_>, conds: &[&Expr<'_>]) {
let eq: &dyn Fn(&&Expr<'_>, &&Expr<'_>) -> bool = &|&lhs, &rhs| -> bool {
// Do not lint if any expr originates from a macro
- if in_macro(lhs.span) || in_macro(rhs.span) {
+ if lhs.span.from_expansion() || rhs.span.from_expansion() {
return false;
}
// Do not spawn warning if `IFS_SAME_COND` already produced it.
diff --git a/src/tools/clippy/clippy_lints/src/copy_iterator.rs b/src/tools/clippy/clippy_lints/src/copy_iterator.rs
index c2e9e8b3ab7..026683f6006 100644
--- a/src/tools/clippy/clippy_lints/src/copy_iterator.rs
+++ b/src/tools/clippy/clippy_lints/src/copy_iterator.rs
@@ -28,6 +28,7 @@ declare_clippy_lint! {
/// let a: Vec<_> = my_iterator.take(1).collect();
/// let b: Vec<_> = my_iterator.collect();
/// ```
+ #[clippy::version = "1.30.0"]
pub COPY_ITERATOR,
pedantic,
"implementing `Iterator` on a `Copy` type"
diff --git a/src/tools/clippy/clippy_lints/src/create_dir.rs b/src/tools/clippy/clippy_lints/src/create_dir.rs
index e4ee2772483..6bc4054a5ab 100644
--- a/src/tools/clippy/clippy_lints/src/create_dir.rs
+++ b/src/tools/clippy/clippy_lints/src/create_dir.rs
@@ -23,6 +23,7 @@ declare_clippy_lint! {
/// ```rust
/// std::fs::create_dir_all("foo");
/// ```
+ #[clippy::version = "1.48.0"]
pub CREATE_DIR,
restriction,
"calling `std::fs::create_dir` instead of `std::fs::create_dir_all`"
diff --git a/src/tools/clippy/clippy_lints/src/dbg_macro.rs b/src/tools/clippy/clippy_lints/src/dbg_macro.rs
index bab4a696f83..5a0b60fdfbc 100644
--- a/src/tools/clippy/clippy_lints/src/dbg_macro.rs
+++ b/src/tools/clippy/clippy_lints/src/dbg_macro.rs
@@ -15,6 +15,14 @@ declare_clippy_lint! {
/// `dbg!` macro is intended as a debugging tool. It
/// should not be in version control.
///
+ /// ### Known problems
+ /// * The lint level is unaffected by crate attributes. The level can still
+ /// be set for functions, modules and other items. To change the level for
+ /// the entire crate, please use command line flags. More information and a
+ /// configuration example can be found in [clippy#6610].
+ ///
+ /// [clippy#6610]: https://github.com/rust-lang/rust-clippy/issues/6610#issuecomment-977120558
+ ///
/// ### Example
/// ```rust,ignore
/// // Bad
@@ -23,6 +31,7 @@ declare_clippy_lint! {
/// // Good
/// true
/// ```
+ #[clippy::version = "1.34.0"]
pub DBG_MACRO,
restriction,
"`dbg!` macro is intended as a debugging tool"
diff --git a/src/tools/clippy/clippy_lints/src/default.rs b/src/tools/clippy/clippy_lints/src/default.rs
index cde27d3ad2a..a0b137efe22 100644
--- a/src/tools/clippy/clippy_lints/src/default.rs
+++ b/src/tools/clippy/clippy_lints/src/default.rs
@@ -1,7 +1,7 @@
use clippy_utils::diagnostics::{span_lint_and_note, span_lint_and_sugg};
use clippy_utils::source::snippet_with_macro_callsite;
use clippy_utils::ty::{has_drop, is_copy};
-use clippy_utils::{any_parent_is_automatically_derived, contains_name, in_macro, match_def_path, paths};
+use clippy_utils::{any_parent_is_automatically_derived, contains_name, match_def_path, paths};
use if_chain::if_chain;
use rustc_data_structures::fx::FxHashSet;
use rustc_errors::Applicability;
@@ -29,6 +29,7 @@ declare_clippy_lint! {
/// // Good
/// let s = String::default();
/// ```
+ #[clippy::version = "pre 1.29.0"]
pub DEFAULT_TRAIT_ACCESS,
pedantic,
"checks for literal calls to `Default::default()`"
@@ -62,6 +63,7 @@ declare_clippy_lint! {
/// .. Default::default()
/// };
/// ```
+ #[clippy::version = "1.49.0"]
pub FIELD_REASSIGN_WITH_DEFAULT,
style,
"binding initialized with Default should have its fields set in the initializer"
@@ -78,7 +80,7 @@ impl_lint_pass!(Default => [DEFAULT_TRAIT_ACCESS, FIELD_REASSIGN_WITH_DEFAULT]);
impl LateLintPass<'_> for Default {
fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
if_chain! {
- if !in_macro(expr.span);
+ if !expr.span.from_expansion();
// Avoid cases already linted by `field_reassign_with_default`
if !self.reassigned_linted.contains(&expr.span);
if let ExprKind::Call(path, ..) = expr.kind;
@@ -125,7 +127,7 @@ impl LateLintPass<'_> for Default {
if let StmtKind::Local(local) = stmt.kind;
if let Some(expr) = local.init;
if !any_parent_is_automatically_derived(cx.tcx, expr.hir_id);
- if !in_macro(expr.span);
+ if !expr.span.from_expansion();
// only take bindings to identifiers
if let PatKind::Binding(_, binding_id, ident, _) = local.pat.kind;
// only when assigning `... = Default::default()`
diff --git a/src/tools/clippy/clippy_lints/src/default_numeric_fallback.rs b/src/tools/clippy/clippy_lints/src/default_numeric_fallback.rs
index 3f1b7ea6214..3573ea5f026 100644
--- a/src/tools/clippy/clippy_lints/src/default_numeric_fallback.rs
+++ b/src/tools/clippy/clippy_lints/src/default_numeric_fallback.rs
@@ -46,6 +46,7 @@ declare_clippy_lint! {
/// let i = 10i32;
/// let f = 1.23f64;
/// ```
+ #[clippy::version = "1.52.0"]
pub DEFAULT_NUMERIC_FALLBACK,
restriction,
"usage of unconstrained numeric literals which may cause default numeric fallback."
diff --git a/src/tools/clippy/clippy_lints/src/deprecated_lints.rs b/src/tools/clippy/clippy_lints/src/deprecated_lints.rs
index 9d8524ec91c..bba27576c89 100644
--- a/src/tools/clippy/clippy_lints/src/deprecated_lints.rs
+++ b/src/tools/clippy/clippy_lints/src/deprecated_lints.rs
@@ -21,6 +21,7 @@ declare_deprecated_lint! {
/// ### Deprecation reason
/// This used to check for `assert!(a == b)` and recommend
/// replacement with `assert_eq!(a, b)`, but this is no longer needed after RFC 2011.
+ #[clippy::version = "pre 1.29.0"]
pub SHOULD_ASSERT_EQ,
"`assert!()` will be more flexible with RFC 2011"
}
@@ -32,6 +33,7 @@ declare_deprecated_lint! {
/// ### Deprecation reason
/// This used to check for `Vec::extend`, which was slower than
/// `Vec::extend_from_slice`. Thanks to specialization, this is no longer true.
+ #[clippy::version = "pre 1.29.0"]
pub EXTEND_FROM_SLICE,
"`.extend_from_slice(_)` is a faster way to extend a Vec by a slice"
}
@@ -45,6 +47,7 @@ declare_deprecated_lint! {
/// an infinite iterator, which is better expressed by `iter::repeat`,
/// but the method has been removed for `Iterator::step_by` which panics
/// if given a zero
+ #[clippy::version = "pre 1.29.0"]
pub RANGE_STEP_BY_ZERO,
"`iterator.step_by(0)` panics nowadays"
}
@@ -56,6 +59,7 @@ declare_deprecated_lint! {
/// ### Deprecation reason
/// This used to check for `Vec::as_slice`, which was unstable with good
/// stable alternatives. `Vec::as_slice` has now been stabilized.
+ #[clippy::version = "pre 1.29.0"]
pub UNSTABLE_AS_SLICE,
"`Vec::as_slice` has been stabilized in 1.7"
}
@@ -67,6 +71,7 @@ declare_deprecated_lint! {
/// ### Deprecation reason
/// This used to check for `Vec::as_mut_slice`, which was unstable with good
/// stable alternatives. `Vec::as_mut_slice` has now been stabilized.
+ #[clippy::version = "pre 1.29.0"]
pub UNSTABLE_AS_MUT_SLICE,
"`Vec::as_mut_slice` has been stabilized in 1.7"
}
@@ -80,6 +85,7 @@ declare_deprecated_lint! {
/// between non-pointer types of differing alignment is well-defined behavior (it's semantically
/// equivalent to a memcpy). This lint has thus been refactored into two separate lints:
/// cast_ptr_alignment and transmute_ptr_to_ptr.
+ #[clippy::version = "pre 1.29.0"]
pub MISALIGNED_TRANSMUTE,
"this lint has been split into cast_ptr_alignment and transmute_ptr_to_ptr"
}
@@ -92,6 +98,7 @@ declare_deprecated_lint! {
/// This lint is too subjective, not having a good reason for being in clippy.
/// Additionally, compound assignment operators may be overloaded separately from their non-assigning
/// counterparts, so this lint may suggest a change in behavior or the code may not compile.
+ #[clippy::version = "1.30.0"]
pub ASSIGN_OPS,
"using compound assignment operators (e.g., `+=`) is harmless"
}
@@ -104,6 +111,7 @@ declare_deprecated_lint! {
/// The original rule will only lint for `if let`. After
/// making it support to lint `match`, naming as `if let` is not suitable for it.
/// So, this lint is deprecated.
+ #[clippy::version = "pre 1.29.0"]
pub IF_LET_REDUNDANT_PATTERN_MATCHING,
"this lint has been changed to redundant_pattern_matching"
}
@@ -117,6 +125,7 @@ declare_deprecated_lint! {
/// Vec::with_capacity(n); vec.set_len(n);` with `let vec = vec![0; n];`. The
/// replacement has very different performance characteristics so the lint is
/// deprecated.
+ #[clippy::version = "pre 1.29.0"]
pub UNSAFE_VECTOR_INITIALIZATION,
"the replacement suggested by this lint had substantially different behavior"
}
@@ -127,6 +136,7 @@ declare_deprecated_lint! {
///
/// ### Deprecation reason
/// This lint has been superseded by #[must_use] in rustc.
+ #[clippy::version = "1.39.0"]
pub UNUSED_COLLECT,
"`collect` has been marked as #[must_use] in rustc and that covers all cases of this lint"
}
@@ -137,6 +147,7 @@ declare_deprecated_lint! {
///
/// ### Deprecation reason
/// Associated-constants are now preferred.
+ #[clippy::version = "1.44.0"]
pub REPLACE_CONSTS,
"associated-constants `MIN`/`MAX` of integers are preferred to `{min,max}_value()` and module constants"
}
@@ -147,6 +158,7 @@ declare_deprecated_lint! {
///
/// ### Deprecation reason
/// The regex! macro does not exist anymore.
+ #[clippy::version = "1.47.0"]
pub REGEX_MACRO,
"the regex! macro has been removed from the regex crate in 2018"
}
@@ -158,6 +170,7 @@ declare_deprecated_lint! {
/// ### Deprecation reason
/// This lint has been replaced by `manual_find_map`, a
/// more specific lint.
+ #[clippy::version = "1.51.0"]
pub FIND_MAP,
"this lint has been replaced by `manual_find_map`, a more specific lint"
}
@@ -169,6 +182,7 @@ declare_deprecated_lint! {
/// ### Deprecation reason
/// This lint has been replaced by `manual_filter_map`, a
/// more specific lint.
+ #[clippy::version = "1.53.0"]
pub FILTER_MAP,
"this lint has been replaced by `manual_filter_map`, a more specific lint"
}
@@ -181,6 +195,7 @@ declare_deprecated_lint! {
/// The `avoid_breaking_exported_api` config option was added, which
/// enables the `enum_variant_names` lint for public items.
/// ```
+ #[clippy::version = "1.54.0"]
pub PUB_ENUM_VARIANT_NAMES,
"set the `avoid-breaking-exported-api` config option to `false` to enable the `enum_variant_names` lint for public items"
}
@@ -192,6 +207,7 @@ declare_deprecated_lint! {
/// ### Deprecation reason
/// The `avoid_breaking_exported_api` config option was added, which
/// enables the `wrong_self_conversion` lint for public items.
+ #[clippy::version = "1.54.0"]
pub WRONG_PUB_SELF_CONVENTION,
"set the `avoid-breaking-exported-api` config option to `false` to enable the `wrong_self_convention` lint for public items"
}
diff --git a/src/tools/clippy/clippy_lints/src/dereference.rs b/src/tools/clippy/clippy_lints/src/dereference.rs
index ce59311c4aa..fa2b348591b 100644
--- a/src/tools/clippy/clippy_lints/src/dereference.rs
+++ b/src/tools/clippy/clippy_lints/src/dereference.rs
@@ -1,14 +1,20 @@
-use clippy_utils::diagnostics::span_lint_and_sugg;
-use clippy_utils::source::snippet_with_context;
+use clippy_utils::diagnostics::{span_lint_and_sugg, span_lint_and_then};
+use clippy_utils::source::{snippet_with_applicability, snippet_with_context};
use clippy_utils::ty::peel_mid_ty_refs;
-use clippy_utils::{get_parent_node, in_macro, is_lint_allowed};
-use rustc_ast::util::parser::PREC_PREFIX;
+use clippy_utils::{get_parent_expr, get_parent_node, is_lint_allowed, path_to_local};
+use rustc_ast::util::parser::{PREC_POSTFIX, PREC_PREFIX};
+use rustc_data_structures::fx::FxIndexMap;
use rustc_errors::Applicability;
-use rustc_hir::{BorrowKind, Expr, ExprKind, HirId, MatchSource, Mutability, Node, UnOp};
+use rustc_hir::{
+ BindingAnnotation, Body, BodyId, BorrowKind, Destination, Expr, ExprKind, HirId, MatchSource, Mutability, Node,
+ Pat, PatKind, UnOp,
+};
use rustc_lint::{LateContext, LateLintPass};
+use rustc_middle::ty::adjustment::{Adjust, Adjustment, AutoBorrow};
use rustc_middle::ty::{self, Ty, TyCtxt, TyS, TypeckResults};
use rustc_session::{declare_tool_lint, impl_lint_pass};
use rustc_span::{symbol::sym, Span};
+use std::iter;
declare_clippy_lint! {
/// ### What it does
@@ -34,13 +40,70 @@ declare_clippy_lint! {
/// ```rust,ignore
/// let _ = d.unwrap().deref();
/// ```
+ #[clippy::version = "1.44.0"]
pub EXPLICIT_DEREF_METHODS,
pedantic,
"Explicit use of deref or deref_mut method while not in a method chain."
}
+declare_clippy_lint! {
+ /// ### What it does
+ /// Checks for address of operations (`&`) that are going to
+ /// be dereferenced immediately by the compiler.
+ ///
+ /// ### Why is this bad?
+ /// Suggests that the receiver of the expression borrows
+ /// the expression.
+ ///
+ /// ### Example
+ /// ```rust
+ /// fn fun(_a: &i32) {}
+ ///
+ /// // Bad
+ /// let x: &i32 = &&&&&&5;
+ /// fun(&x);
+ ///
+ /// // Good
+ /// let x: &i32 = &5;
+ /// fun(x);
+ /// ```
+ #[clippy::version = "pre 1.29.0"]
+ pub NEEDLESS_BORROW,
+ style,
+ "taking a reference that is going to be automatically dereferenced"
+}
+
+declare_clippy_lint! {
+ /// ### What it does
+ /// Checks for `ref` bindings which create a reference to a reference.
+ ///
+ /// ### Why is this bad?
+ /// The address-of operator at the use site is clearer about the need for a reference.
+ ///
+ /// ### Example
+ /// ```rust
+ /// // Bad
+ /// let x = Some("");
+ /// if let Some(ref x) = x {
+ /// // use `x` here
+ /// }
+ ///
+ /// // Good
+ /// let x = Some("");
+ /// if let Some(x) = x {
+ /// // use `&x` here
+ /// }
+ /// ```
+ #[clippy::version = "1.54.0"]
+ pub REF_BINDING_TO_REFERENCE,
+ pedantic,
+ "`ref` binding to a reference"
+}
+
impl_lint_pass!(Dereferencing => [
EXPLICIT_DEREF_METHODS,
+ NEEDLESS_BORROW,
+ REF_BINDING_TO_REFERENCE,
]);
#[derive(Default)]
@@ -51,6 +114,18 @@ pub struct Dereferencing {
// expression. This is to store the id of that expression so it can be skipped when
// `check_expr` is called for it.
skip_expr: Option<HirId>,
+
+ /// The body the first local was found in. Used to emit lints when the traversal of the body has
+ /// been finished. Note we can't lint at the end of every body as they can be nested within each
+ /// other.
+ current_body: Option<BodyId>,
+ /// The list of locals currently being checked by the lint.
+ /// If the value is `None`, then the binding has been seen as a ref pattern, but is not linted.
+ /// This is needed for or patterns where one of the branches can be linted, but another can not
+ /// be.
+ ///
+ /// e.g. `m!(x) | Foo::Bar(ref x)`
+ ref_locals: FxIndexMap<HirId, Option<RefPat>>,
}
struct StateData {
@@ -67,6 +142,9 @@ enum State {
ty_changed_count: usize,
is_final_ufcs: bool,
},
+ DerefedBorrow {
+ count: u32,
+ },
}
// A reference operation considered by this lint pass
@@ -76,15 +154,31 @@ enum RefOp {
AddrOf,
}
+struct RefPat {
+ /// Whether every usage of the binding is dereferenced.
+ always_deref: bool,
+ /// The spans of all the ref bindings for this local.
+ spans: Vec<Span>,
+ /// The applicability of this suggestion.
+ app: Applicability,
+ /// All the replacements which need to be made.
+ replacements: Vec<(Span, String)>,
+}
+
impl<'tcx> LateLintPass<'tcx> for Dereferencing {
+ #[allow(clippy::too_many_lines)]
fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
// Skip path expressions from deref calls. e.g. `Deref::deref(e)`
if Some(expr.hir_id) == self.skip_expr.take() {
return;
}
+ if let Some(local) = path_to_local(expr) {
+ self.check_local_usage(cx, expr, local);
+ }
+
// Stop processing sub expressions when a macro call is seen
- if in_macro(expr.span) {
+ if expr.span.from_expansion() {
if let Some((state, data)) = self.state.take() {
report(cx, expr, state, data);
}
@@ -127,6 +221,48 @@ impl<'tcx> LateLintPass<'tcx> for Dereferencing {
},
));
},
+ RefOp::AddrOf => {
+ // Find the number of times the borrow is auto-derefed.
+ let mut iter = find_adjustments(cx.tcx, typeck, expr).iter();
+ if let Some((i, adjust)) = iter.by_ref().enumerate().find_map(|(i, adjust)| {
+ if !matches!(adjust.kind, Adjust::Deref(_)) {
+ Some((i, adjust))
+ } else if !adjust.target.is_ref() {
+ // Add one to the number of references found.
+ Some((i + 1, adjust))
+ } else {
+ None
+ }
+ }) {
+ // Found two consecutive derefs. At least one can be removed.
+ if i > 1 {
+ let target_mut = iter::once(adjust)
+ .chain(iter)
+ .find_map(|adjust| match adjust.kind {
+ Adjust::Borrow(AutoBorrow::Ref(_, m)) => Some(m.into()),
+ _ => None,
+ })
+ // This default should never happen. Auto-deref always reborrows.
+ .unwrap_or(Mutability::Not);
+ self.state = Some((
+ // Subtract one for the current borrow expression, and one to cover the last
+ // reference which can't be removed (it's either reborrowed, or needed for
+ // auto-deref to happen).
+ State::DerefedBorrow {
+ count:
+ // Truncation here would require more than a `u32::MAX` level reference. The compiler
+ // does not support this.
+ #[allow(clippy::cast_possible_truncation)]
+ { i as u32 - 2 }
+ },
+ StateData {
+ span: expr.span,
+ target_mut,
+ },
+ ));
+ }
+ }
+ },
_ => (),
}
},
@@ -143,10 +279,80 @@ impl<'tcx> LateLintPass<'tcx> for Dereferencing {
data,
));
},
+ (Some((State::DerefedBorrow { count }, data)), RefOp::AddrOf) if count != 0 => {
+ self.state = Some((State::DerefedBorrow { count: count - 1 }, data));
+ },
(Some((state, data)), _) => report(cx, expr, state, data),
}
}
+
+ fn check_pat(&mut self, cx: &LateContext<'tcx>, pat: &'tcx Pat<'_>) {
+ if let PatKind::Binding(BindingAnnotation::Ref, id, name, _) = pat.kind {
+ if let Some(opt_prev_pat) = self.ref_locals.get_mut(&id) {
+ // This binding id has been seen before. Add this pattern to the list of changes.
+ if let Some(prev_pat) = opt_prev_pat {
+ if pat.span.from_expansion() {
+ // Doesn't match the context of the previous pattern. Can't lint here.
+ *opt_prev_pat = None;
+ } else {
+ prev_pat.spans.push(pat.span);
+ prev_pat.replacements.push((
+ pat.span,
+ snippet_with_context(cx, name.span, pat.span.ctxt(), "..", &mut prev_pat.app)
+ .0
+ .into(),
+ ));
+ }
+ }
+ return;
+ }
+
+ if_chain! {
+ if !pat.span.from_expansion();
+ if let ty::Ref(_, tam, _) = *cx.typeck_results().pat_ty(pat).kind();
+ // only lint immutable refs, because borrowed `&mut T` cannot be moved out
+ if let ty::Ref(_, _, Mutability::Not) = *tam.kind();
+ then {
+ let mut app = Applicability::MachineApplicable;
+ let snip = snippet_with_context(cx, name.span, pat.span.ctxt(), "..", &mut app).0;
+ self.current_body = self.current_body.or(cx.enclosing_body);
+ self.ref_locals.insert(
+ id,
+ Some(RefPat {
+ always_deref: true,
+ spans: vec![pat.span],
+ app,
+ replacements: vec![(pat.span, snip.into())],
+ }),
+ );
+ }
+ }
+ }
+ }
+
+ fn check_body_post(&mut self, cx: &LateContext<'tcx>, body: &'tcx Body<'_>) {
+ if Some(body.id()) == self.current_body {
+ for pat in self.ref_locals.drain(..).filter_map(|(_, x)| x) {
+ let replacements = pat.replacements;
+ let app = pat.app;
+ span_lint_and_then(
+ cx,
+ if pat.always_deref {
+ NEEDLESS_BORROW
+ } else {
+ REF_BINDING_TO_REFERENCE
+ },
+ pat.spans,
+ "this pattern creates a reference to a reference",
+ |diag| {
+ diag.multipart_suggestion("try this", replacements, app);
+ },
+ );
+ }
+ self.current_body = None;
+ }
+ }
}
fn try_parse_ref_op(
@@ -250,6 +456,48 @@ fn is_linted_explicit_deref_position(parent: Option<Node<'_>>, child_id: HirId,
}
}
+/// Adjustments are sometimes made in the parent block rather than the expression itself.
+fn find_adjustments(
+ tcx: TyCtxt<'tcx>,
+ typeck: &'tcx TypeckResults<'_>,
+ expr: &'tcx Expr<'_>,
+) -> &'tcx [Adjustment<'tcx>] {
+ let map = tcx.hir();
+ let mut iter = map.parent_iter(expr.hir_id);
+ let mut prev = expr;
+
+ loop {
+ match typeck.expr_adjustments(prev) {
+ [] => (),
+ a => break a,
+ };
+
+ match iter.next().map(|(_, x)| x) {
+ Some(Node::Block(_)) => {
+ if let Some((_, Node::Expr(e))) = iter.next() {
+ prev = e;
+ } else {
+ // This shouldn't happen. Blocks are always contained in an expression.
+ break &[];
+ }
+ },
+ Some(Node::Expr(&Expr {
+ kind: ExprKind::Break(Destination { target_id: Ok(id), .. }, _),
+ ..
+ })) => {
+ if let Some(Node::Expr(e)) = map.find(id) {
+ prev = e;
+ iter = map.parent_iter(id);
+ } else {
+ // This shouldn't happen. The destination should exist.
+ break &[];
+ }
+ },
+ _ => break &[],
+ }
+ }
+}
+
#[allow(clippy::needless_pass_by_value)]
fn report(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>, state: State, data: StateData) {
match state {
@@ -300,5 +548,83 @@ fn report(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>, state: State, data: Stat
app,
);
},
+ State::DerefedBorrow { .. } => {
+ let mut app = Applicability::MachineApplicable;
+ let snip = snippet_with_context(cx, expr.span, data.span.ctxt(), "..", &mut app).0;
+ span_lint_and_sugg(
+ cx,
+ NEEDLESS_BORROW,
+ data.span,
+ &format!(
+ "this expression borrows a reference (`{}`) that is immediately dereferenced by the compiler",
+ cx.typeck_results().expr_ty(expr),
+ ),
+ "change this to",
+ snip.into(),
+ app,
+ );
+ },
+ }
+}
+
+impl Dereferencing {
+ fn check_local_usage(&mut self, cx: &LateContext<'tcx>, e: &'tcx Expr<'_>, local: HirId) {
+ if let Some(outer_pat) = self.ref_locals.get_mut(&local) {
+ if let Some(pat) = outer_pat {
+ // Check for auto-deref
+ if !matches!(
+ cx.typeck_results().expr_adjustments(e),
+ [
+ Adjustment {
+ kind: Adjust::Deref(_),
+ ..
+ },
+ Adjustment {
+ kind: Adjust::Deref(_),
+ ..
+ },
+ ..
+ ]
+ ) {
+ match get_parent_expr(cx, e) {
+ // Field accesses are the same no matter the number of references.
+ Some(Expr {
+ kind: ExprKind::Field(..),
+ ..
+ }) => (),
+ Some(&Expr {
+ span,
+ kind: ExprKind::Unary(UnOp::Deref, _),
+ ..
+ }) if !span.from_expansion() => {
+ // Remove explicit deref.
+ let snip = snippet_with_context(cx, e.span, span.ctxt(), "..", &mut pat.app).0;
+ pat.replacements.push((span, snip.into()));
+ },
+ Some(parent) if !parent.span.from_expansion() => {
+ // Double reference might be needed at this point.
+ if parent.precedence().order() == PREC_POSTFIX {
+ // Parentheses would be needed here, don't lint.
+ *outer_pat = None;
+ } else {
+ pat.always_deref = false;
+ let snip = snippet_with_context(cx, e.span, parent.span.ctxt(), "..", &mut pat.app).0;
+ pat.replacements.push((e.span, format!("&{}", snip)));
+ }
+ },
+ _ if !e.span.from_expansion() => {
+ // Double reference might be needed at this point.
+ pat.always_deref = false;
+ let snip = snippet_with_applicability(cx, e.span, "..", &mut pat.app);
+ pat.replacements.push((e.span, format!("&{}", snip)));
+ },
+ // Edge case for macros. The span of the identifier will usually match the context of the
+ // binding, but not if the identifier was created in a macro. e.g. `concat_idents` and proc
+ // macros
+ _ => *outer_pat = None,
+ }
+ }
+ }
+ }
}
}
diff --git a/src/tools/clippy/clippy_lints/src/derivable_impls.rs b/src/tools/clippy/clippy_lints/src/derivable_impls.rs
index fdef0abe970..eccb18982f3 100644
--- a/src/tools/clippy/clippy_lints/src/derivable_impls.rs
+++ b/src/tools/clippy/clippy_lints/src/derivable_impls.rs
@@ -1,5 +1,5 @@
use clippy_utils::diagnostics::span_lint_and_help;
-use clippy_utils::{in_macro, is_automatically_derived, is_default_equivalent, remove_blocks};
+use clippy_utils::{is_automatically_derived, is_default_equivalent, peel_blocks};
use rustc_hir::{
def::{DefKind, Res},
Body, Expr, ExprKind, GenericArg, Impl, ImplItemKind, Item, ItemKind, Node, PathSegment, QPath, TyKind,
@@ -46,6 +46,7 @@ declare_clippy_lint! {
/// has exactly equal bounds, and therefore this lint is disabled for types with
/// generic parameters.
///
+ #[clippy::version = "1.57.0"]
pub DERIVABLE_IMPLS,
complexity,
"manual implementation of the `Default` trait which is equal to a derive"
@@ -72,7 +73,7 @@ impl<'tcx> LateLintPass<'tcx> for DerivableImpls {
}) = item.kind;
if let attrs = cx.tcx.hir().attrs(item.hir_id());
if !is_automatically_derived(attrs);
- if !in_macro(item.span);
+ if !item.span.from_expansion();
if let Some(def_id) = trait_ref.trait_def_id();
if cx.tcx.is_diagnostic_item(sym::Default, def_id);
if let impl_item_hir = child.id.hir_id();
@@ -94,7 +95,7 @@ impl<'tcx> LateLintPass<'tcx> for DerivableImpls {
}
}
}
- let should_emit = match remove_blocks(func_expr).kind {
+ let should_emit = match peel_blocks(func_expr).kind {
ExprKind::Tup(fields) => fields.iter().all(|e| is_default_equivalent(cx, e)),
ExprKind::Call(callee, args)
if is_path_self(callee) => args.iter().all(|e| is_default_equivalent(cx, e)),
diff --git a/src/tools/clippy/clippy_lints/src/derive.rs b/src/tools/clippy/clippy_lints/src/derive.rs
index 24ac5917dcb..097cb65f56e 100644
--- a/src/tools/clippy/clippy_lints/src/derive.rs
+++ b/src/tools/clippy/clippy_lints/src/derive.rs
@@ -3,7 +3,6 @@ use clippy_utils::paths;
use clippy_utils::ty::{implements_trait, is_copy};
use clippy_utils::{get_trait_def_id, is_automatically_derived, is_lint_allowed, match_def_path};
use if_chain::if_chain;
-use rustc_hir::def_id::DefId;
use rustc_hir::intravisit::{walk_expr, walk_fn, walk_item, FnKind, NestedVisitorMap, Visitor};
use rustc_hir::{
BlockCheckMode, BodyId, Expr, ExprKind, FnDecl, HirId, Impl, Item, ItemKind, TraitRef, UnsafeSource, Unsafety,
@@ -38,6 +37,7 @@ declare_clippy_lint! {
/// ...
/// }
/// ```
+ #[clippy::version = "pre 1.29.0"]
pub DERIVE_HASH_XOR_EQ,
correctness,
"deriving `Hash` but implementing `PartialEq` explicitly"
@@ -88,6 +88,7 @@ declare_clippy_lint! {
/// #[derive(Ord, PartialOrd, PartialEq, Eq)]
/// struct Foo;
/// ```
+ #[clippy::version = "1.47.0"]
pub DERIVE_ORD_XOR_PARTIAL_ORD,
correctness,
"deriving `Ord` but implementing `PartialOrd` explicitly"
@@ -114,6 +115,7 @@ declare_clippy_lint! {
/// // ..
/// }
/// ```
+ #[clippy::version = "pre 1.29.0"]
pub EXPL_IMPL_CLONE_ON_COPY,
pedantic,
"implementing `Clone` explicitly on `Copy` types"
@@ -147,6 +149,7 @@ declare_clippy_lint! {
/// }
/// }
/// ```
+ #[clippy::version = "1.45.0"]
pub UNSAFE_DERIVE_DESERIALIZE,
pedantic,
"deriving `serde::Deserialize` on a type that has methods using `unsafe`"
@@ -343,11 +346,6 @@ fn check_unsafe_derive_deserialize<'tcx>(
trait_ref: &TraitRef<'_>,
ty: Ty<'tcx>,
) {
- fn item_from_def_id<'tcx>(cx: &LateContext<'tcx>, def_id: DefId) -> &'tcx Item<'tcx> {
- let hir_id = cx.tcx.hir().local_def_id_to_hir_id(def_id.expect_local());
- cx.tcx.hir().expect_item(hir_id)
- }
-
fn has_unsafe<'tcx>(cx: &LateContext<'tcx>, item: &'tcx Item<'_>) -> bool {
let mut visitor = UnsafeVisitor { cx, has_unsafe: false };
walk_item(&mut visitor, item);
@@ -363,7 +361,7 @@ fn check_unsafe_derive_deserialize<'tcx>(
if !is_lint_allowed(cx, UNSAFE_DERIVE_DESERIALIZE, adt_hir_id);
if cx.tcx.inherent_impls(def.did)
.iter()
- .map(|imp_did| item_from_def_id(cx, *imp_did))
+ .map(|imp_did| cx.tcx.hir().expect_item(imp_did.expect_local()))
.any(|imp| has_unsafe(cx, imp));
then {
span_lint_and_help(
diff --git a/src/tools/clippy/clippy_lints/src/disallowed_method.rs b/src/tools/clippy/clippy_lints/src/disallowed_methods.rs
index 22d726cdcb7..6d4065907fb 100644
--- a/src/tools/clippy/clippy_lints/src/disallowed_method.rs
+++ b/src/tools/clippy/clippy_lints/src/disallowed_methods.rs
@@ -47,18 +47,19 @@ declare_clippy_lint! {
/// let mut xs = Vec::new(); // Vec::new is _not_ disallowed in the config.
/// xs.push(123); // Vec::push is _not_ disallowed in the config.
/// ```
- pub DISALLOWED_METHOD,
+ #[clippy::version = "1.49.0"]
+ pub DISALLOWED_METHODS,
nursery,
"use of a disallowed method call"
}
#[derive(Clone, Debug)]
-pub struct DisallowedMethod {
+pub struct DisallowedMethods {
conf_disallowed: Vec<conf::DisallowedMethod>,
disallowed: DefIdMap<Option<String>>,
}
-impl DisallowedMethod {
+impl DisallowedMethods {
pub fn new(conf_disallowed: Vec<conf::DisallowedMethod>) -> Self {
Self {
conf_disallowed,
@@ -67,9 +68,9 @@ impl DisallowedMethod {
}
}
-impl_lint_pass!(DisallowedMethod => [DISALLOWED_METHOD]);
+impl_lint_pass!(DisallowedMethods => [DISALLOWED_METHODS]);
-impl<'tcx> LateLintPass<'tcx> for DisallowedMethod {
+impl<'tcx> LateLintPass<'tcx> for DisallowedMethods {
fn check_crate(&mut self, cx: &LateContext<'_>) {
for conf in &self.conf_disallowed {
let (path, reason) = match conf {
@@ -97,7 +98,7 @@ impl<'tcx> LateLintPass<'tcx> for DisallowedMethod {
};
let func_path = cx.tcx.def_path_str(def_id);
let msg = format!("use of a disallowed method `{}`", func_path);
- span_lint_and_then(cx, DISALLOWED_METHOD, expr.span, &msg, |diag| {
+ span_lint_and_then(cx, DISALLOWED_METHODS, expr.span, &msg, |diag| {
if let Some(reason) = reason {
diag.note(reason);
}
diff --git a/src/tools/clippy/clippy_lints/src/disallowed_script_idents.rs b/src/tools/clippy/clippy_lints/src/disallowed_script_idents.rs
index 6d38d30cd0b..3c3f3631849 100644
--- a/src/tools/clippy/clippy_lints/src/disallowed_script_idents.rs
+++ b/src/tools/clippy/clippy_lints/src/disallowed_script_idents.rs
@@ -38,6 +38,7 @@ declare_clippy_lint! {
/// let zähler = 10; // OK, it's still latin.
/// let カウンタ = 10; // Will spawn the lint.
/// ```
+ #[clippy::version = "1.55.0"]
pub DISALLOWED_SCRIPT_IDENTS,
restriction,
"usage of non-allowed Unicode scripts"
diff --git a/src/tools/clippy/clippy_lints/src/disallowed_type.rs b/src/tools/clippy/clippy_lints/src/disallowed_types.rs
index 48f781516f4..eaed4032713 100644
--- a/src/tools/clippy/clippy_lints/src/disallowed_type.rs
+++ b/src/tools/clippy/clippy_lints/src/disallowed_types.rs
@@ -42,18 +42,19 @@ declare_clippy_lint! {
/// // A similar type that is allowed by the config
/// use std::collections::HashMap;
/// ```
- pub DISALLOWED_TYPE,
+ #[clippy::version = "1.55.0"]
+ pub DISALLOWED_TYPES,
nursery,
- "use of a disallowed type"
+ "use of disallowed types"
}
#[derive(Clone, Debug)]
-pub struct DisallowedType {
+pub struct DisallowedTypes {
conf_disallowed: Vec<conf::DisallowedType>,
def_ids: FxHashMap<DefId, Option<String>>,
prim_tys: FxHashMap<PrimTy, Option<String>>,
}
-impl DisallowedType {
+impl DisallowedTypes {
pub fn new(conf_disallowed: Vec<conf::DisallowedType>) -> Self {
Self {
conf_disallowed,
@@ -79,9 +80,9 @@ impl DisallowedType {
}
}
-impl_lint_pass!(DisallowedType => [DISALLOWED_TYPE]);
+impl_lint_pass!(DisallowedTypes => [DISALLOWED_TYPES]);
-impl<'tcx> LateLintPass<'tcx> for DisallowedType {
+impl<'tcx> LateLintPass<'tcx> for DisallowedTypes {
fn check_crate(&mut self, cx: &LateContext<'_>) {
for conf in &self.conf_disallowed {
let (path, reason) = match conf {
@@ -124,7 +125,7 @@ impl<'tcx> LateLintPass<'tcx> for DisallowedType {
fn emit(cx: &LateContext<'_>, name: &str, span: Span, reason: Option<&str>) {
span_lint_and_then(
cx,
- DISALLOWED_TYPE,
+ DISALLOWED_TYPES,
span,
&format!("`{}` is not allowed according to config", name),
|diag| {
diff --git a/src/tools/clippy/clippy_lints/src/doc.rs b/src/tools/clippy/clippy_lints/src/doc.rs
index d4ba072807f..2cdd59c5691 100644
--- a/src/tools/clippy/clippy_lints/src/doc.rs
+++ b/src/tools/clippy/clippy_lints/src/doc.rs
@@ -1,5 +1,5 @@
use clippy_utils::attrs::is_doc_hidden;
-use clippy_utils::diagnostics::{span_lint, span_lint_and_help, span_lint_and_note, span_lint_and_sugg};
+use clippy_utils::diagnostics::{span_lint, span_lint_and_help, span_lint_and_note, span_lint_and_then};
use clippy_utils::source::{first_line_of_span, snippet_with_applicability};
use clippy_utils::ty::{implements_trait, is_type_diagnostic_item};
use clippy_utils::{is_entrypoint_fn, is_expn_of, match_panic_def_id, method_chain_args, return_ty};
@@ -10,7 +10,7 @@ use rustc_ast::token::CommentKind;
use rustc_data_structures::fx::FxHashSet;
use rustc_data_structures::sync::Lrc;
use rustc_errors::emitter::EmitterWriter;
-use rustc_errors::{Applicability, Handler};
+use rustc_errors::{Applicability, Handler, SuggestionStyle};
use rustc_hir as hir;
use rustc_hir::intravisit::{self, NestedVisitorMap, Visitor};
use rustc_hir::{AnonConst, Expr, ExprKind, QPath};
@@ -67,6 +67,7 @@ declare_clippy_lint! {
/// /// [SmallVec]: SmallVec
/// fn main() {}
/// ```
+ #[clippy::version = "pre 1.29.0"]
pub DOC_MARKDOWN,
pedantic,
"presence of `_`, `::` or camel-case outside backticks in documentation"
@@ -101,6 +102,7 @@ declare_clippy_lint! {
/// unimplemented!();
/// }
/// ```
+ #[clippy::version = "1.39.0"]
pub MISSING_SAFETY_DOC,
style,
"`pub unsafe fn` without `# Safety` docs"
@@ -129,6 +131,7 @@ declare_clippy_lint! {
/// unimplemented!();
/// }
/// ```
+ #[clippy::version = "1.41.0"]
pub MISSING_ERRORS_DOC,
pedantic,
"`pub fn` returns `Result` without `# Errors` in doc comment"
@@ -159,6 +162,7 @@ declare_clippy_lint! {
/// }
/// }
/// ```
+ #[clippy::version = "1.52.0"]
pub MISSING_PANICS_DOC,
pedantic,
"`pub fn` may panic without `# Panics` in doc comment"
@@ -187,6 +191,7 @@ declare_clippy_lint! {
/// unimplemented!();
/// }
/// ``````
+ #[clippy::version = "1.40.0"]
pub NEEDLESS_DOCTEST_MAIN,
style,
"presence of `fn main() {` in code examples"
@@ -639,7 +644,9 @@ fn check_code(cx: &LateContext<'_>, text: &str, edition: Edition, span: Span) {
| ItemKind::ExternCrate(..)
| ItemKind::ForeignMod(..) => return false,
// We found a main function ...
- ItemKind::Fn(box Fn { sig, body: Some(block), .. }) if item.ident.name == sym::main => {
+ ItemKind::Fn(box Fn {
+ sig, body: Some(block), ..
+ }) if item.ident.name == sym::main => {
let is_async = matches!(sig.header.asyncness, Async::Yes { .. });
let returns_nothing = match &sig.decl.output {
FnRetTy::Default(..) => true,
@@ -763,14 +770,23 @@ fn check_word(cx: &LateContext<'_>, word: &str, span: Span) {
if has_underscore(word) || word.contains("::") || is_camel_case(word) {
let mut applicability = Applicability::MachineApplicable;
- span_lint_and_sugg(
+ span_lint_and_then(
cx,
DOC_MARKDOWN,
span,
"item in documentation is missing backticks",
- "try",
- format!("`{}`", snippet_with_applicability(cx, span, "..", &mut applicability)),
- applicability,
+ |diag| {
+ let snippet = snippet_with_applicability(cx, span, "..", &mut applicability);
+ diag.span_suggestion_with_style(
+ span,
+ "try",
+ format!("`{}`", snippet),
+ applicability,
+ // always show the suggestion in a separate line, since the
+ // inline presentation adds another pair of backticks
+ SuggestionStyle::ShowAlways,
+ );
+ },
);
}
}
diff --git a/src/tools/clippy/clippy_lints/src/double_comparison.rs b/src/tools/clippy/clippy_lints/src/double_comparison.rs
index 6520bb91faf..176092e5b28 100644
--- a/src/tools/clippy/clippy_lints/src/double_comparison.rs
+++ b/src/tools/clippy/clippy_lints/src/double_comparison.rs
@@ -31,6 +31,7 @@ declare_clippy_lint! {
/// # let y = 2;
/// if x <= y {}
/// ```
+ #[clippy::version = "pre 1.29.0"]
pub DOUBLE_COMPARISONS,
complexity,
"unnecessary double comparisons that can be simplified"
diff --git a/src/tools/clippy/clippy_lints/src/double_parens.rs b/src/tools/clippy/clippy_lints/src/double_parens.rs
index d0d87b6df9a..e10f740d24a 100644
--- a/src/tools/clippy/clippy_lints/src/double_parens.rs
+++ b/src/tools/clippy/clippy_lints/src/double_parens.rs
@@ -32,6 +32,7 @@ declare_clippy_lint! {
/// // Good
/// foo(0);
/// ```
+ #[clippy::version = "pre 1.29.0"]
pub DOUBLE_PARENS,
complexity,
"Warn on unnecessary double parentheses"
diff --git a/src/tools/clippy/clippy_lints/src/drop_forget_ref.rs b/src/tools/clippy/clippy_lints/src/drop_forget_ref.rs
index 0f3dc866afb..a8f8e3d8a42 100644
--- a/src/tools/clippy/clippy_lints/src/drop_forget_ref.rs
+++ b/src/tools/clippy/clippy_lints/src/drop_forget_ref.rs
@@ -25,6 +25,7 @@ declare_clippy_lint! {
/// // still locked
/// operation_that_requires_mutex_to_be_unlocked();
/// ```
+ #[clippy::version = "pre 1.29.0"]
pub DROP_REF,
correctness,
"calls to `std::mem::drop` with a reference instead of an owned value"
@@ -46,6 +47,7 @@ declare_clippy_lint! {
/// let x = Box::new(1);
/// std::mem::forget(&x) // Should have been forget(x), x will still be dropped
/// ```
+ #[clippy::version = "pre 1.29.0"]
pub FORGET_REF,
correctness,
"calls to `std::mem::forget` with a reference instead of an owned value"
@@ -67,6 +69,7 @@ declare_clippy_lint! {
/// std::mem::drop(x) // A copy of x is passed to the function, leaving the
/// // original unaffected
/// ```
+ #[clippy::version = "pre 1.29.0"]
pub DROP_COPY,
correctness,
"calls to `std::mem::drop` with a value that implements Copy"
@@ -94,6 +97,7 @@ declare_clippy_lint! {
/// std::mem::forget(x) // A copy of x is passed to the function, leaving the
/// // original unaffected
/// ```
+ #[clippy::version = "pre 1.29.0"]
pub FORGET_COPY,
correctness,
"calls to `std::mem::forget` with a value that implements Copy"
diff --git a/src/tools/clippy/clippy_lints/src/duration_subsec.rs b/src/tools/clippy/clippy_lints/src/duration_subsec.rs
index 3774de62521..3070d105014 100644
--- a/src/tools/clippy/clippy_lints/src/duration_subsec.rs
+++ b/src/tools/clippy/clippy_lints/src/duration_subsec.rs
@@ -33,6 +33,7 @@ declare_clippy_lint! {
/// let _micros = dur.subsec_micros();
/// let _millis = dur.subsec_millis();
/// ```
+ #[clippy::version = "pre 1.29.0"]
pub DURATION_SUBSEC,
complexity,
"checks for calculation of subsecond microseconds or milliseconds"
diff --git a/src/tools/clippy/clippy_lints/src/else_if_without_else.rs b/src/tools/clippy/clippy_lints/src/else_if_without_else.rs
index b64246515f3..92c56c762aa 100644
--- a/src/tools/clippy/clippy_lints/src/else_if_without_else.rs
+++ b/src/tools/clippy/clippy_lints/src/else_if_without_else.rs
@@ -40,6 +40,7 @@ declare_clippy_lint! {
/// // We don't care about zero.
/// }
/// ```
+ #[clippy::version = "pre 1.29.0"]
pub ELSE_IF_WITHOUT_ELSE,
restriction,
"`if` expression with an `else if`, but without a final `else` branch"
diff --git a/src/tools/clippy/clippy_lints/src/empty_enum.rs b/src/tools/clippy/clippy_lints/src/empty_enum.rs
index 3453c2da278..af9e65e6361 100644
--- a/src/tools/clippy/clippy_lints/src/empty_enum.rs
+++ b/src/tools/clippy/clippy_lints/src/empty_enum.rs
@@ -34,6 +34,7 @@ declare_clippy_lint! {
///
/// struct Test(!);
/// ```
+ #[clippy::version = "pre 1.29.0"]
pub EMPTY_ENUM,
pedantic,
"enum with no variants"
diff --git a/src/tools/clippy/clippy_lints/src/entry.rs b/src/tools/clippy/clippy_lints/src/entry.rs
index 57fd24bd4f0..3d92eb16870 100644
--- a/src/tools/clippy/clippy_lints/src/entry.rs
+++ b/src/tools/clippy/clippy_lints/src/entry.rs
@@ -54,6 +54,7 @@ declare_clippy_lint! {
/// # let v = 1;
/// map.entry(k).or_insert(v);
/// ```
+ #[clippy::version = "pre 1.29.0"]
pub MAP_ENTRY,
perf,
"use of `contains_key` followed by `insert` on a `HashMap` or `BTreeMap`"
diff --git a/src/tools/clippy/clippy_lints/src/enum_clike.rs b/src/tools/clippy/clippy_lints/src/enum_clike.rs
index a2c3c7a7b49..3b6661c817b 100644
--- a/src/tools/clippy/clippy_lints/src/enum_clike.rs
+++ b/src/tools/clippy/clippy_lints/src/enum_clike.rs
@@ -28,6 +28,7 @@ declare_clippy_lint! {
/// Y = 0,
/// }
/// ```
+ #[clippy::version = "pre 1.29.0"]
pub ENUM_CLIKE_UNPORTABLE_VARIANT,
correctness,
"C-like enums that are `repr(isize/usize)` and have values that don't fit into an `i32`"
diff --git a/src/tools/clippy/clippy_lints/src/enum_variants.rs b/src/tools/clippy/clippy_lints/src/enum_variants.rs
index 404b67c8f29..fc3a35efaf8 100644
--- a/src/tools/clippy/clippy_lints/src/enum_variants.rs
+++ b/src/tools/clippy/clippy_lints/src/enum_variants.rs
@@ -34,6 +34,7 @@ declare_clippy_lint! {
/// Battenberg,
/// }
/// ```
+ #[clippy::version = "pre 1.29.0"]
pub ENUM_VARIANT_NAMES,
style,
"enums where all variants share a prefix/postfix"
@@ -59,6 +60,7 @@ declare_clippy_lint! {
/// struct BlackForest;
/// }
/// ```
+ #[clippy::version = "1.33.0"]
pub MODULE_NAME_REPETITIONS,
pedantic,
"type names prefixed/postfixed with their containing module's name"
@@ -89,6 +91,7 @@ declare_clippy_lint! {
/// ...
/// }
/// ```
+ #[clippy::version = "pre 1.29.0"]
pub MODULE_INCEPTION,
style,
"modules that have the same name as their parent module"
diff --git a/src/tools/clippy/clippy_lints/src/eq_op.rs b/src/tools/clippy/clippy_lints/src/eq_op.rs
index 655560afd42..10123460527 100644
--- a/src/tools/clippy/clippy_lints/src/eq_op.rs
+++ b/src/tools/clippy/clippy_lints/src/eq_op.rs
@@ -1,9 +1,7 @@
use clippy_utils::diagnostics::{multispan_sugg, span_lint, span_lint_and_then};
use clippy_utils::source::snippet;
use clippy_utils::ty::{implements_trait, is_copy};
-use clippy_utils::{
- ast_utils::is_useless_with_eq_exprs, eq_expr_value, higher, in_macro, is_expn_of, is_in_test_function,
-};
+use clippy_utils::{ast_utils::is_useless_with_eq_exprs, eq_expr_value, higher, is_expn_of, is_in_test_function};
use if_chain::if_chain;
use rustc_errors::Applicability;
use rustc_hir::{BinOpKind, BorrowKind, Expr, ExprKind, StmtKind};
@@ -36,6 +34,7 @@ declare_clippy_lint! {
/// # let b = 4;
/// assert_eq!(a, a);
/// ```
+ #[clippy::version = "pre 1.29.0"]
pub EQ_OP,
correctness,
"equal operands on both sides of a comparison or bitwise combination (e.g., `x == x`)"
@@ -61,6 +60,7 @@ declare_clippy_lint! {
/// // Good
/// x == *y
/// ```
+ #[clippy::version = "pre 1.29.0"]
pub OP_REF,
style,
"taking a reference to satisfy the type constraints on `==`"
@@ -102,7 +102,7 @@ impl<'tcx> LateLintPass<'tcx> for EqOp {
}
let macro_with_not_op = |expr_kind: &ExprKind<'_>| {
if let ExprKind::Unary(_, expr) = *expr_kind {
- in_macro(expr.span)
+ expr.span.from_expansion()
} else {
false
}
diff --git a/src/tools/clippy/clippy_lints/src/equatable_if_let.rs b/src/tools/clippy/clippy_lints/src/equatable_if_let.rs
index e8b1d6f6eda..06d128f5527 100644
--- a/src/tools/clippy/clippy_lints/src/equatable_if_let.rs
+++ b/src/tools/clippy/clippy_lints/src/equatable_if_let.rs
@@ -32,6 +32,7 @@ declare_clippy_lint! {
/// do_thing();
/// }
/// ```
+ #[clippy::version = "1.57.0"]
pub EQUATABLE_IF_LET,
nursery,
"using pattern matching instead of equality"
@@ -66,20 +67,20 @@ fn is_structural_partial_eq(cx: &LateContext<'tcx>, ty: Ty<'tcx>, other: Ty<'tcx
impl<'tcx> LateLintPass<'tcx> for PatternEquality {
fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>) {
if_chain! {
- if let ExprKind::Let(pat, exp, _) = expr.kind;
- if unary_pattern(pat);
- let exp_ty = cx.typeck_results().expr_ty(exp);
- let pat_ty = cx.typeck_results().pat_ty(pat);
+ if let ExprKind::Let(let_expr) = expr.kind;
+ if unary_pattern(let_expr.pat);
+ let exp_ty = cx.typeck_results().expr_ty(let_expr.init);
+ let pat_ty = cx.typeck_results().pat_ty(let_expr.pat);
if is_structural_partial_eq(cx, exp_ty, pat_ty);
then {
let mut applicability = Applicability::MachineApplicable;
- let pat_str = match pat.kind {
+ let pat_str = match let_expr.pat.kind {
PatKind::Struct(..) => format!(
"({})",
- snippet_with_context(cx, pat.span, expr.span.ctxt(), "..", &mut applicability).0,
+ snippet_with_context(cx, let_expr.pat.span, expr.span.ctxt(), "..", &mut applicability).0,
),
- _ => snippet_with_context(cx, pat.span, expr.span.ctxt(), "..", &mut applicability).0.to_string(),
+ _ => snippet_with_context(cx, let_expr.pat.span, expr.span.ctxt(), "..", &mut applicability).0.to_string(),
};
span_lint_and_sugg(
cx,
@@ -89,7 +90,7 @@ impl<'tcx> LateLintPass<'tcx> for PatternEquality {
"try",
format!(
"{} == {}",
- snippet_with_context(cx, exp.span, expr.span.ctxt(), "..", &mut applicability).0,
+ snippet_with_context(cx, let_expr.init.span, expr.span.ctxt(), "..", &mut applicability).0,
pat_str,
),
applicability,
diff --git a/src/tools/clippy/clippy_lints/src/erasing_op.rs b/src/tools/clippy/clippy_lints/src/erasing_op.rs
index d0944c37cf5..d49cec26be5 100644
--- a/src/tools/clippy/clippy_lints/src/erasing_op.rs
+++ b/src/tools/clippy/clippy_lints/src/erasing_op.rs
@@ -21,6 +21,7 @@ declare_clippy_lint! {
/// 0 * x;
/// x & 0;
/// ```
+ #[clippy::version = "pre 1.29.0"]
pub ERASING_OP,
correctness,
"using erasing operations, e.g., `x * 0` or `y & 0`"
diff --git a/src/tools/clippy/clippy_lints/src/escape.rs b/src/tools/clippy/clippy_lints/src/escape.rs
index 75b1c882c23..bc5d2f6278d 100644
--- a/src/tools/clippy/clippy_lints/src/escape.rs
+++ b/src/tools/clippy/clippy_lints/src/escape.rs
@@ -41,6 +41,7 @@ declare_clippy_lint! {
/// foo(x);
/// println!("{}", x);
/// ```
+ #[clippy::version = "pre 1.29.0"]
pub BOXED_LOCAL,
perf,
"using `Box<T>` where unnecessary"
diff --git a/src/tools/clippy/clippy_lints/src/eta_reduction.rs b/src/tools/clippy/clippy_lints/src/eta_reduction.rs
index 9247343b52a..5a4b4247104 100644
--- a/src/tools/clippy/clippy_lints/src/eta_reduction.rs
+++ b/src/tools/clippy/clippy_lints/src/eta_reduction.rs
@@ -1,8 +1,8 @@
use clippy_utils::diagnostics::{span_lint_and_sugg, span_lint_and_then};
use clippy_utils::higher::VecArgs;
use clippy_utils::source::snippet_opt;
-use clippy_utils::usage::UsedAfterExprVisitor;
-use clippy_utils::{get_enclosing_loop_or_closure, higher, path_to_local_id};
+use clippy_utils::usage::local_used_after_expr;
+use clippy_utils::{get_enclosing_loop_or_closure, higher, path_to_local, path_to_local_id};
use if_chain::if_chain;
use rustc_errors::Applicability;
use rustc_hir::def_id::DefId;
@@ -39,6 +39,7 @@ declare_clippy_lint! {
/// ```
/// where `foo(_)` is a plain function that takes the exact argument type of
/// `x`.
+ #[clippy::version = "pre 1.29.0"]
pub REDUNDANT_CLOSURE,
style,
"redundant closures, i.e., `|a| foo(a)` (which can be written as just `foo`)"
@@ -60,6 +61,7 @@ declare_clippy_lint! {
/// ```rust,ignore
/// Some('a').map(char::to_uppercase);
/// ```
+ #[clippy::version = "1.35.0"]
pub REDUNDANT_CLOSURE_FOR_METHOD_CALLS,
pedantic,
"redundant closures for method calls"
@@ -118,7 +120,7 @@ impl<'tcx> LateLintPass<'tcx> for EtaReduction {
if let ty::Closure(_, substs) = callee_ty.peel_refs().kind();
if substs.as_closure().kind() == ClosureKind::FnMut;
if get_enclosing_loop_or_closure(cx.tcx, expr).is_some()
- || UsedAfterExprVisitor::is_found(cx, callee);
+ || path_to_local(callee).map_or(false, |l| local_used_after_expr(cx, l, callee));
then {
// Mutable closure is used after current expr; we cannot consume it.
diff --git a/src/tools/clippy/clippy_lints/src/eval_order_dependence.rs b/src/tools/clippy/clippy_lints/src/eval_order_dependence.rs
index 1b56dd4b081..cdac9f3e6e1 100644
--- a/src/tools/clippy/clippy_lints/src/eval_order_dependence.rs
+++ b/src/tools/clippy/clippy_lints/src/eval_order_dependence.rs
@@ -40,6 +40,7 @@ declare_clippy_lint! {
/// };
/// let a = tmp + x;
/// ```
+ #[clippy::version = "pre 1.29.0"]
pub EVAL_ORDER_DEPENDENCE,
suspicious,
"whether a variable read occurs before a write depends on sub-expression evaluation order"
@@ -67,6 +68,7 @@ declare_clippy_lint! {
/// let x = (a, b, c, panic!());
/// // can simply be replaced by `panic!()`
/// ```
+ #[clippy::version = "pre 1.29.0"]
pub DIVERGING_SUB_EXPRESSION,
complexity,
"whether an expression contains a diverging sub expression"
diff --git a/src/tools/clippy/clippy_lints/src/excessive_bools.rs b/src/tools/clippy/clippy_lints/src/excessive_bools.rs
index 09b6e200838..245a4fc12fd 100644
--- a/src/tools/clippy/clippy_lints/src/excessive_bools.rs
+++ b/src/tools/clippy/clippy_lints/src/excessive_bools.rs
@@ -1,5 +1,4 @@
use clippy_utils::diagnostics::span_lint_and_help;
-use clippy_utils::in_macro;
use rustc_ast::ast::{AssocItemKind, Extern, Fn, FnSig, Impl, Item, ItemKind, Trait, Ty, TyKind};
use rustc_lint::{EarlyContext, EarlyLintPass};
use rustc_session::{declare_tool_lint, impl_lint_pass};
@@ -38,6 +37,7 @@ declare_clippy_lint! {
/// Finished,
/// }
/// ```
+ #[clippy::version = "1.43.0"]
pub STRUCT_EXCESSIVE_BOOLS,
pedantic,
"using too many bools in a struct"
@@ -76,6 +76,7 @@ declare_clippy_lint! {
///
/// fn f(shape: Shape, temperature: Temperature) { ... }
/// ```
+ #[clippy::version = "1.43.0"]
pub FN_PARAMS_EXCESSIVE_BOOLS,
pedantic,
"using too many bools in function parameters"
@@ -135,7 +136,7 @@ fn is_bool_ty(ty: &Ty) -> bool {
impl EarlyLintPass for ExcessiveBools {
fn check_item(&mut self, cx: &EarlyContext<'_>, item: &Item) {
- if in_macro(item.span) {
+ if item.span.from_expansion() {
return;
}
match &item.kind {
diff --git a/src/tools/clippy/clippy_lints/src/exhaustive_items.rs b/src/tools/clippy/clippy_lints/src/exhaustive_items.rs
index bb4684ce38b..b0f50b5c144 100644
--- a/src/tools/clippy/clippy_lints/src/exhaustive_items.rs
+++ b/src/tools/clippy/clippy_lints/src/exhaustive_items.rs
@@ -31,6 +31,7 @@ declare_clippy_lint! {
/// Baz
/// }
/// ```
+ #[clippy::version = "1.51.0"]
pub EXHAUSTIVE_ENUMS,
restriction,
"detects exported enums that have not been marked #[non_exhaustive]"
@@ -60,6 +61,7 @@ declare_clippy_lint! {
/// baz: String,
/// }
/// ```
+ #[clippy::version = "1.51.0"]
pub EXHAUSTIVE_STRUCTS,
restriction,
"detects exported structs that have not been marked #[non_exhaustive]"
diff --git a/src/tools/clippy/clippy_lints/src/exit.rs b/src/tools/clippy/clippy_lints/src/exit.rs
index 9cd5b2d9f44..d64cc61916c 100644
--- a/src/tools/clippy/clippy_lints/src/exit.rs
+++ b/src/tools/clippy/clippy_lints/src/exit.rs
@@ -18,6 +18,7 @@ declare_clippy_lint! {
/// ```ignore
/// std::process::exit(0)
/// ```
+ #[clippy::version = "1.41.0"]
pub EXIT,
restriction,
"`std::process::exit` is called, terminating the program"
diff --git a/src/tools/clippy/clippy_lints/src/explicit_write.rs b/src/tools/clippy/clippy_lints/src/explicit_write.rs
index 4f46ef906f4..6b327b9ce17 100644
--- a/src/tools/clippy/clippy_lints/src/explicit_write.rs
+++ b/src/tools/clippy/clippy_lints/src/explicit_write.rs
@@ -23,6 +23,7 @@ declare_clippy_lint! {
/// // this would be clearer as `eprintln!("foo: {:?}", bar);`
/// writeln!(&mut std::io::stderr(), "foo: {:?}", bar).unwrap();
/// ```
+ #[clippy::version = "pre 1.29.0"]
pub EXPLICIT_WRITE,
complexity,
"using the `write!()` family of functions instead of the `print!()` family of functions, when using the latter would work"
diff --git a/src/tools/clippy/clippy_lints/src/fallible_impl_from.rs b/src/tools/clippy/clippy_lints/src/fallible_impl_from.rs
index 70337f5bbeb..05d300058cf 100644
--- a/src/tools/clippy/clippy_lints/src/fallible_impl_from.rs
+++ b/src/tools/clippy/clippy_lints/src/fallible_impl_from.rs
@@ -44,6 +44,7 @@ declare_clippy_lint! {
/// }
/// }
/// ```
+ #[clippy::version = "pre 1.29.0"]
pub FALLIBLE_IMPL_FROM,
nursery,
"Warn on impls of `From<..>` that contain `panic!()` or `unwrap()`"
diff --git a/src/tools/clippy/clippy_lints/src/feature_name.rs b/src/tools/clippy/clippy_lints/src/feature_name.rs
index f534327f7a0..dc6bef52ddd 100644
--- a/src/tools/clippy/clippy_lints/src/feature_name.rs
+++ b/src/tools/clippy/clippy_lints/src/feature_name.rs
@@ -31,6 +31,7 @@ declare_clippy_lint! {
/// ghi = []
/// ```
///
+ #[clippy::version = "1.57.0"]
pub REDUNDANT_FEATURE_NAMES,
cargo,
"usage of a redundant feature name"
@@ -60,6 +61,7 @@ declare_clippy_lint! {
/// def = []
///
/// ```
+ #[clippy::version = "1.57.0"]
pub NEGATIVE_FEATURE_NAMES,
cargo,
"usage of a negative feature name"
diff --git a/src/tools/clippy/clippy_lints/src/float_equality_without_abs.rs b/src/tools/clippy/clippy_lints/src/float_equality_without_abs.rs
index c33d80b8e8e..ca8886228de 100644
--- a/src/tools/clippy/clippy_lints/src/float_equality_without_abs.rs
+++ b/src/tools/clippy/clippy_lints/src/float_equality_without_abs.rs
@@ -37,6 +37,7 @@ declare_clippy_lint! {
/// (a - b).abs() < f32::EPSILON
/// }
/// ```
+ #[clippy::version = "1.48.0"]
pub FLOAT_EQUALITY_WITHOUT_ABS,
suspicious,
"float equality check without `.abs()`"
diff --git a/src/tools/clippy/clippy_lints/src/float_literal.rs b/src/tools/clippy/clippy_lints/src/float_literal.rs
index 1e8a5bd7d34..d30dede833c 100644
--- a/src/tools/clippy/clippy_lints/src/float_literal.rs
+++ b/src/tools/clippy/clippy_lints/src/float_literal.rs
@@ -27,6 +27,7 @@ declare_clippy_lint! {
/// let v: f64 = 0.123_456_789_9;
/// println!("{}", v); // 0.123_456_789_9
/// ```
+ #[clippy::version = "pre 1.29.0"]
pub EXCESSIVE_PRECISION,
style,
"excessive precision for float literal"
@@ -50,6 +51,7 @@ declare_clippy_lint! {
/// let _: f32 = 16_777_216.0;
/// let _: f64 = 16_777_217.0;
/// ```
+ #[clippy::version = "1.43.0"]
pub LOSSY_FLOAT_LITERAL,
restriction,
"lossy whole number float literals"
diff --git a/src/tools/clippy/clippy_lints/src/floating_point_arithmetic.rs b/src/tools/clippy/clippy_lints/src/floating_point_arithmetic.rs
index eda611117ba..2de2bfc040b 100644
--- a/src/tools/clippy/clippy_lints/src/floating_point_arithmetic.rs
+++ b/src/tools/clippy/clippy_lints/src/floating_point_arithmetic.rs
@@ -4,7 +4,7 @@ use clippy_utils::consts::{
};
use clippy_utils::diagnostics::span_lint_and_sugg;
use clippy_utils::higher;
-use clippy_utils::{eq_expr_value, get_parent_expr, numeric_literal, sugg};
+use clippy_utils::{eq_expr_value, get_parent_expr, in_constant, numeric_literal, peel_blocks, sugg};
use if_chain::if_chain;
use rustc_errors::Applicability;
use rustc_hir::{BinOpKind, Expr, ExprKind, PathSegment, UnOp};
@@ -43,6 +43,7 @@ declare_clippy_lint! {
/// let _ = a.ln_1p();
/// let _ = a.exp_m1();
/// ```
+ #[clippy::version = "1.43.0"]
pub IMPRECISE_FLOPS,
nursery,
"usage of imprecise floating point operations"
@@ -99,6 +100,7 @@ declare_clippy_lint! {
/// let _ = a.abs();
/// let _ = -a.abs();
/// ```
+ #[clippy::version = "1.43.0"]
pub SUBOPTIMAL_FLOPS,
nursery,
"usage of sub-optimal floating point operations"
@@ -544,13 +546,9 @@ fn are_negated<'a>(cx: &LateContext<'_>, expr1: &'a Expr<'a>, expr2: &'a Expr<'a
fn check_custom_abs(cx: &LateContext<'_>, expr: &Expr<'_>) {
if_chain! {
- if let Some(higher::If { cond, then, r#else }) = higher::If::hir(expr);
- if let ExprKind::Block(block, _) = then.kind;
- if block.stmts.is_empty();
- if let Some(if_body_expr) = block.expr;
- if let Some(ExprKind::Block(else_block, _)) = r#else.map(|el| &el.kind);
- if else_block.stmts.is_empty();
- if let Some(else_body_expr) = else_block.expr;
+ if let Some(higher::If { cond, then, r#else: Some(r#else) }) = higher::If::hir(expr);
+ let if_body_expr = peel_blocks(then);
+ let else_body_expr = peel_blocks(r#else);
if let Some((if_expr_positive, body)) = are_negated(cx, if_body_expr, else_body_expr);
then {
let positive_abs_sugg = (
@@ -685,6 +683,11 @@ fn check_radians(cx: &LateContext<'_>, expr: &Expr<'_>) {
impl<'tcx> LateLintPass<'tcx> for FloatingPointArithmetic {
fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
+ // All of these operations are currently not const.
+ if in_constant(cx, expr.hir_id) {
+ return;
+ }
+
if let ExprKind::MethodCall(path, _, args, _) = &expr.kind {
let recv_ty = cx.typeck_results().expr_ty(&args[0]);
diff --git a/src/tools/clippy/clippy_lints/src/format.rs b/src/tools/clippy/clippy_lints/src/format.rs
index 7169ac9ad6c..3f043e5f2f1 100644
--- a/src/tools/clippy/clippy_lints/src/format.rs
+++ b/src/tools/clippy/clippy_lints/src/format.rs
@@ -33,6 +33,7 @@ declare_clippy_lint! {
/// // Good
/// foo.to_owned();
/// ```
+ #[clippy::version = "pre 1.29.0"]
pub USELESS_FORMAT,
complexity,
"useless use of `format!`"
diff --git a/src/tools/clippy/clippy_lints/src/format_args.rs b/src/tools/clippy/clippy_lints/src/format_args.rs
index 8b27442aa94..f0e1a67dcdd 100644
--- a/src/tools/clippy/clippy_lints/src/format_args.rs
+++ b/src/tools/clippy/clippy_lints/src/format_args.rs
@@ -10,7 +10,7 @@ use rustc_lint::{LateContext, LateLintPass};
use rustc_middle::ty::adjustment::{Adjust, Adjustment};
use rustc_middle::ty::Ty;
use rustc_session::{declare_lint_pass, declare_tool_lint};
-use rustc_span::{sym, BytePos, ExpnData, ExpnKind, Span, Symbol};
+use rustc_span::{sym, ExpnData, ExpnKind, Span, Symbol};
declare_clippy_lint! {
/// ### What it does
@@ -31,6 +31,7 @@ declare_clippy_lint! {
/// # use std::panic::Location;
/// println!("error: something failed at {}", Location::caller());
/// ```
+ #[clippy::version = "1.58.0"]
pub FORMAT_IN_FORMAT_ARGS,
perf,
"`format!` used in a macro that does formatting"
@@ -56,6 +57,7 @@ declare_clippy_lint! {
/// # use std::panic::Location;
/// println!("error: something failed at {}", Location::caller());
/// ```
+ #[clippy::version = "1.58.0"]
pub TO_STRING_IN_FORMAT_ARGS,
perf,
"`to_string` applied to a type that implements `Display` in format args"
@@ -128,7 +130,7 @@ fn check_format_in_format_args(cx: &LateContext<'_>, call_site: Span, name: Symb
span_lint_and_then(
cx,
FORMAT_IN_FORMAT_ARGS,
- trim_semicolon(cx, call_site),
+ call_site,
&format!("`format!` in `{}!` args", name),
|diag| {
diag.help(&format!(
@@ -192,13 +194,6 @@ fn is_aliased(args: &[FormatArgsArg<'_>], i: usize) -> bool {
.any(|(j, arg)| i != j && std::ptr::eq(value, arg.value))
}
-fn trim_semicolon(cx: &LateContext<'_>, span: Span) -> Span {
- snippet_opt(cx, span).map_or(span, |snippet| {
- let snippet = snippet.trim_end_matches(';');
- span.with_hi(span.lo() + BytePos(u32::try_from(snippet.len()).unwrap()))
- })
-}
-
fn count_needed_derefs<'tcx, I>(mut ty: Ty<'tcx>, mut iter: I) -> (usize, Ty<'tcx>)
where
I: Iterator<Item = &'tcx Adjustment<'tcx>>,
diff --git a/src/tools/clippy/clippy_lints/src/formatting.rs b/src/tools/clippy/clippy_lints/src/formatting.rs
index b4f186525c5..3e85c8a9c80 100644
--- a/src/tools/clippy/clippy_lints/src/formatting.rs
+++ b/src/tools/clippy/clippy_lints/src/formatting.rs
@@ -21,6 +21,7 @@ declare_clippy_lint! {
/// ```rust,ignore
/// a =- 42; // confusing, should it be `a -= 42` or `a = -42`?
/// ```
+ #[clippy::version = "pre 1.29.0"]
pub SUSPICIOUS_ASSIGNMENT_FORMATTING,
suspicious,
"suspicious formatting of `*=`, `-=` or `!=`"
@@ -43,6 +44,7 @@ declare_clippy_lint! {
/// if foo &&! bar { // this should be `foo && !bar` but looks like a different operator
/// }
/// ```
+ #[clippy::version = "1.40.0"]
pub SUSPICIOUS_UNARY_OP_FORMATTING,
suspicious,
"suspicious formatting of unary `-` or `!` on the RHS of a BinOp"
@@ -79,6 +81,7 @@ declare_clippy_lint! {
/// if bar { // this is the `else` block of the previous `if`, but should it be?
/// }
/// ```
+ #[clippy::version = "pre 1.29.0"]
pub SUSPICIOUS_ELSE_FORMATTING,
suspicious,
"suspicious formatting of `else`"
@@ -99,6 +102,7 @@ declare_clippy_lint! {
/// -4, -5, -6
/// ];
/// ```
+ #[clippy::version = "pre 1.29.0"]
pub POSSIBLE_MISSING_COMMA,
correctness,
"possible missing comma in array"
diff --git a/src/tools/clippy/clippy_lints/src/from_over_into.rs b/src/tools/clippy/clippy_lints/src/from_over_into.rs
index 347c6eb12cb..866ff216f84 100644
--- a/src/tools/clippy/clippy_lints/src/from_over_into.rs
+++ b/src/tools/clippy/clippy_lints/src/from_over_into.rs
@@ -34,6 +34,7 @@ declare_clippy_lint! {
/// }
/// }
/// ```
+ #[clippy::version = "1.51.0"]
pub FROM_OVER_INTO,
style,
"Warns on implementations of `Into<..>` to use `From<..>`"
diff --git a/src/tools/clippy/clippy_lints/src/from_str_radix_10.rs b/src/tools/clippy/clippy_lints/src/from_str_radix_10.rs
index 98ce3db025c..73e800073b0 100644
--- a/src/tools/clippy/clippy_lints/src/from_str_radix_10.rs
+++ b/src/tools/clippy/clippy_lints/src/from_str_radix_10.rs
@@ -35,6 +35,7 @@ declare_clippy_lint! {
/// let input: &str = get_input();
/// let num: u16 = input.parse()?;
/// ```
+ #[clippy::version = "1.52.0"]
pub FROM_STR_RADIX_10,
style,
"from_str_radix with radix 10"
diff --git a/src/tools/clippy/clippy_lints/src/functions/mod.rs b/src/tools/clippy/clippy_lints/src/functions/mod.rs
index d7c5ec9ba35..ad031cbc09d 100644
--- a/src/tools/clippy/clippy_lints/src/functions/mod.rs
+++ b/src/tools/clippy/clippy_lints/src/functions/mod.rs
@@ -26,6 +26,7 @@ declare_clippy_lint! {
/// // ..
/// }
/// ```
+ #[clippy::version = "pre 1.29.0"]
pub TOO_MANY_ARGUMENTS,
complexity,
"functions with too many arguments"
@@ -49,6 +50,7 @@ declare_clippy_lint! {
/// println!("");
/// }
/// ```
+ #[clippy::version = "1.34.0"]
pub TOO_MANY_LINES,
pedantic,
"functions with too many lines"
@@ -84,6 +86,7 @@ declare_clippy_lint! {
/// println!("{}", unsafe { *x });
/// }
/// ```
+ #[clippy::version = "pre 1.29.0"]
pub NOT_UNSAFE_PTR_ARG_DEREF,
correctness,
"public functions dereferencing raw pointer arguments but not marked `unsafe`"
@@ -103,6 +106,7 @@ declare_clippy_lint! {
/// #[must_use]
/// fn useless() { }
/// ```
+ #[clippy::version = "1.40.0"]
pub MUST_USE_UNIT,
style,
"`#[must_use]` attribute on a unit-returning function / method"
@@ -126,6 +130,7 @@ declare_clippy_lint! {
/// unimplemented!();
/// }
/// ```
+ #[clippy::version = "1.40.0"]
pub DOUBLE_MUST_USE,
style,
"`#[must_use]` attribute on a `#[must_use]`-returning function / method"
@@ -155,6 +160,7 @@ declare_clippy_lint! {
/// // this could be annotated with `#[must_use]`.
/// fn id<T>(t: T) -> T { t }
/// ```
+ #[clippy::version = "1.40.0"]
pub MUST_USE_CANDIDATE,
pedantic,
"function or method that could take a `#[must_use]` attribute"
@@ -204,6 +210,7 @@ declare_clippy_lint! {
///
/// Note that there are crates that simplify creating the error type, e.g.
/// [`thiserror`](https://docs.rs/thiserror).
+ #[clippy::version = "1.49.0"]
pub RESULT_UNIT_ERR,
style,
"public function returning `Result` with an `Err` type of `()`"
diff --git a/src/tools/clippy/clippy_lints/src/functions/too_many_lines.rs b/src/tools/clippy/clippy_lints/src/functions/too_many_lines.rs
index 008ef661b55..65efbbab41a 100644
--- a/src/tools/clippy/clippy_lints/src/functions/too_many_lines.rs
+++ b/src/tools/clippy/clippy_lints/src/functions/too_many_lines.rs
@@ -56,8 +56,8 @@ pub(super) fn check_fn(
continue;
}
} else {
- let multi_idx = line.find("/*").unwrap_or_else(|| line.len());
- let single_idx = line.find("//").unwrap_or_else(|| line.len());
+ let multi_idx = line.find("/*").unwrap_or(line.len());
+ let single_idx = line.find("//").unwrap_or(line.len());
code_in_line |= multi_idx > 0 && single_idx > 0;
// Implies multi_idx is below line.len()
if multi_idx < single_idx {
diff --git a/src/tools/clippy/clippy_lints/src/future_not_send.rs b/src/tools/clippy/clippy_lints/src/future_not_send.rs
index 6b2ac985555..43911a313d5 100644
--- a/src/tools/clippy/clippy_lints/src/future_not_send.rs
+++ b/src/tools/clippy/clippy_lints/src/future_not_send.rs
@@ -41,6 +41,7 @@ declare_clippy_lint! {
/// ```rust
/// async fn is_send(bytes: std::sync::Arc<[u8]>) {}
/// ```
+ #[clippy::version = "1.44.0"]
pub FUTURE_NOT_SEND,
nursery,
"public Futures must be Send"
@@ -67,8 +68,8 @@ impl<'tcx> LateLintPass<'tcx> for FutureNotSend {
let mut is_future = false;
for &(p, _span) in preds {
let p = p.subst(cx.tcx, subst);
- if let Some(trait_ref) = p.to_opt_poly_trait_ref() {
- if Some(trait_ref.value.def_id()) == cx.tcx.lang_items().future_trait() {
+ if let Some(trait_pred) = p.to_opt_poly_trait_pred() {
+ if Some(trait_pred.skip_binder().trait_ref.def_id) == cx.tcx.lang_items().future_trait() {
is_future = true;
break;
}
diff --git a/src/tools/clippy/clippy_lints/src/get_last_with_len.rs b/src/tools/clippy/clippy_lints/src/get_last_with_len.rs
index f3929b0f1e6..edca701869e 100644
--- a/src/tools/clippy/clippy_lints/src/get_last_with_len.rs
+++ b/src/tools/clippy/clippy_lints/src/get_last_with_len.rs
@@ -39,6 +39,7 @@ declare_clippy_lint! {
/// let x = vec![2, 3, 5];
/// let last_element = x.last();
/// ```
+ #[clippy::version = "1.37.0"]
pub GET_LAST_WITH_LEN,
complexity,
"Using `x.get(x.len() - 1)` when `x.last()` is correct and simpler"
diff --git a/src/tools/clippy/clippy_lints/src/identity_op.rs b/src/tools/clippy/clippy_lints/src/identity_op.rs
index 414f465c494..b4e7bbc7671 100644
--- a/src/tools/clippy/clippy_lints/src/identity_op.rs
+++ b/src/tools/clippy/clippy_lints/src/identity_op.rs
@@ -22,6 +22,7 @@ declare_clippy_lint! {
/// # let x = 1;
/// x / 1 + 0 * 1 - 0 | 0;
/// ```
+ #[clippy::version = "pre 1.29.0"]
pub IDENTITY_OP,
complexity,
"using identity operations, e.g., `x + 0` or `y / 1`"
diff --git a/src/tools/clippy/clippy_lints/src/if_let_mutex.rs b/src/tools/clippy/clippy_lints/src/if_let_mutex.rs
index a4118bf54b6..e20741d2407 100644
--- a/src/tools/clippy/clippy_lints/src/if_let_mutex.rs
+++ b/src/tools/clippy/clippy_lints/src/if_let_mutex.rs
@@ -36,6 +36,7 @@ declare_clippy_lint! {
/// use_locked(locked);
/// }
/// ```
+ #[clippy::version = "1.45.0"]
pub IF_LET_MUTEX,
correctness,
"locking a `Mutex` in an `if let` block can cause deadlocks"
diff --git a/src/tools/clippy/clippy_lints/src/if_not_else.rs b/src/tools/clippy/clippy_lints/src/if_not_else.rs
index ac938156237..3d59b783337 100644
--- a/src/tools/clippy/clippy_lints/src/if_not_else.rs
+++ b/src/tools/clippy/clippy_lints/src/if_not_else.rs
@@ -39,6 +39,7 @@ declare_clippy_lint! {
/// a()
/// }
/// ```
+ #[clippy::version = "pre 1.29.0"]
pub IF_NOT_ELSE,
pedantic,
"`if` branches that could be swapped so no negation operation is necessary on the condition"
diff --git a/src/tools/clippy/clippy_lints/src/if_then_some_else_none.rs b/src/tools/clippy/clippy_lints/src/if_then_some_else_none.rs
index a2dac57454f..16e5c5ca603 100644
--- a/src/tools/clippy/clippy_lints/src/if_then_some_else_none.rs
+++ b/src/tools/clippy/clippy_lints/src/if_then_some_else_none.rs
@@ -1,9 +1,9 @@
use clippy_utils::diagnostics::span_lint_and_help;
use clippy_utils::source::snippet_with_macro_callsite;
-use clippy_utils::{higher, is_else_clause, is_lang_ctor, meets_msrv, msrvs};
+use clippy_utils::{contains_return, higher, is_else_clause, is_lang_ctor, meets_msrv, msrvs, peel_blocks};
use if_chain::if_chain;
use rustc_hir::LangItem::{OptionNone, OptionSome};
-use rustc_hir::{Expr, ExprKind};
+use rustc_hir::{Expr, ExprKind, Stmt, StmtKind};
use rustc_lint::{LateContext, LateLintPass, LintContext};
use rustc_middle::lint::in_external_macro;
use rustc_semver::RustcVersion;
@@ -36,6 +36,7 @@ declare_clippy_lint! {
/// 42
/// });
/// ```
+ #[clippy::version = "1.53.0"]
pub IF_THEN_SOME_ELSE_NONE,
restriction,
"Finds if-else that could be written using `bool::then`"
@@ -76,11 +77,9 @@ impl LateLintPass<'_> for IfThenSomeElseNone {
if let ExprKind::Call(then_call, [then_arg]) = then_expr.kind;
if let ExprKind::Path(ref then_call_qpath) = then_call.kind;
if is_lang_ctor(cx, then_call_qpath, OptionSome);
- if let ExprKind::Block(els_block, _) = els.kind;
- if els_block.stmts.is_empty();
- if let Some(els_expr) = els_block.expr;
- if let ExprKind::Path(ref qpath) = els_expr.kind;
+ if let ExprKind::Path(ref qpath) = peel_blocks(els).kind;
if is_lang_ctor(cx, qpath, OptionNone);
+ if !stmts_contains_early_return(then_block.stmts);
then {
let cond_snip = snippet_with_macro_callsite(cx, cond.span, "[condition]");
let cond_snip = if matches!(cond.kind, ExprKind::Unary(_, _) | ExprKind::Binary(_, _, _)) {
@@ -113,3 +112,11 @@ impl LateLintPass<'_> for IfThenSomeElseNone {
extract_msrv_attr!(LateContext);
}
+
+fn stmts_contains_early_return(stmts: &[Stmt<'_>]) -> bool {
+ stmts.iter().any(|stmt| {
+ let Stmt { kind: StmtKind::Semi(e), .. } = stmt else { return false };
+
+ contains_return(e)
+ })
+}
diff --git a/src/tools/clippy/clippy_lints/src/implicit_hasher.rs b/src/tools/clippy/clippy_lints/src/implicit_hasher.rs
index 81eb51e6f7c..6358228dd47 100644
--- a/src/tools/clippy/clippy_lints/src/implicit_hasher.rs
+++ b/src/tools/clippy/clippy_lints/src/implicit_hasher.rs
@@ -54,6 +54,7 @@ declare_clippy_lint! {
///
/// pub fn foo<S: BuildHasher>(map: &mut HashMap<i32, i32, S>) { }
/// ```
+ #[clippy::version = "pre 1.29.0"]
pub IMPLICIT_HASHER,
pedantic,
"missing generalization over different hashers"
diff --git a/src/tools/clippy/clippy_lints/src/implicit_return.rs b/src/tools/clippy/clippy_lints/src/implicit_return.rs
index fa7b5302cb1..07caeada80d 100644
--- a/src/tools/clippy/clippy_lints/src/implicit_return.rs
+++ b/src/tools/clippy/clippy_lints/src/implicit_return.rs
@@ -2,10 +2,10 @@ use clippy_utils::{
diagnostics::span_lint_and_sugg,
get_async_fn_body, is_async_fn,
source::{snippet_with_applicability, snippet_with_context, walk_span_to_context},
- visitors::visit_break_exprs,
+ visitors::expr_visitor_no_bodies,
};
use rustc_errors::Applicability;
-use rustc_hir::intravisit::FnKind;
+use rustc_hir::intravisit::{FnKind, Visitor};
use rustc_hir::{Block, Body, Expr, ExprKind, FnDecl, FnRetTy, HirId};
use rustc_lint::{LateContext, LateLintPass, LintContext};
use rustc_middle::lint::in_external_macro;
@@ -35,6 +35,7 @@ declare_clippy_lint! {
/// return x;
/// }
/// ```
+ #[clippy::version = "1.33.0"]
pub IMPLICIT_RETURN,
restriction,
"use a return statement like `return expr` instead of an expression"
@@ -144,20 +145,24 @@ fn lint_implicit_returns(
ExprKind::Loop(block, ..) => {
let mut add_return = false;
- visit_break_exprs(block, |break_expr, dest, sub_expr| {
- if dest.target_id.ok() == Some(expr.hir_id) {
- if call_site_span.is_none() && break_expr.span.ctxt() == ctxt {
- // At this point sub_expr can be `None` in async functions which either diverge, or return the
- // unit type.
- if let Some(sub_expr) = sub_expr {
- lint_break(cx, break_expr.span, sub_expr.span);
+ expr_visitor_no_bodies(|e| {
+ if let ExprKind::Break(dest, sub_expr) = e.kind {
+ if dest.target_id.ok() == Some(expr.hir_id) {
+ if call_site_span.is_none() && e.span.ctxt() == ctxt {
+ // At this point sub_expr can be `None` in async functions which either diverge, or return
+ // the unit type.
+ if let Some(sub_expr) = sub_expr {
+ lint_break(cx, e.span, sub_expr.span);
+ }
+ } else {
+ // the break expression is from a macro call, add a return to the loop
+ add_return = true;
}
- } else {
- // the break expression is from a macro call, add a return to the loop
- add_return = true;
}
}
- });
+ true
+ })
+ .visit_block(block);
if add_return {
#[allow(clippy::option_if_let_else)]
if let Some(span) = call_site_span {
diff --git a/src/tools/clippy/clippy_lints/src/implicit_saturating_sub.rs b/src/tools/clippy/clippy_lints/src/implicit_saturating_sub.rs
index a4f60ded3a6..26a196aab59 100644
--- a/src/tools/clippy/clippy_lints/src/implicit_saturating_sub.rs
+++ b/src/tools/clippy/clippy_lints/src/implicit_saturating_sub.rs
@@ -1,10 +1,9 @@
use clippy_utils::diagnostics::span_lint_and_sugg;
-use clippy_utils::higher;
-use clippy_utils::{in_macro, SpanlessEq};
+use clippy_utils::{higher, peel_blocks_with_stmt, SpanlessEq};
use if_chain::if_chain;
use rustc_ast::ast::LitKind;
use rustc_errors::Applicability;
-use rustc_hir::{lang_items::LangItem, BinOpKind, Expr, ExprKind, QPath, StmtKind};
+use rustc_hir::{lang_items::LangItem, BinOpKind, Expr, ExprKind, QPath};
use rustc_lint::{LateContext, LateLintPass};
use rustc_session::{declare_lint_pass, declare_tool_lint};
@@ -30,6 +29,7 @@ declare_clippy_lint! {
/// // Good
/// i = i.saturating_sub(1);
/// ```
+ #[clippy::version = "1.44.0"]
pub IMPLICIT_SATURATING_SUB,
pedantic,
"Perform saturating subtraction instead of implicitly checking lower bound of data type"
@@ -39,7 +39,7 @@ declare_lint_pass!(ImplicitSaturatingSub => [IMPLICIT_SATURATING_SUB]);
impl<'tcx> LateLintPass<'tcx> for ImplicitSaturatingSub {
fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>) {
- if in_macro(expr.span) {
+ if expr.span.from_expansion() {
return;
}
if_chain! {
@@ -51,13 +51,8 @@ impl<'tcx> LateLintPass<'tcx> for ImplicitSaturatingSub {
// Ensure that the binary operator is >, != and <
if BinOpKind::Ne == cond_op.node || BinOpKind::Gt == cond_op.node || BinOpKind::Lt == cond_op.node;
- // Check if the true condition block has only one statement
- if let ExprKind::Block(block, _) = then.kind;
- if block.stmts.len() == 1 && block.expr.is_none();
-
// Check if assign operation is done
- if let StmtKind::Semi(e) = block.stmts[0].kind;
- if let Some(target) = subtracts_one(cx, e);
+ if let Some(target) = subtracts_one(cx, then);
// Extracting out the variable name
if let ExprKind::Path(QPath::Resolved(_, ares_path)) = target.kind;
@@ -137,8 +132,8 @@ impl<'tcx> LateLintPass<'tcx> for ImplicitSaturatingSub {
}
}
-fn subtracts_one<'a>(cx: &LateContext<'_>, expr: &Expr<'a>) -> Option<&'a Expr<'a>> {
- match expr.kind {
+fn subtracts_one<'a>(cx: &LateContext<'_>, expr: &'a Expr<'a>) -> Option<&'a Expr<'a>> {
+ match peel_blocks_with_stmt(expr).kind {
ExprKind::AssignOp(ref op1, target, value) => {
if_chain! {
if BinOpKind::Sub == op1.node;
diff --git a/src/tools/clippy/clippy_lints/src/inconsistent_struct_constructor.rs b/src/tools/clippy/clippy_lints/src/inconsistent_struct_constructor.rs
index 1f8240a1f63..1debdef9d86 100644
--- a/src/tools/clippy/clippy_lints/src/inconsistent_struct_constructor.rs
+++ b/src/tools/clippy/clippy_lints/src/inconsistent_struct_constructor.rs
@@ -1,5 +1,4 @@
use clippy_utils::diagnostics::span_lint_and_sugg;
-use clippy_utils::in_macro;
use clippy_utils::source::snippet;
use if_chain::if_chain;
use rustc_data_structures::fx::FxHashMap;
@@ -56,6 +55,7 @@ declare_clippy_lint! {
/// # let y = 2;
/// Foo { x, y };
/// ```
+ #[clippy::version = "1.52.0"]
pub INCONSISTENT_STRUCT_CONSTRUCTOR,
pedantic,
"the order of the field init shorthand is inconsistent with the order in the struct definition"
@@ -66,7 +66,7 @@ declare_lint_pass!(InconsistentStructConstructor => [INCONSISTENT_STRUCT_CONSTRU
impl LateLintPass<'_> for InconsistentStructConstructor {
fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx hir::Expr<'_>) {
if_chain! {
- if !in_macro(expr.span);
+ if !expr.span.from_expansion();
if let ExprKind::Struct(qpath, fields, base) = expr.kind;
let ty = cx.typeck_results().expr_ty(expr);
if let Some(adt_def) = ty.ty_adt_def();
diff --git a/src/tools/clippy/clippy_lints/src/index_refutable_slice.rs b/src/tools/clippy/clippy_lints/src/index_refutable_slice.rs
new file mode 100644
index 00000000000..69f1c90beec
--- /dev/null
+++ b/src/tools/clippy/clippy_lints/src/index_refutable_slice.rs
@@ -0,0 +1,276 @@
+use clippy_utils::consts::{constant, Constant};
+use clippy_utils::diagnostics::span_lint_and_then;
+use clippy_utils::higher::IfLet;
+use clippy_utils::ty::is_copy;
+use clippy_utils::{is_expn_of, is_lint_allowed, meets_msrv, msrvs, path_to_local};
+use if_chain::if_chain;
+use rustc_data_structures::fx::{FxHashMap, FxHashSet};
+use rustc_errors::Applicability;
+use rustc_hir as hir;
+use rustc_hir::intravisit::{self, NestedVisitorMap, Visitor};
+use rustc_lint::{LateContext, LateLintPass, LintContext};
+use rustc_middle::hir::map::Map;
+use rustc_middle::ty;
+use rustc_semver::RustcVersion;
+use rustc_session::{declare_tool_lint, impl_lint_pass};
+use rustc_span::{symbol::Ident, Span};
+use std::convert::TryInto;
+
+declare_clippy_lint! {
+ /// ### What it does
+ /// The lint checks for slice bindings in patterns that are only used to
+ /// access individual slice values.
+ ///
+ /// ### Why is this bad?
+ /// Accessing slice values using indices can lead to panics. Using refutable
+ /// patterns can avoid these. Binding to individual values also improves the
+ /// readability as they can be named.
+ ///
+ /// ### Limitations
+ /// This lint currently only checks for immutable access inside `if let`
+ /// patterns.
+ ///
+ /// ### Example
+ /// ```rust
+ /// let slice: Option<&[u32]> = Some(&[1, 2, 3]);
+ ///
+ /// if let Some(slice) = slice {
+ /// println!("{}", slice[0]);
+ /// }
+ /// ```
+ /// Use instead:
+ /// ```rust
+ /// let slice: Option<&[u32]> = Some(&[1, 2, 3]);
+ ///
+ /// if let Some(&[first, ..]) = slice {
+ /// println!("{}", first);
+ /// }
+ /// ```
+ #[clippy::version = "1.58.0"]
+ pub INDEX_REFUTABLE_SLICE,
+ nursery,
+ "avoid indexing on slices which could be destructed"
+}
+
+#[derive(Copy, Clone)]
+pub struct IndexRefutableSlice {
+ max_suggested_slice: u64,
+ msrv: Option<RustcVersion>,
+}
+
+impl IndexRefutableSlice {
+ pub fn new(max_suggested_slice_pattern_length: u64, msrv: Option<RustcVersion>) -> Self {
+ Self {
+ max_suggested_slice: max_suggested_slice_pattern_length,
+ msrv,
+ }
+ }
+}
+
+impl_lint_pass!(IndexRefutableSlice => [INDEX_REFUTABLE_SLICE]);
+
+impl LateLintPass<'_> for IndexRefutableSlice {
+ fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx hir::Expr<'_>) {
+ if_chain! {
+ if !expr.span.from_expansion() || is_expn_of(expr.span, "if_chain").is_some();
+ if let Some(IfLet {let_pat, if_then, ..}) = IfLet::hir(cx, expr);
+ if !is_lint_allowed(cx, INDEX_REFUTABLE_SLICE, expr.hir_id);
+ if meets_msrv(self.msrv.as_ref(), &msrvs::SLICE_PATTERNS);
+
+ let found_slices = find_slice_values(cx, let_pat);
+ if !found_slices.is_empty();
+ let filtered_slices = filter_lintable_slices(cx, found_slices, self.max_suggested_slice, if_then);
+ if !filtered_slices.is_empty();
+ then {
+ for slice in filtered_slices.values() {
+ lint_slice(cx, slice);
+ }
+ }
+ }
+ }
+
+ extract_msrv_attr!(LateContext);
+}
+
+fn find_slice_values(cx: &LateContext<'_>, pat: &hir::Pat<'_>) -> FxHashMap<hir::HirId, SliceLintInformation> {
+ let mut removed_pat: FxHashSet<hir::HirId> = FxHashSet::default();
+ let mut slices: FxHashMap<hir::HirId, SliceLintInformation> = FxHashMap::default();
+ pat.walk_always(|pat| {
+ if let hir::PatKind::Binding(binding, value_hir_id, ident, sub_pat) = pat.kind {
+ // We'll just ignore mut and ref mut for simplicity sake right now
+ if let hir::BindingAnnotation::Mutable | hir::BindingAnnotation::RefMut = binding {
+ return;
+ }
+
+ // This block catches bindings with sub patterns. It would be hard to build a correct suggestion
+ // for them and it's likely that the user knows what they are doing in such a case.
+ if removed_pat.contains(&value_hir_id) {
+ return;
+ }
+ if sub_pat.is_some() {
+ removed_pat.insert(value_hir_id);
+ slices.remove(&value_hir_id);
+ return;
+ }
+
+ let bound_ty = cx.typeck_results().node_type(pat.hir_id);
+ if let ty::Slice(inner_ty) | ty::Array(inner_ty, _) = bound_ty.peel_refs().kind() {
+ // The values need to use the `ref` keyword if they can't be copied.
+ // This will need to be adjusted if the lint want to support multable access in the future
+ let src_is_ref = bound_ty.is_ref() && binding != hir::BindingAnnotation::Ref;
+ let needs_ref = !(src_is_ref || is_copy(cx, inner_ty));
+
+ let slice_info = slices
+ .entry(value_hir_id)
+ .or_insert_with(|| SliceLintInformation::new(ident, needs_ref));
+ slice_info.pattern_spans.push(pat.span);
+ }
+ }
+ });
+
+ slices
+}
+
+fn lint_slice(cx: &LateContext<'_>, slice: &SliceLintInformation) {
+ let used_indices = slice
+ .index_use
+ .iter()
+ .map(|(index, _)| *index)
+ .collect::<FxHashSet<_>>();
+
+ let value_name = |index| format!("{}_{}", slice.ident.name, index);
+
+ if let Some(max_index) = used_indices.iter().max() {
+ let opt_ref = if slice.needs_ref { "ref " } else { "" };
+ let pat_sugg_idents = (0..=*max_index)
+ .map(|index| {
+ if used_indices.contains(&index) {
+ format!("{}{}", opt_ref, value_name(index))
+ } else {
+ "_".to_string()
+ }
+ })
+ .collect::<Vec<_>>();
+ let pat_sugg = format!("[{}, ..]", pat_sugg_idents.join(", "));
+
+ span_lint_and_then(
+ cx,
+ INDEX_REFUTABLE_SLICE,
+ slice.ident.span,
+ "this binding can be a slice pattern to avoid indexing",
+ |diag| {
+ diag.multipart_suggestion(
+ "try using a slice pattern here",
+ slice
+ .pattern_spans
+ .iter()
+ .map(|span| (*span, pat_sugg.clone()))
+ .collect(),
+ Applicability::MaybeIncorrect,
+ );
+
+ diag.multipart_suggestion(
+ "and replace the index expressions here",
+ slice
+ .index_use
+ .iter()
+ .map(|(index, span)| (*span, value_name(*index)))
+ .collect(),
+ Applicability::MaybeIncorrect,
+ );
+
+ // The lint message doesn't contain a warning about the removed index expression,
+ // since `filter_lintable_slices` will only return slices where all access indices
+ // are known at compile time. Therefore, they can be removed without side effects.
+ },
+ );
+ }
+}
+
+#[derive(Debug)]
+struct SliceLintInformation {
+ ident: Ident,
+ needs_ref: bool,
+ pattern_spans: Vec<Span>,
+ index_use: Vec<(u64, Span)>,
+}
+
+impl SliceLintInformation {
+ fn new(ident: Ident, needs_ref: bool) -> Self {
+ Self {
+ ident,
+ needs_ref,
+ pattern_spans: Vec::new(),
+ index_use: Vec::new(),
+ }
+ }
+}
+
+fn filter_lintable_slices<'a, 'tcx>(
+ cx: &'a LateContext<'tcx>,
+ slice_lint_info: FxHashMap<hir::HirId, SliceLintInformation>,
+ max_suggested_slice: u64,
+ scope: &'tcx hir::Expr<'tcx>,
+) -> FxHashMap<hir::HirId, SliceLintInformation> {
+ let mut visitor = SliceIndexLintingVisitor {
+ cx,
+ slice_lint_info,
+ max_suggested_slice,
+ };
+
+ intravisit::walk_expr(&mut visitor, scope);
+
+ visitor.slice_lint_info
+}
+
+struct SliceIndexLintingVisitor<'a, 'tcx> {
+ cx: &'a LateContext<'tcx>,
+ slice_lint_info: FxHashMap<hir::HirId, SliceLintInformation>,
+ max_suggested_slice: u64,
+}
+
+impl<'a, 'tcx> Visitor<'tcx> for SliceIndexLintingVisitor<'a, 'tcx> {
+ type Map = Map<'tcx>;
+
+ fn nested_visit_map(&mut self) -> NestedVisitorMap<Self::Map> {
+ NestedVisitorMap::OnlyBodies(self.cx.tcx.hir())
+ }
+
+ fn visit_expr(&mut self, expr: &'tcx hir::Expr<'tcx>) {
+ if let Some(local_id) = path_to_local(expr) {
+ let Self {
+ cx,
+ ref mut slice_lint_info,
+ max_suggested_slice,
+ } = *self;
+
+ if_chain! {
+ // Check if this is even a local we're interested in
+ if let Some(use_info) = slice_lint_info.get_mut(&local_id);
+
+ let map = cx.tcx.hir();
+
+ // Checking for slice indexing
+ let parent_id = map.get_parent_node(expr.hir_id);
+ if let Some(hir::Node::Expr(parent_expr)) = map.find(parent_id);
+ if let hir::ExprKind::Index(_, index_expr) = parent_expr.kind;
+ if let Some((Constant::Int(index_value), _)) = constant(cx, cx.typeck_results(), index_expr);
+ if let Ok(index_value) = index_value.try_into();
+ if index_value < max_suggested_slice;
+
+ // Make sure that this slice index is read only
+ let maybe_addrof_id = map.get_parent_node(parent_id);
+ if let Some(hir::Node::Expr(maybe_addrof_expr)) = map.find(maybe_addrof_id);
+ if let hir::ExprKind::AddrOf(_kind, hir::Mutability::Not, _inner_expr) = maybe_addrof_expr.kind;
+ then {
+ use_info.index_use.push((index_value, map.span(parent_expr.hir_id)));
+ return;
+ }
+ }
+
+ // The slice was used for something other than indexing
+ self.slice_lint_info.remove(&local_id);
+ }
+ intravisit::walk_expr(self, expr);
+ }
+}
diff --git a/src/tools/clippy/clippy_lints/src/indexing_slicing.rs b/src/tools/clippy/clippy_lints/src/indexing_slicing.rs
index f52f090d387..9ead4bb27a5 100644
--- a/src/tools/clippy/clippy_lints/src/indexing_slicing.rs
+++ b/src/tools/clippy/clippy_lints/src/indexing_slicing.rs
@@ -33,6 +33,7 @@ declare_clippy_lint! {
/// x[0];
/// x[3];
/// ```
+ #[clippy::version = "pre 1.29.0"]
pub OUT_OF_BOUNDS_INDEXING,
correctness,
"out of bounds constant indexing"
@@ -85,6 +86,7 @@ declare_clippy_lint! {
/// y.get(10..);
/// y.get(..100);
/// ```
+ #[clippy::version = "pre 1.29.0"]
pub INDEXING_SLICING,
restriction,
"indexing/slicing usage"
diff --git a/src/tools/clippy/clippy_lints/src/infinite_iter.rs b/src/tools/clippy/clippy_lints/src/infinite_iter.rs
index 68c1fa35fcc..c7db47a552b 100644
--- a/src/tools/clippy/clippy_lints/src/infinite_iter.rs
+++ b/src/tools/clippy/clippy_lints/src/infinite_iter.rs
@@ -20,6 +20,7 @@ declare_clippy_lint! {
///
/// iter::repeat(1_u8).collect::<Vec<_>>();
/// ```
+ #[clippy::version = "pre 1.29.0"]
pub INFINITE_ITER,
correctness,
"infinite iteration"
@@ -42,6 +43,7 @@ declare_clippy_lint! {
/// let infinite_iter = 0..;
/// [0..].iter().zip(infinite_iter.take_while(|x| *x > 5));
/// ```
+ #[clippy::version = "pre 1.29.0"]
pub MAYBE_INFINITE_ITER,
pedantic,
"possible infinite iteration"
diff --git a/src/tools/clippy/clippy_lints/src/inherent_impl.rs b/src/tools/clippy/clippy_lints/src/inherent_impl.rs
index 0d23bec27a3..254d3f8a4d0 100644
--- a/src/tools/clippy/clippy_lints/src/inherent_impl.rs
+++ b/src/tools/clippy/clippy_lints/src/inherent_impl.rs
@@ -1,7 +1,7 @@
//! lint on inherent implementations
use clippy_utils::diagnostics::span_lint_and_note;
-use clippy_utils::{in_macro, is_lint_allowed};
+use clippy_utils::is_lint_allowed;
use rustc_data_structures::fx::FxHashMap;
use rustc_hir::{def_id::LocalDefId, Item, ItemKind, Node};
use rustc_lint::{LateContext, LateLintPass};
@@ -36,6 +36,7 @@ declare_clippy_lint! {
/// fn other() {}
/// }
/// ```
+ #[clippy::version = "pre 1.29.0"]
pub MULTIPLE_INHERENT_IMPL,
restriction,
"Multiple inherent impl that could be grouped"
@@ -123,8 +124,10 @@ fn get_impl_span(cx: &LateContext<'_>, id: LocalDefId) -> Option<Span> {
..
}) = cx.tcx.hir().get(id)
{
- (!in_macro(span) && impl_item.generics.params.is_empty() && !is_lint_allowed(cx, MULTIPLE_INHERENT_IMPL, id))
- .then(|| span)
+ (!span.from_expansion()
+ && impl_item.generics.params.is_empty()
+ && !is_lint_allowed(cx, MULTIPLE_INHERENT_IMPL, id))
+ .then(|| span)
} else {
None
}
diff --git a/src/tools/clippy/clippy_lints/src/inherent_to_string.rs b/src/tools/clippy/clippy_lints/src/inherent_to_string.rs
index 61dd0eb4af7..60d234cd6f0 100644
--- a/src/tools/clippy/clippy_lints/src/inherent_to_string.rs
+++ b/src/tools/clippy/clippy_lints/src/inherent_to_string.rs
@@ -41,6 +41,7 @@ declare_clippy_lint! {
/// }
/// }
/// ```
+ #[clippy::version = "1.38.0"]
pub INHERENT_TO_STRING,
style,
"type implements inherent method `to_string()`, but should instead implement the `Display` trait"
@@ -88,6 +89,7 @@ declare_clippy_lint! {
/// }
/// }
/// ```
+ #[clippy::version = "1.38.0"]
pub INHERENT_TO_STRING_SHADOW_DISPLAY,
correctness,
"type implements inherent method `to_string()`, which gets shadowed by the implementation of the `Display` trait"
diff --git a/src/tools/clippy/clippy_lints/src/inline_fn_without_body.rs b/src/tools/clippy/clippy_lints/src/inline_fn_without_body.rs
index 3e3df903f17..df69d3dcc51 100644
--- a/src/tools/clippy/clippy_lints/src/inline_fn_without_body.rs
+++ b/src/tools/clippy/clippy_lints/src/inline_fn_without_body.rs
@@ -24,6 +24,7 @@ declare_clippy_lint! {
/// fn name(&self) -> &'static str;
/// }
/// ```
+ #[clippy::version = "pre 1.29.0"]
pub INLINE_FN_WITHOUT_BODY,
correctness,
"use of `#[inline]` on trait methods without bodies"
diff --git a/src/tools/clippy/clippy_lints/src/int_plus_one.rs b/src/tools/clippy/clippy_lints/src/int_plus_one.rs
index 6850e0c3476..3716d36ad88 100644
--- a/src/tools/clippy/clippy_lints/src/int_plus_one.rs
+++ b/src/tools/clippy/clippy_lints/src/int_plus_one.rs
@@ -28,6 +28,7 @@ declare_clippy_lint! {
/// # let y = 1;
/// if x > y {}
/// ```
+ #[clippy::version = "pre 1.29.0"]
pub INT_PLUS_ONE,
complexity,
"instead of using `x >= y + 1`, use `x > y`"
diff --git a/src/tools/clippy/clippy_lints/src/integer_division.rs b/src/tools/clippy/clippy_lints/src/integer_division.rs
index c962e814fa5..fa786205678 100644
--- a/src/tools/clippy/clippy_lints/src/integer_division.rs
+++ b/src/tools/clippy/clippy_lints/src/integer_division.rs
@@ -23,6 +23,7 @@ declare_clippy_lint! {
/// let x = 3f32 / 2f32;
/// println!("{}", x);
/// ```
+ #[clippy::version = "1.37.0"]
pub INTEGER_DIVISION,
restriction,
"integer division may cause loss of precision"
diff --git a/src/tools/clippy/clippy_lints/src/invalid_upcast_comparisons.rs b/src/tools/clippy/clippy_lints/src/invalid_upcast_comparisons.rs
index 82438d85c7a..36e03e50a8e 100644
--- a/src/tools/clippy/clippy_lints/src/invalid_upcast_comparisons.rs
+++ b/src/tools/clippy/clippy_lints/src/invalid_upcast_comparisons.rs
@@ -30,6 +30,7 @@ declare_clippy_lint! {
/// let x: u8 = 1;
/// (x as u32) > 300;
/// ```
+ #[clippy::version = "pre 1.29.0"]
pub INVALID_UPCAST_COMPARISONS,
pedantic,
"a comparison involving an upcast which is always true or false"
diff --git a/src/tools/clippy/clippy_lints/src/items_after_statements.rs b/src/tools/clippy/clippy_lints/src/items_after_statements.rs
index 3736d237642..b118d3c8b87 100644
--- a/src/tools/clippy/clippy_lints/src/items_after_statements.rs
+++ b/src/tools/clippy/clippy_lints/src/items_after_statements.rs
@@ -45,6 +45,7 @@ declare_clippy_lint! {
/// foo(); // prints "foo"
/// }
/// ```
+ #[clippy::version = "pre 1.29.0"]
pub ITEMS_AFTER_STATEMENTS,
pedantic,
"blocks where an item comes after a statement"
diff --git a/src/tools/clippy/clippy_lints/src/iter_not_returning_iterator.rs b/src/tools/clippy/clippy_lints/src/iter_not_returning_iterator.rs
index 6c779348ca2..968bbc524b2 100644
--- a/src/tools/clippy/clippy_lints/src/iter_not_returning_iterator.rs
+++ b/src/tools/clippy/clippy_lints/src/iter_not_returning_iterator.rs
@@ -32,6 +32,7 @@ declare_clippy_lint! {
/// }
/// }
/// ```
+ #[clippy::version = "1.57.0"]
pub ITER_NOT_RETURNING_ITERATOR,
pedantic,
"methods named `iter` or `iter_mut` that do not return an `Iterator`"
diff --git a/src/tools/clippy/clippy_lints/src/large_const_arrays.rs b/src/tools/clippy/clippy_lints/src/large_const_arrays.rs
index fe6814e35d0..80260e4cd83 100644
--- a/src/tools/clippy/clippy_lints/src/large_const_arrays.rs
+++ b/src/tools/clippy/clippy_lints/src/large_const_arrays.rs
@@ -27,6 +27,7 @@ declare_clippy_lint! {
/// // Good
/// pub static a = [0u32; 1_000_000];
/// ```
+ #[clippy::version = "1.44.0"]
pub LARGE_CONST_ARRAYS,
perf,
"large non-scalar const array may cause performance overhead"
diff --git a/src/tools/clippy/clippy_lints/src/large_enum_variant.rs b/src/tools/clippy/clippy_lints/src/large_enum_variant.rs
index 392166237be..0191713f60d 100644
--- a/src/tools/clippy/clippy_lints/src/large_enum_variant.rs
+++ b/src/tools/clippy/clippy_lints/src/large_enum_variant.rs
@@ -40,6 +40,7 @@ declare_clippy_lint! {
/// B(Box<[i32; 8000]>),
/// }
/// ```
+ #[clippy::version = "pre 1.29.0"]
pub LARGE_ENUM_VARIANT,
perf,
"large size difference between variants on an enum"
diff --git a/src/tools/clippy/clippy_lints/src/large_stack_arrays.rs b/src/tools/clippy/clippy_lints/src/large_stack_arrays.rs
index bbb6c1f902c..1cc2c28c04a 100644
--- a/src/tools/clippy/clippy_lints/src/large_stack_arrays.rs
+++ b/src/tools/clippy/clippy_lints/src/large_stack_arrays.rs
@@ -19,6 +19,7 @@ declare_clippy_lint! {
/// ```rust,ignore
/// let a = [0u32; 1_000_000];
/// ```
+ #[clippy::version = "1.41.0"]
pub LARGE_STACK_ARRAYS,
pedantic,
"allocating large arrays on stack may cause stack overflow"
diff --git a/src/tools/clippy/clippy_lints/src/len_zero.rs b/src/tools/clippy/clippy_lints/src/len_zero.rs
index f336fb9d42f..09cd0d22d8b 100644
--- a/src/tools/clippy/clippy_lints/src/len_zero.rs
+++ b/src/tools/clippy/clippy_lints/src/len_zero.rs
@@ -46,6 +46,7 @@ declare_clippy_lint! {
/// ..
/// }
/// ```
+ #[clippy::version = "pre 1.29.0"]
pub LEN_ZERO,
style,
"checking `.len() == 0` or `.len() > 0` (or similar) when `.is_empty()` could be used instead"
@@ -71,6 +72,7 @@ declare_clippy_lint! {
/// }
/// }
/// ```
+ #[clippy::version = "pre 1.29.0"]
pub LEN_WITHOUT_IS_EMPTY,
style,
"traits or impls with a public `len` method but no corresponding `is_empty` method"
@@ -108,6 +110,7 @@ declare_clippy_lint! {
/// ..
/// }
/// ```
+ #[clippy::version = "1.49.0"]
pub COMPARISON_TO_EMPTY,
style,
"checking `x == \"\"` or `x == []` (or similar) when `.is_empty()` could be used instead"
diff --git a/src/tools/clippy/clippy_lints/src/let_if_seq.rs b/src/tools/clippy/clippy_lints/src/let_if_seq.rs
index 7f2c7b707f0..db09d00d730 100644
--- a/src/tools/clippy/clippy_lints/src/let_if_seq.rs
+++ b/src/tools/clippy/clippy_lints/src/let_if_seq.rs
@@ -48,6 +48,7 @@ declare_clippy_lint! {
/// None
/// };
/// ```
+ #[clippy::version = "pre 1.29.0"]
pub USELESS_LET_IF_SEQ,
nursery,
"unidiomatic `let mut` declaration followed by initialization in `if`"
diff --git a/src/tools/clippy/clippy_lints/src/let_underscore.rs b/src/tools/clippy/clippy_lints/src/let_underscore.rs
index 9efd7aba7e8..d03276f7f98 100644
--- a/src/tools/clippy/clippy_lints/src/let_underscore.rs
+++ b/src/tools/clippy/clippy_lints/src/let_underscore.rs
@@ -26,6 +26,7 @@ declare_clippy_lint! {
/// // is_ok() is marked #[must_use]
/// let _ = f().is_ok();
/// ```
+ #[clippy::version = "1.42.0"]
pub LET_UNDERSCORE_MUST_USE,
restriction,
"non-binding let on a `#[must_use]` expression"
@@ -33,7 +34,8 @@ declare_clippy_lint! {
declare_clippy_lint! {
/// ### What it does
- /// Checks for `let _ = sync_lock`
+ /// Checks for `let _ = sync_lock`.
+ /// This supports `mutex` and `rwlock` in `std::sync` and `parking_lot`.
///
/// ### Why is this bad?
/// This statement immediately drops the lock instead of
@@ -53,6 +55,7 @@ declare_clippy_lint! {
/// ```rust,ignore
/// let _lock = mutex.lock();
/// ```
+ #[clippy::version = "1.43.0"]
pub LET_UNDERSCORE_LOCK,
correctness,
"non-binding let on a synchronization lock"
@@ -94,6 +97,7 @@ declare_clippy_lint! {
/// // dropped at end of scope
/// }
/// ```
+ #[clippy::version = "1.50.0"]
pub LET_UNDERSCORE_DROP,
pedantic,
"non-binding let on a type that implements `Drop`"
@@ -101,10 +105,12 @@ declare_clippy_lint! {
declare_lint_pass!(LetUnderscore => [LET_UNDERSCORE_MUST_USE, LET_UNDERSCORE_LOCK, LET_UNDERSCORE_DROP]);
-const SYNC_GUARD_PATHS: [&[&str]; 3] = [
+const SYNC_GUARD_PATHS: [&[&str]; 5] = [
&paths::MUTEX_GUARD,
&paths::RWLOCK_READ_GUARD,
&paths::RWLOCK_WRITE_GUARD,
+ &paths::PARKING_LOT_RAWMUTEX,
+ &paths::PARKING_LOT_RAWRWLOCK,
];
impl<'tcx> LateLintPass<'tcx> for LetUnderscore {
diff --git a/src/tools/clippy/clippy_lints/src/lib.register_all.rs b/src/tools/clippy/clippy_lints/src/lib.register_all.rs
index 15edb79d36c..3d3999d4cc0 100644
--- a/src/tools/clippy/clippy_lints/src/lib.register_all.rs
+++ b/src/tools/clippy/clippy_lints/src/lib.register_all.rs
@@ -33,6 +33,7 @@ store.register_group(true, "clippy::all", Some("clippy_all"), vec![
LintId::of(copies::IFS_SAME_COND),
LintId::of(copies::IF_SAME_THEN_ELSE),
LintId::of(default::FIELD_REASSIGN_WITH_DEFAULT),
+ LintId::of(dereference::NEEDLESS_BORROW),
LintId::of(derivable_impls::DERIVABLE_IMPLS),
LintId::of(derive::DERIVE_HASH_XOR_EQ),
LintId::of(derive::DERIVE_ORD_XOR_PARTIAL_ORD),
@@ -158,7 +159,9 @@ store.register_group(true, "clippy::all", Some("clippy_all"), vec![
LintId::of(methods::MANUAL_SPLIT_ONCE),
LintId::of(methods::MANUAL_STR_REPEAT),
LintId::of(methods::MAP_COLLECT_RESULT_UNIT),
+ LintId::of(methods::MAP_FLATTEN),
LintId::of(methods::MAP_IDENTITY),
+ LintId::of(methods::NEEDLESS_SPLITN),
LintId::of(methods::NEW_RET_NO_SELF),
LintId::of(methods::OK_EXPECT),
LintId::of(methods::OPTION_AS_REF_DEREF),
@@ -178,6 +181,7 @@ store.register_group(true, "clippy::all", Some("clippy_all"), vec![
LintId::of(methods::UNNECESSARY_FILTER_MAP),
LintId::of(methods::UNNECESSARY_FOLD),
LintId::of(methods::UNNECESSARY_LAZY_EVALUATIONS),
+ LintId::of(methods::UNNECESSARY_TO_OWNED),
LintId::of(methods::UNWRAP_OR_ELSE_DEFAULT),
LintId::of(methods::USELESS_ASREF),
LintId::of(methods::WRONG_SELF_CONVENTION),
@@ -203,8 +207,8 @@ store.register_group(true, "clippy::all", Some("clippy_all"), vec![
LintId::of(needless_arbitrary_self_type::NEEDLESS_ARBITRARY_SELF_TYPE),
LintId::of(needless_bool::BOOL_COMPARISON),
LintId::of(needless_bool::NEEDLESS_BOOL),
- LintId::of(needless_borrow::NEEDLESS_BORROW),
LintId::of(needless_borrowed_ref::NEEDLESS_BORROWED_REFERENCE),
+ LintId::of(needless_late_init::NEEDLESS_LATE_INIT),
LintId::of(needless_option_as_deref::NEEDLESS_OPTION_AS_DEREF),
LintId::of(needless_question_mark::NEEDLESS_QUESTION_MARK),
LintId::of(needless_update::NEEDLESS_UPDATE),
@@ -217,7 +221,7 @@ store.register_group(true, "clippy::all", Some("clippy_all"), vec![
LintId::of(non_copy_const::DECLARE_INTERIOR_MUTABLE_CONST),
LintId::of(non_expressive_names::JUST_UNDERSCORES_AND_DIGITS),
LintId::of(non_octal_unix_permissions::NON_OCTAL_UNIX_PERMISSIONS),
- LintId::of(non_send_fields_in_send_ty::NON_SEND_FIELDS_IN_SEND_TY),
+ LintId::of(octal_escapes::OCTAL_ESCAPES),
LintId::of(open_options::NONSENSICAL_OPEN_OPTIONS),
LintId::of(option_env_unwrap::OPTION_ENV_UNWRAP),
LintId::of(overflow_check_conditional::OVERFLOW_CHECK_CONDITIONAL),
@@ -242,6 +246,7 @@ store.register_group(true, "clippy::all", Some("clippy_all"), vec![
LintId::of(reference::REF_IN_DEREF),
LintId::of(regex::INVALID_REGEX),
LintId::of(repeat_once::REPEAT_ONCE),
+ LintId::of(return_self_not_must_use::RETURN_SELF_NOT_MUST_USE),
LintId::of(returns::LET_AND_RETURN),
LintId::of(returns::NEEDLESS_RETURN),
LintId::of(self_assignment::SELF_ASSIGNMENT),
diff --git a/src/tools/clippy/clippy_lints/src/lib.register_complexity.rs b/src/tools/clippy/clippy_lints/src/lib.register_complexity.rs
index c51341bdf0c..a21ddf73a11 100644
--- a/src/tools/clippy/clippy_lints/src/lib.register_complexity.rs
+++ b/src/tools/clippy/clippy_lints/src/lib.register_complexity.rs
@@ -41,7 +41,9 @@ store.register_group(true, "clippy::complexity", Some("clippy_complexity"), vec!
LintId::of(methods::MANUAL_FILTER_MAP),
LintId::of(methods::MANUAL_FIND_MAP),
LintId::of(methods::MANUAL_SPLIT_ONCE),
+ LintId::of(methods::MAP_FLATTEN),
LintId::of(methods::MAP_IDENTITY),
+ LintId::of(methods::NEEDLESS_SPLITN),
LintId::of(methods::OPTION_AS_REF_DEREF),
LintId::of(methods::OPTION_FILTER_MAP),
LintId::of(methods::SEARCH_IS_SOME),
diff --git a/src/tools/clippy/clippy_lints/src/lib.register_internal.rs b/src/tools/clippy/clippy_lints/src/lib.register_internal.rs
index c8c1e0262ab..7d4c7d2adb5 100644
--- a/src/tools/clippy/clippy_lints/src/lib.register_internal.rs
+++ b/src/tools/clippy/clippy_lints/src/lib.register_internal.rs
@@ -9,9 +9,11 @@ store.register_group(true, "clippy::internal", Some("clippy_internal"), vec![
LintId::of(utils::internal_lints::DEFAULT_LINT),
LintId::of(utils::internal_lints::IF_CHAIN_STYLE),
LintId::of(utils::internal_lints::INTERNING_DEFINED_SYMBOL),
+ LintId::of(utils::internal_lints::INVALID_CLIPPY_VERSION_ATTRIBUTE),
LintId::of(utils::internal_lints::INVALID_PATHS),
LintId::of(utils::internal_lints::LINT_WITHOUT_LINT_PASS),
LintId::of(utils::internal_lints::MATCH_TYPE_ON_DIAGNOSTIC_ITEM),
+ LintId::of(utils::internal_lints::MISSING_CLIPPY_VERSION_ATTRIBUTE),
LintId::of(utils::internal_lints::OUTER_EXPN_EXPN_DATA),
LintId::of(utils::internal_lints::PRODUCE_ICE),
LintId::of(utils::internal_lints::UNNECESSARY_SYMBOL_STR),
diff --git a/src/tools/clippy/clippy_lints/src/lib.register_lints.rs b/src/tools/clippy/clippy_lints/src/lib.register_lints.rs
index 2cb86418e3c..766c5ba1bcb 100644
--- a/src/tools/clippy/clippy_lints/src/lib.register_lints.rs
+++ b/src/tools/clippy/clippy_lints/src/lib.register_lints.rs
@@ -16,12 +16,16 @@ store.register_lints(&[
#[cfg(feature = "internal-lints")]
utils::internal_lints::INTERNING_DEFINED_SYMBOL,
#[cfg(feature = "internal-lints")]
+ utils::internal_lints::INVALID_CLIPPY_VERSION_ATTRIBUTE,
+ #[cfg(feature = "internal-lints")]
utils::internal_lints::INVALID_PATHS,
#[cfg(feature = "internal-lints")]
utils::internal_lints::LINT_WITHOUT_LINT_PASS,
#[cfg(feature = "internal-lints")]
utils::internal_lints::MATCH_TYPE_ON_DIAGNOSTIC_ITEM,
#[cfg(feature = "internal-lints")]
+ utils::internal_lints::MISSING_CLIPPY_VERSION_ATTRIBUTE,
+ #[cfg(feature = "internal-lints")]
utils::internal_lints::OUTER_EXPN_EXPN_DATA,
#[cfg(feature = "internal-lints")]
utils::internal_lints::PRODUCE_ICE,
@@ -88,14 +92,16 @@ store.register_lints(&[
default::FIELD_REASSIGN_WITH_DEFAULT,
default_numeric_fallback::DEFAULT_NUMERIC_FALLBACK,
dereference::EXPLICIT_DEREF_METHODS,
+ dereference::NEEDLESS_BORROW,
+ dereference::REF_BINDING_TO_REFERENCE,
derivable_impls::DERIVABLE_IMPLS,
derive::DERIVE_HASH_XOR_EQ,
derive::DERIVE_ORD_XOR_PARTIAL_ORD,
derive::EXPL_IMPL_CLONE_ON_COPY,
derive::UNSAFE_DERIVE_DESERIALIZE,
- disallowed_method::DISALLOWED_METHOD,
+ disallowed_methods::DISALLOWED_METHODS,
disallowed_script_idents::DISALLOWED_SCRIPT_IDENTS,
- disallowed_type::DISALLOWED_TYPE,
+ disallowed_types::DISALLOWED_TYPES,
doc::DOC_MARKDOWN,
doc::MISSING_ERRORS_DOC,
doc::MISSING_PANICS_DOC,
@@ -164,6 +170,7 @@ store.register_lints(&[
implicit_return::IMPLICIT_RETURN,
implicit_saturating_sub::IMPLICIT_SATURATING_SUB,
inconsistent_struct_constructor::INCONSISTENT_STRUCT_CONSTRUCTOR,
+ index_refutable_slice::INDEX_REFUTABLE_SLICE,
indexing_slicing::INDEXING_SLICING,
indexing_slicing::OUT_OF_BOUNDS_INDEXING,
infinite_iter::INFINITE_ITER,
@@ -288,6 +295,7 @@ store.register_lints(&[
methods::MAP_FLATTEN,
methods::MAP_IDENTITY,
methods::MAP_UNWRAP_OR,
+ methods::NEEDLESS_SPLITN,
methods::NEW_RET_NO_SELF,
methods::OK_EXPECT,
methods::OPTION_AS_REF_DEREF,
@@ -307,6 +315,7 @@ store.register_lints(&[
methods::UNNECESSARY_FILTER_MAP,
methods::UNNECESSARY_FOLD,
methods::UNNECESSARY_LAZY_EVALUATIONS,
+ methods::UNNECESSARY_TO_OWNED,
methods::UNWRAP_OR_ELSE_DEFAULT,
methods::UNWRAP_USED,
methods::USELESS_ASREF,
@@ -351,11 +360,10 @@ store.register_lints(&[
needless_bitwise_bool::NEEDLESS_BITWISE_BOOL,
needless_bool::BOOL_COMPARISON,
needless_bool::NEEDLESS_BOOL,
- needless_borrow::NEEDLESS_BORROW,
- needless_borrow::REF_BINDING_TO_REFERENCE,
needless_borrowed_ref::NEEDLESS_BORROWED_REFERENCE,
needless_continue::NEEDLESS_CONTINUE,
needless_for_each::NEEDLESS_FOR_EACH,
+ needless_late_init::NEEDLESS_LATE_INIT,
needless_option_as_deref::NEEDLESS_OPTION_AS_DEREF,
needless_pass_by_value::NEEDLESS_PASS_BY_VALUE,
needless_question_mark::NEEDLESS_QUESTION_MARK,
@@ -374,6 +382,7 @@ store.register_lints(&[
non_octal_unix_permissions::NON_OCTAL_UNIX_PERMISSIONS,
non_send_fields_in_send_ty::NON_SEND_FIELDS_IN_SEND_TY,
nonstandard_macro_braces::NONSTANDARD_MACRO_BRACES,
+ octal_escapes::OCTAL_ESCAPES,
open_options::NONSENSICAL_OPEN_OPTIONS,
option_env_unwrap::OPTION_ENV_UNWRAP,
option_if_let_else::OPTION_IF_LET_ELSE,
@@ -414,6 +423,7 @@ store.register_lints(&[
regex::INVALID_REGEX,
regex::TRIVIAL_REGEX,
repeat_once::REPEAT_ONCE,
+ return_self_not_must_use::RETURN_SELF_NOT_MUST_USE,
returns::LET_AND_RETURN,
returns::NEEDLESS_RETURN,
same_name_method::SAME_NAME_METHOD,
diff --git a/src/tools/clippy/clippy_lints/src/lib.register_nursery.rs b/src/tools/clippy/clippy_lints/src/lib.register_nursery.rs
index 44c75a11eec..e3cf0670018 100644
--- a/src/tools/clippy/clippy_lints/src/lib.register_nursery.rs
+++ b/src/tools/clippy/clippy_lints/src/lib.register_nursery.rs
@@ -6,17 +6,19 @@ store.register_group(true, "clippy::nursery", Some("clippy_nursery"), vec![
LintId::of(attrs::EMPTY_LINE_AFTER_OUTER_ATTR),
LintId::of(cognitive_complexity::COGNITIVE_COMPLEXITY),
LintId::of(copies::BRANCHES_SHARING_CODE),
- LintId::of(disallowed_method::DISALLOWED_METHOD),
- LintId::of(disallowed_type::DISALLOWED_TYPE),
+ LintId::of(disallowed_methods::DISALLOWED_METHODS),
+ LintId::of(disallowed_types::DISALLOWED_TYPES),
LintId::of(equatable_if_let::EQUATABLE_IF_LET),
LintId::of(fallible_impl_from::FALLIBLE_IMPL_FROM),
LintId::of(floating_point_arithmetic::IMPRECISE_FLOPS),
LintId::of(floating_point_arithmetic::SUBOPTIMAL_FLOPS),
LintId::of(future_not_send::FUTURE_NOT_SEND),
+ LintId::of(index_refutable_slice::INDEX_REFUTABLE_SLICE),
LintId::of(let_if_seq::USELESS_LET_IF_SEQ),
LintId::of(missing_const_for_fn::MISSING_CONST_FOR_FN),
LintId::of(mutable_debug_assertion::DEBUG_ASSERT_WITH_MUT_CALL),
LintId::of(mutex_atomic::MUTEX_INTEGER),
+ LintId::of(non_send_fields_in_send_ty::NON_SEND_FIELDS_IN_SEND_TY),
LintId::of(nonstandard_macro_braces::NONSTANDARD_MACRO_BRACES),
LintId::of(option_if_let_else::OPTION_IF_LET_ELSE),
LintId::of(path_buf_push_overwrite::PATH_BUF_PUSH_OVERWRITE),
diff --git a/src/tools/clippy/clippy_lints/src/lib.register_pedantic.rs b/src/tools/clippy/clippy_lints/src/lib.register_pedantic.rs
index 404ca20b5ab..70a4a624378 100644
--- a/src/tools/clippy/clippy_lints/src/lib.register_pedantic.rs
+++ b/src/tools/clippy/clippy_lints/src/lib.register_pedantic.rs
@@ -21,6 +21,7 @@ store.register_group(true, "clippy::pedantic", Some("clippy_pedantic"), vec![
LintId::of(copy_iterator::COPY_ITERATOR),
LintId::of(default::DEFAULT_TRAIT_ACCESS),
LintId::of(dereference::EXPLICIT_DEREF_METHODS),
+ LintId::of(dereference::REF_BINDING_TO_REFERENCE),
LintId::of(derive::EXPL_IMPL_CLONE_ON_COPY),
LintId::of(derive::UNSAFE_DERIVE_DESERIALIZE),
LintId::of(doc::DOC_MARKDOWN),
@@ -62,13 +63,11 @@ store.register_group(true, "clippy::pedantic", Some("clippy_pedantic"), vec![
LintId::of(methods::FROM_ITER_INSTEAD_OF_COLLECT),
LintId::of(methods::IMPLICIT_CLONE),
LintId::of(methods::INEFFICIENT_TO_STRING),
- LintId::of(methods::MAP_FLATTEN),
LintId::of(methods::MAP_UNWRAP_OR),
LintId::of(misc::FLOAT_CMP),
LintId::of(misc::USED_UNDERSCORE_BINDING),
LintId::of(mut_mut::MUT_MUT),
LintId::of(needless_bitwise_bool::NEEDLESS_BITWISE_BOOL),
- LintId::of(needless_borrow::REF_BINDING_TO_REFERENCE),
LintId::of(needless_continue::NEEDLESS_CONTINUE),
LintId::of(needless_for_each::NEEDLESS_FOR_EACH),
LintId::of(needless_pass_by_value::NEEDLESS_PASS_BY_VALUE),
diff --git a/src/tools/clippy/clippy_lints/src/lib.register_perf.rs b/src/tools/clippy/clippy_lints/src/lib.register_perf.rs
index a0d5cf9418e..2ea0b696f1f 100644
--- a/src/tools/clippy/clippy_lints/src/lib.register_perf.rs
+++ b/src/tools/clippy/clippy_lints/src/lib.register_perf.rs
@@ -17,6 +17,7 @@ store.register_group(true, "clippy::perf", Some("clippy_perf"), vec![
LintId::of(methods::MANUAL_STR_REPEAT),
LintId::of(methods::OR_FUN_CALL),
LintId::of(methods::SINGLE_CHAR_PATTERN),
+ LintId::of(methods::UNNECESSARY_TO_OWNED),
LintId::of(misc::CMP_OWNED),
LintId::of(mutex_atomic::MUTEX_ATOMIC),
LintId::of(redundant_clone::REDUNDANT_CLONE),
diff --git a/src/tools/clippy/clippy_lints/src/lib.register_style.rs b/src/tools/clippy/clippy_lints/src/lib.register_style.rs
index 744880bda3e..ea87e7e7a73 100644
--- a/src/tools/clippy/clippy_lints/src/lib.register_style.rs
+++ b/src/tools/clippy/clippy_lints/src/lib.register_style.rs
@@ -15,6 +15,7 @@ store.register_group(true, "clippy::style", Some("clippy_style"), vec![
LintId::of(collapsible_match::COLLAPSIBLE_MATCH),
LintId::of(comparison_chain::COMPARISON_CHAIN),
LintId::of(default::FIELD_REASSIGN_WITH_DEFAULT),
+ LintId::of(dereference::NEEDLESS_BORROW),
LintId::of(doc::MISSING_SAFETY_DOC),
LintId::of(doc::NEEDLESS_DOCTEST_MAIN),
LintId::of(enum_variants::ENUM_VARIANT_NAMES),
@@ -81,7 +82,7 @@ store.register_group(true, "clippy::style", Some("clippy_style"), vec![
LintId::of(misc_early::REDUNDANT_PATTERN),
LintId::of(mut_mutex_lock::MUT_MUTEX_LOCK),
LintId::of(mut_reference::UNNECESSARY_MUT_PASSED),
- LintId::of(needless_borrow::NEEDLESS_BORROW),
+ LintId::of(needless_late_init::NEEDLESS_LATE_INIT),
LintId::of(neg_multiply::NEG_MULTIPLY),
LintId::of(new_without_default::NEW_WITHOUT_DEFAULT),
LintId::of(non_copy_const::BORROW_INTERIOR_MUTABLE_CONST),
diff --git a/src/tools/clippy/clippy_lints/src/lib.register_suspicious.rs b/src/tools/clippy/clippy_lints/src/lib.register_suspicious.rs
index a3f964d1580..8594338ffa5 100644
--- a/src/tools/clippy/clippy_lints/src/lib.register_suspicious.rs
+++ b/src/tools/clippy/clippy_lints/src/lib.register_suspicious.rs
@@ -15,7 +15,8 @@ store.register_group(true, "clippy::suspicious", Some("clippy_suspicious"), vec!
LintId::of(loops::MUT_RANGE_BOUND),
LintId::of(methods::SUSPICIOUS_MAP),
LintId::of(mut_key::MUTABLE_KEY_TYPE),
- LintId::of(non_send_fields_in_send_ty::NON_SEND_FIELDS_IN_SEND_TY),
+ LintId::of(octal_escapes::OCTAL_ESCAPES),
+ LintId::of(return_self_not_must_use::RETURN_SELF_NOT_MUST_USE),
LintId::of(suspicious_trait_impl::SUSPICIOUS_ARITHMETIC_IMPL),
LintId::of(suspicious_trait_impl::SUSPICIOUS_OP_ASSIGN_IMPL),
])
diff --git a/src/tools/clippy/clippy_lints/src/lib.rs b/src/tools/clippy/clippy_lints/src/lib.rs
index 7174d0a082e..d1c7956a7a5 100644
--- a/src/tools/clippy/clippy_lints/src/lib.rs
+++ b/src/tools/clippy/clippy_lints/src/lib.rs
@@ -3,11 +3,11 @@
#![feature(box_patterns)]
#![feature(drain_filter)]
#![feature(in_band_lifetimes)]
-#![feature(iter_zip)]
#![feature(once_cell)]
#![feature(rustc_private)]
#![feature(stmt_expr_attributes)]
#![feature(control_flow_enum)]
+#![feature(let_else)]
#![recursion_limit = "512"]
#![cfg_attr(feature = "deny-warnings", deny(warnings))]
#![allow(clippy::missing_docs_in_private_items, clippy::must_use_candidate)]
@@ -153,6 +153,10 @@ macro_rules! declare_clippy_lint {
#[cfg(feature = "metadata-collector-lint")]
mod deprecated_lints;
+#[cfg_attr(
+ any(feature = "internal-lints", feature = "metadata-collector-lint"),
+ allow(clippy::missing_clippy_version_attribute)
+)]
mod utils;
// begin lints modules, do not remove this comment, it’s used in `update_lints`
@@ -189,9 +193,9 @@ mod default_numeric_fallback;
mod dereference;
mod derivable_impls;
mod derive;
-mod disallowed_method;
+mod disallowed_methods;
mod disallowed_script_idents;
-mod disallowed_type;
+mod disallowed_types;
mod doc;
mod double_comparison;
mod double_parens;
@@ -233,6 +237,7 @@ mod implicit_hasher;
mod implicit_return;
mod implicit_saturating_sub;
mod inconsistent_struct_constructor;
+mod index_refutable_slice;
mod indexing_slicing;
mod infinite_iter;
mod inherent_impl;
@@ -290,10 +295,10 @@ mod mutex_atomic;
mod needless_arbitrary_self_type;
mod needless_bitwise_bool;
mod needless_bool;
-mod needless_borrow;
mod needless_borrowed_ref;
mod needless_continue;
mod needless_for_each;
+mod needless_late_init;
mod needless_option_as_deref;
mod needless_pass_by_value;
mod needless_question_mark;
@@ -307,6 +312,7 @@ mod non_expressive_names;
mod non_octal_unix_permissions;
mod non_send_fields_in_send_ty;
mod nonstandard_macro_braces;
+mod octal_escapes;
mod open_options;
mod option_env_unwrap;
mod option_if_let_else;
@@ -334,6 +340,7 @@ mod ref_option_ref;
mod reference;
mod regex;
mod repeat_once;
+mod return_self_not_must_use;
mod returns;
mod same_name_method;
mod self_assignment;
@@ -404,10 +411,21 @@ use crate::utils::conf::TryConf;
/// level (i.e `#![cfg_attr(...)]`) will still be expanded even when using a pre-expansion pass.
///
/// Used in `./src/driver.rs`.
-pub fn register_pre_expansion_lints(store: &mut rustc_lint::LintStore) {
+pub fn register_pre_expansion_lints(store: &mut rustc_lint::LintStore, sess: &Session, conf: &Conf) {
// NOTE: Do not add any more pre-expansion passes. These should be removed eventually.
+
+ let msrv = conf.msrv.as_ref().and_then(|s| {
+ parse_msrv(s, None, None).or_else(|| {
+ sess.err(&format!(
+ "error reading Clippy's configuration file. `{}` is not a valid Rust version",
+ s
+ ));
+ None
+ })
+ });
+
store.register_pre_expansion_pass(|| Box::new(write::Write::default()));
- store.register_pre_expansion_pass(|| Box::new(attrs::EarlyAttributes));
+ store.register_pre_expansion_pass(move || Box::new(attrs::EarlyAttributes { msrv }));
store.register_pre_expansion_pass(|| Box::new(dbg_macro::DbgMacro));
}
@@ -441,7 +459,6 @@ pub fn read_conf(sess: &Session) -> Conf {
///
/// Used in `./src/driver.rs`.
#[allow(clippy::too_many_lines)]
-#[rustfmt::skip]
pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: &Conf) {
register_removed_non_tool_lints(store);
@@ -493,11 +510,13 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
let vec_box_size_threshold = conf.vec_box_size_threshold;
let type_complexity_threshold = conf.type_complexity_threshold;
let avoid_breaking_exported_api = conf.avoid_breaking_exported_api;
- store.register_late_pass(move || Box::new(types::Types::new(
- vec_box_size_threshold,
- type_complexity_threshold,
- avoid_breaking_exported_api,
- )));
+ store.register_late_pass(move || {
+ Box::new(types::Types::new(
+ vec_box_size_threshold,
+ type_complexity_threshold,
+ avoid_breaking_exported_api,
+ ))
+ });
store.register_late_pass(|| Box::new(booleans::NonminimalBool));
store.register_late_pass(|| Box::new(needless_bitwise_bool::NeedlessBitwiseBool));
store.register_late_pass(|| Box::new(eq_op::EqOp));
@@ -535,7 +554,10 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
let msrv = conf.msrv.as_ref().and_then(|s| {
parse_msrv(s, None, None).or_else(|| {
- sess.err(&format!("error reading Clippy's configuration file. `{}` is not a valid Rust version", s));
+ sess.err(&format!(
+ "error reading Clippy's configuration file. `{}` is not a valid Rust version",
+ s
+ ));
None
})
});
@@ -560,6 +582,13 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
store.register_late_pass(|| Box::new(size_of_in_element_count::SizeOfInElementCount));
store.register_late_pass(|| Box::new(same_name_method::SameNameMethod));
+ let max_suggested_slice_pattern_length = conf.max_suggested_slice_pattern_length;
+ store.register_late_pass(move || {
+ Box::new(index_refutable_slice::IndexRefutableSlice::new(
+ max_suggested_slice_pattern_length,
+ msrv,
+ ))
+ });
store.register_late_pass(|| Box::new(map_clone::MapClone));
store.register_late_pass(|| Box::new(map_err_ignore::MapErrIgnore));
store.register_late_pass(|| Box::new(shadow::Shadow::default()));
@@ -573,16 +602,19 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
store.register_late_pass(|| Box::new(zero_div_zero::ZeroDiv));
store.register_late_pass(|| Box::new(mutex_atomic::Mutex));
store.register_late_pass(|| Box::new(needless_update::NeedlessUpdate));
- store.register_late_pass(|| Box::new(needless_borrow::NeedlessBorrow::default()));
store.register_late_pass(|| Box::new(needless_borrowed_ref::NeedlessBorrowedRef));
store.register_late_pass(|| Box::new(no_effect::NoEffect));
store.register_late_pass(|| Box::new(temporary_assignment::TemporaryAssignment));
store.register_late_pass(|| Box::new(transmute::Transmute));
let cognitive_complexity_threshold = conf.cognitive_complexity_threshold;
- store.register_late_pass(move || Box::new(cognitive_complexity::CognitiveComplexity::new(cognitive_complexity_threshold)));
+ store.register_late_pass(move || {
+ Box::new(cognitive_complexity::CognitiveComplexity::new(
+ cognitive_complexity_threshold,
+ ))
+ });
let too_large_for_stack = conf.too_large_for_stack;
- store.register_late_pass(move || Box::new(escape::BoxedLocal{too_large_for_stack}));
- store.register_late_pass(move || Box::new(vec::UselessVec{too_large_for_stack}));
+ store.register_late_pass(move || Box::new(escape::BoxedLocal { too_large_for_stack }));
+ store.register_late_pass(move || Box::new(vec::UselessVec { too_large_for_stack }));
store.register_late_pass(|| Box::new(panic_unimplemented::PanicUnimplemented));
store.register_late_pass(|| Box::new(strings::StringLitAsBytes));
store.register_late_pass(|| Box::new(derive::Derive));
@@ -603,7 +635,12 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
store.register_late_pass(move || Box::new(blacklisted_name::BlacklistedName::new(blacklisted_names.clone())));
let too_many_arguments_threshold = conf.too_many_arguments_threshold;
let too_many_lines_threshold = conf.too_many_lines_threshold;
- store.register_late_pass(move || Box::new(functions::Functions::new(too_many_arguments_threshold, too_many_lines_threshold)));
+ store.register_late_pass(move || {
+ Box::new(functions::Functions::new(
+ too_many_arguments_threshold,
+ too_many_lines_threshold,
+ ))
+ });
let doc_valid_idents = conf.doc_valid_idents.iter().cloned().collect::<FxHashSet<_>>();
store.register_late_pass(move || Box::new(doc::DocMarkdown::new(doc_valid_idents.clone())));
store.register_late_pass(|| Box::new(neg_multiply::NegMultiply));
@@ -688,14 +725,32 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
store.register_late_pass(|| Box::new(multiple_crate_versions::MultipleCrateVersions));
store.register_late_pass(|| Box::new(wildcard_dependencies::WildcardDependencies));
let literal_representation_lint_fraction_readability = conf.unreadable_literal_lint_fractions;
- store.register_early_pass(move || Box::new(literal_representation::LiteralDigitGrouping::new(literal_representation_lint_fraction_readability)));
+ store.register_early_pass(move || {
+ Box::new(literal_representation::LiteralDigitGrouping::new(
+ literal_representation_lint_fraction_readability,
+ ))
+ });
let literal_representation_threshold = conf.literal_representation_threshold;
- store.register_early_pass(move || Box::new(literal_representation::DecimalLiteralRepresentation::new(literal_representation_threshold)));
+ store.register_early_pass(move || {
+ Box::new(literal_representation::DecimalLiteralRepresentation::new(
+ literal_representation_threshold,
+ ))
+ });
let enum_variant_name_threshold = conf.enum_variant_name_threshold;
- store.register_late_pass(move || Box::new(enum_variants::EnumVariantNames::new(enum_variant_name_threshold, avoid_breaking_exported_api)));
+ store.register_late_pass(move || {
+ Box::new(enum_variants::EnumVariantNames::new(
+ enum_variant_name_threshold,
+ avoid_breaking_exported_api,
+ ))
+ });
store.register_early_pass(|| Box::new(tabs_in_doc_comments::TabsInDocComments));
let upper_case_acronyms_aggressive = conf.upper_case_acronyms_aggressive;
- store.register_late_pass(move || Box::new(upper_case_acronyms::UpperCaseAcronyms::new(avoid_breaking_exported_api, upper_case_acronyms_aggressive)));
+ store.register_late_pass(move || {
+ Box::new(upper_case_acronyms::UpperCaseAcronyms::new(
+ avoid_breaking_exported_api,
+ upper_case_acronyms_aggressive,
+ ))
+ });
store.register_late_pass(|| Box::new(default::Default::default()));
store.register_late_pass(|| Box::new(unused_self::UnusedSelf));
store.register_late_pass(|| Box::new(mutable_debug_assertion::DebugAssertWithMutCall));
@@ -710,7 +765,12 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
store.register_early_pass(|| Box::new(single_component_path_imports::SingleComponentPathImports));
let max_fn_params_bools = conf.max_fn_params_bools;
let max_struct_bools = conf.max_struct_bools;
- store.register_early_pass(move || Box::new(excessive_bools::ExcessiveBools::new(max_struct_bools, max_fn_params_bools)));
+ store.register_early_pass(move || {
+ Box::new(excessive_bools::ExcessiveBools::new(
+ max_struct_bools,
+ max_fn_params_bools,
+ ))
+ });
store.register_early_pass(|| Box::new(option_env_unwrap::OptionEnvUnwrap));
let warn_on_all_wildcard_imports = conf.warn_on_all_wildcard_imports;
store.register_late_pass(move || Box::new(wildcard_imports::WildcardImports::new(warn_on_all_wildcard_imports)));
@@ -729,9 +789,11 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
store.register_late_pass(|| Box::new(vec_resize_to_zero::VecResizeToZero));
store.register_late_pass(|| Box::new(panic_in_result_fn::PanicInResultFn));
let single_char_binding_names_threshold = conf.single_char_binding_names_threshold;
- store.register_early_pass(move || Box::new(non_expressive_names::NonExpressiveNames {
- single_char_binding_names_threshold,
- }));
+ store.register_early_pass(move || {
+ Box::new(non_expressive_names::NonExpressiveNames {
+ single_char_binding_names_threshold,
+ })
+ });
let macro_matcher = conf.standard_macro_braces.iter().cloned().collect::<FxHashSet<_>>();
store.register_early_pass(move || Box::new(nonstandard_macro_braces::MacroBraces::new(&macro_matcher)));
store.register_late_pass(|| Box::new(macro_use::MacroUseImports::default()));
@@ -746,7 +808,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
store.register_late_pass(|| Box::new(semicolon_if_nothing_returned::SemicolonIfNothingReturned));
store.register_late_pass(|| Box::new(async_yields_async::AsyncYieldsAsync));
let disallowed_methods = conf.disallowed_methods.clone();
- store.register_late_pass(move || Box::new(disallowed_method::DisallowedMethod::new(disallowed_methods.clone())));
+ store.register_late_pass(move || Box::new(disallowed_methods::DisallowedMethods::new(disallowed_methods.clone())));
store.register_early_pass(|| Box::new(asm_syntax::InlineAsmX86AttSyntax));
store.register_early_pass(|| Box::new(asm_syntax::InlineAsmX86IntelSyntax));
store.register_late_pass(|| Box::new(undropped_manually_drops::UndroppedManuallyDrops));
@@ -754,7 +816,9 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
store.register_late_pass(|| Box::new(strings::StringToString));
store.register_late_pass(|| Box::new(zero_sized_map_values::ZeroSizedMapValues));
store.register_late_pass(|| Box::new(vec_init_then_push::VecInitThenPush::default()));
- store.register_late_pass(|| Box::new(case_sensitive_file_extension_comparisons::CaseSensitiveFileExtensionComparisons));
+ store.register_late_pass(|| {
+ Box::new(case_sensitive_file_extension_comparisons::CaseSensitiveFileExtensionComparisons)
+ });
store.register_late_pass(|| Box::new(redundant_slicing::RedundantSlicing));
store.register_late_pass(|| Box::new(from_str_radix_10::FromStrRadix10));
store.register_late_pass(|| Box::new(manual_map::ManualMap));
@@ -763,9 +827,13 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
store.register_early_pass(move || Box::new(module_style::ModStyle));
store.register_late_pass(|| Box::new(unused_async::UnusedAsync));
let disallowed_types = conf.disallowed_types.clone();
- store.register_late_pass(move || Box::new(disallowed_type::DisallowedType::new(disallowed_types.clone())));
+ store.register_late_pass(move || Box::new(disallowed_types::DisallowedTypes::new(disallowed_types.clone())));
let import_renames = conf.enforced_import_renames.clone();
- store.register_late_pass(move || Box::new(missing_enforced_import_rename::ImportRename::new(import_renames.clone())));
+ store.register_late_pass(move || {
+ Box::new(missing_enforced_import_rename::ImportRename::new(
+ import_renames.clone(),
+ ))
+ });
let scripts = conf.allowed_scripts.clone();
store.register_early_pass(move || Box::new(disallowed_script_idents::DisallowedScriptIdents::new(&scripts)));
store.register_late_pass(|| Box::new(strlen_on_c_strings::StrlenOnCStrings));
@@ -774,11 +842,18 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
store.register_late_pass(move || Box::new(iter_not_returning_iterator::IterNotReturningIterator));
store.register_late_pass(move || Box::new(manual_assert::ManualAssert));
let enable_raw_pointer_heuristic_for_send = conf.enable_raw_pointer_heuristic_for_send;
- store.register_late_pass(move || Box::new(non_send_fields_in_send_ty::NonSendFieldInSendTy::new(enable_raw_pointer_heuristic_for_send)));
+ store.register_late_pass(move || {
+ Box::new(non_send_fields_in_send_ty::NonSendFieldInSendTy::new(
+ enable_raw_pointer_heuristic_for_send,
+ ))
+ });
store.register_late_pass(move || Box::new(undocumented_unsafe_blocks::UndocumentedUnsafeBlocks::default()));
store.register_late_pass(|| Box::new(match_str_case_mismatch::MatchStrCaseMismatch));
store.register_late_pass(move || Box::new(format_args::FormatArgs));
store.register_late_pass(|| Box::new(trailing_empty_array::TrailingEmptyArray));
+ store.register_early_pass(|| Box::new(octal_escapes::OctalEscapes));
+ store.register_late_pass(|| Box::new(needless_late_init::NeedlessLateInit));
+ store.register_late_pass(|| Box::new(return_self_not_must_use::ReturnSelfNotMustUse));
// add lints here, do not remove this comment, it's used in `new_lint`
}
@@ -852,6 +927,8 @@ pub fn register_renamed(ls: &mut rustc_lint::LintStore) {
ls.register_renamed("clippy::zero_width_space", "clippy::invisible_characters");
ls.register_renamed("clippy::single_char_push_str", "clippy::single_char_add_str");
ls.register_renamed("clippy::if_let_some_result", "clippy::match_result_ok");
+ ls.register_renamed("clippy::disallowed_type", "clippy::disallowed_types");
+ ls.register_renamed("clippy::disallowed_method", "clippy::disallowed_methods");
// uplifted lints
ls.register_renamed("clippy::invalid_ref", "invalid_value");
diff --git a/src/tools/clippy/clippy_lints/src/lifetimes.rs b/src/tools/clippy/clippy_lints/src/lifetimes.rs
index cb0b96e0652..0e2b78609c2 100644
--- a/src/tools/clippy/clippy_lints/src/lifetimes.rs
+++ b/src/tools/clippy/clippy_lints/src/lifetimes.rs
@@ -1,5 +1,5 @@
use clippy_utils::diagnostics::span_lint;
-use clippy_utils::{in_macro, trait_ref_of_method};
+use clippy_utils::trait_ref_of_method;
use rustc_data_structures::fx::{FxHashMap, FxHashSet};
use rustc_hir::intravisit::{
walk_fn_decl, walk_generic_param, walk_generics, walk_item, walk_param_bound, walk_poly_trait_ref, walk_ty,
@@ -29,7 +29,7 @@ declare_clippy_lint! {
///
/// ### Known problems
/// - We bail out if the function has a `where` clause where lifetimes
- /// are mentioned due to potenial false positives.
+ /// are mentioned due to potential false positives.
/// - Lifetime bounds such as `impl Foo + 'a` and `T: 'a` must be elided with the
/// placeholder notation `'_` because the fully elided notation leaves the type bound to `'static`.
///
@@ -45,6 +45,7 @@ declare_clippy_lint! {
/// x
/// }
/// ```
+ #[clippy::version = "pre 1.29.0"]
pub NEEDLESS_LIFETIMES,
complexity,
"using explicit lifetimes for references in function arguments when elision rules \
@@ -73,6 +74,7 @@ declare_clippy_lint! {
/// // ...
/// }
/// ```
+ #[clippy::version = "pre 1.29.0"]
pub EXTRA_UNUSED_LIFETIMES,
complexity,
"unused lifetimes in function definitions"
@@ -128,7 +130,7 @@ fn check_fn_inner<'tcx>(
span: Span,
report_extra_lifetimes: bool,
) {
- if in_macro(span) || has_where_lifetimes(cx, &generics.where_clause) {
+ if span.from_expansion() || has_where_lifetimes(cx, &generics.where_clause) {
return;
}
diff --git a/src/tools/clippy/clippy_lints/src/literal_representation.rs b/src/tools/clippy/clippy_lints/src/literal_representation.rs
index 0e5121ca3d7..130543bbbee 100644
--- a/src/tools/clippy/clippy_lints/src/literal_representation.rs
+++ b/src/tools/clippy/clippy_lints/src/literal_representation.rs
@@ -2,11 +2,8 @@
//! floating-point literal expressions.
use clippy_utils::diagnostics::span_lint_and_sugg;
+use clippy_utils::numeric_literal::{NumericLiteral, Radix};
use clippy_utils::source::snippet_opt;
-use clippy_utils::{
- in_macro,
- numeric_literal::{NumericLiteral, Radix},
-};
use if_chain::if_chain;
use rustc_ast::ast::{Expr, ExprKind, Lit, LitKind};
use rustc_errors::Applicability;
@@ -31,6 +28,7 @@ declare_clippy_lint! {
/// // Good
/// let x: u64 = 61_864_918_973_511;
/// ```
+ #[clippy::version = "pre 1.29.0"]
pub UNREADABLE_LITERAL,
pedantic,
"long literal without underscores"
@@ -56,6 +54,7 @@ declare_clippy_lint! {
/// // Good
/// 2_i32;
/// ```
+ #[clippy::version = "1.30.0"]
pub MISTYPED_LITERAL_SUFFIXES,
correctness,
"mistyped literal suffix"
@@ -78,6 +77,7 @@ declare_clippy_lint! {
/// // Good
/// let x: u64 = 61_864_918_973_511;
/// ```
+ #[clippy::version = "pre 1.29.0"]
pub INCONSISTENT_DIGIT_GROUPING,
style,
"integer literals with digits grouped inconsistently"
@@ -96,6 +96,7 @@ declare_clippy_lint! {
/// let x: u32 = 0xFFF_FFF;
/// let y: u8 = 0b01_011_101;
/// ```
+ #[clippy::version = "1.49.0"]
pub UNUSUAL_BYTE_GROUPINGS,
style,
"binary or hex literals that aren't grouped by four"
@@ -114,6 +115,7 @@ declare_clippy_lint! {
/// ```rust
/// let x: u64 = 6186491_8973511;
/// ```
+ #[clippy::version = "pre 1.29.0"]
pub LARGE_DIGIT_GROUPS,
pedantic,
"grouping digits into groups that are too large"
@@ -131,6 +133,7 @@ declare_clippy_lint! {
/// `255` => `0xFF`
/// `65_535` => `0xFFFF`
/// `4_042_322_160` => `0xF0F0_F0F0`
+ #[clippy::version = "pre 1.29.0"]
pub DECIMAL_LITERAL_REPRESENTATION,
restriction,
"using decimal representation when hexadecimal would be better"
@@ -283,7 +286,7 @@ impl LiteralDigitGrouping {
| WarningType::InconsistentDigitGrouping
| WarningType::UnusualByteGroupings
| WarningType::LargeDigitGroups => {
- !in_macro(lit.span)
+ !lit.span.from_expansion()
}
WarningType::DecimalRepresentation | WarningType::MistypedLiteralSuffix => {
true
diff --git a/src/tools/clippy/clippy_lints/src/loops/explicit_counter_loop.rs b/src/tools/clippy/clippy_lints/src/loops/explicit_counter_loop.rs
index 6f213d7a699..e0150990cfe 100644
--- a/src/tools/clippy/clippy_lints/src/loops/explicit_counter_loop.rs
+++ b/src/tools/clippy/clippy_lints/src/loops/explicit_counter_loop.rs
@@ -1,5 +1,5 @@
use super::{make_iterator_snippet, IncrementVisitor, InitializeVisitor, EXPLICIT_COUNTER_LOOP};
-use clippy_utils::diagnostics::span_lint_and_sugg;
+use clippy_utils::diagnostics::{span_lint_and_sugg, span_lint_and_then};
use clippy_utils::source::snippet_with_applicability;
use clippy_utils::{get_enclosing_block, is_integer_const};
use if_chain::if_chain;
@@ -7,6 +7,7 @@ use rustc_errors::Applicability;
use rustc_hir::intravisit::{walk_block, walk_expr};
use rustc_hir::{Expr, Pat};
use rustc_lint::LateContext;
+use rustc_middle::ty::{self, UintTy};
// To trigger the EXPLICIT_COUNTER_LOOP lint, a variable must be
// incremented exactly once in the loop body, and initialized to zero
@@ -30,24 +31,59 @@ pub(super) fn check<'tcx>(
walk_block(&mut initialize_visitor, block);
if_chain! {
- if let Some((name, initializer)) = initialize_visitor.get_result();
+ if let Some((name, ty, initializer)) = initialize_visitor.get_result();
if is_integer_const(cx, initializer, 0);
then {
let mut applicability = Applicability::MachineApplicable;
- span_lint_and_sugg(
+ let int_name = match ty.map(ty::TyS::kind) {
+ // usize or inferred
+ Some(ty::Uint(UintTy::Usize)) | None => {
+ span_lint_and_sugg(
+ cx,
+ EXPLICIT_COUNTER_LOOP,
+ expr.span.with_hi(arg.span.hi()),
+ &format!("the variable `{}` is used as a loop counter", name),
+ "consider using",
+ format!(
+ "for ({}, {}) in {}.enumerate()",
+ name,
+ snippet_with_applicability(cx, pat.span, "item", &mut applicability),
+ make_iterator_snippet(cx, arg, &mut applicability),
+ ),
+ applicability,
+ );
+ return;
+ }
+ Some(ty::Int(int_ty)) => int_ty.name_str(),
+ Some(ty::Uint(uint_ty)) => uint_ty.name_str(),
+ _ => return,
+ };
+
+ span_lint_and_then(
cx,
EXPLICIT_COUNTER_LOOP,
expr.span.with_hi(arg.span.hi()),
&format!("the variable `{}` is used as a loop counter", name),
- "consider using",
- format!(
- "for ({}, {}) in {}.enumerate()",
- name,
- snippet_with_applicability(cx, pat.span, "item", &mut applicability),
- make_iterator_snippet(cx, arg, &mut applicability),
- ),
- applicability,
+ |diag| {
+ diag.span_suggestion(
+ expr.span.with_hi(arg.span.hi()),
+ "consider using",
+ format!(
+ "for ({}, {}) in (0_{}..).zip({})",
+ name,
+ snippet_with_applicability(cx, pat.span, "item", &mut applicability),
+ int_name,
+ make_iterator_snippet(cx, arg, &mut applicability),
+ ),
+ applicability,
+ );
+
+ diag.note(&format!(
+ "`{}` is of type `{}`, making it ineligible for `Iterator::enumerate`",
+ name, int_name
+ ));
+ },
);
}
}
diff --git a/src/tools/clippy/clippy_lints/src/loops/manual_flatten.rs b/src/tools/clippy/clippy_lints/src/loops/manual_flatten.rs
index 5b6e27085d5..d276c901059 100644
--- a/src/tools/clippy/clippy_lints/src/loops/manual_flatten.rs
+++ b/src/tools/clippy/clippy_lints/src/loops/manual_flatten.rs
@@ -3,11 +3,11 @@ use super::MANUAL_FLATTEN;
use clippy_utils::diagnostics::span_lint_and_then;
use clippy_utils::higher;
use clippy_utils::visitors::is_local_used;
-use clippy_utils::{is_lang_ctor, path_to_local_id};
+use clippy_utils::{is_lang_ctor, path_to_local_id, peel_blocks_with_stmt};
use if_chain::if_chain;
use rustc_errors::Applicability;
use rustc_hir::LangItem::{OptionSome, ResultOk};
-use rustc_hir::{Expr, ExprKind, Pat, PatKind, StmtKind};
+use rustc_hir::{Expr, Pat, PatKind};
use rustc_lint::LateContext;
use rustc_middle::ty;
use rustc_span::source_map::Span;
@@ -21,71 +21,55 @@ pub(super) fn check<'tcx>(
body: &'tcx Expr<'_>,
span: Span,
) {
- if let ExprKind::Block(block, _) = body.kind {
- // Ensure the `if let` statement is the only expression or statement in the for-loop
- let inner_expr = if block.stmts.len() == 1 && block.expr.is_none() {
- let match_stmt = &block.stmts[0];
- if let StmtKind::Semi(inner_expr) = match_stmt.kind {
- Some(inner_expr)
- } else {
- None
- }
- } else if block.stmts.is_empty() {
- block.expr
- } else {
- None
- };
+ let inner_expr = peel_blocks_with_stmt(body);
+ if_chain! {
+ if let Some(higher::IfLet { let_pat, let_expr, if_then, if_else: None })
+ = higher::IfLet::hir(cx, inner_expr);
+ // Ensure match_expr in `if let` statement is the same as the pat from the for-loop
+ if let PatKind::Binding(_, pat_hir_id, _, _) = pat.kind;
+ if path_to_local_id(let_expr, pat_hir_id);
+ // Ensure the `if let` statement is for the `Some` variant of `Option` or the `Ok` variant of `Result`
+ if let PatKind::TupleStruct(ref qpath, _, _) = let_pat.kind;
+ let some_ctor = is_lang_ctor(cx, qpath, OptionSome);
+ let ok_ctor = is_lang_ctor(cx, qpath, ResultOk);
+ if some_ctor || ok_ctor;
+ // Ensure expr in `if let` is not used afterwards
+ if !is_local_used(cx, if_then, pat_hir_id);
+ then {
+ let if_let_type = if some_ctor { "Some" } else { "Ok" };
+ // Prepare the error message
+ let msg = format!("unnecessary `if let` since only the `{}` variant of the iterator element is used", if_let_type);
- if_chain! {
- if let Some(inner_expr) = inner_expr;
- if let Some(higher::IfLet { let_pat, let_expr, if_then, if_else: None })
- = higher::IfLet::hir(cx, inner_expr);
- // Ensure match_expr in `if let` statement is the same as the pat from the for-loop
- if let PatKind::Binding(_, pat_hir_id, _, _) = pat.kind;
- if path_to_local_id(let_expr, pat_hir_id);
- // Ensure the `if let` statement is for the `Some` variant of `Option` or the `Ok` variant of `Result`
- if let PatKind::TupleStruct(ref qpath, _, _) = let_pat.kind;
- let some_ctor = is_lang_ctor(cx, qpath, OptionSome);
- let ok_ctor = is_lang_ctor(cx, qpath, ResultOk);
- if some_ctor || ok_ctor;
- // Ensure epxr in `if let` is not used afterwards
- if !is_local_used(cx, if_then, pat_hir_id);
- then {
- let if_let_type = if some_ctor { "Some" } else { "Ok" };
- // Prepare the error message
- let msg = format!("unnecessary `if let` since only the `{}` variant of the iterator element is used", if_let_type);
-
- // Prepare the help message
- let mut applicability = Applicability::MaybeIncorrect;
- let arg_snippet = make_iterator_snippet(cx, arg, &mut applicability);
- let copied = match cx.typeck_results().expr_ty(let_expr).kind() {
- ty::Ref(_, inner, _) => match inner.kind() {
- ty::Ref(..) => ".copied()",
- _ => ""
- }
+ // Prepare the help message
+ let mut applicability = Applicability::MaybeIncorrect;
+ let arg_snippet = make_iterator_snippet(cx, arg, &mut applicability);
+ let copied = match cx.typeck_results().expr_ty(let_expr).kind() {
+ ty::Ref(_, inner, _) => match inner.kind() {
+ ty::Ref(..) => ".copied()",
_ => ""
- };
+ }
+ _ => ""
+ };
- span_lint_and_then(
- cx,
- MANUAL_FLATTEN,
- span,
- &msg,
- |diag| {
- let sugg = format!("{}{}.flatten()", arg_snippet, copied);
- diag.span_suggestion(
- arg.span,
- "try",
- sugg,
- Applicability::MaybeIncorrect,
- );
- diag.span_help(
- inner_expr.span,
- "...and remove the `if let` statement in the for loop",
- );
- }
- );
- }
+ span_lint_and_then(
+ cx,
+ MANUAL_FLATTEN,
+ span,
+ &msg,
+ |diag| {
+ let sugg = format!("{}{}.flatten()", arg_snippet, copied);
+ diag.span_suggestion(
+ arg.span,
+ "try",
+ sugg,
+ Applicability::MaybeIncorrect,
+ );
+ diag.span_help(
+ inner_expr.span,
+ "...and remove the `if let` statement in the for loop",
+ );
+ }
+ );
}
}
}
diff --git a/src/tools/clippy/clippy_lints/src/loops/manual_memcpy.rs b/src/tools/clippy/clippy_lints/src/loops/manual_memcpy.rs
index 2362b4b2067..6cda9268534 100644
--- a/src/tools/clippy/clippy_lints/src/loops/manual_memcpy.rs
+++ b/src/tools/clippy/clippy_lints/src/loops/manual_memcpy.rs
@@ -445,7 +445,7 @@ fn get_loop_counters<'a, 'tcx>(
let mut initialize_visitor = InitializeVisitor::new(cx, expr, var_id);
walk_block(&mut initialize_visitor, block);
- initialize_visitor.get_result().map(|(_, initializer)| Start {
+ initialize_visitor.get_result().map(|(_, _, initializer)| Start {
id: var_id,
kind: StartKind::Counter { initializer },
})
diff --git a/src/tools/clippy/clippy_lints/src/loops/mod.rs b/src/tools/clippy/clippy_lints/src/loops/mod.rs
index fd4881b2947..e2f9aee063d 100644
--- a/src/tools/clippy/clippy_lints/src/loops/mod.rs
+++ b/src/tools/clippy/clippy_lints/src/loops/mod.rs
@@ -47,6 +47,7 @@ declare_clippy_lint! {
/// # let mut dst = vec![0; 65];
/// dst[64..(src.len() + 64)].clone_from_slice(&src[..]);
/// ```
+ #[clippy::version = "pre 1.29.0"]
pub MANUAL_MEMCPY,
perf,
"manually copying items between slices"
@@ -75,6 +76,7 @@ declare_clippy_lint! {
/// println!("{}", i);
/// }
/// ```
+ #[clippy::version = "pre 1.29.0"]
pub NEEDLESS_RANGE_LOOP,
style,
"for-looping over a range of indices where an iterator over items would do"
@@ -107,6 +109,7 @@ declare_clippy_lint! {
/// // ..
/// }
/// ```
+ #[clippy::version = "pre 1.29.0"]
pub EXPLICIT_ITER_LOOP,
pedantic,
"for-looping over `_.iter()` or `_.iter_mut()` when `&_` or `&mut _` would do"
@@ -135,6 +138,7 @@ declare_clippy_lint! {
/// // ..
/// }
/// ```
+ #[clippy::version = "pre 1.29.0"]
pub EXPLICIT_INTO_ITER_LOOP,
pedantic,
"for-looping over `_.into_iter()` when `_` would do"
@@ -158,6 +162,7 @@ declare_clippy_lint! {
/// ..
/// }
/// ```
+ #[clippy::version = "pre 1.29.0"]
pub ITER_NEXT_LOOP,
correctness,
"for-looping over `_.next()` which is probably not intended"
@@ -201,6 +206,7 @@ declare_clippy_lint! {
/// // ..
/// }
/// ```
+ #[clippy::version = "1.45.0"]
pub FOR_LOOPS_OVER_FALLIBLES,
suspicious,
"for-looping over an `Option` or a `Result`, which is more clearly expressed as an `if let`"
@@ -233,6 +239,7 @@ declare_clippy_lint! {
/// // .. do something with x
/// };
/// ```
+ #[clippy::version = "pre 1.29.0"]
pub WHILE_LET_LOOP,
complexity,
"`loop { if let { ... } else break }`, which can be written as a `while let` loop"
@@ -254,6 +261,7 @@ declare_clippy_lint! {
/// // should be
/// let len = iterator.count();
/// ```
+ #[clippy::version = "1.30.0"]
pub NEEDLESS_COLLECT,
perf,
"collecting an iterator when collect is not needed"
@@ -284,6 +292,7 @@ declare_clippy_lint! {
/// # fn bar(bar: usize, baz: usize) {}
/// for (i, item) in v.iter().enumerate() { bar(i, *item); }
/// ```
+ #[clippy::version = "pre 1.29.0"]
pub EXPLICIT_COUNTER_LOOP,
complexity,
"for-looping with an explicit counter when `_.enumerate()` would do"
@@ -317,6 +326,7 @@ declare_clippy_lint! {
/// ```no_run
/// loop {}
/// ```
+ #[clippy::version = "pre 1.29.0"]
pub EMPTY_LOOP,
suspicious,
"empty `loop {}`, which should block or sleep"
@@ -336,6 +346,7 @@ declare_clippy_lint! {
/// ..
/// }
/// ```
+ #[clippy::version = "pre 1.29.0"]
pub WHILE_LET_ON_ITERATOR,
style,
"using a `while let` loop instead of a for loop on an iterator"
@@ -364,6 +375,7 @@ declare_clippy_lint! {
/// ..
/// }
/// ```
+ #[clippy::version = "pre 1.29.0"]
pub FOR_KV_MAP,
style,
"looping on a map using `iter` when `keys` or `values` would do"
@@ -385,6 +397,7 @@ declare_clippy_lint! {
/// break;
/// }
/// ```
+ #[clippy::version = "pre 1.29.0"]
pub NEVER_LOOP,
correctness,
"any loop that will always `break` or `return`"
@@ -420,6 +433,7 @@ declare_clippy_lint! {
/// println!("{}", i); // prints numbers from 0 to 42, not 0 to 21
/// }
/// ```
+ #[clippy::version = "pre 1.29.0"]
pub MUT_RANGE_BOUND,
suspicious,
"for loop over a range where one of the bounds is a mutable variable"
@@ -446,6 +460,7 @@ declare_clippy_lint! {
/// println!("let me loop forever!");
/// }
/// ```
+ #[clippy::version = "pre 1.29.0"]
pub WHILE_IMMUTABLE_CONDITION,
correctness,
"variables used within while expression are not mutated in the body"
@@ -480,6 +495,7 @@ declare_clippy_lint! {
/// let mut vec: Vec<u8> = vec![item1; 20];
/// vec.resize(20 + 30, item2);
/// ```
+ #[clippy::version = "1.47.0"]
pub SAME_ITEM_PUSH,
style,
"the same item is pushed inside of a for loop"
@@ -506,6 +522,7 @@ declare_clippy_lint! {
/// let item = &item1;
/// println!("{}", item);
/// ```
+ #[clippy::version = "1.49.0"]
pub SINGLE_ELEMENT_LOOP,
complexity,
"there is no reason to have a single element loop"
@@ -537,6 +554,7 @@ declare_clippy_lint! {
/// println!("{}", n);
/// }
/// ```
+ #[clippy::version = "1.52.0"]
pub MANUAL_FLATTEN,
complexity,
"for loops over `Option`s or `Result`s with a single expression can be simplified"
diff --git a/src/tools/clippy/clippy_lints/src/loops/needless_collect.rs b/src/tools/clippy/clippy_lints/src/loops/needless_collect.rs
index e87f4b66912..6f3acb45ba4 100644
--- a/src/tools/clippy/clippy_lints/src/loops/needless_collect.rs
+++ b/src/tools/clippy/clippy_lints/src/loops/needless_collect.rs
@@ -3,13 +3,16 @@ use clippy_utils::diagnostics::{span_lint_and_sugg, span_lint_hir_and_then};
use clippy_utils::source::{snippet, snippet_with_applicability};
use clippy_utils::sugg::Sugg;
use clippy_utils::ty::is_type_diagnostic_item;
-use clippy_utils::{is_trait_method, path_to_local_id};
+use clippy_utils::{can_move_expr_to_closure, is_trait_method, path_to_local, path_to_local_id, CaptureKind};
use if_chain::if_chain;
+use rustc_data_structures::fx::FxHashMap;
use rustc_errors::Applicability;
use rustc_hir::intravisit::{walk_block, walk_expr, NestedVisitorMap, Visitor};
-use rustc_hir::{Block, Expr, ExprKind, HirId, PatKind, StmtKind};
+use rustc_hir::{Block, Expr, ExprKind, HirId, HirIdSet, Local, Mutability, Node, PatKind, Stmt, StmtKind};
use rustc_lint::LateContext;
use rustc_middle::hir::map::Map;
+use rustc_middle::ty::subst::GenericArgKind;
+use rustc_middle::ty::{self, TyS};
use rustc_span::sym;
use rustc_span::{MultiSpan, Span};
@@ -83,7 +86,8 @@ fn check_needless_collect_indirect_usage<'tcx>(expr: &'tcx Expr<'_>, cx: &LateCo
is_type_diagnostic_item(cx, ty, sym::VecDeque) ||
is_type_diagnostic_item(cx, ty, sym::BinaryHeap) ||
is_type_diagnostic_item(cx, ty, sym::LinkedList);
- if let Some(iter_calls) = detect_iter_and_into_iters(block, id);
+ let iter_ty = cx.typeck_results().expr_ty(iter_source);
+ if let Some(iter_calls) = detect_iter_and_into_iters(block, id, cx, get_captured_ids(cx, iter_ty));
if let [iter_call] = &*iter_calls;
then {
let mut used_count_visitor = UsedCountVisitor {
@@ -167,37 +171,89 @@ enum IterFunctionKind {
Contains(Span),
}
-struct IterFunctionVisitor {
- uses: Vec<IterFunction>,
+struct IterFunctionVisitor<'a, 'tcx> {
+ illegal_mutable_capture_ids: HirIdSet,
+ current_mutably_captured_ids: HirIdSet,
+ cx: &'a LateContext<'tcx>,
+ uses: Vec<Option<IterFunction>>,
+ hir_id_uses_map: FxHashMap<HirId, usize>,
+ current_statement_hir_id: Option<HirId>,
seen_other: bool,
target: HirId,
}
-impl<'tcx> Visitor<'tcx> for IterFunctionVisitor {
+impl<'tcx> Visitor<'tcx> for IterFunctionVisitor<'_, 'tcx> {
+ fn visit_block(&mut self, block: &'tcx Block<'tcx>) {
+ for (expr, hir_id) in block.stmts.iter().filter_map(get_expr_and_hir_id_from_stmt) {
+ self.visit_block_expr(expr, hir_id);
+ }
+ if let Some(expr) = block.expr {
+ self.visit_block_expr(expr, None);
+ }
+ }
+
fn visit_expr(&mut self, expr: &'tcx Expr<'tcx>) {
// Check function calls on our collection
if let ExprKind::MethodCall(method_name, _, [recv, args @ ..], _) = &expr.kind {
+ if method_name.ident.name == sym!(collect) && is_trait_method(self.cx, expr, sym::Iterator) {
+ self.current_mutably_captured_ids = get_captured_ids(self.cx, self.cx.typeck_results().expr_ty(recv));
+ self.visit_expr(recv);
+ return;
+ }
+
if path_to_local_id(recv, self.target) {
- match &*method_name.ident.name.as_str() {
- "into_iter" => self.uses.push(IterFunction {
- func: IterFunctionKind::IntoIter,
- span: expr.span,
- }),
- "len" => self.uses.push(IterFunction {
- func: IterFunctionKind::Len,
- span: expr.span,
- }),
- "is_empty" => self.uses.push(IterFunction {
- func: IterFunctionKind::IsEmpty,
- span: expr.span,
- }),
- "contains" => self.uses.push(IterFunction {
- func: IterFunctionKind::Contains(args[0].span),
- span: expr.span,
- }),
- _ => self.seen_other = true,
+ if self
+ .illegal_mutable_capture_ids
+ .intersection(&self.current_mutably_captured_ids)
+ .next()
+ .is_none()
+ {
+ if let Some(hir_id) = self.current_statement_hir_id {
+ self.hir_id_uses_map.insert(hir_id, self.uses.len());
+ }
+ match &*method_name.ident.name.as_str() {
+ "into_iter" => self.uses.push(Some(IterFunction {
+ func: IterFunctionKind::IntoIter,
+ span: expr.span,
+ })),
+ "len" => self.uses.push(Some(IterFunction {
+ func: IterFunctionKind::Len,
+ span: expr.span,
+ })),
+ "is_empty" => self.uses.push(Some(IterFunction {
+ func: IterFunctionKind::IsEmpty,
+ span: expr.span,
+ })),
+ "contains" => self.uses.push(Some(IterFunction {
+ func: IterFunctionKind::Contains(args[0].span),
+ span: expr.span,
+ })),
+ _ => {
+ self.seen_other = true;
+ if let Some(hir_id) = self.current_statement_hir_id {
+ self.hir_id_uses_map.remove(&hir_id);
+ }
+ },
+ }
}
return;
}
+
+ if let Some(hir_id) = path_to_local(recv) {
+ if let Some(index) = self.hir_id_uses_map.remove(&hir_id) {
+ if self
+ .illegal_mutable_capture_ids
+ .intersection(&self.current_mutably_captured_ids)
+ .next()
+ .is_none()
+ {
+ if let Some(hir_id) = self.current_statement_hir_id {
+ self.hir_id_uses_map.insert(hir_id, index);
+ }
+ } else {
+ self.uses[index] = None;
+ }
+ }
+ }
}
// Check if the collection is used for anything else
if path_to_local_id(expr, self.target) {
@@ -213,6 +269,28 @@ impl<'tcx> Visitor<'tcx> for IterFunctionVisitor {
}
}
+impl<'tcx> IterFunctionVisitor<'_, 'tcx> {
+ fn visit_block_expr(&mut self, expr: &'tcx Expr<'tcx>, hir_id: Option<HirId>) {
+ self.current_statement_hir_id = hir_id;
+ self.current_mutably_captured_ids = get_captured_ids(self.cx, self.cx.typeck_results().expr_ty(expr));
+ self.visit_expr(expr);
+ }
+}
+
+fn get_expr_and_hir_id_from_stmt<'v>(stmt: &'v Stmt<'v>) -> Option<(&'v Expr<'v>, Option<HirId>)> {
+ match stmt.kind {
+ StmtKind::Expr(expr) | StmtKind::Semi(expr) => Some((expr, None)),
+ StmtKind::Item(..) => None,
+ StmtKind::Local(Local { init, pat, .. }) => {
+ if let PatKind::Binding(_, hir_id, ..) = pat.kind {
+ init.map(|init_expr| (init_expr, Some(hir_id)))
+ } else {
+ init.map(|init_expr| (init_expr, None))
+ }
+ },
+ }
+}
+
struct UsedCountVisitor<'a, 'tcx> {
cx: &'a LateContext<'tcx>,
id: HirId,
@@ -237,12 +315,60 @@ impl<'a, 'tcx> Visitor<'tcx> for UsedCountVisitor<'a, 'tcx> {
/// Detect the occurrences of calls to `iter` or `into_iter` for the
/// given identifier
-fn detect_iter_and_into_iters<'tcx>(block: &'tcx Block<'tcx>, id: HirId) -> Option<Vec<IterFunction>> {
+fn detect_iter_and_into_iters<'tcx: 'a, 'a>(
+ block: &'tcx Block<'tcx>,
+ id: HirId,
+ cx: &'a LateContext<'tcx>,
+ captured_ids: HirIdSet,
+) -> Option<Vec<IterFunction>> {
let mut visitor = IterFunctionVisitor {
uses: Vec::new(),
target: id,
seen_other: false,
+ cx,
+ current_mutably_captured_ids: HirIdSet::default(),
+ illegal_mutable_capture_ids: captured_ids,
+ hir_id_uses_map: FxHashMap::default(),
+ current_statement_hir_id: None,
};
visitor.visit_block(block);
- if visitor.seen_other { None } else { Some(visitor.uses) }
+ if visitor.seen_other {
+ None
+ } else {
+ Some(visitor.uses.into_iter().flatten().collect())
+ }
+}
+
+fn get_captured_ids(cx: &LateContext<'tcx>, ty: &'_ TyS<'_>) -> HirIdSet {
+ fn get_captured_ids_recursive(cx: &LateContext<'tcx>, ty: &'_ TyS<'_>, set: &mut HirIdSet) {
+ match ty.kind() {
+ ty::Adt(_, generics) => {
+ for generic in *generics {
+ if let GenericArgKind::Type(ty) = generic.unpack() {
+ get_captured_ids_recursive(cx, ty, set);
+ }
+ }
+ },
+ ty::Closure(def_id, _) => {
+ let closure_hir_node = cx.tcx.hir().get_if_local(*def_id).unwrap();
+ if let Node::Expr(closure_expr) = closure_hir_node {
+ can_move_expr_to_closure(cx, closure_expr)
+ .unwrap()
+ .into_iter()
+ .for_each(|(hir_id, capture_kind)| {
+ if matches!(capture_kind, CaptureKind::Ref(Mutability::Mut)) {
+ set.insert(hir_id);
+ }
+ });
+ }
+ },
+ _ => (),
+ }
+ }
+
+ let mut set = HirIdSet::default();
+
+ get_captured_ids_recursive(cx, ty, &mut set);
+
+ set
}
diff --git a/src/tools/clippy/clippy_lints/src/loops/never_loop.rs b/src/tools/clippy/clippy_lints/src/loops/never_loop.rs
index 86b7d6d989a..a3aa6be6afd 100644
--- a/src/tools/clippy/clippy_lints/src/loops/never_loop.rs
+++ b/src/tools/clippy/clippy_lints/src/loops/never_loop.rs
@@ -92,9 +92,7 @@ fn combine_branches(b1: NeverLoopResult, b2: NeverLoopResult) -> NeverLoopResult
}
fn never_loop_block(block: &Block<'_>, main_loop_id: HirId) -> NeverLoopResult {
- let stmts = block.stmts.iter().map(stmt_to_expr);
- let expr = once(block.expr);
- let mut iter = stmts.chain(expr).flatten();
+ let mut iter = block.stmts.iter().filter_map(stmt_to_expr).chain(block.expr);
never_loop_expr_seq(&mut iter, main_loop_id)
}
@@ -117,12 +115,12 @@ fn never_loop_expr(expr: &Expr<'_>, main_loop_id: HirId) -> NeverLoopResult {
| ExprKind::Unary(_, e)
| ExprKind::Cast(e, _)
| ExprKind::Type(e, _)
- | ExprKind::Let(_, e, _)
| ExprKind::Field(e, _)
| ExprKind::AddrOf(_, _, e)
| ExprKind::Struct(_, _, Some(e))
| ExprKind::Repeat(e, _)
| ExprKind::DropTemps(e) => never_loop_expr(e, main_loop_id),
+ ExprKind::Let(let_expr) => never_loop_expr(let_expr.init, main_loop_id),
ExprKind::Array(es) | ExprKind::MethodCall(_, _, es, _) | ExprKind::Tup(es) => {
never_loop_expr_all(&mut es.iter(), main_loop_id)
},
diff --git a/src/tools/clippy/clippy_lints/src/loops/utils.rs b/src/tools/clippy/clippy_lints/src/loops/utils.rs
index c3939a66c6a..f6b7e1bc353 100644
--- a/src/tools/clippy/clippy_lints/src/loops/utils.rs
+++ b/src/tools/clippy/clippy_lints/src/loops/utils.rs
@@ -1,13 +1,16 @@
use clippy_utils::ty::{has_iter_method, implements_trait};
use clippy_utils::{get_parent_expr, is_integer_const, path_to_local, path_to_local_id, sugg};
use if_chain::if_chain;
+use rustc_ast::ast::{LitIntType, LitKind};
use rustc_errors::Applicability;
-use rustc_hir::intravisit::{walk_expr, walk_pat, walk_stmt, NestedVisitorMap, Visitor};
-use rustc_hir::HirIdMap;
-use rustc_hir::{BinOpKind, BorrowKind, Expr, ExprKind, HirId, Mutability, Pat, PatKind, Stmt, StmtKind};
+use rustc_hir::intravisit::{walk_expr, walk_local, walk_pat, walk_stmt, NestedVisitorMap, Visitor};
+use rustc_hir::{BinOpKind, BorrowKind, Expr, ExprKind, HirId, HirIdMap, Local, Mutability, Pat, PatKind, Stmt};
use rustc_lint::LateContext;
use rustc_middle::hir::map::Map;
+use rustc_middle::ty::Ty;
+use rustc_span::source_map::Spanned;
use rustc_span::symbol::{sym, Symbol};
+use rustc_typeck::hir_ty_to_ty;
use std::iter::Iterator;
#[derive(Debug, PartialEq)]
@@ -105,10 +108,11 @@ impl<'a, 'tcx> Visitor<'tcx> for IncrementVisitor<'a, 'tcx> {
}
enum InitializeVisitorState<'hir> {
- Initial, // Not examined yet
- Declared(Symbol), // Declared but not (yet) initialized
+ Initial, // Not examined yet
+ Declared(Symbol, Option<Ty<'hir>>), // Declared but not (yet) initialized
Initialized {
name: Symbol,
+ ty: Option<Ty<'hir>>,
initializer: &'hir Expr<'hir>,
},
DontWarn,
@@ -137,9 +141,9 @@ impl<'a, 'tcx> InitializeVisitor<'a, 'tcx> {
}
}
- pub(super) fn get_result(&self) -> Option<(Symbol, &'tcx Expr<'tcx>)> {
- if let InitializeVisitorState::Initialized { name, initializer } = self.state {
- Some((name, initializer))
+ pub(super) fn get_result(&self) -> Option<(Symbol, Option<Ty<'tcx>>, &'tcx Expr<'tcx>)> {
+ if let InitializeVisitorState::Initialized { name, ty, initializer } = self.state {
+ Some((name, ty, initializer))
} else {
None
}
@@ -149,22 +153,25 @@ impl<'a, 'tcx> InitializeVisitor<'a, 'tcx> {
impl<'a, 'tcx> Visitor<'tcx> for InitializeVisitor<'a, 'tcx> {
type Map = Map<'tcx>;
- fn visit_stmt(&mut self, stmt: &'tcx Stmt<'_>) {
+ fn visit_local(&mut self, l: &'tcx Local<'_>) {
// Look for declarations of the variable
if_chain! {
- if let StmtKind::Local(local) = stmt.kind;
- if local.pat.hir_id == self.var_id;
- if let PatKind::Binding(.., ident, _) = local.pat.kind;
+ if l.pat.hir_id == self.var_id;
+ if let PatKind::Binding(.., ident, _) = l.pat.kind;
then {
- self.state = local.init.map_or(InitializeVisitorState::Declared(ident.name), |init| {
+ let ty = l.ty.map(|ty| hir_ty_to_ty(self.cx.tcx, ty));
+
+ self.state = l.init.map_or(InitializeVisitorState::Declared(ident.name, ty), |init| {
InitializeVisitorState::Initialized {
initializer: init,
+ ty,
name: ident.name,
}
})
}
}
- walk_stmt(self, stmt);
+
+ walk_local(self, l);
}
fn visit_expr(&mut self, expr: &'tcx Expr<'_>) {
@@ -194,15 +201,38 @@ impl<'a, 'tcx> Visitor<'tcx> for InitializeVisitor<'a, 'tcx> {
self.state = InitializeVisitorState::DontWarn;
},
ExprKind::Assign(lhs, rhs, _) if lhs.hir_id == expr.hir_id => {
- self.state = if_chain! {
- if self.depth == 0;
- if let InitializeVisitorState::Declared(name)
- | InitializeVisitorState::Initialized { name, ..} = self.state;
- then {
- InitializeVisitorState::Initialized { initializer: rhs, name }
- } else {
- InitializeVisitorState::DontWarn
+ self.state = if self.depth == 0 {
+ match self.state {
+ InitializeVisitorState::Declared(name, mut ty) => {
+ if ty.is_none() {
+ if let ExprKind::Lit(Spanned {
+ node: LitKind::Int(_, LitIntType::Unsuffixed),
+ ..
+ }) = rhs.kind
+ {
+ ty = None;
+ } else {
+ ty = self.cx.typeck_results().expr_ty_opt(rhs);
+ }
+ }
+
+ InitializeVisitorState::Initialized {
+ initializer: rhs,
+ ty,
+ name,
+ }
+ },
+ InitializeVisitorState::Initialized { ty, name, .. } => {
+ InitializeVisitorState::Initialized {
+ initializer: rhs,
+ ty,
+ name,
+ }
+ },
+ _ => InitializeVisitorState::DontWarn,
}
+ } else {
+ InitializeVisitorState::DontWarn
}
},
ExprKind::AddrOf(BorrowKind::Ref, mutability, _) if mutability == Mutability::Mut => {
diff --git a/src/tools/clippy/clippy_lints/src/macro_use.rs b/src/tools/clippy/clippy_lints/src/macro_use.rs
index c38162743a3..5b22b64a370 100644
--- a/src/tools/clippy/clippy_lints/src/macro_use.rs
+++ b/src/tools/clippy/clippy_lints/src/macro_use.rs
@@ -1,5 +1,4 @@
use clippy_utils::diagnostics::span_lint_and_sugg;
-use clippy_utils::in_macro;
use clippy_utils::source::snippet;
use hir::def::{DefKind, Res};
use if_chain::if_chain;
@@ -9,6 +8,7 @@ use rustc_errors::Applicability;
use rustc_hir as hir;
use rustc_lint::{LateContext, LateLintPass, LintContext};
use rustc_session::{declare_tool_lint, impl_lint_pass};
+use rustc_span::hygiene::ExpnKind;
use rustc_span::{edition::Edition, sym, Span};
declare_clippy_lint! {
@@ -24,6 +24,7 @@ declare_clippy_lint! {
/// #[macro_use]
/// use some_macro;
/// ```
+ #[clippy::version = "1.44.0"]
pub MACRO_USE_IMPORTS,
pedantic,
"#[macro_use] is no longer needed"
@@ -212,3 +213,7 @@ impl<'tcx> LateLintPass<'tcx> for MacroUseImports {
}
}
}
+
+fn in_macro(span: Span) -> bool {
+ span.from_expansion() && !matches!(span.ctxt().outer_expn_data().kind, ExpnKind::Desugaring(..))
+}
diff --git a/src/tools/clippy/clippy_lints/src/main_recursion.rs b/src/tools/clippy/clippy_lints/src/main_recursion.rs
index 23b3ba2296e..fad8fa467d4 100644
--- a/src/tools/clippy/clippy_lints/src/main_recursion.rs
+++ b/src/tools/clippy/clippy_lints/src/main_recursion.rs
@@ -20,6 +20,7 @@ declare_clippy_lint! {
/// main();
/// }
/// ```
+ #[clippy::version = "1.38.0"]
pub MAIN_RECURSION,
style,
"recursion using the entrypoint"
diff --git a/src/tools/clippy/clippy_lints/src/manual_assert.rs b/src/tools/clippy/clippy_lints/src/manual_assert.rs
index e55aa3f1850..5a2a965716c 100644
--- a/src/tools/clippy/clippy_lints/src/manual_assert.rs
+++ b/src/tools/clippy/clippy_lints/src/manual_assert.rs
@@ -26,6 +26,7 @@ declare_clippy_lint! {
/// let sad_people: Vec<&str> = vec![];
/// assert!(sad_people.is_empty(), "there are sad people: {:?}", sad_people);
/// ```
+ #[clippy::version = "1.57.0"]
pub MANUAL_ASSERT,
pedantic,
"`panic!` and only a `panic!` in `if`-then statement"
@@ -49,7 +50,7 @@ impl LateLintPass<'_> for ManualAssert {
..
} = &expr;
if is_expn_of(stmt.span, "panic").is_some();
- if !matches!(cond.kind, ExprKind::Let(_, _, _));
+ if !matches!(cond.kind, ExprKind::Let(_));
if let StmtKind::Semi(semi) = stmt.kind;
if !cx.tcx.sess.source_map().is_multiline(cond.span);
diff --git a/src/tools/clippy/clippy_lints/src/manual_async_fn.rs b/src/tools/clippy/clippy_lints/src/manual_async_fn.rs
index b632af455f8..86819752f90 100644
--- a/src/tools/clippy/clippy_lints/src/manual_async_fn.rs
+++ b/src/tools/clippy/clippy_lints/src/manual_async_fn.rs
@@ -30,6 +30,7 @@ declare_clippy_lint! {
/// ```rust
/// async fn foo() -> i32 { 42 }
/// ```
+ #[clippy::version = "1.45.0"]
pub MANUAL_ASYNC_FN,
style,
"manual implementations of `async` functions can be simplified using the dedicated syntax"
diff --git a/src/tools/clippy/clippy_lints/src/manual_map.rs b/src/tools/clippy/clippy_lints/src/manual_map.rs
index 96df3d0a490..34a70ca76c6 100644
--- a/src/tools/clippy/clippy_lints/src/manual_map.rs
+++ b/src/tools/clippy/clippy_lints/src/manual_map.rs
@@ -2,16 +2,17 @@ use crate::{map_unit_fn::OPTION_MAP_UNIT_FN, matches::MATCH_AS_REF};
use clippy_utils::diagnostics::span_lint_and_sugg;
use clippy_utils::higher::IfLetOrMatch;
use clippy_utils::source::{snippet_with_applicability, snippet_with_context};
-use clippy_utils::ty::{is_type_diagnostic_item, peel_mid_ty_refs_is_mutable};
+use clippy_utils::ty::{is_type_diagnostic_item, peel_mid_ty_refs_is_mutable, type_is_unsafe_function};
use clippy_utils::{
can_move_expr_to_closure, in_constant, is_else_clause, is_lang_ctor, is_lint_allowed, path_to_local_id,
- peel_hir_expr_refs, peel_hir_expr_while, CaptureKind,
+ peel_blocks, peel_hir_expr_refs, peel_hir_expr_while, CaptureKind,
};
use rustc_ast::util::parser::PREC_POSTFIX;
use rustc_errors::Applicability;
use rustc_hir::LangItem::{OptionNone, OptionSome};
use rustc_hir::{
- def::Res, Arm, BindingAnnotation, Block, Expr, ExprKind, HirId, Mutability, Pat, PatKind, Path, QPath,
+ def::Res, Arm, BindingAnnotation, Block, BlockCheckMode, Expr, ExprKind, HirId, Mutability, Pat, PatKind, Path,
+ QPath, UnsafeSource,
};
use rustc_lint::{LateContext, LateLintPass, LintContext};
use rustc_middle::lint::in_external_macro;
@@ -36,6 +37,7 @@ declare_clippy_lint! {
/// ```rust
/// Some(0).map(|x| x + 1);
/// ```
+ #[clippy::version = "1.52.0"]
pub MANUAL_MAP,
style,
"reimplementation of `map`"
@@ -92,20 +94,20 @@ impl LateLintPass<'_> for ManualMap {
return;
}
- let some_expr = match get_some_expr(cx, some_expr, expr_ctxt) {
+ let some_expr = match get_some_expr(cx, some_expr, false, expr_ctxt) {
Some(expr) => expr,
None => return,
};
// These two lints will go back and forth with each other.
- if cx.typeck_results().expr_ty(some_expr) == cx.tcx.types.unit
+ if cx.typeck_results().expr_ty(some_expr.expr) == cx.tcx.types.unit
&& !is_lint_allowed(cx, OPTION_MAP_UNIT_FN, expr.hir_id)
{
return;
}
// `map` won't perform any adjustments.
- if !cx.typeck_results().expr_adjustments(some_expr).is_empty() {
+ if !cx.typeck_results().expr_adjustments(some_expr.expr).is_empty() {
return;
}
@@ -119,7 +121,7 @@ impl LateLintPass<'_> for ManualMap {
None => "",
};
- match can_move_expr_to_closure(cx, some_expr) {
+ match can_move_expr_to_closure(cx, some_expr.expr) {
Some(captures) => {
// Check if captures the closure will need conflict with borrows made in the scrutinee.
// TODO: check all the references made in the scrutinee expression. This will require interacting
@@ -157,12 +159,14 @@ impl LateLintPass<'_> for ManualMap {
};
let body_str = if let PatKind::Binding(annotation, id, some_binding, None) = some_pat.kind {
- match can_pass_as_func(cx, id, some_expr) {
- Some(func) if func.span.ctxt() == some_expr.span.ctxt() => {
+ if_chain! {
+ if !some_expr.needs_unsafe_block;
+ if let Some(func) = can_pass_as_func(cx, id, some_expr.expr);
+ if func.span.ctxt() == some_expr.expr.span.ctxt();
+ then {
snippet_with_applicability(cx, func.span, "..", &mut app).into_owned()
- },
- _ => {
- if path_to_local_id(some_expr, id)
+ } else {
+ if path_to_local_id(some_expr.expr, id)
&& !is_lint_allowed(cx, MATCH_AS_REF, expr.hir_id)
&& binding_ref.is_some()
{
@@ -175,21 +179,23 @@ impl LateLintPass<'_> for ManualMap {
} else {
""
};
- format!(
- "|{}{}| {}",
- annotation,
- some_binding,
- snippet_with_context(cx, some_expr.span, expr_ctxt, "..", &mut app).0
- )
- },
+ let expr_snip = snippet_with_context(cx, some_expr.expr.span, expr_ctxt, "..", &mut app).0;
+ if some_expr.needs_unsafe_block {
+ format!("|{}{}| unsafe {{ {} }}", annotation, some_binding, expr_snip)
+ } else {
+ format!("|{}{}| {}", annotation, some_binding, expr_snip)
+ }
+ }
}
} else if !is_wild_none && explicit_ref.is_none() {
// TODO: handle explicit reference annotations.
- format!(
- "|{}| {}",
- snippet_with_context(cx, some_pat.span, expr_ctxt, "..", &mut app).0,
- snippet_with_context(cx, some_expr.span, expr_ctxt, "..", &mut app).0
- )
+ let pat_snip = snippet_with_context(cx, some_pat.span, expr_ctxt, "..", &mut app).0;
+ let expr_snip = snippet_with_context(cx, some_expr.expr.span, expr_ctxt, "..", &mut app).0;
+ if some_expr.needs_unsafe_block {
+ format!("|{}| unsafe {{ {} }}", pat_snip, expr_snip)
+ } else {
+ format!("|{}| {}", pat_snip, expr_snip)
+ }
} else {
// Refutable bindings and mixed reference annotations can't be handled by `map`.
return;
@@ -216,7 +222,9 @@ impl LateLintPass<'_> for ManualMap {
fn can_pass_as_func(cx: &LateContext<'tcx>, binding: HirId, expr: &'tcx Expr<'_>) -> Option<&'tcx Expr<'tcx>> {
match expr.kind {
ExprKind::Call(func, [arg])
- if path_to_local_id(arg, binding) && cx.typeck_results().expr_adjustments(arg).is_empty() =>
+ if path_to_local_id(arg, binding)
+ && cx.typeck_results().expr_adjustments(arg).is_empty()
+ && !type_is_unsafe_function(cx, cx.typeck_results().expr_ty(func).peel_refs()) =>
{
Some(func)
},
@@ -236,6 +244,11 @@ enum OptionPat<'a> {
},
}
+struct SomeExpr<'tcx> {
+ expr: &'tcx Expr<'tcx>,
+ needs_unsafe_block: bool,
+}
+
// Try to parse into a recognized `Option` pattern.
// i.e. `_`, `None`, `Some(..)`, or a reference to any of those.
fn try_parse_pattern(cx: &LateContext<'tcx>, pat: &'tcx Pat<'_>, ctxt: SyntaxContext) -> Option<OptionPat<'tcx>> {
@@ -256,7 +269,12 @@ fn try_parse_pattern(cx: &LateContext<'tcx>, pat: &'tcx Pat<'_>, ctxt: SyntaxCon
}
// Checks for an expression wrapped by the `Some` constructor. Returns the contained expression.
-fn get_some_expr(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>, ctxt: SyntaxContext) -> Option<&'tcx Expr<'tcx>> {
+fn get_some_expr(
+ cx: &LateContext<'tcx>,
+ expr: &'tcx Expr<'_>,
+ needs_unsafe_block: bool,
+ ctxt: SyntaxContext,
+) -> Option<SomeExpr<'tcx>> {
// TODO: Allow more complex expressions.
match expr.kind {
ExprKind::Call(
@@ -265,31 +283,29 @@ fn get_some_expr(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>, ctxt: SyntaxConte
..
},
[arg],
- ) if ctxt == expr.span.ctxt() && is_lang_ctor(cx, qpath, OptionSome) => Some(arg),
+ ) if ctxt == expr.span.ctxt() && is_lang_ctor(cx, qpath, OptionSome) => Some(SomeExpr {
+ expr: arg,
+ needs_unsafe_block,
+ }),
ExprKind::Block(
Block {
stmts: [],
expr: Some(expr),
+ rules,
..
},
_,
- ) => get_some_expr(cx, expr, ctxt),
+ ) => get_some_expr(
+ cx,
+ expr,
+ needs_unsafe_block || *rules == BlockCheckMode::UnsafeBlock(UnsafeSource::UserProvided),
+ ctxt,
+ ),
_ => None,
}
}
// Checks for the `None` value.
fn is_none_expr(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) -> bool {
- match expr.kind {
- ExprKind::Path(ref qpath) => is_lang_ctor(cx, qpath, OptionNone),
- ExprKind::Block(
- Block {
- stmts: [],
- expr: Some(expr),
- ..
- },
- _,
- ) => is_none_expr(cx, expr),
- _ => false,
- }
+ matches!(peel_blocks(expr).kind, ExprKind::Path(ref qpath) if is_lang_ctor(cx, qpath, OptionNone))
}
diff --git a/src/tools/clippy/clippy_lints/src/manual_non_exhaustive.rs b/src/tools/clippy/clippy_lints/src/manual_non_exhaustive.rs
index 335ea001ee4..63a72d4fdde 100644
--- a/src/tools/clippy/clippy_lints/src/manual_non_exhaustive.rs
+++ b/src/tools/clippy/clippy_lints/src/manual_non_exhaustive.rs
@@ -52,6 +52,7 @@ declare_clippy_lint! {
/// #[non_exhaustive]
/// struct T(pub i32, pub i32);
/// ```
+ #[clippy::version = "1.45.0"]
pub MANUAL_NON_EXHAUSTIVE,
style,
"manual implementations of the non-exhaustive pattern can be simplified using #[non_exhaustive]"
diff --git a/src/tools/clippy/clippy_lints/src/manual_ok_or.rs b/src/tools/clippy/clippy_lints/src/manual_ok_or.rs
index cf641d0ce86..b60e2dc366b 100644
--- a/src/tools/clippy/clippy_lints/src/manual_ok_or.rs
+++ b/src/tools/clippy/clippy_lints/src/manual_ok_or.rs
@@ -32,6 +32,7 @@ declare_clippy_lint! {
/// let foo: Option<i32> = None;
/// foo.ok_or("error");
/// ```
+ #[clippy::version = "1.49.0"]
pub MANUAL_OK_OR,
pedantic,
"finds patterns that can be encoded more concisely with `Option::ok_or`"
diff --git a/src/tools/clippy/clippy_lints/src/manual_strip.rs b/src/tools/clippy/clippy_lints/src/manual_strip.rs
index 4e040508b6b..f8e28f1671f 100644
--- a/src/tools/clippy/clippy_lints/src/manual_strip.rs
+++ b/src/tools/clippy/clippy_lints/src/manual_strip.rs
@@ -42,6 +42,7 @@ declare_clippy_lint! {
/// assert_eq!(end.to_uppercase(), "WORLD!");
/// }
/// ```
+ #[clippy::version = "1.48.0"]
pub MANUAL_STRIP,
complexity,
"suggests using `strip_{prefix,suffix}` over `str::{starts,ends}_with` and slicing"
diff --git a/src/tools/clippy/clippy_lints/src/manual_unwrap_or.rs b/src/tools/clippy/clippy_lints/src/manual_unwrap_or.rs
index 42478e3416e..aac3c6e0de2 100644
--- a/src/tools/clippy/clippy_lints/src/manual_unwrap_or.rs
+++ b/src/tools/clippy/clippy_lints/src/manual_unwrap_or.rs
@@ -35,6 +35,7 @@ declare_clippy_lint! {
/// let foo: Option<i32> = None;
/// foo.unwrap_or(1);
/// ```
+ #[clippy::version = "1.49.0"]
pub MANUAL_UNWRAP_OR,
complexity,
"finds patterns that can be encoded more concisely with `Option::unwrap_or` or `Result::unwrap_or`"
diff --git a/src/tools/clippy/clippy_lints/src/map_clone.rs b/src/tools/clippy/clippy_lints/src/map_clone.rs
index 7db5c7e52ea..174c7da28d3 100644
--- a/src/tools/clippy/clippy_lints/src/map_clone.rs
+++ b/src/tools/clippy/clippy_lints/src/map_clone.rs
@@ -1,8 +1,7 @@
use clippy_utils::diagnostics::span_lint_and_sugg;
-use clippy_utils::is_trait_method;
-use clippy_utils::remove_blocks;
use clippy_utils::source::snippet_with_applicability;
use clippy_utils::ty::{is_copy, is_type_diagnostic_item};
+use clippy_utils::{is_trait_method, peel_blocks};
use if_chain::if_chain;
use rustc_errors::Applicability;
use rustc_hir as hir;
@@ -37,6 +36,7 @@ declare_clippy_lint! {
/// let y = x.iter();
/// let z = y.cloned();
/// ```
+ #[clippy::version = "pre 1.29.0"]
pub MAP_CLONE,
style,
"using `iterator.map(|x| x.clone())`, or dereferencing closures for `Copy` types"
@@ -59,7 +59,7 @@ impl<'tcx> LateLintPass<'tcx> for MapClone {
if let hir::ExprKind::Closure(_, _, body_id, _, _) = args[1].kind;
then {
let closure_body = cx.tcx.hir().body(body_id);
- let closure_expr = remove_blocks(&closure_body.value);
+ let closure_expr = peel_blocks(&closure_body.value);
match closure_body.params[0].pat.kind {
hir::PatKind::Ref(inner, hir::Mutability::Not) => if let hir::PatKind::Binding(
hir::BindingAnnotation::Unannotated, .., name, None
diff --git a/src/tools/clippy/clippy_lints/src/map_err_ignore.rs b/src/tools/clippy/clippy_lints/src/map_err_ignore.rs
index 82d3732326e..61f21d532c5 100644
--- a/src/tools/clippy/clippy_lints/src/map_err_ignore.rs
+++ b/src/tools/clippy/clippy_lints/src/map_err_ignore.rs
@@ -97,6 +97,7 @@ declare_clippy_lint! {
/// })
/// }
/// ```
+ #[clippy::version = "1.48.0"]
pub MAP_ERR_IGNORE,
restriction,
"`map_err` should not ignore the original error"
diff --git a/src/tools/clippy/clippy_lints/src/map_unit_fn.rs b/src/tools/clippy/clippy_lints/src/map_unit_fn.rs
index 40de9ffcd4e..58c686d95b3 100644
--- a/src/tools/clippy/clippy_lints/src/map_unit_fn.rs
+++ b/src/tools/clippy/clippy_lints/src/map_unit_fn.rs
@@ -47,6 +47,7 @@ declare_clippy_lint! {
/// log_err_msg(format_msg(msg));
/// }
/// ```
+ #[clippy::version = "pre 1.29.0"]
pub OPTION_MAP_UNIT_FN,
complexity,
"using `option.map(f)`, where `f` is a function or closure that returns `()`"
@@ -87,6 +88,7 @@ declare_clippy_lint! {
/// log_err_msg(format_msg(msg));
/// };
/// ```
+ #[clippy::version = "pre 1.29.0"]
pub RESULT_MAP_UNIT_FN,
complexity,
"using `result.map(f)`, where `f` is a function or closure that returns `()`"
@@ -188,7 +190,7 @@ fn unit_closure<'tcx>(
/// Anything else will return `a`.
fn let_binding_name(cx: &LateContext<'_>, var_arg: &hir::Expr<'_>) -> String {
match &var_arg.kind {
- hir::ExprKind::Field(_, _) => snippet(cx, var_arg.span, "_").replace(".", "_"),
+ hir::ExprKind::Field(_, _) => snippet(cx, var_arg.span, "_").replace('.', "_"),
hir::ExprKind::Path(_) => format!("_{}", snippet(cx, var_arg.span, "")),
_ => "a".to_string(),
}
diff --git a/src/tools/clippy/clippy_lints/src/match_on_vec_items.rs b/src/tools/clippy/clippy_lints/src/match_on_vec_items.rs
index 552c9a58897..583b577ffe2 100644
--- a/src/tools/clippy/clippy_lints/src/match_on_vec_items.rs
+++ b/src/tools/clippy/clippy_lints/src/match_on_vec_items.rs
@@ -40,6 +40,7 @@ declare_clippy_lint! {
/// _ => {},
/// }
/// ```
+ #[clippy::version = "1.45.0"]
pub MATCH_ON_VEC_ITEMS,
pedantic,
"matching on vector elements can panic"
diff --git a/src/tools/clippy/clippy_lints/src/match_result_ok.rs b/src/tools/clippy/clippy_lints/src/match_result_ok.rs
index ecf6ad316a4..b1839f00aae 100644
--- a/src/tools/clippy/clippy_lints/src/match_result_ok.rs
+++ b/src/tools/clippy/clippy_lints/src/match_result_ok.rs
@@ -38,6 +38,7 @@ declare_clippy_lint! {
/// vec.push(value)
/// }
/// ```
+ #[clippy::version = "1.57.0"]
pub MATCH_RESULT_OK,
style,
"usage of `ok()` in `let Some(pat)` statements is unnecessary, match on `Ok(pat)` instead"
diff --git a/src/tools/clippy/clippy_lints/src/match_str_case_mismatch.rs b/src/tools/clippy/clippy_lints/src/match_str_case_mismatch.rs
index f501593c518..3316ebf4051 100644
--- a/src/tools/clippy/clippy_lints/src/match_str_case_mismatch.rs
+++ b/src/tools/clippy/clippy_lints/src/match_str_case_mismatch.rs
@@ -39,6 +39,7 @@ declare_clippy_lint! {
/// _ => {},
/// }
/// ```
+ #[clippy::version = "1.58.0"]
pub MATCH_STR_CASE_MISMATCH,
correctness,
"creation of a case altering match expression with non-compliant arms"
diff --git a/src/tools/clippy/clippy_lints/src/matches.rs b/src/tools/clippy/clippy_lints/src/matches.rs
index 7142df98c3f..acac0887226 100644
--- a/src/tools/clippy/clippy_lints/src/matches.rs
+++ b/src/tools/clippy/clippy_lints/src/matches.rs
@@ -8,12 +8,11 @@ use clippy_utils::sugg::Sugg;
use clippy_utils::ty::{implements_trait, is_type_diagnostic_item, match_type, peel_mid_ty_refs};
use clippy_utils::visitors::is_local_used;
use clippy_utils::{
- get_parent_expr, in_macro, is_expn_of, is_lang_ctor, is_lint_allowed, is_refutable, is_unit_expr, is_wild,
- meets_msrv, msrvs, path_to_local, path_to_local_id, peel_hir_pat_refs, peel_n_hir_expr_refs, recurse_or_patterns,
- remove_blocks, strip_pat_refs,
+ get_parent_expr, is_expn_of, is_lang_ctor, is_lint_allowed, is_refutable, is_unit_expr, is_wild, meets_msrv, msrvs,
+ path_to_local, path_to_local_id, peel_blocks, peel_hir_pat_refs, peel_n_hir_expr_refs, recurse_or_patterns,
+ strip_pat_refs,
};
use clippy_utils::{paths, search_same, SpanlessEq, SpanlessHash};
-use core::array;
use core::iter::{once, ExactSizeIterator};
use if_chain::if_chain;
use rustc_ast::ast::{Attribute, LitKind};
@@ -26,7 +25,6 @@ use rustc_hir::{
};
use rustc_hir::{HirIdMap, HirIdSet};
use rustc_lint::{LateContext, LateLintPass, LintContext};
-use rustc_middle::lint::in_external_macro;
use rustc_middle::ty::{self, Ty, TyS, VariantDef};
use rustc_semver::RustcVersion;
use rustc_session::{declare_tool_lint, impl_lint_pass};
@@ -34,8 +32,6 @@ use rustc_span::source_map::{Span, Spanned};
use rustc_span::sym;
use std::cmp::Ordering;
use std::collections::hash_map::Entry;
-use std::iter;
-use std::ops::Bound;
declare_clippy_lint! {
/// ### What it does
@@ -60,6 +56,7 @@ declare_clippy_lint! {
/// bar(foo);
/// }
/// ```
+ #[clippy::version = "pre 1.29.0"]
pub SINGLE_MATCH,
style,
"a `match` statement with a single nontrivial arm (i.e., where the other arm is `_ => {}`) instead of `if let`"
@@ -101,6 +98,7 @@ declare_clippy_lint! {
/// bar(&other_ref);
/// }
/// ```
+ #[clippy::version = "pre 1.29.0"]
pub SINGLE_MATCH_ELSE,
pedantic,
"a `match` statement with two arms where the second arm's pattern is a placeholder instead of a specific match pattern"
@@ -132,6 +130,7 @@ declare_clippy_lint! {
/// _ => frob(x),
/// }
/// ```
+ #[clippy::version = "pre 1.29.0"]
pub MATCH_REF_PATS,
style,
"a `match` or `if let` with all arms prefixed with `&` instead of deref-ing the match expression"
@@ -166,6 +165,7 @@ declare_clippy_lint! {
/// bar();
/// }
/// ```
+ #[clippy::version = "pre 1.29.0"]
pub MATCH_BOOL,
pedantic,
"a `match` on a boolean expression instead of an `if..else` block"
@@ -188,6 +188,7 @@ declare_clippy_lint! {
/// _ => (),
/// }
/// ```
+ #[clippy::version = "pre 1.29.0"]
pub MATCH_OVERLAPPING_ARM,
style,
"a `match` with overlapping arms"
@@ -210,6 +211,7 @@ declare_clippy_lint! {
/// Err(_) => panic!("err"),
/// }
/// ```
+ #[clippy::version = "pre 1.29.0"]
pub MATCH_WILD_ERR_ARM,
pedantic,
"a `match` with `Err(_)` arm and take drastic actions"
@@ -236,6 +238,7 @@ declare_clippy_lint! {
/// // Good
/// let r: Option<&()> = x.as_ref();
/// ```
+ #[clippy::version = "pre 1.29.0"]
pub MATCH_AS_REF,
complexity,
"a `match` on an Option value instead of using `as_ref()` or `as_mut`"
@@ -268,6 +271,7 @@ declare_clippy_lint! {
/// Foo::B(_) => {},
/// }
/// ```
+ #[clippy::version = "1.34.0"]
pub WILDCARD_ENUM_MATCH_ARM,
restriction,
"a wildcard enum match arm using `_`"
@@ -302,6 +306,7 @@ declare_clippy_lint! {
/// Foo::C => {},
/// }
/// ```
+ #[clippy::version = "1.45.0"]
pub MATCH_WILDCARD_FOR_SINGLE_VARIANTS,
pedantic,
"a wildcard enum match for a single variant"
@@ -329,6 +334,7 @@ declare_clippy_lint! {
/// _ => {},
/// }
/// ```
+ #[clippy::version = "1.42.0"]
pub WILDCARD_IN_OR_PATTERNS,
complexity,
"a wildcard pattern used with others patterns in same match arm"
@@ -364,6 +370,7 @@ declare_clippy_lint! {
/// let wrapper = Wrapper::Data(42);
/// let Wrapper::Data(data) = wrapper;
/// ```
+ #[clippy::version = "pre 1.29.0"]
pub INFALLIBLE_DESTRUCTURING_MATCH,
style,
"a `match` statement with a single infallible arm instead of a `let`"
@@ -395,6 +402,7 @@ declare_clippy_lint! {
/// // Good
/// let (c, d) = (a, b);
/// ```
+ #[clippy::version = "1.43.0"]
pub MATCH_SINGLE_BINDING,
complexity,
"a match with a single binding instead of using `let` statement"
@@ -425,6 +433,7 @@ declare_clippy_lint! {
/// _ => {},
/// }
/// ```
+ #[clippy::version = "1.43.0"]
pub REST_PAT_IN_FULLY_BOUND_STRUCTS,
restriction,
"a match on a struct that binds all fields but still uses the wildcard pattern"
@@ -480,6 +489,7 @@ declare_clippy_lint! {
/// if IpAddr::V6(Ipv6Addr::LOCALHOST).is_ipv6() {}
/// Ok::<i32, i32>(42).is_ok();
/// ```
+ #[clippy::version = "1.31.0"]
pub REDUNDANT_PATTERN_MATCHING,
style,
"use the proper utility function avoiding an `if let`"
@@ -516,6 +526,7 @@ declare_clippy_lint! {
/// // Good
/// let a = matches!(x, Some(0));
/// ```
+ #[clippy::version = "1.47.0"]
pub MATCH_LIKE_MATCHES_MACRO,
style,
"a match that could be written with the matches! macro"
@@ -560,6 +571,7 @@ declare_clippy_lint! {
/// Quz => quz(),
/// }
/// ```
+ #[clippy::version = "pre 1.29.0"]
pub MATCH_SAME_ARMS,
pedantic,
"`match` with identical arm bodies"
@@ -602,7 +614,7 @@ impl_lint_pass!(Matches => [
impl<'tcx> LateLintPass<'tcx> for Matches {
fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
- if in_external_macro(cx.sess(), expr.span) || in_macro(expr.span) {
+ if expr.span.from_expansion() {
return;
}
@@ -634,15 +646,11 @@ impl<'tcx> LateLintPass<'tcx> for Matches {
if let ExprKind::Match(ex, arms, _) = expr.kind {
check_match_ref_pats(cx, ex, arms.iter().map(|el| el.pat), expr);
}
- if let Some(higher::IfLet { let_pat, let_expr, .. }) = higher::IfLet::hir(cx, expr) {
- check_match_ref_pats(cx, let_expr, once(let_pat), expr);
- }
}
fn check_local(&mut self, cx: &LateContext<'tcx>, local: &'tcx Local<'_>) {
if_chain! {
- if !in_external_macro(cx.sess(), local.span);
- if !in_macro(local.span);
+ if !local.span.from_expansion();
if let Some(expr) = local.init;
if let ExprKind::Match(target, arms, MatchSource::Normal) = expr.kind;
if arms.len() == 1 && arms[0].guard.is_none();
@@ -650,7 +658,7 @@ impl<'tcx> LateLintPass<'tcx> for Matches {
QPath::Resolved(None, variant_name), args, _) = arms[0].pat.kind;
if args.len() == 1;
if let PatKind::Binding(_, arg, ..) = strip_pat_refs(&args[0]).kind;
- let body = remove_blocks(arms[0].body);
+ let body = peel_blocks(arms[0].body);
if path_to_local_id(body, arg);
then {
@@ -677,8 +685,7 @@ impl<'tcx> LateLintPass<'tcx> for Matches {
fn check_pat(&mut self, cx: &LateContext<'tcx>, pat: &'tcx Pat<'_>) {
if_chain! {
- if !in_external_macro(cx.sess(), pat.span);
- if !in_macro(pat.span);
+ if !pat.span.from_expansion();
if let PatKind::Struct(QPath::Resolved(_, path), fields, true) = pat.kind;
if let Some(def_id) = path.res.opt_def_id();
let ty = cx.tcx.type_of(def_id);
@@ -705,7 +712,7 @@ impl<'tcx> LateLintPass<'tcx> for Matches {
#[rustfmt::skip]
fn check_single_match(cx: &LateContext<'_>, ex: &Expr<'_>, arms: &[Arm<'_>], expr: &Expr<'_>) {
if arms.len() == 2 && arms[0].guard.is_none() && arms[1].guard.is_none() {
- if in_macro(expr.span) {
+ if expr.span.from_expansion() {
// Don't lint match expressions present in
// macro_rules! block
return;
@@ -716,7 +723,7 @@ fn check_single_match(cx: &LateContext<'_>, ex: &Expr<'_>, arms: &[Arm<'_>], exp
return;
}
let els = arms[1].body;
- let els = if is_unit_expr(remove_blocks(els)) {
+ let els = if is_unit_expr(peel_blocks(els)) {
None
} else if let ExprKind::Block(Block { stmts, expr: block_expr, .. }, _) = els.kind {
if stmts.len() == 1 && block_expr.is_none() || stmts.is_empty() && block_expr.is_some() {
@@ -1306,7 +1313,7 @@ fn check_match_like_matches<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>)
return find_matches_sugg(
cx,
let_expr,
- array::IntoIter::new([(&[][..], Some(let_pat), if_then, None), (&[][..], None, if_else, None)]),
+ IntoIterator::into_iter([(&[][..], Some(let_pat), if_then, None), (&[][..], None, if_else, None)]),
expr,
true,
);
@@ -1451,7 +1458,7 @@ fn find_bool_lit(ex: &ExprKind<'_>, is_if_let: bool) -> Option<bool> {
#[allow(clippy::too_many_lines)]
fn check_match_single_binding<'a>(cx: &LateContext<'a>, ex: &Expr<'a>, arms: &[Arm<'_>], expr: &Expr<'_>) {
- if in_macro(expr.span) || arms.len() != 1 || is_refutable(cx, arms[0].pat) {
+ if expr.span.from_expansion() || arms.len() != 1 || is_refutable(cx, arms[0].pat) {
return;
}
@@ -1474,7 +1481,7 @@ fn check_match_single_binding<'a>(cx: &LateContext<'a>, ex: &Expr<'a>, arms: &[A
let matched_vars = ex.span;
let bind_names = arms[0].pat.span;
- let match_body = remove_blocks(arms[0].body);
+ let match_body = peel_blocks(arms[0].body);
let mut snippet_body = if match_body.span.from_expansion() {
Sugg::hir_with_macro_callsite(cx, match_body, "..").to_string()
} else {
@@ -1606,27 +1613,27 @@ fn opt_parent_let<'a>(cx: &LateContext<'a>, ex: &Expr<'a>) -> Option<&'a Local<'
None
}
-/// Gets all arms that are unbounded `PatRange`s.
+/// Gets the ranges for each range pattern arm. Applies `ty` bounds for open ranges.
fn all_ranges<'tcx>(cx: &LateContext<'tcx>, arms: &'tcx [Arm<'_>], ty: Ty<'tcx>) -> Vec<SpannedRange<FullInt>> {
arms.iter()
.filter_map(|arm| {
if let Arm { pat, guard: None, .. } = *arm {
if let PatKind::Range(ref lhs, ref rhs, range_end) = pat.kind {
- let lhs = match lhs {
+ let lhs_const = match lhs {
Some(lhs) => constant(cx, cx.typeck_results(), lhs)?.0,
None => miri_to_const(ty.numeric_min_val(cx.tcx)?)?,
};
- let rhs = match rhs {
+ let rhs_const = match rhs {
Some(rhs) => constant(cx, cx.typeck_results(), rhs)?.0,
None => miri_to_const(ty.numeric_max_val(cx.tcx)?)?,
};
- let lhs_val = lhs.int_value(cx, ty)?;
- let rhs_val = rhs.int_value(cx, ty)?;
+ let lhs_val = lhs_const.int_value(cx, ty)?;
+ let rhs_val = rhs_const.int_value(cx, ty)?;
let rhs_bound = match range_end {
- RangeEnd::Included => Bound::Included(rhs_val),
- RangeEnd::Excluded => Bound::Excluded(rhs_val),
+ RangeEnd::Included => EndBound::Included(rhs_val),
+ RangeEnd::Excluded => EndBound::Excluded(rhs_val),
};
return Some(SpannedRange {
span: pat.span,
@@ -1638,7 +1645,7 @@ fn all_ranges<'tcx>(cx: &LateContext<'tcx>, arms: &'tcx [Arm<'_>], ty: Ty<'tcx>)
let value = constant_full_int(cx, cx.typeck_results(), value)?;
return Some(SpannedRange {
span: pat.span,
- node: (value, Bound::Included(value)),
+ node: (value, EndBound::Included(value)),
});
}
}
@@ -1647,10 +1654,16 @@ fn all_ranges<'tcx>(cx: &LateContext<'tcx>, arms: &'tcx [Arm<'_>], ty: Ty<'tcx>)
.collect()
}
+#[derive(Clone, Copy, Debug, Eq, PartialEq)]
+pub enum EndBound<T> {
+ Included(T),
+ Excluded(T),
+}
+
#[derive(Debug, Eq, PartialEq)]
-pub struct SpannedRange<T> {
+struct SpannedRange<T> {
pub span: Span,
- pub node: (T, Bound<T>),
+ pub node: (T, EndBound<T>),
}
// Checks if arm has the form `None => None`
@@ -1665,7 +1678,7 @@ fn is_ref_some_arm(cx: &LateContext<'_>, arm: &Arm<'_>) -> Option<BindingAnnotat
if is_lang_ctor(cx, qpath, OptionSome);
if let PatKind::Binding(rb, .., ident, _) = first_pat.kind;
if rb == BindingAnnotation::Ref || rb == BindingAnnotation::RefMut;
- if let ExprKind::Call(e, args) = remove_blocks(arm.body).kind;
+ if let ExprKind::Call(e, args) = peel_blocks(arm.body).kind;
if let ExprKind::Path(ref some_path) = e.kind;
if is_lang_ctor(cx, some_path, OptionSome) && args.len() == 1;
if let ExprKind::Path(QPath::Resolved(_, path2)) = args[0].kind;
@@ -1699,82 +1712,63 @@ where
ref_count > 1
}
-pub fn overlapping<T>(ranges: &[SpannedRange<T>]) -> Option<(&SpannedRange<T>, &SpannedRange<T>)>
+fn overlapping<T>(ranges: &[SpannedRange<T>]) -> Option<(&SpannedRange<T>, &SpannedRange<T>)>
where
T: Copy + Ord,
{
- #[derive(Copy, Clone, Debug, Eq, PartialEq)]
- enum Kind<'a, T> {
- Start(T, &'a SpannedRange<T>),
- End(Bound<T>, &'a SpannedRange<T>),
+ #[derive(Copy, Clone, Debug, Eq, Ord, PartialEq, PartialOrd)]
+ enum BoundKind {
+ EndExcluded,
+ Start,
+ EndIncluded,
}
- impl<'a, T: Copy> Kind<'a, T> {
- fn range(&self) -> &'a SpannedRange<T> {
- match *self {
- Kind::Start(_, r) | Kind::End(_, r) => r,
- }
- }
-
- fn value(self) -> Bound<T> {
- match self {
- Kind::Start(t, _) => Bound::Included(t),
- Kind::End(t, _) => t,
- }
- }
- }
+ #[derive(Copy, Clone, Debug, Eq, PartialEq)]
+ struct RangeBound<'a, T>(T, BoundKind, &'a SpannedRange<T>);
- impl<'a, T: Copy + Ord> PartialOrd for Kind<'a, T> {
+ impl<'a, T: Copy + Ord> PartialOrd for RangeBound<'a, T> {
fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
Some(self.cmp(other))
}
}
- impl<'a, T: Copy + Ord> Ord for Kind<'a, T> {
- fn cmp(&self, other: &Self) -> Ordering {
- match (self.value(), other.value()) {
- (Bound::Included(a), Bound::Included(b)) | (Bound::Excluded(a), Bound::Excluded(b)) => a.cmp(&b),
- // Range patterns cannot be unbounded (yet)
- (Bound::Unbounded, _) | (_, Bound::Unbounded) => unimplemented!(),
- (Bound::Included(a), Bound::Excluded(b)) => match a.cmp(&b) {
- Ordering::Equal => Ordering::Greater,
- other => other,
- },
- (Bound::Excluded(a), Bound::Included(b)) => match a.cmp(&b) {
- Ordering::Equal => Ordering::Less,
- other => other,
- },
- }
+ impl<'a, T: Copy + Ord> Ord for RangeBound<'a, T> {
+ fn cmp(&self, RangeBound(other_value, other_kind, _): &Self) -> Ordering {
+ let RangeBound(self_value, self_kind, _) = *self;
+ (self_value, self_kind).cmp(&(*other_value, *other_kind))
}
}
let mut values = Vec::with_capacity(2 * ranges.len());
- for r in ranges {
- values.push(Kind::Start(r.node.0, r));
- values.push(Kind::End(r.node.1, r));
+ for r @ SpannedRange { node: (start, end), .. } in ranges {
+ values.push(RangeBound(*start, BoundKind::Start, r));
+ values.push(match end {
+ EndBound::Excluded(val) => RangeBound(*val, BoundKind::EndExcluded, r),
+ EndBound::Included(val) => RangeBound(*val, BoundKind::EndIncluded, r),
+ });
}
values.sort();
- for (a, b) in iter::zip(&values, values.iter().skip(1)) {
- match (a, b) {
- (&Kind::Start(_, ra), &Kind::End(_, rb)) => {
- if ra.node != rb.node {
- return Some((ra, rb));
- }
- },
- (&Kind::End(a, _), &Kind::Start(b, _)) if a != Bound::Included(b) => (),
- _ => {
- // skip if the range `a` is completely included into the range `b`
- if let Ordering::Equal | Ordering::Less = a.cmp(b) {
- let kind_a = Kind::End(a.range().node.1, a.range());
- let kind_b = Kind::End(b.range().node.1, b.range());
- if let Ordering::Equal | Ordering::Greater = kind_a.cmp(&kind_b) {
- return None;
+ let mut started = vec![];
+
+ for RangeBound(_, kind, range) in values {
+ match kind {
+ BoundKind::Start => started.push(range),
+ BoundKind::EndExcluded | BoundKind::EndIncluded => {
+ let mut overlap = None;
+
+ while let Some(last_started) = started.pop() {
+ if last_started == range {
+ break;
}
+ overlap = Some(last_started);
+ }
+
+ if let Some(first_overlapping) = overlap {
+ return Some((range, first_overlapping));
}
- return Some((a.range(), b.range()));
},
}
}
@@ -1786,7 +1780,8 @@ mod redundant_pattern_match {
use super::REDUNDANT_PATTERN_MATCHING;
use clippy_utils::diagnostics::span_lint_and_then;
use clippy_utils::higher;
- use clippy_utils::source::{snippet, snippet_with_applicability};
+ use clippy_utils::source::snippet;
+ use clippy_utils::sugg::Sugg;
use clippy_utils::ty::{implements_trait, is_type_diagnostic_item, is_type_lang_item, match_type};
use clippy_utils::{is_lang_ctor, is_qpath_def_path, is_trait_method, paths};
use if_chain::if_chain;
@@ -1796,7 +1791,7 @@ mod redundant_pattern_match {
use rustc_hir::LangItem::{OptionNone, OptionSome, PollPending, PollReady, ResultErr, ResultOk};
use rustc_hir::{
intravisit::{walk_expr, ErasedMap, NestedVisitorMap, Visitor},
- Arm, Block, Expr, ExprKind, LangItem, MatchSource, Node, Pat, PatKind, QPath,
+ Arm, Block, Expr, ExprKind, LangItem, MatchSource, Node, Pat, PatKind, QPath, UnOp,
};
use rustc_lint::LateContext;
use rustc_middle::ty::{self, subst::GenericArgKind, Ty};
@@ -2050,8 +2045,10 @@ mod redundant_pattern_match {
let result_expr = match &let_expr.kind {
ExprKind::AddrOf(_, _, borrowed) => borrowed,
+ ExprKind::Unary(UnOp::Deref, deref) => deref,
_ => let_expr,
};
+
span_lint_and_then(
cx,
REDUNDANT_PATTERN_MATCHING,
@@ -2070,12 +2067,15 @@ mod redundant_pattern_match {
// ^^^^^^^^^^^^^^^^^^^
let span = expr_span.until(op_span.shrink_to_hi());
- let mut app = if needs_drop {
+ let app = if needs_drop {
Applicability::MaybeIncorrect
} else {
Applicability::MachineApplicable
};
- let sugg = snippet_with_applicability(cx, op_span, "_", &mut app);
+
+ let sugg = Sugg::hir_with_macro_callsite(cx, result_expr, "_")
+ .maybe_par()
+ .to_string();
diag.span_suggestion(span, "try this", format!("{} {}.{}", keyword, sugg, good_method), app);
@@ -2225,29 +2225,29 @@ fn test_overlapping() {
};
assert_eq!(None, overlapping::<u8>(&[]));
- assert_eq!(None, overlapping(&[sp(1, Bound::Included(4))]));
+ assert_eq!(None, overlapping(&[sp(1, EndBound::Included(4))]));
assert_eq!(
None,
- overlapping(&[sp(1, Bound::Included(4)), sp(5, Bound::Included(6))])
+ overlapping(&[sp(1, EndBound::Included(4)), sp(5, EndBound::Included(6))])
);
assert_eq!(
None,
overlapping(&[
- sp(1, Bound::Included(4)),
- sp(5, Bound::Included(6)),
- sp(10, Bound::Included(11))
+ sp(1, EndBound::Included(4)),
+ sp(5, EndBound::Included(6)),
+ sp(10, EndBound::Included(11))
],)
);
assert_eq!(
- Some((&sp(1, Bound::Included(4)), &sp(3, Bound::Included(6)))),
- overlapping(&[sp(1, Bound::Included(4)), sp(3, Bound::Included(6))])
+ Some((&sp(1, EndBound::Included(4)), &sp(3, EndBound::Included(6)))),
+ overlapping(&[sp(1, EndBound::Included(4)), sp(3, EndBound::Included(6))])
);
assert_eq!(
- Some((&sp(5, Bound::Included(6)), &sp(6, Bound::Included(11)))),
+ Some((&sp(5, EndBound::Included(6)), &sp(6, EndBound::Included(11)))),
overlapping(&[
- sp(1, Bound::Included(4)),
- sp(5, Bound::Included(6)),
- sp(6, Bound::Included(11))
+ sp(1, EndBound::Included(4)),
+ sp(5, EndBound::Included(6)),
+ sp(6, EndBound::Included(11))
],)
);
}
diff --git a/src/tools/clippy/clippy_lints/src/mem_forget.rs b/src/tools/clippy/clippy_lints/src/mem_forget.rs
index eb437dc47af..5ffcfd4d264 100644
--- a/src/tools/clippy/clippy_lints/src/mem_forget.rs
+++ b/src/tools/clippy/clippy_lints/src/mem_forget.rs
@@ -19,6 +19,7 @@ declare_clippy_lint! {
/// # use std::rc::Rc;
/// mem::forget(Rc::new(55))
/// ```
+ #[clippy::version = "pre 1.29.0"]
pub MEM_FORGET,
restriction,
"`mem::forget` usage on `Drop` types, likely to cause memory leaks"
diff --git a/src/tools/clippy/clippy_lints/src/mem_replace.rs b/src/tools/clippy/clippy_lints/src/mem_replace.rs
index 1e6057a8fe9..7fc39f17232 100644
--- a/src/tools/clippy/clippy_lints/src/mem_replace.rs
+++ b/src/tools/clippy/clippy_lints/src/mem_replace.rs
@@ -1,7 +1,7 @@
use clippy_utils::diagnostics::{span_lint_and_help, span_lint_and_sugg, span_lint_and_then};
use clippy_utils::source::{snippet, snippet_with_applicability};
use clippy_utils::ty::is_non_aggregate_primitive_type;
-use clippy_utils::{in_macro, is_default_equivalent, is_lang_ctor, match_def_path, meets_msrv, msrvs, paths};
+use clippy_utils::{is_default_equivalent, is_lang_ctor, match_def_path, meets_msrv, msrvs, paths};
use if_chain::if_chain;
use rustc_errors::Applicability;
use rustc_hir::LangItem::OptionNone;
@@ -35,6 +35,7 @@ declare_clippy_lint! {
/// let mut an_option = Some(0);
/// let taken = an_option.take();
/// ```
+ #[clippy::version = "1.31.0"]
pub MEM_REPLACE_OPTION_WITH_NONE,
style,
"replacing an `Option` with `None` instead of `take()`"
@@ -66,6 +67,7 @@ declare_clippy_lint! {
/// The [take_mut](https://docs.rs/take_mut) crate offers a sound solution,
/// at the cost of either lazily creating a replacement value or aborting
/// on panic, to ensure that the uninitialized value cannot be observed.
+ #[clippy::version = "1.39.0"]
pub MEM_REPLACE_WITH_UNINIT,
correctness,
"`mem::replace(&mut _, mem::uninitialized())` or `mem::replace(&mut _, mem::zeroed())`"
@@ -90,6 +92,7 @@ declare_clippy_lint! {
/// let mut text = String::from("foo");
/// let taken = std::mem::take(&mut text);
/// ```
+ #[clippy::version = "1.42.0"]
pub MEM_REPLACE_WITH_DEFAULT,
style,
"replacing a value of type `T` with `T::default()` instead of using `std::mem::take`"
@@ -213,7 +216,7 @@ fn check_replace_with_default(cx: &LateContext<'_>, src: &Expr<'_>, dest: &Expr<
expr_span,
"replacing a value of type `T` with `T::default()` is better expressed using `std::mem::take`",
|diag| {
- if !in_macro(expr_span) {
+ if !expr_span.from_expansion() {
let suggestion = format!("std::mem::take({})", snippet(cx, dest.span, ""));
diag.span_suggestion(
diff --git a/src/tools/clippy/clippy_lints/src/methods/bind_instead_of_map.rs b/src/tools/clippy/clippy_lints/src/methods/bind_instead_of_map.rs
index da428a7b487..150bafc0f5d 100644
--- a/src/tools/clippy/clippy_lints/src/methods/bind_instead_of_map.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/bind_instead_of_map.rs
@@ -1,7 +1,7 @@
use super::{contains_return, BIND_INSTEAD_OF_MAP};
use clippy_utils::diagnostics::{multispan_sugg_with_applicability, span_lint_and_sugg, span_lint_and_then};
use clippy_utils::source::{snippet, snippet_with_macro_callsite};
-use clippy_utils::{in_macro, remove_blocks, visitors::find_all_ret_expressions};
+use clippy_utils::{peel_blocks, visitors::find_all_ret_expressions};
use if_chain::if_chain;
use rustc_errors::Applicability;
use rustc_hir as hir;
@@ -106,7 +106,7 @@ pub(crate) trait BindInsteadOfMap {
let mut suggs = Vec::new();
let can_sugg: bool = find_all_ret_expressions(cx, closure_expr, |ret_expr| {
if_chain! {
- if !in_macro(ret_expr.span);
+ if !ret_expr.span.from_expansion();
if let hir::ExprKind::Call(func_path, [arg]) = ret_expr.kind;
if let hir::ExprKind::Path(QPath::Resolved(_, path)) = func_path.kind;
if Self::is_variant(cx, path.res);
@@ -152,7 +152,7 @@ pub(crate) trait BindInsteadOfMap {
match arg.kind {
hir::ExprKind::Closure(_, _, body_id, closure_args_span, _) => {
let closure_body = cx.tcx.hir().body(body_id);
- let closure_expr = remove_blocks(&closure_body.value);
+ let closure_expr = peel_blocks(&closure_body.value);
if Self::lint_closure_autofixable(cx, expr, recv, closure_expr, closure_args_span) {
true
diff --git a/src/tools/clippy/clippy_lints/src/methods/filter_map.rs b/src/tools/clippy/clippy_lints/src/methods/filter_map.rs
index c96c817bb8b..6d8733c08b4 100644
--- a/src/tools/clippy/clippy_lints/src/methods/filter_map.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/filter_map.rs
@@ -1,7 +1,7 @@
use clippy_utils::diagnostics::span_lint_and_sugg;
use clippy_utils::source::{indent_of, reindent_multiline, snippet};
use clippy_utils::ty::is_type_diagnostic_item;
-use clippy_utils::{is_trait_method, path_to_local_id, remove_blocks, SpanlessEq};
+use clippy_utils::{is_trait_method, path_to_local_id, peel_blocks, SpanlessEq};
use if_chain::if_chain;
use rustc_errors::Applicability;
use rustc_hir as hir;
@@ -25,7 +25,7 @@ fn is_method<'tcx>(cx: &LateContext<'tcx>, expr: &hir::Expr<'_>, method_name: Sy
},
hir::ExprKind::Closure(_, _, c, _, _) => {
let body = cx.tcx.hir().body(*c);
- let closure_expr = remove_blocks(&body.value);
+ let closure_expr = peel_blocks(&body.value);
let arg_id = body.params[0].pat.hir_id;
match closure_expr.kind {
hir::ExprKind::MethodCall(hir::PathSegment { ident, .. }, _, args, _) => {
diff --git a/src/tools/clippy/clippy_lints/src/methods/from_iter_instead_of_collect.rs b/src/tools/clippy/clippy_lints/src/methods/from_iter_instead_of_collect.rs
index 99c03844f49..8ea9312c0f7 100644
--- a/src/tools/clippy/clippy_lints/src/methods/from_iter_instead_of_collect.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/from_iter_instead_of_collect.rs
@@ -69,7 +69,7 @@ fn extract_turbofish(cx: &LateContext<'_>, expr: &hir::Expr<'_>, ty: Ty<'tcx>) -
// i.e.: 2 wildcards in `std::collections::BTreeMap<&i32, &char>`
let ty_str = ty.to_string();
let start = ty_str.find('<').unwrap_or(0);
- let end = ty_str.find('>').unwrap_or_else(|| ty_str.len());
+ let end = ty_str.find('>').unwrap_or(ty_str.len());
let nb_wildcard = ty_str[start..end].split(',').count();
let wildcards = format!("_{}", ", _".repeat(nb_wildcard - 1));
format!("{}<{}>", elements.join("::"), wildcards)
diff --git a/src/tools/clippy/clippy_lints/src/methods/implicit_clone.rs b/src/tools/clippy/clippy_lints/src/methods/implicit_clone.rs
index 81c42de145f..90492ffda3c 100644
--- a/src/tools/clippy/clippy_lints/src/methods/implicit_clone.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/implicit_clone.rs
@@ -12,15 +12,7 @@ use super::IMPLICIT_CLONE;
pub fn check(cx: &LateContext<'_>, method_name: &str, expr: &hir::Expr<'_>, recv: &hir::Expr<'_>, span: Span) {
if_chain! {
if let Some(method_def_id) = cx.typeck_results().type_dependent_def_id(expr.hir_id);
- if match method_name {
- "to_os_string" => is_diag_item_method(cx, method_def_id, sym::OsStr),
- "to_owned" => is_diag_trait_item(cx, method_def_id, sym::ToOwned),
- "to_path_buf" => is_diag_item_method(cx, method_def_id, sym::Path),
- "to_vec" => cx.tcx.impl_of_method(method_def_id)
- .map(|impl_did| Some(impl_did) == cx.tcx.lang_items().slice_alloc_impl())
- == Some(true),
- _ => false,
- };
+ if is_clone_like(cx, method_name, method_def_id);
let return_type = cx.typeck_results().expr_ty(expr);
let input_type = cx.typeck_results().expr_ty(recv).peel_refs();
if let Some(ty_name) = input_type.ty_adt_def().map(|adt_def| cx.tcx.item_name(adt_def.did));
@@ -38,3 +30,22 @@ pub fn check(cx: &LateContext<'_>, method_name: &str, expr: &hir::Expr<'_>, recv
}
}
}
+
+/// Returns true if the named method can be used to clone the receiver.
+/// Note that `to_string` is not flagged by `implicit_clone`. So other lints that call
+/// `is_clone_like` and that do flag `to_string` must handle it separately. See, e.g.,
+/// `is_to_owned_like` in `unnecessary_to_owned.rs`.
+pub fn is_clone_like(cx: &LateContext<'_>, method_name: &str, method_def_id: hir::def_id::DefId) -> bool {
+ match method_name {
+ "to_os_string" => is_diag_item_method(cx, method_def_id, sym::OsStr),
+ "to_owned" => is_diag_trait_item(cx, method_def_id, sym::ToOwned),
+ "to_path_buf" => is_diag_item_method(cx, method_def_id, sym::Path),
+ "to_vec" => {
+ cx.tcx
+ .impl_of_method(method_def_id)
+ .map(|impl_did| Some(impl_did) == cx.tcx.lang_items().slice_alloc_impl())
+ == Some(true)
+ },
+ _ => false,
+ }
+}
diff --git a/src/tools/clippy/clippy_lints/src/methods/iter_cloned_collect.rs b/src/tools/clippy/clippy_lints/src/methods/iter_cloned_collect.rs
index dd4ef6e4b58..30d56113c6c 100644
--- a/src/tools/clippy/clippy_lints/src/methods/iter_cloned_collect.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/iter_cloned_collect.rs
@@ -9,7 +9,7 @@ use rustc_span::sym;
use super::ITER_CLONED_COLLECT;
-pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, expr: &hir::Expr<'_>, recv: &'tcx hir::Expr<'_>) {
+pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, method_name: &str, expr: &hir::Expr<'_>, recv: &'tcx hir::Expr<'_>) {
if_chain! {
if is_type_diagnostic_item(cx, cx.typeck_results().expr_ty(expr), sym::Vec);
if let Some(slice) = derefs_to_slice(cx, recv, cx.typeck_results().expr_ty(recv));
@@ -20,8 +20,8 @@ pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, expr: &hir::Expr<'_>, recv: &'
cx,
ITER_CLONED_COLLECT,
to_replace,
- "called `iter().cloned().collect()` on a slice to create a `Vec`. Calling `to_vec()` is both faster and \
- more readable",
+ &format!("called `iter().{}().collect()` on a slice to create a `Vec`. Calling `to_vec()` is both faster and \
+ more readable", method_name),
"try",
".to_vec()".to_string(),
Applicability::MachineApplicable,
diff --git a/src/tools/clippy/clippy_lints/src/methods/mod.rs b/src/tools/clippy/clippy_lints/src/methods/mod.rs
index 26c29fbb289..3c43671dd34 100644
--- a/src/tools/clippy/clippy_lints/src/methods/mod.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/mod.rs
@@ -33,7 +33,6 @@ mod iter_nth_zero;
mod iter_skip_next;
mod iterator_step_by_zero;
mod manual_saturating_arithmetic;
-mod manual_split_once;
mod manual_str_repeat;
mod map_collect_result_unit;
mod map_flatten;
@@ -50,13 +49,16 @@ mod single_char_insert_string;
mod single_char_pattern;
mod single_char_push_string;
mod skip_while_next;
+mod str_splitn;
mod string_extend_chars;
mod suspicious_map;
mod suspicious_splitn;
mod uninit_assumed_init;
mod unnecessary_filter_map;
mod unnecessary_fold;
+mod unnecessary_iter_cloned;
mod unnecessary_lazy_eval;
+mod unnecessary_to_owned;
mod unwrap_or_else_default;
mod unwrap_used;
mod useless_asref;
@@ -68,7 +70,7 @@ use bind_instead_of_map::BindInsteadOfMap;
use clippy_utils::consts::{constant, Constant};
use clippy_utils::diagnostics::{span_lint, span_lint_and_help};
use clippy_utils::ty::{contains_adt_constructor, contains_ty, implements_trait, is_copy, is_type_diagnostic_item};
-use clippy_utils::{contains_return, get_trait_def_id, in_macro, iter_input_pats, meets_msrv, msrvs, paths, return_ty};
+use clippy_utils::{contains_return, get_trait_def_id, iter_input_pats, meets_msrv, msrvs, paths, return_ty};
use if_chain::if_chain;
use rustc_hir as hir;
use rustc_hir::def::Res;
@@ -99,6 +101,7 @@ declare_clippy_lint! {
/// ```rust
/// [1, 2, 3].iter().copied();
/// ```
+ #[clippy::version = "1.53.0"]
pub CLONED_INSTEAD_OF_COPIED,
pedantic,
"used `cloned` where `copied` could be used instead"
@@ -121,6 +124,7 @@ declare_clippy_lint! {
/// ```rust
/// let nums: Vec<i32> = ["1", "2", "whee!"].iter().filter_map(|x| x.parse().ok()).collect();
/// ```
+ #[clippy::version = "1.53.0"]
pub FLAT_MAP_OPTION,
pedantic,
"used `flat_map` where `filter_map` could be used instead"
@@ -166,6 +170,7 @@ declare_clippy_lint! {
/// // Good
/// res.expect("more helpful message");
/// ```
+ #[clippy::version = "1.45.0"]
pub UNWRAP_USED,
restriction,
"using `.unwrap()` on `Result` or `Option`, which should at least get a better message using `expect()`"
@@ -208,6 +213,7 @@ declare_clippy_lint! {
/// res?;
/// # Ok::<(), ()>(())
/// ```
+ #[clippy::version = "1.45.0"]
pub EXPECT_USED,
restriction,
"using `.expect()` on `Result` or `Option`, which might be better handled"
@@ -237,6 +243,7 @@ declare_clippy_lint! {
/// }
/// }
/// ```
+ #[clippy::version = "pre 1.29.0"]
pub SHOULD_IMPLEMENT_TRAIT,
style,
"defining a method that should be implementing a std trait"
@@ -284,6 +291,7 @@ declare_clippy_lint! {
/// }
/// }
/// ```
+ #[clippy::version = "pre 1.29.0"]
pub WRONG_SELF_CONVENTION,
style,
"defining a method named with an established prefix (like \"into_\") that takes `self` with the wrong convention"
@@ -310,6 +318,7 @@ declare_clippy_lint! {
/// // Good
/// x.expect("why did I do this again?");
/// ```
+ #[clippy::version = "pre 1.29.0"]
pub OK_EXPECT,
style,
"using `ok().expect()`, which gives worse error messages than calling `expect` directly on the Result"
@@ -335,6 +344,7 @@ declare_clippy_lint! {
/// // Good
/// x.unwrap_or_default();
/// ```
+ #[clippy::version = "1.56.0"]
pub UNWRAP_OR_ELSE_DEFAULT,
style,
"using `.unwrap_or_else(Default::default)`, which is more succinctly expressed as `.unwrap_or_default()`"
@@ -375,6 +385,7 @@ declare_clippy_lint! {
/// // Good
/// x.map_or_else(some_function, |a| a + 1);
/// ```
+ #[clippy::version = "1.45.0"]
pub MAP_UNWRAP_OR,
pedantic,
"using `.map(f).unwrap_or(a)` or `.map(f).unwrap_or_else(func)`, which are more succinctly expressed as `map_or(a, f)` or `map_or_else(a, f)`"
@@ -401,6 +412,7 @@ declare_clippy_lint! {
/// // Good
/// opt.and_then(|a| Some(a + 1));
/// ```
+ #[clippy::version = "pre 1.29.0"]
pub OPTION_MAP_OR_NONE,
style,
"using `Option.map_or(None, f)`, which is more succinctly expressed as `and_then(f)`"
@@ -426,6 +438,7 @@ declare_clippy_lint! {
/// # let r: Result<u32, &str> = Ok(1);
/// assert_eq!(Some(1), r.ok());
/// ```
+ #[clippy::version = "1.44.0"]
pub RESULT_MAP_OR_INTO_OPTION,
style,
"using `Result.map_or(None, Some)`, which is more succinctly expressed as `ok()`"
@@ -458,6 +471,7 @@ declare_clippy_lint! {
/// let _ = res().map(|s| if s.len() == 42 { 10 } else { 20 });
/// let _ = res().map_err(|s| if s.len() == 42 { 10 } else { 20 });
/// ```
+ #[clippy::version = "1.45.0"]
pub BIND_INSTEAD_OF_MAP,
complexity,
"using `Option.and_then(|x| Some(y))`, which is more succinctly expressed as `map(|x| y)`"
@@ -481,6 +495,7 @@ declare_clippy_lint! {
/// # let vec = vec![1];
/// vec.iter().find(|x| **x == 0);
/// ```
+ #[clippy::version = "pre 1.29.0"]
pub FILTER_NEXT,
complexity,
"using `filter(p).next()`, which is more succinctly expressed as `.find(p)`"
@@ -504,6 +519,7 @@ declare_clippy_lint! {
/// # let vec = vec![1];
/// vec.iter().find(|x| **x != 0);
/// ```
+ #[clippy::version = "1.42.0"]
pub SKIP_WHILE_NEXT,
complexity,
"using `skip_while(p).next()`, which is more succinctly expressed as `.find(!p)`"
@@ -527,8 +543,9 @@ declare_clippy_lint! {
/// // Good
/// vec.iter().flat_map(|x| x.iter());
/// ```
+ #[clippy::version = "1.31.0"]
pub MAP_FLATTEN,
- pedantic,
+ complexity,
"using combinations of `flatten` and `map` which can usually be written as a single method call"
}
@@ -553,6 +570,7 @@ declare_clippy_lint! {
/// ```rust
/// (0_i32..10).filter_map(|n| n.checked_add(1));
/// ```
+ #[clippy::version = "1.51.0"]
pub MANUAL_FILTER_MAP,
complexity,
"using `_.filter(_).map(_)` in a way that can be written more simply as `filter_map(_)`"
@@ -579,6 +597,7 @@ declare_clippy_lint! {
/// ```rust
/// (0_i32..10).find_map(|n| n.checked_add(1));
/// ```
+ #[clippy::version = "1.51.0"]
pub MANUAL_FIND_MAP,
complexity,
"using `_.find(_).map(_)` in a way that can be written more simply as `find_map(_)`"
@@ -601,6 +620,7 @@ declare_clippy_lint! {
/// ```rust
/// (0..3).find_map(|x| if x == 2 { Some(x) } else { None });
/// ```
+ #[clippy::version = "1.36.0"]
pub FILTER_MAP_NEXT,
pedantic,
"using combination of `filter_map` and `next` which can usually be written as a single method call"
@@ -623,6 +643,7 @@ declare_clippy_lint! {
/// # let iter = vec![vec![0]].into_iter();
/// iter.flatten();
/// ```
+ #[clippy::version = "1.39.0"]
pub FLAT_MAP_IDENTITY,
complexity,
"call to `flat_map` where `flatten` is sufficient"
@@ -652,6 +673,7 @@ declare_clippy_lint! {
///
/// let _ = !"hello world".contains("world");
/// ```
+ #[clippy::version = "pre 1.29.0"]
pub SEARCH_IS_SOME,
complexity,
"using an iterator or string search followed by `is_some()` or `is_none()`, which is more succinctly expressed as a call to `any()` or `contains()` (with negation in case of `is_none()`)"
@@ -676,6 +698,7 @@ declare_clippy_lint! {
/// let name = "foo";
/// if name.starts_with('_') {};
/// ```
+ #[clippy::version = "pre 1.29.0"]
pub CHARS_NEXT_CMP,
style,
"using `.chars().next()` to check if a string starts with a char"
@@ -710,6 +733,7 @@ declare_clippy_lint! {
/// # let foo = Some(String::new());
/// foo.unwrap_or_default();
/// ```
+ #[clippy::version = "pre 1.29.0"]
pub OR_FUN_CALL,
perf,
"using any `*or` method with a function call, which suggests `*or_else`"
@@ -748,6 +772,7 @@ declare_clippy_lint! {
/// # let err_msg = "I'm a teapot";
/// foo.unwrap_or_else(|| panic!("Err {}: {}", err_code, err_msg));
/// ```
+ #[clippy::version = "pre 1.29.0"]
pub EXPECT_FUN_CALL,
perf,
"using any `expect` method with a function call"
@@ -765,6 +790,7 @@ declare_clippy_lint! {
/// ```rust
/// 42u64.clone();
/// ```
+ #[clippy::version = "pre 1.29.0"]
pub CLONE_ON_COPY,
complexity,
"using `clone` on a `Copy` type"
@@ -792,6 +818,7 @@ declare_clippy_lint! {
/// // Good
/// Rc::clone(&x);
/// ```
+ #[clippy::version = "pre 1.29.0"]
pub CLONE_ON_REF_PTR,
restriction,
"using 'clone' on a ref-counted pointer"
@@ -814,6 +841,7 @@ declare_clippy_lint! {
/// println!("{:p} {:p}", *y, z); // prints out the same pointer
/// }
/// ```
+ #[clippy::version = "pre 1.29.0"]
pub CLONE_DOUBLE_REF,
correctness,
"using `clone` on `&&T`"
@@ -837,6 +865,7 @@ declare_clippy_lint! {
/// // OK, the specialized impl is used
/// ["foo", "bar"].iter().map(|&s| s.to_string());
/// ```
+ #[clippy::version = "1.40.0"]
pub INEFFICIENT_TO_STRING,
pedantic,
"using `to_string` on `&&T` where `T: ToString`"
@@ -898,6 +927,7 @@ declare_clippy_lint! {
/// fn new() -> Self;
/// }
/// ```
+ #[clippy::version = "pre 1.29.0"]
pub NEW_RET_NO_SELF,
style,
"not returning type containing `Self` in a `new` method"
@@ -922,6 +952,7 @@ declare_clippy_lint! {
///
/// // Good
/// _.split('x');
+ #[clippy::version = "pre 1.29.0"]
pub SINGLE_CHAR_PATTERN,
perf,
"using a single-character str where a char could be used, e.g., `_.split(\"x\")`"
@@ -941,6 +972,7 @@ declare_clippy_lint! {
/// //..
/// }
/// ```
+ #[clippy::version = "pre 1.29.0"]
pub ITERATOR_STEP_BY_ZERO,
correctness,
"using `Iterator::step_by(0)`, which will panic at runtime"
@@ -962,6 +994,7 @@ declare_clippy_lint! {
/// ```rust
/// let _ = std::iter::empty::<Option<i32>>().flatten();
/// ```
+ #[clippy::version = "1.53.0"]
pub OPTION_FILTER_MAP,
complexity,
"filtering `Option` for `Some` then force-unwrapping, which can be one type-safe operation"
@@ -989,6 +1022,7 @@ declare_clippy_lint! {
/// # s.insert(1);
/// let x = s.iter().next();
/// ```
+ #[clippy::version = "1.42.0"]
pub ITER_NTH_ZERO,
style,
"replace `iter.nth(0)` with `iter.next()`"
@@ -1015,6 +1049,7 @@ declare_clippy_lint! {
/// let bad_vec = some_vec.get(3);
/// let bad_slice = &some_vec[..].get(3);
/// ```
+ #[clippy::version = "pre 1.29.0"]
pub ITER_NTH,
perf,
"using `.iter().nth()` on a standard library type with O(1) element access"
@@ -1039,6 +1074,7 @@ declare_clippy_lint! {
/// let bad_vec = some_vec.iter().nth(3);
/// let bad_slice = &some_vec[..].iter().nth(3);
/// ```
+ #[clippy::version = "pre 1.29.0"]
pub ITER_SKIP_NEXT,
style,
"using `.skip(x).next()` on an iterator"
@@ -1075,6 +1111,7 @@ declare_clippy_lint! {
/// let last = some_vec[3];
/// some_vec[0] = 1;
/// ```
+ #[clippy::version = "pre 1.29.0"]
pub GET_UNWRAP,
restriction,
"using `.get().unwrap()` or `.get_mut().unwrap()` when using `[]` would work instead"
@@ -1098,6 +1135,7 @@ declare_clippy_lint! {
/// // Good
/// a.append(&mut b);
/// ```
+ #[clippy::version = "1.55.0"]
pub EXTEND_WITH_DRAIN,
perf,
"using vec.append(&mut vec) to move the full range of a vecor to another"
@@ -1127,6 +1165,7 @@ declare_clippy_lint! {
/// s.push_str(abc);
/// s.push_str(&def);
/// ```
+ #[clippy::version = "pre 1.29.0"]
pub STRING_EXTEND_CHARS,
style,
"using `x.extend(s.chars())` where s is a `&str` or `String`"
@@ -1150,6 +1189,7 @@ declare_clippy_lint! {
/// let s = [1, 2, 3, 4, 5];
/// let s2: Vec<isize> = s.to_vec();
/// ```
+ #[clippy::version = "pre 1.29.0"]
pub ITER_CLONED_COLLECT,
style,
"using `.cloned().collect()` on slice to create a `Vec`"
@@ -1174,6 +1214,7 @@ declare_clippy_lint! {
/// // Good
/// name.ends_with('_') || name.ends_with('-');
/// ```
+ #[clippy::version = "pre 1.29.0"]
pub CHARS_LAST_CMP,
style,
"using `.chars().last()` or `.chars().next_back()` to check if a string ends with a char"
@@ -1199,6 +1240,7 @@ declare_clippy_lint! {
/// let x: &[i32] = &[1, 2, 3, 4, 5];
/// do_stuff(x);
/// ```
+ #[clippy::version = "pre 1.29.0"]
pub USELESS_ASREF,
complexity,
"using `as_ref` where the types before and after the call are the same"
@@ -1221,6 +1263,7 @@ declare_clippy_lint! {
/// ```rust
/// let _ = (0..3).any(|x| x > 2);
/// ```
+ #[clippy::version = "pre 1.29.0"]
pub UNNECESSARY_FOLD,
style,
"using `fold` when a more succinct alternative exists"
@@ -1250,6 +1293,7 @@ declare_clippy_lint! {
/// // As there is no conditional check on the argument this could be written as:
/// let _ = (0..4).map(|x| x + 1);
/// ```
+ #[clippy::version = "1.31.0"]
pub UNNECESSARY_FILTER_MAP,
complexity,
"using `filter_map` when a more succinct alternative exists"
@@ -1273,6 +1317,7 @@ declare_clippy_lint! {
/// // Good
/// let _ = (&vec![3, 4, 5]).iter();
/// ```
+ #[clippy::version = "1.32.0"]
pub INTO_ITER_ON_REF,
style,
"using `.into_iter()` on a reference"
@@ -1292,6 +1337,7 @@ declare_clippy_lint! {
/// ```rust
/// let _ = (0..3).map(|x| x + 2).count();
/// ```
+ #[clippy::version = "1.39.0"]
pub SUSPICIOUS_MAP,
suspicious,
"suspicious usage of map"
@@ -1326,6 +1372,7 @@ declare_clippy_lint! {
/// MaybeUninit::uninit().assume_init()
/// };
/// ```
+ #[clippy::version = "1.39.0"]
pub UNINIT_ASSUMED_INIT,
correctness,
"`MaybeUninit::uninit().assume_init()`"
@@ -1354,6 +1401,7 @@ declare_clippy_lint! {
/// let add = x.saturating_add(y);
/// let sub = x.saturating_sub(y);
/// ```
+ #[clippy::version = "1.39.0"]
pub MANUAL_SATURATING_ARITHMETIC,
style,
"`.chcked_add/sub(x).unwrap_or(MAX/MIN)`"
@@ -1371,6 +1419,7 @@ declare_clippy_lint! {
/// ```rust
/// unsafe { (&() as *const ()).offset(1) };
/// ```
+ #[clippy::version = "1.41.0"]
pub ZST_OFFSET,
correctness,
"Check for offset calculations on raw pointers to zero-sized types"
@@ -1412,6 +1461,7 @@ declare_clippy_lint! {
/// # Ok::<_, std::io::Error>(())
/// # };
/// ```
+ #[clippy::version = "1.42.0"]
pub FILETYPE_IS_FILE,
restriction,
"`FileType::is_file` is not recommended to test for readable file type"
@@ -1437,6 +1487,7 @@ declare_clippy_lint! {
/// opt.as_deref()
/// # ;
/// ```
+ #[clippy::version = "1.42.0"]
pub OPTION_AS_REF_DEREF,
complexity,
"using `as_ref().map(Deref::deref)`, which is more succinctly expressed as `as_deref()`"
@@ -1463,6 +1514,7 @@ declare_clippy_lint! {
/// a.get(2);
/// b.get(0);
/// ```
+ #[clippy::version = "1.46.0"]
pub ITER_NEXT_SLICE,
style,
"using `.iter().next()` on a sliced array, which can be shortened to just `.get()`"
@@ -1488,6 +1540,7 @@ declare_clippy_lint! {
/// string.insert(0, 'R');
/// string.push('R');
/// ```
+ #[clippy::version = "1.49.0"]
pub SINGLE_CHAR_ADD_STR,
style,
"`push_str()` or `insert_str()` used with a single-character string literal as parameter"
@@ -1526,6 +1579,7 @@ declare_clippy_lint! {
///
/// opt.unwrap_or(42);
/// ```
+ #[clippy::version = "1.48.0"]
pub UNNECESSARY_LAZY_EVALUATIONS,
style,
"using unnecessary lazy evaluation, which can be replaced with simpler eager evaluation"
@@ -1546,6 +1600,7 @@ declare_clippy_lint! {
/// ```rust
/// (0..3).try_for_each(|t| Err(t));
/// ```
+ #[clippy::version = "1.49.0"]
pub MAP_COLLECT_RESULT_UNIT,
style,
"using `.map(_).collect::<Result<(),_>()`, which can be replaced with `try_for_each`"
@@ -1578,6 +1633,7 @@ declare_clippy_lint! {
///
/// assert_eq!(v, vec![5, 5, 5, 5, 5]);
/// ```
+ #[clippy::version = "1.49.0"]
pub FROM_ITER_INSTEAD_OF_COLLECT,
pedantic,
"use `.collect()` instead of `::from_iter()`"
@@ -1607,6 +1663,7 @@ declare_clippy_lint! {
/// assert!(x >= 0);
/// });
/// ```
+ #[clippy::version = "1.51.0"]
pub INSPECT_FOR_EACH,
complexity,
"using `.inspect().for_each()`, which can be replaced with `.for_each()`"
@@ -1629,6 +1686,7 @@ declare_clippy_lint! {
/// # let iter = vec![Some(1)].into_iter();
/// iter.flatten();
/// ```
+ #[clippy::version = "1.52.0"]
pub FILTER_MAP_IDENTITY,
complexity,
"call to `filter_map` where `flatten` is sufficient"
@@ -1651,6 +1709,7 @@ declare_clippy_lint! {
/// let x = [1, 2, 3];
/// let y: Vec<_> = x.iter().map(|x| 2*x).collect();
/// ```
+ #[clippy::version = "1.52.0"]
pub MAP_IDENTITY,
complexity,
"using iterator.map(|x| x)"
@@ -1672,6 +1731,7 @@ declare_clippy_lint! {
/// // Good
/// let _ = "Hello".as_bytes().get(3);
/// ```
+ #[clippy::version = "1.52.0"]
pub BYTES_NTH,
style,
"replace `.bytes().nth()` with `.as_bytes().get()`"
@@ -1697,6 +1757,7 @@ declare_clippy_lint! {
/// let b = a.clone();
/// let c = a.clone();
/// ```
+ #[clippy::version = "1.52.0"]
pub IMPLICIT_CLONE,
pedantic,
"implicitly cloning a value by invoking a function on its dereferenced type"
@@ -1722,6 +1783,7 @@ declare_clippy_lint! {
/// let _ = some_vec.len();
/// let _ = &some_vec[..].len();
/// ```
+ #[clippy::version = "1.52.0"]
pub ITER_COUNT,
complexity,
"replace `.iter().count()` with `.len()`"
@@ -1751,6 +1813,7 @@ declare_clippy_lint! {
/// // use x
/// }
/// ```
+ #[clippy::version = "1.54.0"]
pub SUSPICIOUS_SPLITN,
correctness,
"checks for `.splitn(0, ..)` and `.splitn(1, ..)`"
@@ -1771,6 +1834,7 @@ declare_clippy_lint! {
/// // Good
/// let x: String = "x".repeat(10);
/// ```
+ #[clippy::version = "1.54.0"]
pub MANUAL_STR_REPEAT,
perf,
"manual implementation of `str::repeat`"
@@ -1793,11 +1857,62 @@ declare_clippy_lint! {
/// let (key, value) = _.split_once('=')?;
/// let value = _.split_once('=')?.1;
/// ```
+ #[clippy::version = "1.57.0"]
pub MANUAL_SPLIT_ONCE,
complexity,
"replace `.splitn(2, pat)` with `.split_once(pat)`"
}
+declare_clippy_lint! {
+ /// ### What it does
+ /// Checks for usages of `str::splitn` (or `str::rsplitn`) where using `str::split` would be the same.
+ /// ### Why is this bad?
+ /// The function `split` is simpler and there is no performance difference in these cases, considering
+ /// that both functions return a lazy iterator.
+ /// ### Example
+ /// ```rust
+ /// // Bad
+ /// let str = "key=value=add";
+ /// let _ = str.splitn(3, '=').next().unwrap();
+ /// ```
+ /// Use instead:
+ /// ```rust
+ /// // Good
+ /// let str = "key=value=add";
+ /// let _ = str.split('=').next().unwrap();
+ /// ```
+ #[clippy::version = "1.58.0"]
+ pub NEEDLESS_SPLITN,
+ complexity,
+ "usages of `str::splitn` that can be replaced with `str::split`"
+}
+
+declare_clippy_lint! {
+ /// ### What it does
+ /// Checks for unnecessary calls to [`ToOwned::to_owned`](https://doc.rust-lang.org/std/borrow/trait.ToOwned.html#tymethod.to_owned)
+ /// and other `to_owned`-like functions.
+ ///
+ /// ### Why is this bad?
+ /// The unnecessary calls result in useless allocations.
+ ///
+ /// ### Example
+ /// ```rust
+ /// let path = std::path::Path::new("x");
+ /// foo(&path.to_string_lossy().to_string());
+ /// fn foo(s: &str) {}
+ /// ```
+ /// Use instead:
+ /// ```rust
+ /// let path = std::path::Path::new("x");
+ /// foo(&path.to_string_lossy());
+ /// fn foo(s: &str) {}
+ /// ```
+ #[clippy::version = "1.58.0"]
+ pub UNNECESSARY_TO_OWNED,
+ perf,
+ "unnecessary calls to `to_owned`-like functions"
+}
+
pub struct Methods {
avoid_breaking_exported_api: bool,
msrv: Option<RustcVersion>,
@@ -1876,7 +1991,9 @@ impl_lint_pass!(Methods => [
SUSPICIOUS_SPLITN,
MANUAL_STR_REPEAT,
EXTEND_WITH_DRAIN,
- MANUAL_SPLIT_ONCE
+ MANUAL_SPLIT_ONCE,
+ NEEDLESS_SPLITN,
+ UNNECESSARY_TO_OWNED,
]);
/// Extracts a method call name, args, and `Span` of the method name.
@@ -1900,7 +2017,7 @@ macro_rules! method_call {
impl<'tcx> LateLintPass<'tcx> for Methods {
fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx hir::Expr<'_>) {
- if in_macro(expr.span) {
+ if expr.span.from_expansion() {
return;
}
@@ -1919,6 +2036,7 @@ impl<'tcx> LateLintPass<'tcx> for Methods {
single_char_add_str::check(cx, expr, args);
into_iter_on_ref::check(cx, expr, *method_span, method_call.ident.name, args);
single_char_pattern::check(cx, expr, method_call.ident.name, args);
+ unnecessary_to_owned::check(cx, expr, method_call.ident.name, args);
},
hir::ExprKind::Binary(op, lhs, rhs) if op.node == hir::BinOpKind::Eq || op.node == hir::BinOpKind::Ne => {
let mut info = BinaryExprInfo {
@@ -1939,7 +2057,7 @@ impl<'tcx> LateLintPass<'tcx> for Methods {
return;
}
let name = impl_item.ident.name.as_str();
- let parent = cx.tcx.hir().get_parent_item(impl_item.hir_id());
+ let parent = cx.tcx.hir().get_parent_did(impl_item.hir_id());
let item = cx.tcx.hir().expect_item(parent);
let self_ty = cx.tcx.type_of(item.def_id);
@@ -2116,7 +2234,9 @@ fn check_methods<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>, msrv: Optio
("assume_init", []) => uninit_assumed_init::check(cx, expr, recv),
("cloned", []) => cloned_instead_of_copied::check(cx, expr, recv, span, msrv),
("collect", []) => match method_call!(recv) {
- Some(("cloned", [recv2], _)) => iter_cloned_collect::check(cx, expr, recv2),
+ Some((name @ ("cloned" | "copied"), [recv2], _)) => {
+ iter_cloned_collect::check(cx, name, expr, recv2);
+ },
Some(("map", [m_recv, m_arg], _)) => {
map_collect_result_unit::check(cx, expr, m_recv, m_arg, recv);
},
@@ -2208,7 +2328,10 @@ fn check_methods<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>, msrv: Optio
if let Some((Constant::Int(count), _)) = constant(cx, cx.typeck_results(), count_arg) {
suspicious_splitn::check(cx, name, expr, recv, count);
if count == 2 && meets_msrv(msrv, &msrvs::STR_SPLIT_ONCE) {
- manual_split_once::check(cx, name, expr, recv, pat_arg);
+ str_splitn::check_manual_split_once(cx, name, expr, recv, pat_arg);
+ }
+ if count >= 2 {
+ str_splitn::check_needless_splitn(cx, name, expr, recv, pat_arg, count);
}
}
},
diff --git a/src/tools/clippy/clippy_lints/src/methods/option_as_ref_deref.rs b/src/tools/clippy/clippy_lints/src/methods/option_as_ref_deref.rs
index d3f40d26208..fa74a8f3dc3 100644
--- a/src/tools/clippy/clippy_lints/src/methods/option_as_ref_deref.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/option_as_ref_deref.rs
@@ -1,7 +1,7 @@
use clippy_utils::diagnostics::span_lint_and_sugg;
use clippy_utils::source::snippet;
use clippy_utils::ty::is_type_diagnostic_item;
-use clippy_utils::{match_def_path, meets_msrv, msrvs, path_to_local_id, paths, remove_blocks};
+use clippy_utils::{match_def_path, meets_msrv, msrvs, path_to_local_id, paths, peel_blocks};
use if_chain::if_chain;
use rustc_errors::Applicability;
use rustc_hir as hir;
@@ -53,7 +53,7 @@ pub(super) fn check<'tcx>(
}),
hir::ExprKind::Closure(_, _, body_id, _, _) => {
let closure_body = cx.tcx.hir().body(body_id);
- let closure_expr = remove_blocks(&closure_body.value);
+ let closure_expr = peel_blocks(&closure_body.value);
match &closure_expr.kind {
hir::ExprKind::MethodCall(_, _, args, _) => {
diff --git a/src/tools/clippy/clippy_lints/src/methods/option_map_or_none.rs b/src/tools/clippy/clippy_lints/src/methods/option_map_or_none.rs
index e99b6b07d15..5e5c1038e82 100644
--- a/src/tools/clippy/clippy_lints/src/methods/option_map_or_none.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/option_map_or_none.rs
@@ -1,7 +1,7 @@
use clippy_utils::diagnostics::span_lint_and_sugg;
-use clippy_utils::is_lang_ctor;
use clippy_utils::source::snippet;
use clippy_utils::ty::is_type_diagnostic_item;
+use clippy_utils::{is_lang_ctor, single_segment_path};
use rustc_errors::Applicability;
use rustc_hir as hir;
use rustc_hir::LangItem::{OptionNone, OptionSome};
@@ -11,6 +11,28 @@ use rustc_span::symbol::sym;
use super::OPTION_MAP_OR_NONE;
use super::RESULT_MAP_OR_INTO_OPTION;
+// The expression inside a closure may or may not have surrounding braces
+// which causes problems when generating a suggestion.
+fn reduce_unit_expression<'a>(
+ cx: &LateContext<'_>,
+ expr: &'a hir::Expr<'_>,
+) -> Option<(&'a hir::Expr<'a>, &'a [hir::Expr<'a>])> {
+ match expr.kind {
+ hir::ExprKind::Call(func, arg_char) => Some((func, arg_char)),
+ hir::ExprKind::Block(block, _) => {
+ match (block.stmts, block.expr) {
+ (&[], Some(inner_expr)) => {
+ // If block only contains an expression,
+ // reduce `|x| { x + 1 }` to `|x| x + 1`
+ reduce_unit_expression(cx, inner_expr)
+ },
+ _ => None,
+ }
+ },
+ _ => None,
+ }
+}
+
/// lint use of `_.map_or(None, _)` for `Option`s and `Result`s
pub(super) fn check<'tcx>(
cx: &LateContext<'tcx>,
@@ -31,58 +53,75 @@ pub(super) fn check<'tcx>(
return;
}
- let (lint_name, msg, instead, hint) = {
- let default_arg_is_none = if let hir::ExprKind::Path(ref qpath) = def_arg.kind {
- is_lang_ctor(cx, qpath, OptionNone)
- } else {
- return;
- };
+ let default_arg_is_none = if let hir::ExprKind::Path(ref qpath) = def_arg.kind {
+ is_lang_ctor(cx, qpath, OptionNone)
+ } else {
+ return;
+ };
- if !default_arg_is_none {
- // nothing to lint!
- return;
- }
+ if !default_arg_is_none {
+ // nothing to lint!
+ return;
+ }
- let f_arg_is_some = if let hir::ExprKind::Path(ref qpath) = map_arg.kind {
- is_lang_ctor(cx, qpath, OptionSome)
- } else {
- false
- };
+ let f_arg_is_some = if let hir::ExprKind::Path(ref qpath) = map_arg.kind {
+ is_lang_ctor(cx, qpath, OptionSome)
+ } else {
+ false
+ };
+
+ if is_option {
+ let self_snippet = snippet(cx, recv.span, "..");
+ if_chain! {
+ if let hir::ExprKind::Closure(_, _, id, span, _) = map_arg.kind;
+ let arg_snippet = snippet(cx, span, "..");
+ let body = cx.tcx.hir().body(id);
+ if let Some((func, arg_char)) = reduce_unit_expression(cx, &body.value);
+ if arg_char.len() == 1;
+ if let hir::ExprKind::Path(ref qpath) = func.kind;
+ if let Some(segment) = single_segment_path(qpath);
+ if segment.ident.name == sym::Some;
+ then {
+ let func_snippet = snippet(cx, arg_char[0].span, "..");
+ let msg = "called `map_or(None, ..)` on an `Option` value. This can be done more directly by calling \
+ `map(..)` instead";
+ return span_lint_and_sugg(
+ cx,
+ OPTION_MAP_OR_NONE,
+ expr.span,
+ msg,
+ "try using `map` instead",
+ format!("{0}.map({1} {2})", self_snippet, arg_snippet,func_snippet),
+ Applicability::MachineApplicable,
+ );
+ }
- if is_option {
- let self_snippet = snippet(cx, recv.span, "..");
- let func_snippet = snippet(cx, map_arg.span, "..");
- let msg = "called `map_or(None, ..)` on an `Option` value. This can be done more directly by calling \
- `and_then(..)` instead";
- (
- OPTION_MAP_OR_NONE,
- msg,
- "try using `and_then` instead",
- format!("{0}.and_then({1})", self_snippet, func_snippet),
- )
- } else if f_arg_is_some {
- let msg = "called `map_or(None, Some)` on a `Result` value. This can be done more directly by calling \
- `ok()` instead";
- let self_snippet = snippet(cx, recv.span, "..");
- (
- RESULT_MAP_OR_INTO_OPTION,
- msg,
- "try using `ok` instead",
- format!("{0}.ok()", self_snippet),
- )
- } else {
- // nothing to lint!
- return;
}
- };
- span_lint_and_sugg(
- cx,
- lint_name,
- expr.span,
- msg,
- instead,
- hint,
- Applicability::MachineApplicable,
- );
+ let func_snippet = snippet(cx, map_arg.span, "..");
+ let msg = "called `map_or(None, ..)` on an `Option` value. This can be done more directly by calling \
+ `and_then(..)` instead";
+ return span_lint_and_sugg(
+ cx,
+ OPTION_MAP_OR_NONE,
+ expr.span,
+ msg,
+ "try using `and_then` instead",
+ format!("{0}.and_then({1})", self_snippet, func_snippet),
+ Applicability::MachineApplicable,
+ );
+ } else if f_arg_is_some {
+ let msg = "called `map_or(None, Some)` on a `Result` value. This can be done more directly by calling \
+ `ok()` instead";
+ let self_snippet = snippet(cx, recv.span, "..");
+ return span_lint_and_sugg(
+ cx,
+ RESULT_MAP_OR_INTO_OPTION,
+ expr.span,
+ msg,
+ "try using `ok` instead",
+ format!("{0}.ok()", self_snippet),
+ Applicability::MachineApplicable,
+ );
+ }
}
diff --git a/src/tools/clippy/clippy_lints/src/methods/or_fun_call.rs b/src/tools/clippy/clippy_lints/src/methods/or_fun_call.rs
index fe9ffde0d33..4e4653dadca 100644
--- a/src/tools/clippy/clippy_lints/src/methods/or_fun_call.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/or_fun_call.rs
@@ -1,16 +1,12 @@
use clippy_utils::diagnostics::span_lint_and_sugg;
-use clippy_utils::eager_or_lazy::is_lazyness_candidate;
-use clippy_utils::is_trait_item;
+use clippy_utils::eager_or_lazy::switch_to_lazy_eval;
use clippy_utils::source::{snippet, snippet_with_applicability, snippet_with_macro_callsite};
-use clippy_utils::ty::implements_trait;
-use clippy_utils::ty::{is_type_diagnostic_item, match_type};
-use clippy_utils::{contains_return, last_path_segment, paths};
+use clippy_utils::ty::{implements_trait, match_type};
+use clippy_utils::{contains_return, is_trait_item, last_path_segment, paths};
use if_chain::if_chain;
use rustc_errors::Applicability;
use rustc_hir as hir;
-use rustc_hir::{BlockCheckMode, UnsafeSource};
use rustc_lint::LateContext;
-use rustc_middle::ty;
use rustc_span::source_map::Span;
use rustc_span::symbol::{kw, sym};
use std::borrow::Cow;
@@ -96,25 +92,10 @@ pub(super) fn check<'tcx>(
(&paths::RESULT, true, &["or", "unwrap_or"], "else"),
];
- if let hir::ExprKind::MethodCall(path, _, [self_arg, ..], _) = &arg.kind {
- if path.ident.name == sym::len {
- let ty = cx.typeck_results().expr_ty(self_arg).peel_refs();
-
- match ty.kind() {
- ty::Slice(_) | ty::Array(_, _) | ty::Str => return,
- _ => (),
- }
-
- if is_type_diagnostic_item(cx, ty, sym::Vec) {
- return;
- }
- }
- }
-
if_chain! {
if KNOW_TYPES.iter().any(|k| k.2.contains(&name));
- if is_lazyness_candidate(cx, arg);
+ if switch_to_lazy_eval(cx, arg);
if !contains_return(arg);
let self_ty = cx.typeck_results().expr_ty(self_expr);
@@ -166,26 +147,30 @@ pub(super) fn check<'tcx>(
}
}
- if args.len() == 2 {
- match args[1].kind {
+ if let [self_arg, arg] = args {
+ let inner_arg = if let hir::ExprKind::Block(
+ hir::Block {
+ stmts: [],
+ expr: Some(expr),
+ ..
+ },
+ _,
+ ) = arg.kind
+ {
+ expr
+ } else {
+ arg
+ };
+ match inner_arg.kind {
hir::ExprKind::Call(fun, or_args) => {
let or_has_args = !or_args.is_empty();
- if !check_unwrap_or_default(cx, name, fun, &args[0], &args[1], or_has_args, expr.span) {
+ if !check_unwrap_or_default(cx, name, fun, self_arg, arg, or_has_args, expr.span) {
let fun_span = if or_has_args { None } else { Some(fun.span) };
- check_general_case(cx, name, method_span, &args[0], &args[1], expr.span, fun_span);
+ check_general_case(cx, name, method_span, self_arg, arg, expr.span, fun_span);
}
},
hir::ExprKind::Index(..) | hir::ExprKind::MethodCall(..) => {
- check_general_case(cx, name, method_span, &args[0], &args[1], expr.span, None);
- },
- hir::ExprKind::Block(block, _)
- if block.rules == BlockCheckMode::UnsafeBlock(UnsafeSource::UserProvided) =>
- {
- if let Some(block_expr) = block.expr {
- if let hir::ExprKind::MethodCall(..) = block_expr.kind {
- check_general_case(cx, name, method_span, &args[0], &args[1], expr.span, None);
- }
- }
+ check_general_case(cx, name, method_span, self_arg, arg, expr.span, None);
},
_ => (),
}
diff --git a/src/tools/clippy/clippy_lints/src/methods/search_is_some.rs b/src/tools/clippy/clippy_lints/src/methods/search_is_some.rs
index 0f2e58d8983..5ed4ba94884 100644
--- a/src/tools/clippy/clippy_lints/src/methods/search_is_some.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/search_is_some.rs
@@ -1,5 +1,6 @@
use clippy_utils::diagnostics::{span_lint_and_help, span_lint_and_sugg};
use clippy_utils::source::{snippet, snippet_with_applicability};
+use clippy_utils::sugg::deref_closure_args;
use clippy_utils::ty::is_type_diagnostic_item;
use clippy_utils::{is_trait_method, strip_pat_refs};
use if_chain::if_chain;
@@ -37,6 +38,7 @@ pub(super) fn check<'tcx>(
if search_snippet.lines().count() <= 1 {
// suggest `any(|x| ..)` instead of `any(|&x| ..)` for `find(|&x| ..).is_some()`
// suggest `any(|..| *..)` instead of `any(|..| **..)` for `find(|..| **..).is_some()`
+ let mut applicability = Applicability::MachineApplicable;
let any_search_snippet = if_chain! {
if search_method == "find";
if let hir::ExprKind::Closure(_, _, body_id, ..) = search_arg.kind;
@@ -45,9 +47,15 @@ pub(super) fn check<'tcx>(
then {
if let hir::PatKind::Ref(..) = closure_arg.pat.kind {
Some(search_snippet.replacen('&', "", 1))
- } else if let PatKind::Binding(_, _, ident, _) = strip_pat_refs(closure_arg.pat).kind {
- let name = &*ident.name.as_str();
- Some(search_snippet.replace(&format!("*{}", name), name))
+ } else if let PatKind::Binding(..) = strip_pat_refs(closure_arg.pat).kind {
+ // `find()` provides a reference to the item, but `any` does not,
+ // so we should fix item usages for suggestion
+ if let Some(closure_sugg) = deref_closure_args(cx, search_arg) {
+ applicability = closure_sugg.applicability;
+ Some(closure_sugg.suggestion)
+ } else {
+ Some(search_snippet.to_string())
+ }
} else {
None
}
@@ -67,7 +75,7 @@ pub(super) fn check<'tcx>(
"any({})",
any_search_snippet.as_ref().map_or(&*search_snippet, String::as_str)
),
- Applicability::MachineApplicable,
+ applicability,
);
} else {
let iter = snippet(cx, search_recv.span, "..");
@@ -82,7 +90,7 @@ pub(super) fn check<'tcx>(
iter,
any_search_snippet.as_ref().map_or(&*search_snippet, String::as_str)
),
- Applicability::MachineApplicable,
+ applicability,
);
}
} else {
diff --git a/src/tools/clippy/clippy_lints/src/methods/single_char_pattern.rs b/src/tools/clippy/clippy_lints/src/methods/single_char_pattern.rs
index d313a3db479..bf9006c6906 100644
--- a/src/tools/clippy/clippy_lints/src/methods/single_char_pattern.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/single_char_pattern.rs
@@ -9,18 +9,21 @@ use rustc_span::symbol::Symbol;
use super::SINGLE_CHAR_PATTERN;
-const PATTERN_METHODS: [(&str, usize); 19] = [
+const PATTERN_METHODS: [(&str, usize); 24] = [
("contains", 1),
("starts_with", 1),
("ends_with", 1),
("find", 1),
("rfind", 1),
("split", 1),
+ ("split_inclusive", 1),
("rsplit", 1),
("split_terminator", 1),
("rsplit_terminator", 1),
("splitn", 2),
("rsplitn", 2),
+ ("split_once", 1),
+ ("rsplit_once", 1),
("matches", 1),
("rmatches", 1),
("match_indices", 1),
@@ -29,6 +32,8 @@ const PATTERN_METHODS: [(&str, usize); 19] = [
("strip_suffix", 1),
("trim_start_matches", 1),
("trim_end_matches", 1),
+ ("replace", 1),
+ ("replacen", 1),
];
/// lint for length-1 `str`s for methods in `PATTERN_METHODS`
diff --git a/src/tools/clippy/clippy_lints/src/methods/manual_split_once.rs b/src/tools/clippy/clippy_lints/src/methods/str_splitn.rs
index 13eb72251bb..e5fafdb075c 100644
--- a/src/tools/clippy/clippy_lints/src/methods/manual_split_once.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/str_splitn.rs
@@ -11,7 +11,13 @@ use rustc_span::{symbol::sym, Span, SyntaxContext};
use super::MANUAL_SPLIT_ONCE;
-pub(super) fn check(cx: &LateContext<'_>, method_name: &str, expr: &Expr<'_>, self_arg: &Expr<'_>, pat_arg: &Expr<'_>) {
+pub(super) fn check_manual_split_once(
+ cx: &LateContext<'_>,
+ method_name: &str,
+ expr: &Expr<'_>,
+ self_arg: &Expr<'_>,
+ pat_arg: &Expr<'_>,
+) {
if !cx.typeck_results().expr_ty_adjusted(self_arg).peel_refs().is_str() {
return;
}
@@ -36,7 +42,7 @@ pub(super) fn check(cx: &LateContext<'_>, method_name: &str, expr: &Expr<'_>, se
format!("{}.{}({})", self_snip, method_name, pat_snip)
},
IterUsageKind::RNextTuple => format!("{}.{}({}).map(|(x, y)| (y, x))", self_snip, method_name, pat_snip),
- IterUsageKind::Next => {
+ IterUsageKind::Next | IterUsageKind::Second => {
let self_deref = {
let adjust = cx.typeck_results().expr_adjustments(self_arg);
if adjust.is_empty() {
@@ -51,26 +57,49 @@ pub(super) fn check(cx: &LateContext<'_>, method_name: &str, expr: &Expr<'_>, se
"*".repeat(adjust.len() - 2)
}
};
- if usage.unwrap_kind.is_some() {
- format!(
- "{}.{}({}).map_or({}{}, |x| x.0)",
- &self_snip, method_name, pat_snip, self_deref, &self_snip
- )
+ if matches!(usage.kind, IterUsageKind::Next) {
+ match usage.unwrap_kind {
+ Some(UnwrapKind::Unwrap) => {
+ if reverse {
+ format!("{}.{}({}).unwrap().0", self_snip, method_name, pat_snip)
+ } else {
+ format!(
+ "{}.{}({}).map_or({}{}, |x| x.0)",
+ self_snip, method_name, pat_snip, self_deref, &self_snip
+ )
+ }
+ },
+ Some(UnwrapKind::QuestionMark) => {
+ format!(
+ "{}.{}({}).map_or({}{}, |x| x.0)",
+ self_snip, method_name, pat_snip, self_deref, &self_snip
+ )
+ },
+ None => {
+ format!(
+ "Some({}.{}({}).map_or({}{}, |x| x.0))",
+ &self_snip, method_name, pat_snip, self_deref, &self_snip
+ )
+ },
+ }
} else {
- format!(
- "Some({}.{}({}).map_or({}{}, |x| x.0))",
- &self_snip, method_name, pat_snip, self_deref, &self_snip
- )
+ match usage.unwrap_kind {
+ Some(UnwrapKind::Unwrap) => {
+ if reverse {
+ // In this case, no better suggestion is offered.
+ return;
+ }
+ format!("{}.{}({}).unwrap().1", self_snip, method_name, pat_snip)
+ },
+ Some(UnwrapKind::QuestionMark) => {
+ format!("{}.{}({})?.1", self_snip, method_name, pat_snip)
+ },
+ None => {
+ format!("{}.{}({}).map(|x| x.1)", self_snip, method_name, pat_snip)
+ },
+ }
}
},
- IterUsageKind::Second => {
- let access_str = match usage.unwrap_kind {
- Some(UnwrapKind::Unwrap) => ".unwrap().1",
- Some(UnwrapKind::QuestionMark) => "?.1",
- None => ".map(|x| x.1)",
- };
- format!("{}.{}({}){}", self_snip, method_name, pat_snip, access_str)
- },
};
span_lint_and_sugg(cx, MANUAL_SPLIT_ONCE, usage.span, msg, "try this", sugg, app);
@@ -175,7 +204,7 @@ fn parse_iter_usage(
match e.kind {
ExprKind::Call(
Expr {
- kind: ExprKind::Path(QPath::LangItem(LangItem::TryTraitBranch, _)),
+ kind: ExprKind::Path(QPath::LangItem(LangItem::TryTraitBranch, ..)),
..
},
_,
@@ -209,3 +238,86 @@ fn parse_iter_usage(
span,
})
}
+
+use super::NEEDLESS_SPLITN;
+
+pub(super) fn check_needless_splitn(
+ cx: &LateContext<'_>,
+ method_name: &str,
+ expr: &Expr<'_>,
+ self_arg: &Expr<'_>,
+ pat_arg: &Expr<'_>,
+ count: u128,
+) {
+ if !cx.typeck_results().expr_ty_adjusted(self_arg).peel_refs().is_str() {
+ return;
+ }
+ let ctxt = expr.span.ctxt();
+ let mut app = Applicability::MachineApplicable;
+ let (reverse, message) = if method_name == "splitn" {
+ (false, "unnecessary use of `splitn`")
+ } else {
+ (true, "unnecessary use of `rsplitn`")
+ };
+ if_chain! {
+ if count >= 2;
+ if check_iter(cx, ctxt, cx.tcx.hir().parent_iter(expr.hir_id), count);
+ then {
+ span_lint_and_sugg(
+ cx,
+ NEEDLESS_SPLITN,
+ expr.span,
+ message,
+ "try this",
+ format!(
+ "{}.{}({})",
+ snippet_with_context(cx, self_arg.span, ctxt, "..", &mut app).0,
+ if reverse {"rsplit"} else {"split"},
+ snippet_with_context(cx, pat_arg.span, ctxt, "..", &mut app).0
+ ),
+ app,
+ );
+ }
+ }
+}
+
+fn check_iter(
+ cx: &LateContext<'tcx>,
+ ctxt: SyntaxContext,
+ mut iter: impl Iterator<Item = (HirId, Node<'tcx>)>,
+ count: u128,
+) -> bool {
+ match iter.next() {
+ Some((_, Node::Expr(e))) if e.span.ctxt() == ctxt => {
+ let (name, args) = if let ExprKind::MethodCall(name, _, [_, args @ ..], _) = e.kind {
+ (name, args)
+ } else {
+ return false;
+ };
+ if_chain! {
+ if let Some(did) = cx.typeck_results().type_dependent_def_id(e.hir_id);
+ if let Some(iter_id) = cx.tcx.get_diagnostic_item(sym::Iterator);
+ then {
+ match (&*name.ident.as_str(), args) {
+ ("next", []) if cx.tcx.trait_of_item(did) == Some(iter_id) => {
+ return true;
+ },
+ ("next_tuple", []) if count > 2 => {
+ return true;
+ },
+ ("nth", [idx_expr]) if cx.tcx.trait_of_item(did) == Some(iter_id) => {
+ if let Some((Constant::Int(idx), _)) = constant(cx, cx.typeck_results(), idx_expr) {
+ if count > idx + 1 {
+ return true;
+ }
+ }
+ },
+ _ => return false,
+ }
+ }
+ }
+ },
+ _ => return false,
+ };
+ false
+}
diff --git a/src/tools/clippy/clippy_lints/src/methods/unnecessary_fold.rs b/src/tools/clippy/clippy_lints/src/methods/unnecessary_fold.rs
index 4c4034437da..47a81199608 100644
--- a/src/tools/clippy/clippy_lints/src/methods/unnecessary_fold.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/unnecessary_fold.rs
@@ -1,6 +1,6 @@
use clippy_utils::diagnostics::span_lint_and_sugg;
use clippy_utils::source::snippet_with_applicability;
-use clippy_utils::{is_trait_method, path_to_local_id, remove_blocks, strip_pat_refs};
+use clippy_utils::{is_trait_method, path_to_local_id, peel_blocks, strip_pat_refs};
use if_chain::if_chain;
use rustc_ast::ast;
use rustc_errors::Applicability;
@@ -31,7 +31,7 @@ pub(super) fn check(
// Extract the body of the closure passed to fold
if let hir::ExprKind::Closure(_, _, body_id, _, _) = acc.kind;
let closure_body = cx.tcx.hir().body(body_id);
- let closure_expr = remove_blocks(&closure_body.value);
+ let closure_expr = peel_blocks(&closure_body.value);
// Check if the closure body is of the form `acc <op> some_expr(x)`
if let hir::ExprKind::Binary(ref bin_op, left_expr, right_expr) = closure_expr.kind;
diff --git a/src/tools/clippy/clippy_lints/src/methods/unnecessary_iter_cloned.rs b/src/tools/clippy/clippy_lints/src/methods/unnecessary_iter_cloned.rs
new file mode 100644
index 00000000000..8300df03e99
--- /dev/null
+++ b/src/tools/clippy/clippy_lints/src/methods/unnecessary_iter_cloned.rs
@@ -0,0 +1,177 @@
+use clippy_utils::diagnostics::span_lint_and_then;
+use clippy_utils::higher::ForLoop;
+use clippy_utils::source::snippet_opt;
+use clippy_utils::ty::{get_associated_type, get_iterator_item_ty, implements_trait};
+use clippy_utils::{fn_def_id, get_parent_expr, path_to_local_id, usage};
+use rustc_errors::Applicability;
+use rustc_hir::intravisit::{walk_expr, NestedVisitorMap, Visitor};
+use rustc_hir::{def_id::DefId, BorrowKind, Expr, ExprKind, HirId, LangItem, Mutability, Pat};
+use rustc_lint::LateContext;
+use rustc_middle::{hir::map::Map, ty};
+use rustc_span::{sym, Symbol};
+
+use super::UNNECESSARY_TO_OWNED;
+
+pub fn check(cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>, method_name: Symbol, receiver: &'tcx Expr<'tcx>) -> bool {
+ if_chain! {
+ if let Some(parent) = get_parent_expr(cx, expr);
+ if let Some(callee_def_id) = fn_def_id(cx, parent);
+ if is_into_iter(cx, callee_def_id);
+ then {
+ check_for_loop_iter(cx, parent, method_name, receiver)
+ } else {
+ false
+ }
+ }
+}
+
+/// Checks whether `expr` is an iterator in a `for` loop and, if so, determines whether the
+/// iterated-over items could be iterated over by reference. The reason why `check` above does not
+/// include this code directly is so that it can be called from
+/// `unnecessary_into_owned::check_into_iter_call_arg`.
+pub fn check_for_loop_iter(
+ cx: &LateContext<'tcx>,
+ expr: &'tcx Expr<'tcx>,
+ method_name: Symbol,
+ receiver: &'tcx Expr<'tcx>,
+) -> bool {
+ if_chain! {
+ if let Some(grandparent) = get_parent_expr(cx, expr).and_then(|parent| get_parent_expr(cx, parent));
+ if let Some(ForLoop { pat, body, .. }) = ForLoop::hir(grandparent);
+ let (clone_or_copy_needed, addr_of_exprs) = clone_or_copy_needed(cx, pat, body);
+ if !clone_or_copy_needed;
+ if let Some(receiver_snippet) = snippet_opt(cx, receiver.span);
+ then {
+ let snippet = if_chain! {
+ if let ExprKind::MethodCall(maybe_iter_method_name, _, [collection], _) = receiver.kind;
+ if maybe_iter_method_name.ident.name == sym::iter;
+
+ if let Some(iterator_trait_id) = cx.tcx.get_diagnostic_item(sym::Iterator);
+ let receiver_ty = cx.typeck_results().expr_ty(receiver);
+ if implements_trait(cx, receiver_ty, iterator_trait_id, &[]);
+ if let Some(iter_item_ty) = get_iterator_item_ty(cx, receiver_ty);
+
+ if let Some(into_iterator_trait_id) = cx.tcx.get_diagnostic_item(sym::IntoIterator);
+ let collection_ty = cx.typeck_results().expr_ty(collection);
+ if implements_trait(cx, collection_ty, into_iterator_trait_id, &[]);
+ if let Some(into_iter_item_ty) = get_associated_type(cx, collection_ty, into_iterator_trait_id, "Item");
+
+ if iter_item_ty == into_iter_item_ty;
+ if let Some(collection_snippet) = snippet_opt(cx, collection.span);
+ then {
+ collection_snippet
+ } else {
+ receiver_snippet
+ }
+ };
+ span_lint_and_then(
+ cx,
+ UNNECESSARY_TO_OWNED,
+ expr.span,
+ &format!("unnecessary use of `{}`", method_name),
+ |diag| {
+ diag.span_suggestion(expr.span, "use", snippet, Applicability::MachineApplicable);
+ for addr_of_expr in addr_of_exprs {
+ match addr_of_expr.kind {
+ ExprKind::AddrOf(_, _, referent) => {
+ let span = addr_of_expr.span.with_hi(referent.span.lo());
+ diag.span_suggestion(span, "remove this `&`", String::new(), Applicability::MachineApplicable);
+ }
+ _ => unreachable!(),
+ }
+ }
+ }
+ );
+ return true;
+ }
+ }
+ false
+}
+
+/// The core logic of `check_for_loop_iter` above, this function wraps a use of
+/// `CloneOrCopyVisitor`.
+fn clone_or_copy_needed(
+ cx: &LateContext<'tcx>,
+ pat: &Pat<'tcx>,
+ body: &'tcx Expr<'tcx>,
+) -> (bool, Vec<&'tcx Expr<'tcx>>) {
+ let mut visitor = CloneOrCopyVisitor {
+ cx,
+ binding_hir_ids: pat_bindings(pat),
+ clone_or_copy_needed: false,
+ addr_of_exprs: Vec::new(),
+ };
+ visitor.visit_expr(body);
+ (visitor.clone_or_copy_needed, visitor.addr_of_exprs)
+}
+
+/// Returns a vector of all `HirId`s bound by the pattern.
+fn pat_bindings(pat: &Pat<'_>) -> Vec<HirId> {
+ let mut collector = usage::ParamBindingIdCollector {
+ binding_hir_ids: Vec::new(),
+ };
+ collector.visit_pat(pat);
+ collector.binding_hir_ids
+}
+
+/// `clone_or_copy_needed` will be false when `CloneOrCopyVisitor` is done visiting if the only
+/// operations performed on `binding_hir_ids` are:
+/// * to take non-mutable references to them
+/// * to use them as non-mutable `&self` in method calls
+/// If any of `binding_hir_ids` is used in any other way, then `clone_or_copy_needed` will be true
+/// when `CloneOrCopyVisitor` is done visiting.
+struct CloneOrCopyVisitor<'cx, 'tcx> {
+ cx: &'cx LateContext<'tcx>,
+ binding_hir_ids: Vec<HirId>,
+ clone_or_copy_needed: bool,
+ addr_of_exprs: Vec<&'tcx Expr<'tcx>>,
+}
+
+impl<'cx, 'tcx> Visitor<'tcx> for CloneOrCopyVisitor<'cx, 'tcx> {
+ type Map = Map<'tcx>;
+
+ fn nested_visit_map(&mut self) -> NestedVisitorMap<Self::Map> {
+ NestedVisitorMap::OnlyBodies(self.cx.tcx.hir())
+ }
+
+ fn visit_expr(&mut self, expr: &'tcx Expr<'tcx>) {
+ walk_expr(self, expr);
+ if self.is_binding(expr) {
+ if let Some(parent) = get_parent_expr(self.cx, expr) {
+ match parent.kind {
+ ExprKind::AddrOf(BorrowKind::Ref, Mutability::Not, _) => {
+ self.addr_of_exprs.push(parent);
+ return;
+ },
+ ExprKind::MethodCall(_, _, args, _) => {
+ if_chain! {
+ if args.iter().skip(1).all(|arg| !self.is_binding(arg));
+ if let Some(method_def_id) = self.cx.typeck_results().type_dependent_def_id(parent.hir_id);
+ let method_ty = self.cx.tcx.type_of(method_def_id);
+ let self_ty = method_ty.fn_sig(self.cx.tcx).input(0).skip_binder();
+ if matches!(self_ty.kind(), ty::Ref(_, _, Mutability::Not));
+ then {
+ return;
+ }
+ }
+ },
+ _ => {},
+ }
+ }
+ self.clone_or_copy_needed = true;
+ }
+ }
+}
+
+impl<'cx, 'tcx> CloneOrCopyVisitor<'cx, 'tcx> {
+ fn is_binding(&self, expr: &Expr<'tcx>) -> bool {
+ self.binding_hir_ids
+ .iter()
+ .any(|hir_id| path_to_local_id(expr, *hir_id))
+ }
+}
+
+/// Returns true if the named method is `IntoIterator::into_iter`.
+pub fn is_into_iter(cx: &LateContext<'_>, callee_def_id: DefId) -> bool {
+ cx.tcx.lang_items().require(LangItem::IntoIterIntoIter) == Ok(callee_def_id)
+}
diff --git a/src/tools/clippy/clippy_lints/src/methods/unnecessary_lazy_eval.rs b/src/tools/clippy/clippy_lints/src/methods/unnecessary_lazy_eval.rs
index 740af750b48..1e2765263c8 100644
--- a/src/tools/clippy/clippy_lints/src/methods/unnecessary_lazy_eval.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/unnecessary_lazy_eval.rs
@@ -30,7 +30,7 @@ pub(super) fn check<'tcx>(
return;
}
- if eager_or_lazy::is_eagerness_candidate(cx, body_expr) {
+ if eager_or_lazy::switch_to_eager_eval(cx, body_expr) {
let msg = if is_option {
"unnecessary closure used to substitute value for `Option::None`"
} else {
diff --git a/src/tools/clippy/clippy_lints/src/methods/unnecessary_to_owned.rs b/src/tools/clippy/clippy_lints/src/methods/unnecessary_to_owned.rs
new file mode 100644
index 00000000000..c48bacfce0d
--- /dev/null
+++ b/src/tools/clippy/clippy_lints/src/methods/unnecessary_to_owned.rs
@@ -0,0 +1,397 @@
+use super::implicit_clone::is_clone_like;
+use super::unnecessary_iter_cloned::{self, is_into_iter};
+use clippy_utils::diagnostics::span_lint_and_sugg;
+use clippy_utils::source::snippet_opt;
+use clippy_utils::ty::{get_associated_type, get_iterator_item_ty, implements_trait, is_copy, peel_mid_ty_refs};
+use clippy_utils::{fn_def_id, get_parent_expr, is_diag_item_method, is_diag_trait_item};
+use rustc_errors::Applicability;
+use rustc_hir::{def_id::DefId, BorrowKind, Expr, ExprKind};
+use rustc_lint::LateContext;
+use rustc_middle::mir::Mutability;
+use rustc_middle::ty::adjustment::{Adjust, Adjustment, OverloadedDeref};
+use rustc_middle::ty::subst::{GenericArg, GenericArgKind, SubstsRef};
+use rustc_middle::ty::{self, PredicateKind, ProjectionPredicate, TraitPredicate, Ty};
+use rustc_span::{sym, Symbol};
+use std::cmp::max;
+
+use super::UNNECESSARY_TO_OWNED;
+
+pub fn check(cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>, method_name: Symbol, args: &'tcx [Expr<'tcx>]) {
+ if_chain! {
+ if let Some(method_def_id) = cx.typeck_results().type_dependent_def_id(expr.hir_id);
+ if let [receiver] = args;
+ then {
+ if is_cloned_or_copied(cx, method_name, method_def_id) {
+ unnecessary_iter_cloned::check(cx, expr, method_name, receiver);
+ } else if is_to_owned_like(cx, method_name, method_def_id) {
+ // At this point, we know the call is of a `to_owned`-like function. The functions
+ // `check_addr_of_expr` and `check_call_arg` determine whether the call is unnecessary
+ // based on its context, that is, whether it is a referent in an `AddrOf` expression, an
+ // argument in a `into_iter` call, or an argument in the call of some other function.
+ if check_addr_of_expr(cx, expr, method_name, method_def_id, receiver) {
+ return;
+ }
+ if check_into_iter_call_arg(cx, expr, method_name, receiver) {
+ return;
+ }
+ check_other_call_arg(cx, expr, method_name, receiver);
+ }
+ }
+ }
+}
+
+/// Checks whether `expr` is a referent in an `AddrOf` expression and, if so, determines whether its
+/// call of a `to_owned`-like function is unnecessary.
+#[allow(clippy::too_many_lines)]
+fn check_addr_of_expr(
+ cx: &LateContext<'tcx>,
+ expr: &'tcx Expr<'tcx>,
+ method_name: Symbol,
+ method_def_id: DefId,
+ receiver: &'tcx Expr<'tcx>,
+) -> bool {
+ if_chain! {
+ if let Some(parent) = get_parent_expr(cx, expr);
+ if let ExprKind::AddrOf(BorrowKind::Ref, Mutability::Not, _) = parent.kind;
+ let adjustments = cx.typeck_results().expr_adjustments(parent).iter().collect::<Vec<_>>();
+ if let Some(target_ty) = match adjustments[..]
+ {
+ // For matching uses of `Cow::from`
+ [
+ Adjustment {
+ kind: Adjust::Deref(None),
+ ..
+ },
+ Adjustment {
+ kind: Adjust::Borrow(_),
+ target: target_ty,
+ },
+ ]
+ // For matching uses of arrays
+ | [
+ Adjustment {
+ kind: Adjust::Deref(None),
+ ..
+ },
+ Adjustment {
+ kind: Adjust::Borrow(_),
+ ..
+ },
+ Adjustment {
+ kind: Adjust::Pointer(_),
+ target: target_ty,
+ },
+ ]
+ // For matching everything else
+ | [
+ Adjustment {
+ kind: Adjust::Deref(None),
+ ..
+ },
+ Adjustment {
+ kind: Adjust::Deref(Some(OverloadedDeref { .. })),
+ ..
+ },
+ Adjustment {
+ kind: Adjust::Borrow(_),
+ target: target_ty,
+ },
+ ] => Some(target_ty),
+ _ => None,
+ };
+ let receiver_ty = cx.typeck_results().expr_ty(receiver);
+ // Only flag cases where the receiver is copyable or the method is `Cow::into_owned`. This
+ // restriction is to ensure there is not overlap between `redundant_clone` and this lint.
+ if is_copy(cx, receiver_ty) || is_cow_into_owned(cx, method_name, method_def_id);
+ if let Some(receiver_snippet) = snippet_opt(cx, receiver.span);
+ then {
+ let (target_ty, n_target_refs) = peel_mid_ty_refs(target_ty);
+ let (receiver_ty, n_receiver_refs) = peel_mid_ty_refs(receiver_ty);
+ if receiver_ty == target_ty && n_target_refs >= n_receiver_refs {
+ span_lint_and_sugg(
+ cx,
+ UNNECESSARY_TO_OWNED,
+ parent.span,
+ &format!("unnecessary use of `{}`", method_name),
+ "use",
+ format!("{:&>width$}{}", "", receiver_snippet, width = n_target_refs - n_receiver_refs),
+ Applicability::MachineApplicable,
+ );
+ return true;
+ }
+ if_chain! {
+ if let Some(deref_trait_id) = cx.tcx.get_diagnostic_item(sym::Deref);
+ if implements_trait(cx, receiver_ty, deref_trait_id, &[]);
+ if get_associated_type(cx, receiver_ty, deref_trait_id, "Target") == Some(target_ty);
+ then {
+ if n_receiver_refs > 0 {
+ span_lint_and_sugg(
+ cx,
+ UNNECESSARY_TO_OWNED,
+ parent.span,
+ &format!("unnecessary use of `{}`", method_name),
+ "use",
+ receiver_snippet,
+ Applicability::MachineApplicable,
+ );
+ } else {
+ span_lint_and_sugg(
+ cx,
+ UNNECESSARY_TO_OWNED,
+ expr.span.with_lo(receiver.span.hi()),
+ &format!("unnecessary use of `{}`", method_name),
+ "remove this",
+ String::new(),
+ Applicability::MachineApplicable,
+ );
+ }
+ return true;
+ }
+ }
+ if_chain! {
+ if let Some(as_ref_trait_id) = cx.tcx.get_diagnostic_item(sym::AsRef);
+ if implements_trait(cx, receiver_ty, as_ref_trait_id, &[GenericArg::from(target_ty)]);
+ then {
+ span_lint_and_sugg(
+ cx,
+ UNNECESSARY_TO_OWNED,
+ parent.span,
+ &format!("unnecessary use of `{}`", method_name),
+ "use",
+ format!("{}.as_ref()", receiver_snippet),
+ Applicability::MachineApplicable,
+ );
+ return true;
+ }
+ }
+ }
+ }
+ false
+}
+
+/// Checks whether `expr` is an argument in an `into_iter` call and, if so, determines whether its
+/// call of a `to_owned`-like function is unnecessary.
+fn check_into_iter_call_arg(
+ cx: &LateContext<'tcx>,
+ expr: &'tcx Expr<'tcx>,
+ method_name: Symbol,
+ receiver: &'tcx Expr<'tcx>,
+) -> bool {
+ if_chain! {
+ if let Some(parent) = get_parent_expr(cx, expr);
+ if let Some(callee_def_id) = fn_def_id(cx, parent);
+ if is_into_iter(cx, callee_def_id);
+ if let Some(iterator_trait_id) = cx.tcx.get_diagnostic_item(sym::Iterator);
+ let parent_ty = cx.typeck_results().expr_ty(parent);
+ if implements_trait(cx, parent_ty, iterator_trait_id, &[]);
+ if let Some(item_ty) = get_iterator_item_ty(cx, parent_ty);
+ if let Some(receiver_snippet) = snippet_opt(cx, receiver.span);
+ then {
+ if unnecessary_iter_cloned::check_for_loop_iter(cx, parent, method_name, receiver) {
+ return true;
+ }
+ let cloned_or_copied = if is_copy(cx, item_ty) {
+ "copied"
+ } else {
+ "cloned"
+ };
+ span_lint_and_sugg(
+ cx,
+ UNNECESSARY_TO_OWNED,
+ parent.span,
+ &format!("unnecessary use of `{}`", method_name),
+ "use",
+ format!("{}.iter().{}()", receiver_snippet, cloned_or_copied),
+ Applicability::MachineApplicable,
+ );
+ return true;
+ }
+ }
+ false
+}
+
+/// Checks whether `expr` is an argument in a function call and, if so, determines whether its call
+/// of a `to_owned`-like function is unnecessary.
+fn check_other_call_arg(
+ cx: &LateContext<'tcx>,
+ expr: &'tcx Expr<'tcx>,
+ method_name: Symbol,
+ receiver: &'tcx Expr<'tcx>,
+) -> bool {
+ if_chain! {
+ if let Some((maybe_call, maybe_arg)) = skip_addr_of_ancestors(cx, expr);
+ if let Some((callee_def_id, call_substs, call_args)) = get_callee_substs_and_args(cx, maybe_call);
+ let fn_sig = cx.tcx.fn_sig(callee_def_id).skip_binder();
+ if let Some(i) = call_args.iter().position(|arg| arg.hir_id == maybe_arg.hir_id);
+ if let Some(input) = fn_sig.inputs().get(i);
+ let (input, n_refs) = peel_mid_ty_refs(input);
+ if let (trait_predicates, projection_predicates) = get_input_traits_and_projections(cx, callee_def_id, input);
+ if let Some(sized_def_id) = cx.tcx.lang_items().sized_trait();
+ if let [trait_predicate] = trait_predicates
+ .iter()
+ .filter(|trait_predicate| trait_predicate.def_id() != sized_def_id)
+ .collect::<Vec<_>>()[..];
+ if let Some(deref_trait_id) = cx.tcx.get_diagnostic_item(sym::Deref);
+ if let Some(as_ref_trait_id) = cx.tcx.get_diagnostic_item(sym::AsRef);
+ let receiver_ty = cx.typeck_results().expr_ty(receiver);
+ // If the callee has type parameters, they could appear in `projection_predicate.ty` or the
+ // types of `trait_predicate.trait_ref.substs`.
+ if if trait_predicate.def_id() == deref_trait_id {
+ if let [projection_predicate] = projection_predicates[..] {
+ let normalized_ty =
+ cx.tcx.subst_and_normalize_erasing_regions(call_substs, cx.param_env, projection_predicate.ty);
+ implements_trait(cx, receiver_ty, deref_trait_id, &[])
+ && get_associated_type(cx, receiver_ty, deref_trait_id, "Target") == Some(normalized_ty)
+ } else {
+ false
+ }
+ } else if trait_predicate.def_id() == as_ref_trait_id {
+ let composed_substs = compose_substs(
+ cx,
+ &trait_predicate.trait_ref.substs.iter().skip(1).collect::<Vec<_>>()[..],
+ call_substs
+ );
+ implements_trait(cx, receiver_ty, as_ref_trait_id, &composed_substs)
+ } else {
+ false
+ };
+ // We can't add an `&` when the trait is `Deref` because `Target = &T` won't match
+ // `Target = T`.
+ if n_refs > 0 || is_copy(cx, receiver_ty) || trait_predicate.def_id() != deref_trait_id;
+ let n_refs = max(n_refs, if is_copy(cx, receiver_ty) { 0 } else { 1 });
+ if let Some(receiver_snippet) = snippet_opt(cx, receiver.span);
+ then {
+ span_lint_and_sugg(
+ cx,
+ UNNECESSARY_TO_OWNED,
+ maybe_arg.span,
+ &format!("unnecessary use of `{}`", method_name),
+ "use",
+ format!("{:&>width$}{}", "", receiver_snippet, width = n_refs),
+ Applicability::MachineApplicable,
+ );
+ return true;
+ }
+ }
+ false
+}
+
+/// Walks an expression's ancestors until it finds a non-`AddrOf` expression. Returns the first such
+/// expression found (if any) along with the immediately prior expression.
+fn skip_addr_of_ancestors(
+ cx: &LateContext<'tcx>,
+ mut expr: &'tcx Expr<'tcx>,
+) -> Option<(&'tcx Expr<'tcx>, &'tcx Expr<'tcx>)> {
+ while let Some(parent) = get_parent_expr(cx, expr) {
+ if let ExprKind::AddrOf(BorrowKind::Ref, Mutability::Not, _) = parent.kind {
+ expr = parent;
+ } else {
+ return Some((parent, expr));
+ }
+ }
+ None
+}
+
+/// Checks whether an expression is a function or method call and, if so, returns its `DefId`,
+/// `Substs`, and arguments.
+fn get_callee_substs_and_args(
+ cx: &LateContext<'tcx>,
+ expr: &'tcx Expr<'tcx>,
+) -> Option<(DefId, SubstsRef<'tcx>, &'tcx [Expr<'tcx>])> {
+ if_chain! {
+ if let ExprKind::Call(callee, args) = expr.kind;
+ let callee_ty = cx.typeck_results().expr_ty(callee);
+ if let ty::FnDef(callee_def_id, _) = callee_ty.kind();
+ then {
+ let substs = cx.typeck_results().node_substs(callee.hir_id);
+ return Some((*callee_def_id, substs, args));
+ }
+ }
+ if_chain! {
+ if let ExprKind::MethodCall(_, _, args, _) = expr.kind;
+ if let Some(method_def_id) = cx.typeck_results().type_dependent_def_id(expr.hir_id);
+ then {
+ let substs = cx.typeck_results().node_substs(expr.hir_id);
+ return Some((method_def_id, substs, args));
+ }
+ }
+ None
+}
+
+/// Returns the `TraitPredicate`s and `ProjectionPredicate`s for a function's input type.
+fn get_input_traits_and_projections(
+ cx: &LateContext<'tcx>,
+ callee_def_id: DefId,
+ input: Ty<'tcx>,
+) -> (Vec<TraitPredicate<'tcx>>, Vec<ProjectionPredicate<'tcx>>) {
+ let mut trait_predicates = Vec::new();
+ let mut projection_predicates = Vec::new();
+ for (predicate, _) in cx.tcx.predicates_of(callee_def_id).predicates.iter() {
+ // `substs` should have 1 + n elements. The first is the type on the left hand side of an
+ // `as`. The remaining n are trait parameters.
+ let is_input_substs = |substs: SubstsRef<'tcx>| {
+ if_chain! {
+ if let Some(arg) = substs.iter().next();
+ if let GenericArgKind::Type(arg_ty) = arg.unpack();
+ if arg_ty == input;
+ then {
+ true
+ } else {
+ false
+ }
+ }
+ };
+ match predicate.kind().skip_binder() {
+ PredicateKind::Trait(trait_predicate) => {
+ if is_input_substs(trait_predicate.trait_ref.substs) {
+ trait_predicates.push(trait_predicate);
+ }
+ },
+ PredicateKind::Projection(projection_predicate) => {
+ if is_input_substs(projection_predicate.projection_ty.substs) {
+ projection_predicates.push(projection_predicate);
+ }
+ },
+ _ => {},
+ }
+ }
+ (trait_predicates, projection_predicates)
+}
+
+/// Composes two substitutions by applying the latter to the types of the former.
+fn compose_substs(cx: &LateContext<'tcx>, left: &[GenericArg<'tcx>], right: SubstsRef<'tcx>) -> Vec<GenericArg<'tcx>> {
+ left.iter()
+ .map(|arg| {
+ if let GenericArgKind::Type(arg_ty) = arg.unpack() {
+ let normalized_ty = cx.tcx.subst_and_normalize_erasing_regions(right, cx.param_env, arg_ty);
+ GenericArg::from(normalized_ty)
+ } else {
+ *arg
+ }
+ })
+ .collect()
+}
+
+/// Returns true if the named method is `Iterator::cloned` or `Iterator::copied`.
+fn is_cloned_or_copied(cx: &LateContext<'_>, method_name: Symbol, method_def_id: DefId) -> bool {
+ (method_name.as_str() == "cloned" || method_name.as_str() == "copied")
+ && is_diag_trait_item(cx, method_def_id, sym::Iterator)
+}
+
+/// Returns true if the named method can be used to convert the receiver to its "owned"
+/// representation.
+fn is_to_owned_like(cx: &LateContext<'_>, method_name: Symbol, method_def_id: DefId) -> bool {
+ is_clone_like(cx, &*method_name.as_str(), method_def_id)
+ || is_cow_into_owned(cx, method_name, method_def_id)
+ || is_to_string(cx, method_name, method_def_id)
+}
+
+/// Returns true if the named method is `Cow::into_owned`.
+fn is_cow_into_owned(cx: &LateContext<'_>, method_name: Symbol, method_def_id: DefId) -> bool {
+ method_name.as_str() == "into_owned" && is_diag_item_method(cx, method_def_id, sym::Cow)
+}
+
+/// Returns true if the named method is `ToString::to_string`.
+fn is_to_string(cx: &LateContext<'_>, method_name: Symbol, method_def_id: DefId) -> bool {
+ method_name.as_str() == "to_string" && is_diag_trait_item(cx, method_def_id, sym::ToString)
+}
diff --git a/src/tools/clippy/clippy_lints/src/methods/utils.rs b/src/tools/clippy/clippy_lints/src/methods/utils.rs
index ba2ce73a116..11ad881ee7b 100644
--- a/src/tools/clippy/clippy_lints/src/methods/utils.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/utils.rs
@@ -66,7 +66,13 @@ pub(super) fn get_hint_if_single_char_arg(
// for regular string: "a"
&snip[1..(snip.len() - 1)]
};
- let hint = format!("'{}'", if ch == "'" { "\\'" } else { ch });
+
+ let hint = format!("'{}'", match ch {
+ "'" => "\\'" ,
+ r"\" => "\\\\",
+ _ => ch,
+ });
+
Some(hint)
} else {
None
diff --git a/src/tools/clippy/clippy_lints/src/minmax.rs b/src/tools/clippy/clippy_lints/src/minmax.rs
index dc2dd45e4ed..a6450aec4f7 100644
--- a/src/tools/clippy/clippy_lints/src/minmax.rs
+++ b/src/tools/clippy/clippy_lints/src/minmax.rs
@@ -26,6 +26,7 @@ declare_clippy_lint! {
/// ```
/// It will always be equal to `0`. Probably the author meant to clamp the value
/// between 0 and 100, but has erroneously swapped `min` and `max`.
+ #[clippy::version = "pre 1.29.0"]
pub MIN_MAX,
correctness,
"`min(_, max(_, _))` (or vice versa) with bounds clamping the result to a constant"
diff --git a/src/tools/clippy/clippy_lints/src/misc.rs b/src/tools/clippy/clippy_lints/src/misc.rs
index 78183add9cc..2299a099910 100644
--- a/src/tools/clippy/clippy_lints/src/misc.rs
+++ b/src/tools/clippy/clippy_lints/src/misc.rs
@@ -56,6 +56,7 @@ declare_clippy_lint! {
/// true
/// }
/// ```
+ #[clippy::version = "pre 1.29.0"]
pub TOPLEVEL_REF_ARG,
style,
"an entire binding declared as `ref`, in a function argument or a `let` statement"
@@ -79,6 +80,7 @@ declare_clippy_lint! {
/// // Good
/// if x.is_nan() { }
/// ```
+ #[clippy::version = "pre 1.29.0"]
pub CMP_NAN,
correctness,
"comparisons to `NAN`, which will always return false, probably not intended"
@@ -112,6 +114,7 @@ declare_clippy_lint! {
/// if (y - 1.23f64).abs() < error_margin { }
/// if (y - x).abs() > error_margin { }
/// ```
+ #[clippy::version = "pre 1.29.0"]
pub FLOAT_CMP,
pedantic,
"using `==` or `!=` on float values instead of comparing difference with an epsilon"
@@ -139,6 +142,7 @@ declare_clippy_lint! {
/// # let y = String::from("foo");
/// if x == y {}
/// ```
+ #[clippy::version = "pre 1.29.0"]
pub CMP_OWNED,
perf,
"creating owned instances for comparing with others, e.g., `x == \"foo\".to_string()`"
@@ -162,6 +166,7 @@ declare_clippy_lint! {
/// let a = x % 1;
/// let a = x % -1;
/// ```
+ #[clippy::version = "pre 1.29.0"]
pub MODULO_ONE,
correctness,
"taking a number modulo +/-1, which can either panic/overflow or always returns 0"
@@ -187,6 +192,7 @@ declare_clippy_lint! {
/// let y = _x + 1; // Here we are using `_x`, even though it has a leading
/// // underscore. We should rename `_x` to `x`
/// ```
+ #[clippy::version = "pre 1.29.0"]
pub USED_UNDERSCORE_BINDING,
pedantic,
"using a binding which is prefixed with an underscore"
@@ -207,6 +213,7 @@ declare_clippy_lint! {
/// ```rust,ignore
/// f() && g(); // We should write `if f() { g(); }`.
/// ```
+ #[clippy::version = "pre 1.29.0"]
pub SHORT_CIRCUIT_STATEMENT,
complexity,
"using a short circuit boolean condition as a statement"
@@ -228,6 +235,7 @@ declare_clippy_lint! {
/// // Good
/// let a = std::ptr::null::<u32>();
/// ```
+ #[clippy::version = "pre 1.29.0"]
pub ZERO_PTR,
style,
"using `0 as *{const, mut} T`"
@@ -259,6 +267,7 @@ declare_clippy_lint! {
/// // let error_margin = std::f64::EPSILON;
/// if (x - ONE).abs() < error_margin { }
/// ```
+ #[clippy::version = "pre 1.29.0"]
pub FLOAT_CMP_CONST,
restriction,
"using `==` or `!=` on float constants instead of comparing difference with an epsilon"
diff --git a/src/tools/clippy/clippy_lints/src/misc_early/mod.rs b/src/tools/clippy/clippy_lints/src/misc_early/mod.rs
index 7c3f5f22ade..6e09e25109f 100644
--- a/src/tools/clippy/clippy_lints/src/misc_early/mod.rs
+++ b/src/tools/clippy/clippy_lints/src/misc_early/mod.rs
@@ -46,6 +46,7 @@ declare_clippy_lint! {
/// Foo { .. } => {},
/// }
/// ```
+ #[clippy::version = "pre 1.29.0"]
pub UNNEEDED_FIELD_PATTERN,
restriction,
"struct fields bound to a wildcard instead of using `..`"
@@ -67,6 +68,7 @@ declare_clippy_lint! {
/// // Good
/// fn bar(a: i32, _b: i32) {}
/// ```
+ #[clippy::version = "pre 1.29.0"]
pub DUPLICATE_UNDERSCORE_ARGUMENT,
style,
"function arguments having names which only differ by an underscore"
@@ -85,6 +87,7 @@ declare_clippy_lint! {
/// let mut x = 3;
/// --x;
/// ```
+ #[clippy::version = "pre 1.29.0"]
pub DOUBLE_NEG,
style,
"`--x`, which is a double negation of `x` and not a pre-decrement as in C/C++"
@@ -106,6 +109,7 @@ declare_clippy_lint! {
/// // Good
/// let y = 0x1A9BACD;
/// ```
+ #[clippy::version = "pre 1.29.0"]
pub MIXED_CASE_HEX_LITERALS,
style,
"hex literals whose letter digits are not consistently upper- or lowercased"
@@ -129,6 +133,7 @@ declare_clippy_lint! {
/// // Good
/// let y = 123832_i32;
/// ```
+ #[clippy::version = "pre 1.29.0"]
pub UNSEPARATED_LITERAL_SUFFIX,
restriction,
"literals whose suffix is not separated by an underscore"
@@ -151,6 +156,7 @@ declare_clippy_lint! {
/// // Good
/// let y = 123832i32;
/// ```
+ #[clippy::version = "1.58.0"]
pub SEPARATED_LITERAL_SUFFIX,
restriction,
"literals whose suffix is separated by an underscore"
@@ -189,6 +195,7 @@ declare_clippy_lint! {
/// ```
///
/// prints `83` (as `83 == 0o123` while `123 == 0o173`).
+ #[clippy::version = "pre 1.29.0"]
pub ZERO_PREFIXED_LITERAL,
complexity,
"integer literals starting with `0`"
@@ -210,6 +217,7 @@ declare_clippy_lint! {
/// }
/// }
/// ```
+ #[clippy::version = "pre 1.29.0"]
pub BUILTIN_TYPE_SHADOW,
style,
"shadowing a builtin type"
@@ -239,6 +247,7 @@ declare_clippy_lint! {
/// y => (),
/// }
/// ```
+ #[clippy::version = "pre 1.29.0"]
pub REDUNDANT_PATTERN,
style,
"using `name @ _` in a pattern"
@@ -273,6 +282,7 @@ declare_clippy_lint! {
/// _ => (),
/// }
/// ```
+ #[clippy::version = "1.40.0"]
pub UNNEEDED_WILDCARD_PATTERN,
complexity,
"tuple patterns with a wildcard pattern (`_`) is next to a rest pattern (`..`)"
diff --git a/src/tools/clippy/clippy_lints/src/missing_const_for_fn.rs b/src/tools/clippy/clippy_lints/src/missing_const_for_fn.rs
index 5b2584d43a1..a8d41050856 100644
--- a/src/tools/clippy/clippy_lints/src/missing_const_for_fn.rs
+++ b/src/tools/clippy/clippy_lints/src/missing_const_for_fn.rs
@@ -63,6 +63,7 @@ declare_clippy_lint! {
/// }
/// # }
/// ```
+ #[clippy::version = "1.34.0"]
pub MISSING_CONST_FOR_FN,
nursery,
"Lint functions definitions that could be made `const fn`"
diff --git a/src/tools/clippy/clippy_lints/src/missing_doc.rs b/src/tools/clippy/clippy_lints/src/missing_doc.rs
index 564f021268c..fc0483a929a 100644
--- a/src/tools/clippy/clippy_lints/src/missing_doc.rs
+++ b/src/tools/clippy/clippy_lints/src/missing_doc.rs
@@ -26,6 +26,7 @@ declare_clippy_lint! {
/// allowed-by-default lint for
/// public members, but has no way to enforce documentation of private items.
/// This lint fixes that.
+ #[clippy::version = "pre 1.29.0"]
pub MISSING_DOCS_IN_PRIVATE_ITEMS,
restriction,
"detects missing documentation for public and private members"
diff --git a/src/tools/clippy/clippy_lints/src/missing_enforced_import_rename.rs b/src/tools/clippy/clippy_lints/src/missing_enforced_import_rename.rs
index 448bfc2fdd6..68d49e0f150 100644
--- a/src/tools/clippy/clippy_lints/src/missing_enforced_import_rename.rs
+++ b/src/tools/clippy/clippy_lints/src/missing_enforced_import_rename.rs
@@ -33,6 +33,7 @@ declare_clippy_lint! {
/// ```rust,ignore
/// use serde_json::Value as JsonValue;
/// ```
+ #[clippy::version = "1.55.0"]
pub MISSING_ENFORCED_IMPORT_RENAMES,
restriction,
"enforce import renames"
diff --git a/src/tools/clippy/clippy_lints/src/missing_inline.rs b/src/tools/clippy/clippy_lints/src/missing_inline.rs
index b593c747498..ac2f16b49e3 100644
--- a/src/tools/clippy/clippy_lints/src/missing_inline.rs
+++ b/src/tools/clippy/clippy_lints/src/missing_inline.rs
@@ -52,6 +52,7 @@ declare_clippy_lint! {
/// fn def_bar() {} // missing #[inline]
/// }
/// ```
+ #[clippy::version = "pre 1.29.0"]
pub MISSING_INLINE_IN_PUBLIC_ITEMS,
restriction,
"detects missing `#[inline]` attribute for public callables (functions, trait methods, methods...)"
diff --git a/src/tools/clippy/clippy_lints/src/module_style.rs b/src/tools/clippy/clippy_lints/src/module_style.rs
index d41b5474564..3b65f80cba2 100644
--- a/src/tools/clippy/clippy_lints/src/module_style.rs
+++ b/src/tools/clippy/clippy_lints/src/module_style.rs
@@ -32,6 +32,7 @@ declare_clippy_lint! {
/// stuff.rs
/// lib.rs
/// ```
+ #[clippy::version = "1.57.0"]
pub MOD_MODULE_FILES,
restriction,
"checks that module layout is consistent"
@@ -61,6 +62,7 @@ declare_clippy_lint! {
/// lib.rs
/// ```
+ #[clippy::version = "1.57.0"]
pub SELF_NAMED_MODULE_FILES,
restriction,
"checks that module layout is consistent"
diff --git a/src/tools/clippy/clippy_lints/src/modulo_arithmetic.rs b/src/tools/clippy/clippy_lints/src/modulo_arithmetic.rs
index f45e68233a1..d182a7d5249 100644
--- a/src/tools/clippy/clippy_lints/src/modulo_arithmetic.rs
+++ b/src/tools/clippy/clippy_lints/src/modulo_arithmetic.rs
@@ -24,6 +24,7 @@ declare_clippy_lint! {
/// ```rust
/// let x = -17 % 3;
/// ```
+ #[clippy::version = "1.42.0"]
pub MODULO_ARITHMETIC,
restriction,
"any modulo arithmetic statement"
diff --git a/src/tools/clippy/clippy_lints/src/multiple_crate_versions.rs b/src/tools/clippy/clippy_lints/src/multiple_crate_versions.rs
index 816b2f275fb..e45cc86d417 100644
--- a/src/tools/clippy/clippy_lints/src/multiple_crate_versions.rs
+++ b/src/tools/clippy/clippy_lints/src/multiple_crate_versions.rs
@@ -33,6 +33,7 @@ declare_clippy_lint! {
/// ctrlc = "=3.1.0"
/// ansi_term = "=0.11.0"
/// ```
+ #[clippy::version = "pre 1.29.0"]
pub MULTIPLE_CRATE_VERSIONS,
cargo,
"multiple versions of the same crate being used"
diff --git a/src/tools/clippy/clippy_lints/src/mut_key.rs b/src/tools/clippy/clippy_lints/src/mut_key.rs
index 8476257f086..5fe887a4573 100644
--- a/src/tools/clippy/clippy_lints/src/mut_key.rs
+++ b/src/tools/clippy/clippy_lints/src/mut_key.rs
@@ -72,6 +72,7 @@ declare_clippy_lint! {
/// let _: HashSet<Bad> = HashSet::new();
/// }
/// ```
+ #[clippy::version = "1.42.0"]
pub MUTABLE_KEY_TYPE,
suspicious,
"Check for mutable `Map`/`Set` key type"
diff --git a/src/tools/clippy/clippy_lints/src/mut_mut.rs b/src/tools/clippy/clippy_lints/src/mut_mut.rs
index 7c4cac29ba8..bcbea8f1e66 100644
--- a/src/tools/clippy/clippy_lints/src/mut_mut.rs
+++ b/src/tools/clippy/clippy_lints/src/mut_mut.rs
@@ -22,6 +22,7 @@ declare_clippy_lint! {
/// # let mut y = 1;
/// let x = &mut &mut y;
/// ```
+ #[clippy::version = "pre 1.29.0"]
pub MUT_MUT,
pedantic,
"usage of double-mut refs, e.g., `&mut &mut ...`"
diff --git a/src/tools/clippy/clippy_lints/src/mut_mutex_lock.rs b/src/tools/clippy/clippy_lints/src/mut_mutex_lock.rs
index b96fa4774cb..b1e6308d2e1 100644
--- a/src/tools/clippy/clippy_lints/src/mut_mutex_lock.rs
+++ b/src/tools/clippy/clippy_lints/src/mut_mutex_lock.rs
@@ -38,6 +38,7 @@ declare_clippy_lint! {
/// let value = value_mutex.get_mut().unwrap();
/// *value += 1;
/// ```
+ #[clippy::version = "1.49.0"]
pub MUT_MUTEX_LOCK,
style,
"`&mut Mutex::lock` does unnecessary locking"
diff --git a/src/tools/clippy/clippy_lints/src/mut_reference.rs b/src/tools/clippy/clippy_lints/src/mut_reference.rs
index 8d5d7951fc5..63a1cf7b7d5 100644
--- a/src/tools/clippy/clippy_lints/src/mut_reference.rs
+++ b/src/tools/clippy/clippy_lints/src/mut_reference.rs
@@ -23,6 +23,7 @@ declare_clippy_lint! {
/// // Good
/// my_vec.push(&value)
/// ```
+ #[clippy::version = "pre 1.29.0"]
pub UNNECESSARY_MUT_PASSED,
style,
"an argument passed as a mutable reference although the callee only demands an immutable reference"
diff --git a/src/tools/clippy/clippy_lints/src/mutable_debug_assertion.rs b/src/tools/clippy/clippy_lints/src/mutable_debug_assertion.rs
index 9b44cf9d43a..12e219cd5c8 100644
--- a/src/tools/clippy/clippy_lints/src/mutable_debug_assertion.rs
+++ b/src/tools/clippy/clippy_lints/src/mutable_debug_assertion.rs
@@ -26,6 +26,7 @@ declare_clippy_lint! {
/// fn take_a_mut_parameter(_: &mut u32) -> bool { unimplemented!() }
/// debug_assert!(take_a_mut_parameter(&mut 5));
/// ```
+ #[clippy::version = "1.40.0"]
pub DEBUG_ASSERT_WITH_MUT_CALL,
nursery,
"mutable arguments in `debug_assert{,_ne,_eq}!`"
diff --git a/src/tools/clippy/clippy_lints/src/mutex_atomic.rs b/src/tools/clippy/clippy_lints/src/mutex_atomic.rs
index 5feddcbfc61..816377fe65e 100644
--- a/src/tools/clippy/clippy_lints/src/mutex_atomic.rs
+++ b/src/tools/clippy/clippy_lints/src/mutex_atomic.rs
@@ -36,6 +36,7 @@ declare_clippy_lint! {
/// # use std::sync::atomic::AtomicBool;
/// let x = AtomicBool::new(y);
/// ```
+ #[clippy::version = "pre 1.29.0"]
pub MUTEX_ATOMIC,
perf,
"using a mutex where an atomic value could be used instead"
@@ -64,6 +65,7 @@ declare_clippy_lint! {
/// # use std::sync::atomic::AtomicUsize;
/// let x = AtomicUsize::new(0usize);
/// ```
+ #[clippy::version = "pre 1.29.0"]
pub MUTEX_INTEGER,
nursery,
"using a mutex for an integer type"
diff --git a/src/tools/clippy/clippy_lints/src/needless_arbitrary_self_type.rs b/src/tools/clippy/clippy_lints/src/needless_arbitrary_self_type.rs
index 9a3d9383cd9..9838d3cad9f 100644
--- a/src/tools/clippy/clippy_lints/src/needless_arbitrary_self_type.rs
+++ b/src/tools/clippy/clippy_lints/src/needless_arbitrary_self_type.rs
@@ -1,5 +1,4 @@
use clippy_utils::diagnostics::span_lint_and_sugg;
-use clippy_utils::in_macro;
use if_chain::if_chain;
use rustc_ast::ast::{BindingMode, Lifetime, Mutability, Param, PatKind, Path, TyKind};
use rustc_errors::Applicability;
@@ -53,6 +52,7 @@ declare_clippy_lint! {
/// }
/// }
/// ```
+ #[clippy::version = "1.47.0"]
pub NEEDLESS_ARBITRARY_SELF_TYPE,
complexity,
"type of `self` parameter is already by default `Self`"
@@ -78,7 +78,7 @@ fn check_param_inner(cx: &EarlyContext<'_>, path: &Path, span: Span, binding_mod
let self_param = match (binding_mode, mutbl) {
(Mode::Ref(None), Mutability::Mut) => "&mut self".to_string(),
(Mode::Ref(Some(lifetime)), Mutability::Mut) => {
- if in_macro(lifetime.ident.span) {
+ if lifetime.ident.span.from_expansion() {
applicability = Applicability::HasPlaceholders;
"&'_ mut self".to_string()
} else {
@@ -87,7 +87,7 @@ fn check_param_inner(cx: &EarlyContext<'_>, path: &Path, span: Span, binding_mod
},
(Mode::Ref(None), Mutability::Not) => "&self".to_string(),
(Mode::Ref(Some(lifetime)), Mutability::Not) => {
- if in_macro(lifetime.ident.span) {
+ if lifetime.ident.span.from_expansion() {
applicability = Applicability::HasPlaceholders;
"&'_ self".to_string()
} else {
@@ -114,7 +114,7 @@ fn check_param_inner(cx: &EarlyContext<'_>, path: &Path, span: Span, binding_mod
impl EarlyLintPass for NeedlessArbitrarySelfType {
fn check_param(&mut self, cx: &EarlyContext<'_>, p: &Param) {
// Bail out if the parameter it's not a receiver or was not written by the user
- if !p.is_self() || in_macro(p.span) {
+ if !p.is_self() || p.span.from_expansion() {
return;
}
diff --git a/src/tools/clippy/clippy_lints/src/needless_bitwise_bool.rs b/src/tools/clippy/clippy_lints/src/needless_bitwise_bool.rs
index 203da29cb91..a8a8d174a82 100644
--- a/src/tools/clippy/clippy_lints/src/needless_bitwise_bool.rs
+++ b/src/tools/clippy/clippy_lints/src/needless_bitwise_bool.rs
@@ -1,5 +1,4 @@
use clippy_utils::diagnostics::span_lint_and_then;
-use clippy_utils::in_macro;
use clippy_utils::source::snippet_opt;
use if_chain::if_chain;
use rustc_errors::Applicability;
@@ -31,6 +30,7 @@ declare_clippy_lint! {
/// let (x,y) = (true, false);
/// if x && !y {}
/// ```
+ #[clippy::version = "1.54.0"]
pub NEEDLESS_BITWISE_BOOL,
pedantic,
"Boolean expressions that use bitwise rather than lazy operators"
@@ -41,7 +41,7 @@ declare_lint_pass!(NeedlessBitwiseBool => [NEEDLESS_BITWISE_BOOL]);
fn is_bitwise_operation(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool {
let ty = cx.typeck_results().expr_ty(expr);
if_chain! {
- if !in_macro(expr.span);
+ if !expr.span.from_expansion();
if let (&ExprKind::Binary(ref op, _, right), &ty::Bool) = (&expr.kind, &ty.kind());
if op.node == BinOpKind::BitAnd || op.node == BinOpKind::BitOr;
if let ExprKind::Call(..) | ExprKind::MethodCall(..) | ExprKind::Binary(..) | ExprKind::Unary(..) = right.kind;
diff --git a/src/tools/clippy/clippy_lints/src/needless_bool.rs b/src/tools/clippy/clippy_lints/src/needless_bool.rs
index 91944653500..d391fbecf82 100644
--- a/src/tools/clippy/clippy_lints/src/needless_bool.rs
+++ b/src/tools/clippy/clippy_lints/src/needless_bool.rs
@@ -6,10 +6,10 @@ use clippy_utils::diagnostics::{span_lint, span_lint_and_sugg};
use clippy_utils::higher;
use clippy_utils::source::snippet_with_applicability;
use clippy_utils::sugg::Sugg;
-use clippy_utils::{is_else_clause, is_expn_of};
+use clippy_utils::{get_parent_node, is_else_clause, is_expn_of, peel_blocks, peel_blocks_with_stmt};
use rustc_ast::ast::LitKind;
use rustc_errors::Applicability;
-use rustc_hir::{BinOpKind, Block, Expr, ExprKind, StmtKind, UnOp};
+use rustc_hir::{BinOpKind, Block, Expr, ExprKind, HirId, Node, UnOp};
use rustc_lint::{LateContext, LateLintPass};
use rustc_session::{declare_lint_pass, declare_tool_lint};
use rustc_span::source_map::Spanned;
@@ -41,6 +41,7 @@ declare_clippy_lint! {
/// ```rust,ignore
/// !x
/// ```
+ #[clippy::version = "pre 1.29.0"]
pub NEEDLESS_BOOL,
complexity,
"if-statements with plain booleans in the then- and else-clause, e.g., `if p { true } else { false }`"
@@ -65,6 +66,7 @@ declare_clippy_lint! {
/// if x {}
/// if !y {}
/// ```
+ #[clippy::version = "pre 1.29.0"]
pub BOOL_COMPARISON,
complexity,
"comparing a variable to a boolean, e.g., `if x == true` or `if x != true`"
@@ -72,6 +74,36 @@ declare_clippy_lint! {
declare_lint_pass!(NeedlessBool => [NEEDLESS_BOOL]);
+fn condition_needs_parentheses(e: &Expr<'_>) -> bool {
+ let mut inner = e;
+ while let ExprKind::Binary(_, i, _)
+ | ExprKind::Call(i, _)
+ | ExprKind::Cast(i, _)
+ | ExprKind::Type(i, _)
+ | ExprKind::Index(i, _) = inner.kind
+ {
+ if matches!(
+ i.kind,
+ ExprKind::Block(..)
+ | ExprKind::ConstBlock(..)
+ | ExprKind::If(..)
+ | ExprKind::Loop(..)
+ | ExprKind::Match(..)
+ ) {
+ return true;
+ }
+ inner = i;
+ }
+ false
+}
+
+fn is_parent_stmt(cx: &LateContext<'_>, id: HirId) -> bool {
+ matches!(
+ get_parent_node(cx.tcx, id),
+ Some(Node::Stmt(..) | Node::Block(Block { stmts: &[], .. }))
+ )
+}
+
impl<'tcx> LateLintPass<'tcx> for NeedlessBool {
fn check_expr(&mut self, cx: &LateContext<'tcx>, e: &'tcx Expr<'_>) {
use self::Expression::{Bool, RetBool};
@@ -97,6 +129,10 @@ impl<'tcx> LateLintPass<'tcx> for NeedlessBool {
snip = snip.blockify();
}
+ if condition_needs_parentheses(cond) && is_parent_stmt(cx, e.hir_id) {
+ snip = snip.maybe_par();
+ }
+
span_lint_and_sugg(
cx,
NEEDLESS_BOOL,
@@ -107,8 +143,8 @@ impl<'tcx> LateLintPass<'tcx> for NeedlessBool {
applicability,
);
};
- if let ExprKind::Block(then, _) = then.kind {
- match (fetch_bool_block(then), fetch_bool_expr(r#else)) {
+ if let Some((a, b)) = fetch_bool_block(then).and_then(|a| Some((a, fetch_bool_block(r#else)?))) {
+ match (a, b) {
(RetBool(true), RetBool(true)) | (Bool(true), Bool(true)) => {
span_lint(
cx,
@@ -131,8 +167,6 @@ impl<'tcx> LateLintPass<'tcx> for NeedlessBool {
(Bool(false), Bool(true)) => reduce(false, true),
_ => (),
}
- } else {
- panic!("IfExpr `then` node is not an `ExprKind::Block`");
}
}
}
@@ -235,8 +269,6 @@ fn check_comparison<'a, 'tcx>(
right_false: Option<(impl FnOnce(Sugg<'a>) -> Sugg<'a>, &str)>,
no_literal: Option<(impl FnOnce(Sugg<'a>, Sugg<'a>) -> Sugg<'a>, &str)>,
) {
- use self::Expression::{Bool, Other};
-
if let ExprKind::Binary(op, left_side, right_side) = e.kind {
let (l_ty, r_ty) = (
cx.typeck_results().expr_ty(left_side),
@@ -268,19 +300,19 @@ fn check_comparison<'a, 'tcx>(
}
match (fetch_bool_expr(left_side), fetch_bool_expr(right_side)) {
- (Bool(true), Other) => left_true.map_or((), |(h, m)| {
+ (Some(true), None) => left_true.map_or((), |(h, m)| {
suggest_bool_comparison(cx, e, right_side, applicability, m, h);
}),
- (Other, Bool(true)) => right_true.map_or((), |(h, m)| {
+ (None, Some(true)) => right_true.map_or((), |(h, m)| {
suggest_bool_comparison(cx, e, left_side, applicability, m, h);
}),
- (Bool(false), Other) => left_false.map_or((), |(h, m)| {
+ (Some(false), None) => left_false.map_or((), |(h, m)| {
suggest_bool_comparison(cx, e, right_side, applicability, m, h);
}),
- (Other, Bool(false)) => right_false.map_or((), |(h, m)| {
+ (None, Some(false)) => right_false.map_or((), |(h, m)| {
suggest_bool_comparison(cx, e, left_side, applicability, m, h);
}),
- (Other, Other) => no_literal.map_or((), |(h, m)| {
+ (None, None) => no_literal.map_or((), |(h, m)| {
let left_side = Sugg::hir_with_applicability(cx, left_side, "..", &mut applicability);
let right_side = Sugg::hir_with_applicability(cx, right_side, "..", &mut applicability);
span_lint_and_sugg(
@@ -329,41 +361,20 @@ fn suggest_bool_comparison<'a, 'tcx>(
enum Expression {
Bool(bool),
RetBool(bool),
- Other,
}
-fn fetch_bool_block(block: &Block<'_>) -> Expression {
- match (&*block.stmts, block.expr.as_ref()) {
- (&[], Some(e)) => fetch_bool_expr(&**e),
- (&[ref e], None) => {
- if let StmtKind::Semi(e) = e.kind {
- if let ExprKind::Ret(_) = e.kind {
- fetch_bool_expr(e)
- } else {
- Expression::Other
- }
- } else {
- Expression::Other
- }
- },
- _ => Expression::Other,
+fn fetch_bool_block(expr: &Expr<'_>) -> Option<Expression> {
+ match peel_blocks_with_stmt(expr).kind {
+ ExprKind::Ret(Some(ret)) => Some(Expression::RetBool(fetch_bool_expr(ret)?)),
+ _ => Some(Expression::Bool(fetch_bool_expr(expr)?)),
}
}
-fn fetch_bool_expr(expr: &Expr<'_>) -> Expression {
- match expr.kind {
- ExprKind::Block(block, _) => fetch_bool_block(block),
- ExprKind::Lit(ref lit_ptr) => {
- if let LitKind::Bool(value) = lit_ptr.node {
- Expression::Bool(value)
- } else {
- Expression::Other
- }
- },
- ExprKind::Ret(Some(expr)) => match fetch_bool_expr(expr) {
- Expression::Bool(value) => Expression::RetBool(value),
- _ => Expression::Other,
- },
- _ => Expression::Other,
+fn fetch_bool_expr(expr: &Expr<'_>) -> Option<bool> {
+ if let ExprKind::Lit(ref lit_ptr) = peel_blocks(expr).kind {
+ if let LitKind::Bool(value) = lit_ptr.node {
+ return Some(value);
+ }
}
+ None
}
diff --git a/src/tools/clippy/clippy_lints/src/needless_borrow.rs b/src/tools/clippy/clippy_lints/src/needless_borrow.rs
deleted file mode 100644
index f1be90c44f9..00000000000
--- a/src/tools/clippy/clippy_lints/src/needless_borrow.rs
+++ /dev/null
@@ -1,282 +0,0 @@
-//! Checks for needless address of operations (`&`)
-//!
-//! This lint is **warn** by default
-
-use clippy_utils::diagnostics::span_lint_and_then;
-use clippy_utils::source::{snippet_opt, snippet_with_applicability, snippet_with_context};
-use clippy_utils::{get_parent_expr, in_macro, path_to_local};
-use if_chain::if_chain;
-use rustc_ast::util::parser::PREC_POSTFIX;
-use rustc_data_structures::fx::FxIndexMap;
-use rustc_errors::Applicability;
-use rustc_hir::{BindingAnnotation, Body, BodyId, BorrowKind, Expr, ExprKind, HirId, Mutability, Pat, PatKind, UnOp};
-use rustc_lint::{LateContext, LateLintPass};
-use rustc_middle::ty;
-use rustc_middle::ty::adjustment::{Adjust, Adjustment};
-use rustc_session::{declare_tool_lint, impl_lint_pass};
-use rustc_span::Span;
-
-declare_clippy_lint! {
- /// ### What it does
- /// Checks for address of operations (`&`) that are going to
- /// be dereferenced immediately by the compiler.
- ///
- /// ### Why is this bad?
- /// Suggests that the receiver of the expression borrows
- /// the expression.
- ///
- /// ### Example
- /// ```rust
- /// fn fun(_a: &i32) {}
- ///
- /// // Bad
- /// let x: &i32 = &&&&&&5;
- /// fun(&x);
- ///
- /// // Good
- /// let x: &i32 = &5;
- /// fun(x);
- /// ```
- pub NEEDLESS_BORROW,
- style,
- "taking a reference that is going to be automatically dereferenced"
-}
-
-declare_clippy_lint! {
- /// ### What it does
- /// Checks for `ref` bindings which create a reference to a reference.
- ///
- /// ### Why is this bad?
- /// The address-of operator at the use site is clearer about the need for a reference.
- ///
- /// ### Example
- /// ```rust
- /// // Bad
- /// let x = Some("");
- /// if let Some(ref x) = x {
- /// // use `x` here
- /// }
- ///
- /// // Good
- /// let x = Some("");
- /// if let Some(x) = x {
- /// // use `&x` here
- /// }
- /// ```
- pub REF_BINDING_TO_REFERENCE,
- pedantic,
- "`ref` binding to a reference"
-}
-
-impl_lint_pass!(NeedlessBorrow => [NEEDLESS_BORROW, REF_BINDING_TO_REFERENCE]);
-#[derive(Default)]
-pub struct NeedlessBorrow {
- /// The body the first local was found in. Used to emit lints when the traversal of the body has
- /// been finished. Note we can't lint at the end of every body as they can be nested within each
- /// other.
- current_body: Option<BodyId>,
- /// The list of locals currently being checked by the lint.
- /// If the value is `None`, then the binding has been seen as a ref pattern, but is not linted.
- /// This is needed for or patterns where one of the branches can be linted, but another can not
- /// be.
- ///
- /// e.g. `m!(x) | Foo::Bar(ref x)`
- ref_locals: FxIndexMap<HirId, Option<RefPat>>,
-}
-
-struct RefPat {
- /// Whether every usage of the binding is dereferenced.
- always_deref: bool,
- /// The spans of all the ref bindings for this local.
- spans: Vec<Span>,
- /// The applicability of this suggestion.
- app: Applicability,
- /// All the replacements which need to be made.
- replacements: Vec<(Span, String)>,
-}
-
-impl<'tcx> LateLintPass<'tcx> for NeedlessBorrow {
- fn check_expr(&mut self, cx: &LateContext<'tcx>, e: &'tcx Expr<'_>) {
- if let Some(local) = path_to_local(e) {
- self.check_local_usage(cx, e, local);
- }
-
- if e.span.from_expansion() {
- return;
- }
- if let ExprKind::AddrOf(BorrowKind::Ref, mutability, inner) = e.kind {
- if let ty::Ref(_, ty, _) = cx.typeck_results().expr_ty(inner).kind() {
- for adj3 in cx.typeck_results().expr_adjustments(e).windows(3) {
- if let [
- Adjustment {
- kind: Adjust::Deref(_), ..
- },
- Adjustment {
- kind: Adjust::Deref(_), ..
- },
- Adjustment {
- kind: Adjust::Borrow(_),
- ..
- },
- ] = *adj3
- {
- let help_msg_ty = if matches!(mutability, Mutability::Not) {
- format!("&{}", ty)
- } else {
- format!("&mut {}", ty)
- };
-
- span_lint_and_then(
- cx,
- NEEDLESS_BORROW,
- e.span,
- &format!(
- "this expression borrows a reference (`{}`) that is immediately dereferenced \
- by the compiler",
- help_msg_ty
- ),
- |diag| {
- if let Some(snippet) = snippet_opt(cx, inner.span) {
- diag.span_suggestion(
- e.span,
- "change this to",
- snippet,
- Applicability::MachineApplicable,
- );
- }
- },
- );
- }
- }
- }
- }
- }
-
- fn check_pat(&mut self, cx: &LateContext<'tcx>, pat: &'tcx Pat<'_>) {
- if let PatKind::Binding(BindingAnnotation::Ref, id, name, _) = pat.kind {
- if let Some(opt_prev_pat) = self.ref_locals.get_mut(&id) {
- // This binding id has been seen before. Add this pattern to the list of changes.
- if let Some(prev_pat) = opt_prev_pat {
- if in_macro(pat.span) {
- // Doesn't match the context of the previous pattern. Can't lint here.
- *opt_prev_pat = None;
- } else {
- prev_pat.spans.push(pat.span);
- prev_pat.replacements.push((
- pat.span,
- snippet_with_context(cx, name.span, pat.span.ctxt(), "..", &mut prev_pat.app)
- .0
- .into(),
- ));
- }
- }
- return;
- }
-
- if_chain! {
- if !in_macro(pat.span);
- if let ty::Ref(_, tam, _) = *cx.typeck_results().pat_ty(pat).kind();
- // only lint immutable refs, because borrowed `&mut T` cannot be moved out
- if let ty::Ref(_, _, Mutability::Not) = *tam.kind();
- then {
- let mut app = Applicability::MachineApplicable;
- let snip = snippet_with_context(cx, name.span, pat.span.ctxt(), "..", &mut app).0;
- self.current_body = self.current_body.or(cx.enclosing_body);
- self.ref_locals.insert(
- id,
- Some(RefPat {
- always_deref: true,
- spans: vec![pat.span],
- app,
- replacements: vec![(pat.span, snip.into())],
- }),
- );
- }
- }
- }
- }
-
- fn check_body_post(&mut self, cx: &LateContext<'tcx>, body: &'tcx Body<'_>) {
- if Some(body.id()) == self.current_body {
- for pat in self.ref_locals.drain(..).filter_map(|(_, x)| x) {
- let replacements = pat.replacements;
- let app = pat.app;
- span_lint_and_then(
- cx,
- if pat.always_deref {
- NEEDLESS_BORROW
- } else {
- REF_BINDING_TO_REFERENCE
- },
- pat.spans,
- "this pattern creates a reference to a reference",
- |diag| {
- diag.multipart_suggestion("try this", replacements, app);
- },
- );
- }
- self.current_body = None;
- }
- }
-}
-impl NeedlessBorrow {
- fn check_local_usage(&mut self, cx: &LateContext<'tcx>, e: &'tcx Expr<'_>, local: HirId) {
- if let Some(outer_pat) = self.ref_locals.get_mut(&local) {
- if let Some(pat) = outer_pat {
- // Check for auto-deref
- if !matches!(
- cx.typeck_results().expr_adjustments(e),
- [
- Adjustment {
- kind: Adjust::Deref(_),
- ..
- },
- Adjustment {
- kind: Adjust::Deref(_),
- ..
- },
- ..
- ]
- ) {
- match get_parent_expr(cx, e) {
- // Field accesses are the same no matter the number of references.
- Some(Expr {
- kind: ExprKind::Field(..),
- ..
- }) => (),
- Some(&Expr {
- span,
- kind: ExprKind::Unary(UnOp::Deref, _),
- ..
- }) if !in_macro(span) => {
- // Remove explicit deref.
- let snip = snippet_with_context(cx, e.span, span.ctxt(), "..", &mut pat.app).0;
- pat.replacements.push((span, snip.into()));
- },
- Some(parent) if !in_macro(parent.span) => {
- // Double reference might be needed at this point.
- if parent.precedence().order() == PREC_POSTFIX {
- // Parentheses would be needed here, don't lint.
- *outer_pat = None;
- } else {
- pat.always_deref = false;
- let snip = snippet_with_context(cx, e.span, parent.span.ctxt(), "..", &mut pat.app).0;
- pat.replacements.push((e.span, format!("&{}", snip)));
- }
- },
- _ if !in_macro(e.span) => {
- // Double reference might be needed at this point.
- pat.always_deref = false;
- let snip = snippet_with_applicability(cx, e.span, "..", &mut pat.app);
- pat.replacements.push((e.span, format!("&{}", snip)));
- },
- // Edge case for macros. The span of the identifier will usually match the context of the
- // binding, but not if the identifier was created in a macro. e.g. `concat_idents` and proc
- // macros
- _ => *outer_pat = None,
- }
- }
- }
- }
- }
-}
diff --git a/src/tools/clippy/clippy_lints/src/needless_borrowed_ref.rs b/src/tools/clippy/clippy_lints/src/needless_borrowed_ref.rs
index 36879eda7c0..0fcc419e722 100644
--- a/src/tools/clippy/clippy_lints/src/needless_borrowed_ref.rs
+++ b/src/tools/clippy/clippy_lints/src/needless_borrowed_ref.rs
@@ -38,6 +38,7 @@ declare_clippy_lint! {
/// let mut v = Vec::<String>::new();
/// let _ = v.iter_mut().filter(|a| a.is_empty());
/// ```
+ #[clippy::version = "pre 1.29.0"]
pub NEEDLESS_BORROWED_REFERENCE,
complexity,
"destructuring a reference and borrowing the inner value"
diff --git a/src/tools/clippy/clippy_lints/src/needless_continue.rs b/src/tools/clippy/clippy_lints/src/needless_continue.rs
index 7aa93ed7839..98a3bce1ff3 100644
--- a/src/tools/clippy/clippy_lints/src/needless_continue.rs
+++ b/src/tools/clippy/clippy_lints/src/needless_continue.rs
@@ -110,6 +110,7 @@ declare_clippy_lint! {
/// # break;
/// }
/// ```
+ #[clippy::version = "pre 1.29.0"]
pub NEEDLESS_CONTINUE,
pedantic,
"`continue` statements that can be replaced by a rearrangement of code"
diff --git a/src/tools/clippy/clippy_lints/src/needless_for_each.rs b/src/tools/clippy/clippy_lints/src/needless_for_each.rs
index 9a6ddc72ce5..0c1da035173 100644
--- a/src/tools/clippy/clippy_lints/src/needless_for_each.rs
+++ b/src/tools/clippy/clippy_lints/src/needless_for_each.rs
@@ -40,6 +40,7 @@ declare_clippy_lint! {
/// println!("{}", elem);
/// }
/// ```
+ #[clippy::version = "1.53.0"]
pub NEEDLESS_FOR_EACH,
pedantic,
"using `for_each` where a `for` loop would be simpler"
diff --git a/src/tools/clippy/clippy_lints/src/needless_late_init.rs b/src/tools/clippy/clippy_lints/src/needless_late_init.rs
new file mode 100644
index 00000000000..094a3f111ba
--- /dev/null
+++ b/src/tools/clippy/clippy_lints/src/needless_late_init.rs
@@ -0,0 +1,355 @@
+use clippy_utils::diagnostics::span_lint_and_then;
+use clippy_utils::path_to_local;
+use clippy_utils::source::snippet_opt;
+use clippy_utils::visitors::{expr_visitor, is_local_used};
+use rustc_errors::Applicability;
+use rustc_hir::intravisit::Visitor;
+use rustc_hir::{Block, Expr, ExprKind, HirId, Local, LocalSource, MatchSource, Node, Pat, PatKind, Stmt, StmtKind};
+use rustc_lint::{LateContext, LateLintPass};
+use rustc_session::{declare_lint_pass, declare_tool_lint};
+use rustc_span::Span;
+
+declare_clippy_lint! {
+ /// ### What it does
+ /// Checks for late initializations that can be replaced by a `let` statement
+ /// with an initializer.
+ ///
+ /// ### Why is this bad?
+ /// Assigning in the `let` statement is less repetitive.
+ ///
+ /// ### Example
+ /// ```rust
+ /// let a;
+ /// a = 1;
+ ///
+ /// let b;
+ /// match 3 {
+ /// 0 => b = "zero",
+ /// 1 => b = "one",
+ /// _ => b = "many",
+ /// }
+ ///
+ /// let c;
+ /// if true {
+ /// c = 1;
+ /// } else {
+ /// c = -1;
+ /// }
+ /// ```
+ /// Use instead:
+ /// ```rust
+ /// let a = 1;
+ ///
+ /// let b = match 3 {
+ /// 0 => "zero",
+ /// 1 => "one",
+ /// _ => "many",
+ /// };
+ ///
+ /// let c = if true {
+ /// 1
+ /// } else {
+ /// -1
+ /// };
+ /// ```
+ #[clippy::version = "1.58.0"]
+ pub NEEDLESS_LATE_INIT,
+ style,
+ "late initializations that can be replaced by a `let` statement with an initializer"
+}
+declare_lint_pass!(NeedlessLateInit => [NEEDLESS_LATE_INIT]);
+
+fn contains_assign_expr<'tcx>(cx: &LateContext<'tcx>, stmt: &'tcx Stmt<'tcx>) -> bool {
+ let mut seen = false;
+ expr_visitor(cx, |expr| {
+ if let ExprKind::Assign(..) = expr.kind {
+ seen = true;
+ }
+
+ !seen
+ })
+ .visit_stmt(stmt);
+
+ seen
+}
+
+#[derive(Debug)]
+struct LocalAssign {
+ lhs_id: HirId,
+ lhs_span: Span,
+ rhs_span: Span,
+ span: Span,
+}
+
+impl LocalAssign {
+ fn from_expr(expr: &Expr<'_>, span: Span) -> Option<Self> {
+ if let ExprKind::Assign(lhs, rhs, _) = expr.kind {
+ if lhs.span.from_expansion() {
+ return None;
+ }
+
+ Some(Self {
+ lhs_id: path_to_local(lhs)?,
+ lhs_span: lhs.span,
+ rhs_span: rhs.span.source_callsite(),
+ span,
+ })
+ } else {
+ None
+ }
+ }
+
+ fn new<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>, binding_id: HirId) -> Option<LocalAssign> {
+ let assign = match expr.kind {
+ ExprKind::Block(Block { expr: Some(expr), .. }, _) => Self::from_expr(expr, expr.span),
+ ExprKind::Block(block, _) => {
+ if_chain! {
+ if let Some((last, other_stmts)) = block.stmts.split_last();
+ if let StmtKind::Expr(expr) | StmtKind::Semi(expr) = last.kind;
+
+ let assign = Self::from_expr(expr, last.span)?;
+
+ // avoid visiting if not needed
+ if assign.lhs_id == binding_id;
+ if other_stmts.iter().all(|stmt| !contains_assign_expr(cx, stmt));
+
+ then {
+ Some(assign)
+ } else {
+ None
+ }
+ }
+ },
+ ExprKind::Assign(..) => Self::from_expr(expr, expr.span),
+ _ => None,
+ }?;
+
+ if assign.lhs_id == binding_id {
+ Some(assign)
+ } else {
+ None
+ }
+ }
+}
+
+fn assignment_suggestions<'tcx>(
+ cx: &LateContext<'tcx>,
+ binding_id: HirId,
+ exprs: impl IntoIterator<Item = &'tcx Expr<'tcx>>,
+) -> Option<(Applicability, Vec<(Span, String)>)> {
+ let mut assignments = Vec::new();
+
+ for expr in exprs {
+ let ty = cx.typeck_results().expr_ty(expr);
+
+ if ty.is_never() {
+ continue;
+ }
+ if !ty.is_unit() {
+ return None;
+ }
+
+ let assign = LocalAssign::new(cx, expr, binding_id)?;
+
+ assignments.push(assign);
+ }
+
+ let suggestions = assignments
+ .iter()
+ .map(|assignment| Some((assignment.span.until(assignment.rhs_span), String::new())))
+ .chain(assignments.iter().map(|assignment| {
+ Some((
+ assignment.rhs_span.shrink_to_hi().with_hi(assignment.span.hi()),
+ String::new(),
+ ))
+ }))
+ .collect::<Option<Vec<(Span, String)>>>()?;
+
+ let applicability = if suggestions.len() > 1 {
+ // multiple suggestions don't work with rustfix in multipart_suggest
+ // https://github.com/rust-lang/rustfix/issues/141
+ Applicability::Unspecified
+ } else {
+ Applicability::MachineApplicable
+ };
+ Some((applicability, suggestions))
+}
+
+struct Usage<'tcx> {
+ stmt: &'tcx Stmt<'tcx>,
+ expr: &'tcx Expr<'tcx>,
+ needs_semi: bool,
+}
+
+fn first_usage<'tcx>(
+ cx: &LateContext<'tcx>,
+ binding_id: HirId,
+ local_stmt_id: HirId,
+ block: &'tcx Block<'tcx>,
+) -> Option<Usage<'tcx>> {
+ block
+ .stmts
+ .iter()
+ .skip_while(|stmt| stmt.hir_id != local_stmt_id)
+ .skip(1)
+ .find(|&stmt| is_local_used(cx, stmt, binding_id))
+ .and_then(|stmt| match stmt.kind {
+ StmtKind::Expr(expr) => Some(Usage {
+ stmt,
+ expr,
+ needs_semi: true,
+ }),
+ StmtKind::Semi(expr) => Some(Usage {
+ stmt,
+ expr,
+ needs_semi: false,
+ }),
+ _ => None,
+ })
+}
+
+fn local_snippet_without_semicolon(cx: &LateContext<'_>, local: &Local<'_>) -> Option<String> {
+ let span = local.span.with_hi(match local.ty {
+ // let <pat>: <ty>;
+ // ~~~~~~~~~~~~~~~
+ Some(ty) => ty.span.hi(),
+ // let <pat>;
+ // ~~~~~~~~~
+ None => local.pat.span.hi(),
+ });
+
+ snippet_opt(cx, span)
+}
+
+fn check<'tcx>(
+ cx: &LateContext<'tcx>,
+ local: &'tcx Local<'tcx>,
+ local_stmt: &'tcx Stmt<'tcx>,
+ block: &'tcx Block<'tcx>,
+ binding_id: HirId,
+) -> Option<()> {
+ let usage = first_usage(cx, binding_id, local_stmt.hir_id, block)?;
+ let binding_name = cx.tcx.hir().opt_name(binding_id)?;
+ let let_snippet = local_snippet_without_semicolon(cx, local)?;
+
+ match usage.expr.kind {
+ ExprKind::Assign(..) => {
+ let assign = LocalAssign::new(cx, usage.expr, binding_id)?;
+
+ span_lint_and_then(
+ cx,
+ NEEDLESS_LATE_INIT,
+ local_stmt.span,
+ "unneeded late initalization",
+ |diag| {
+ diag.tool_only_span_suggestion(
+ local_stmt.span,
+ "remove the local",
+ String::new(),
+ Applicability::MachineApplicable,
+ );
+
+ diag.span_suggestion(
+ assign.lhs_span,
+ &format!("declare `{}` here", binding_name),
+ let_snippet,
+ Applicability::MachineApplicable,
+ );
+ },
+ );
+ },
+ ExprKind::If(_, then_expr, Some(else_expr)) => {
+ let (applicability, suggestions) = assignment_suggestions(cx, binding_id, [then_expr, else_expr])?;
+
+ span_lint_and_then(
+ cx,
+ NEEDLESS_LATE_INIT,
+ local_stmt.span,
+ "unneeded late initalization",
+ |diag| {
+ diag.tool_only_span_suggestion(local_stmt.span, "remove the local", String::new(), applicability);
+
+ diag.span_suggestion_verbose(
+ usage.stmt.span.shrink_to_lo(),
+ &format!("declare `{}` here", binding_name),
+ format!("{} = ", let_snippet),
+ applicability,
+ );
+
+ diag.multipart_suggestion("remove the assignments from the branches", suggestions, applicability);
+
+ if usage.needs_semi {
+ diag.span_suggestion(
+ usage.stmt.span.shrink_to_hi(),
+ "add a semicolon after the `if` expression",
+ ";".to_string(),
+ applicability,
+ );
+ }
+ },
+ );
+ },
+ ExprKind::Match(_, arms, MatchSource::Normal) => {
+ let (applicability, suggestions) = assignment_suggestions(cx, binding_id, arms.iter().map(|arm| arm.body))?;
+
+ span_lint_and_then(
+ cx,
+ NEEDLESS_LATE_INIT,
+ local_stmt.span,
+ "unneeded late initalization",
+ |diag| {
+ diag.tool_only_span_suggestion(local_stmt.span, "remove the local", String::new(), applicability);
+
+ diag.span_suggestion_verbose(
+ usage.stmt.span.shrink_to_lo(),
+ &format!("declare `{}` here", binding_name),
+ format!("{} = ", let_snippet),
+ applicability,
+ );
+
+ diag.multipart_suggestion(
+ "remove the assignments from the `match` arms",
+ suggestions,
+ applicability,
+ );
+
+ if usage.needs_semi {
+ diag.span_suggestion(
+ usage.stmt.span.shrink_to_hi(),
+ "add a semicolon after the `match` expression",
+ ";".to_string(),
+ applicability,
+ );
+ }
+ },
+ );
+ },
+ _ => {},
+ };
+
+ Some(())
+}
+
+impl LateLintPass<'tcx> for NeedlessLateInit {
+ fn check_local(&mut self, cx: &LateContext<'tcx>, local: &'tcx Local<'tcx>) {
+ let mut parents = cx.tcx.hir().parent_iter(local.hir_id);
+
+ if_chain! {
+ if let Local {
+ init: None,
+ pat: &Pat {
+ kind: PatKind::Binding(_, binding_id, _, None),
+ ..
+ },
+ source: LocalSource::Normal,
+ ..
+ } = local;
+ if let Some((_, Node::Stmt(local_stmt))) = parents.next();
+ if let Some((_, Node::Block(block))) = parents.next();
+
+ then {
+ check(cx, local, local_stmt, block, binding_id);
+ }
+ }
+ }
+}
diff --git a/src/tools/clippy/clippy_lints/src/needless_option_as_deref.rs b/src/tools/clippy/clippy_lints/src/needless_option_as_deref.rs
index fbdaaf51f74..a28b08c33ec 100644
--- a/src/tools/clippy/clippy_lints/src/needless_option_as_deref.rs
+++ b/src/tools/clippy/clippy_lints/src/needless_option_as_deref.rs
@@ -1,5 +1,4 @@
use clippy_utils::diagnostics::span_lint_and_sugg;
-use clippy_utils::in_macro;
use clippy_utils::source::snippet_opt;
use clippy_utils::ty::is_type_diagnostic_item;
use rustc_errors::Applicability;
@@ -27,6 +26,7 @@ declare_clippy_lint! {
/// let a = Some(&1);
/// let b = a;
/// ```
+ #[clippy::version = "1.57.0"]
pub NEEDLESS_OPTION_AS_DEREF,
complexity,
"no-op use of `deref` or `deref_mut` method to `Option`."
@@ -38,7 +38,7 @@ declare_lint_pass!(OptionNeedlessDeref=> [
impl<'tcx> LateLintPass<'tcx> for OptionNeedlessDeref {
fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
- if expr.span.from_expansion() || in_macro(expr.span) {
+ if expr.span.from_expansion() {
return;
}
let typeck = cx.typeck_results();
diff --git a/src/tools/clippy/clippy_lints/src/needless_pass_by_value.rs b/src/tools/clippy/clippy_lints/src/needless_pass_by_value.rs
index 352dc6f8bec..35877d51c0c 100644
--- a/src/tools/clippy/clippy_lints/src/needless_pass_by_value.rs
+++ b/src/tools/clippy/clippy_lints/src/needless_pass_by_value.rs
@@ -51,6 +51,7 @@ declare_clippy_lint! {
/// assert_eq!(v.len(), 42);
/// }
/// ```
+ #[clippy::version = "pre 1.29.0"]
pub NEEDLESS_PASS_BY_VALUE,
pedantic,
"functions taking arguments by value, but not consuming them in its body"
diff --git a/src/tools/clippy/clippy_lints/src/needless_question_mark.rs b/src/tools/clippy/clippy_lints/src/needless_question_mark.rs
index 42e48336e15..0e7ae43ce2d 100644
--- a/src/tools/clippy/clippy_lints/src/needless_question_mark.rs
+++ b/src/tools/clippy/clippy_lints/src/needless_question_mark.rs
@@ -53,6 +53,7 @@ declare_clippy_lint! {
/// tr.and_then(|t| t.magic)
/// }
/// ```
+ #[clippy::version = "1.51.0"]
pub NEEDLESS_QUESTION_MARK,
complexity,
"Suggest `value.inner_option` instead of `Some(value.inner_option?)`. The same goes for `Result<T, E>`."
@@ -92,26 +93,33 @@ impl LateLintPass<'_> for NeedlessQuestionMark {
}
fn check(cx: &LateContext<'_>, expr: &Expr<'_>) {
- let inner_expr = if_chain! {
+ if_chain! {
if let ExprKind::Call(path, [arg]) = &expr.kind;
if let ExprKind::Path(ref qpath) = &path.kind;
- if is_lang_ctor(cx, qpath, OptionSome) || is_lang_ctor(cx, qpath, ResultOk);
+ let sugg_remove = if is_lang_ctor(cx, qpath, OptionSome) {
+ "Some()"
+ } else if is_lang_ctor(cx, qpath, ResultOk) {
+ "Ok()"
+ } else {
+ return;
+ };
if let ExprKind::Match(inner_expr_with_q, _, MatchSource::TryDesugar) = &arg.kind;
if let ExprKind::Call(called, [inner_expr]) = &inner_expr_with_q.kind;
- if let ExprKind::Path(QPath::LangItem(LangItem::TryTraitBranch, _)) = &called.kind;
+ if let ExprKind::Path(QPath::LangItem(LangItem::TryTraitBranch, ..)) = &called.kind;
if expr.span.ctxt() == inner_expr.span.ctxt();
let expr_ty = cx.typeck_results().expr_ty(expr);
let inner_ty = cx.typeck_results().expr_ty(inner_expr);
if TyS::same_type(expr_ty, inner_ty);
- then { inner_expr } else { return; }
- };
- span_lint_and_sugg(
- cx,
- NEEDLESS_QUESTION_MARK,
- expr.span,
- "question mark operator is useless here",
- "try",
- format!("{}", snippet(cx, inner_expr.span, r#""...""#)),
- Applicability::MachineApplicable,
- );
+ then {
+ span_lint_and_sugg(
+ cx,
+ NEEDLESS_QUESTION_MARK,
+ expr.span,
+ "question mark operator is useless here",
+ &format!("try removing question mark and `{}`", sugg_remove),
+ format!("{}", snippet(cx, inner_expr.span, r#""...""#)),
+ Applicability::MachineApplicable,
+ );
+ }
+ }
}
diff --git a/src/tools/clippy/clippy_lints/src/needless_update.rs b/src/tools/clippy/clippy_lints/src/needless_update.rs
index 2a33b7392ca..ed315efaa2f 100644
--- a/src/tools/clippy/clippy_lints/src/needless_update.rs
+++ b/src/tools/clippy/clippy_lints/src/needless_update.rs
@@ -40,6 +40,7 @@ declare_clippy_lint! {
/// ..zero_point
/// };
/// ```
+ #[clippy::version = "pre 1.29.0"]
pub NEEDLESS_UPDATE,
complexity,
"using `Foo { ..base }` when there are no missing fields"
diff --git a/src/tools/clippy/clippy_lints/src/neg_cmp_op_on_partial_ord.rs b/src/tools/clippy/clippy_lints/src/neg_cmp_op_on_partial_ord.rs
index 6ad49b70605..efe31a15441 100644
--- a/src/tools/clippy/clippy_lints/src/neg_cmp_op_on_partial_ord.rs
+++ b/src/tools/clippy/clippy_lints/src/neg_cmp_op_on_partial_ord.rs
@@ -36,6 +36,7 @@ declare_clippy_lint! {
/// _ => false,
/// };
/// ```
+ #[clippy::version = "pre 1.29.0"]
pub NEG_CMP_OP_ON_PARTIAL_ORD,
complexity,
"The use of negated comparison operators on partially ordered types may produce confusing code."
diff --git a/src/tools/clippy/clippy_lints/src/neg_multiply.rs b/src/tools/clippy/clippy_lints/src/neg_multiply.rs
index 1b15d29439f..cb67fab1740 100644
--- a/src/tools/clippy/clippy_lints/src/neg_multiply.rs
+++ b/src/tools/clippy/clippy_lints/src/neg_multiply.rs
@@ -20,6 +20,7 @@ declare_clippy_lint! {
/// ```ignore
/// x * -1
/// ```
+ #[clippy::version = "pre 1.29.0"]
pub NEG_MULTIPLY,
style,
"multiplying integers with `-1`"
diff --git a/src/tools/clippy/clippy_lints/src/new_without_default.rs b/src/tools/clippy/clippy_lints/src/new_without_default.rs
index 0ac27f1cba2..f0c0c89ca8f 100644
--- a/src/tools/clippy/clippy_lints/src/new_without_default.rs
+++ b/src/tools/clippy/clippy_lints/src/new_without_default.rs
@@ -45,6 +45,7 @@ declare_clippy_lint! {
/// }
/// }
/// ```
+ #[clippy::version = "pre 1.29.0"]
pub NEW_WITHOUT_DEFAULT,
style,
"`fn new() -> Self` method without `Default` implementation"
diff --git a/src/tools/clippy/clippy_lints/src/no_effect.rs b/src/tools/clippy/clippy_lints/src/no_effect.rs
index 6dae8f32043..9d5babc5de8 100644
--- a/src/tools/clippy/clippy_lints/src/no_effect.rs
+++ b/src/tools/clippy/clippy_lints/src/no_effect.rs
@@ -1,5 +1,6 @@
use clippy_utils::diagnostics::{span_lint_hir, span_lint_hir_and_then};
use clippy_utils::is_lint_allowed;
+use clippy_utils::peel_blocks;
use clippy_utils::source::snippet_opt;
use clippy_utils::ty::has_drop;
use rustc_errors::Applicability;
@@ -22,6 +23,7 @@ declare_clippy_lint! {
/// ```rust
/// 0;
/// ```
+ #[clippy::version = "pre 1.29.0"]
pub NO_EFFECT,
complexity,
"statements with no effect"
@@ -44,6 +46,7 @@ declare_clippy_lint! {
/// ```rust,ignore
/// let _i_serve_no_purpose = 1;
/// ```
+ #[clippy::version = "1.58.0"]
pub NO_EFFECT_UNDERSCORE_BINDING,
pedantic,
"binding to `_` prefixed variable with no side-effect"
@@ -62,6 +65,7 @@ declare_clippy_lint! {
/// ```rust,ignore
/// compute_array()[0];
/// ```
+ #[clippy::version = "pre 1.29.0"]
pub UNNECESSARY_OPERATION,
complexity,
"outer expressions with no effect"
@@ -111,7 +115,7 @@ fn has_no_effect(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool {
if expr.span.from_expansion() {
return false;
}
- match expr.kind {
+ match peel_blocks(expr).kind {
ExprKind::Lit(..) | ExprKind::Closure(..) => true,
ExprKind::Path(..) => !has_drop(cx, cx.typeck_results().expr_ty(expr)),
ExprKind::Index(a, b) | ExprKind::Binary(_, a, b) => has_no_effect(cx, a) && has_no_effect(cx, b),
@@ -130,9 +134,12 @@ fn has_no_effect(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool {
},
ExprKind::Call(callee, args) => {
if let ExprKind::Path(ref qpath) = callee.kind {
- let res = cx.qpath_res(qpath, callee.hir_id);
+ if cx.typeck_results().type_dependent_def(expr.hir_id).is_some() {
+ // type-dependent function call like `impl FnOnce for X`
+ return false;
+ }
let def_matched = matches!(
- res,
+ cx.qpath_res(qpath, callee.hir_id),
Res::Def(DefKind::Struct | DefKind::Variant | DefKind::Ctor(..), ..)
);
if def_matched || is_range_literal(expr) {
@@ -144,9 +151,6 @@ fn has_no_effect(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool {
false
}
},
- ExprKind::Block(block, _) => {
- block.stmts.is_empty() && block.expr.as_ref().map_or(false, |expr| has_no_effect(cx, expr))
- },
_ => false,
}
}
@@ -158,12 +162,13 @@ fn check_unnecessary_operation(cx: &LateContext<'tcx>, stmt: &'tcx Stmt<'_>) {
if !&reduced.iter().any(|e| e.span.from_expansion());
then {
if let ExprKind::Index(..) = &expr.kind {
- let snippet;
- if let (Some(arr), Some(func)) = (snippet_opt(cx, reduced[0].span), snippet_opt(cx, reduced[1].span)) {
- snippet = format!("assert!({}.len() > {});", &arr, &func);
+ let snippet = if let (Some(arr), Some(func)) =
+ (snippet_opt(cx, reduced[0].span), snippet_opt(cx, reduced[1].span))
+ {
+ format!("assert!({}.len() > {});", &arr, &func)
} else {
return;
- }
+ };
span_lint_hir_and_then(
cx,
UNNECESSARY_OPERATION,
@@ -235,6 +240,10 @@ fn reduce_expression<'a>(cx: &LateContext<'_>, expr: &'a Expr<'a>) -> Option<Vec
},
ExprKind::Call(callee, args) => {
if let ExprKind::Path(ref qpath) = callee.kind {
+ if cx.typeck_results().type_dependent_def(expr.hir_id).is_some() {
+ // type-dependent function call like `impl FnOnce for X`
+ return None;
+ }
let res = cx.qpath_res(qpath, callee.hir_id);
match res {
Res::Def(DefKind::Struct | DefKind::Variant | DefKind::Ctor(..), ..)
diff --git a/src/tools/clippy/clippy_lints/src/non_copy_const.rs b/src/tools/clippy/clippy_lints/src/non_copy_const.rs
index 2a85a67fa09..074ba9e92ba 100644
--- a/src/tools/clippy/clippy_lints/src/non_copy_const.rs
+++ b/src/tools/clippy/clippy_lints/src/non_copy_const.rs
@@ -69,6 +69,7 @@ declare_clippy_lint! {
/// STATIC_ATOM.store(9, SeqCst);
/// assert_eq!(STATIC_ATOM.load(SeqCst), 9); // use a `static` item to refer to the same instance
/// ```
+ #[clippy::version = "pre 1.29.0"]
pub DECLARE_INTERIOR_MUTABLE_CONST,
style,
"declaring `const` with interior mutability"
@@ -113,6 +114,7 @@ declare_clippy_lint! {
/// STATIC_ATOM.store(9, SeqCst);
/// assert_eq!(STATIC_ATOM.load(SeqCst), 9); // use a `static` item to refer to the same instance
/// ```
+ #[clippy::version = "pre 1.29.0"]
pub BORROW_INTERIOR_MUTABLE_CONST,
style,
"referencing `const` with interior mutability"
@@ -279,8 +281,8 @@ impl<'tcx> LateLintPass<'tcx> for NonCopyConst {
fn check_impl_item(&mut self, cx: &LateContext<'tcx>, impl_item: &'tcx ImplItem<'_>) {
if let ImplItemKind::Const(hir_ty, body_id) = &impl_item.kind {
- let item_hir_id = cx.tcx.hir().get_parent_node(impl_item.hir_id());
- let item = cx.tcx.hir().expect_item(item_hir_id);
+ let item_def_id = cx.tcx.hir().get_parent_did(impl_item.hir_id());
+ let item = cx.tcx.hir().expect_item(item_def_id);
match &item.kind {
ItemKind::Impl(Impl {
diff --git a/src/tools/clippy/clippy_lints/src/non_expressive_names.rs b/src/tools/clippy/clippy_lints/src/non_expressive_names.rs
index e28cc49bf2a..5559fac0a8a 100644
--- a/src/tools/clippy/clippy_lints/src/non_expressive_names.rs
+++ b/src/tools/clippy/clippy_lints/src/non_expressive_names.rs
@@ -24,6 +24,7 @@ declare_clippy_lint! {
/// let checked_exp = something;
/// let checked_expr = something_else;
/// ```
+ #[clippy::version = "pre 1.29.0"]
pub SIMILAR_NAMES,
pedantic,
"similarly named items and bindings"
@@ -42,6 +43,7 @@ declare_clippy_lint! {
/// ```ignore
/// let (a, b, c, d, e, f, g) = (...);
/// ```
+ #[clippy::version = "pre 1.29.0"]
pub MANY_SINGLE_CHAR_NAMES,
pedantic,
"too many single character bindings"
@@ -62,6 +64,7 @@ declare_clippy_lint! {
/// let ___1 = 1;
/// let __1___2 = 11;
/// ```
+ #[clippy::version = "pre 1.29.0"]
pub JUST_UNDERSCORES_AND_DIGITS,
style,
"unclear name"
@@ -357,7 +360,12 @@ impl EarlyLintPass for NonExpressiveNames {
return;
}
- if let ItemKind::Fn(box ast::Fn { ref sig, body: Some(ref blk), .. }) = item.kind {
+ if let ItemKind::Fn(box ast::Fn {
+ ref sig,
+ body: Some(ref blk),
+ ..
+ }) = item.kind
+ {
do_check(self, cx, &item.attrs, &sig.decl, blk);
}
}
@@ -367,7 +375,12 @@ impl EarlyLintPass for NonExpressiveNames {
return;
}
- if let AssocItemKind::Fn(box ast::Fn { ref sig, body: Some(ref blk), .. }) = item.kind {
+ if let AssocItemKind::Fn(box ast::Fn {
+ ref sig,
+ body: Some(ref blk),
+ ..
+ }) = item.kind
+ {
do_check(self, cx, &item.attrs, &sig.decl, blk);
}
}
diff --git a/src/tools/clippy/clippy_lints/src/non_octal_unix_permissions.rs b/src/tools/clippy/clippy_lints/src/non_octal_unix_permissions.rs
index 3b74f69d375..4b57dbc4c41 100644
--- a/src/tools/clippy/clippy_lints/src/non_octal_unix_permissions.rs
+++ b/src/tools/clippy/clippy_lints/src/non_octal_unix_permissions.rs
@@ -32,6 +32,7 @@ declare_clippy_lint! {
/// let mut options = OpenOptions::new();
/// options.mode(0o644);
/// ```
+ #[clippy::version = "1.53.0"]
pub NON_OCTAL_UNIX_PERMISSIONS,
correctness,
"use of non-octal value to set unix file permissions, which will be translated into octal"
diff --git a/src/tools/clippy/clippy_lints/src/non_send_fields_in_send_ty.rs b/src/tools/clippy/clippy_lints/src/non_send_fields_in_send_ty.rs
index 7ebf84d400f..203f03d3603 100644
--- a/src/tools/clippy/clippy_lints/src/non_send_fields_in_send_ty.rs
+++ b/src/tools/clippy/clippy_lints/src/non_send_fields_in_send_ty.rs
@@ -1,35 +1,40 @@
use clippy_utils::diagnostics::span_lint_and_then;
-use clippy_utils::is_lint_allowed;
use clippy_utils::source::snippet;
use clippy_utils::ty::{implements_trait, is_copy};
+use clippy_utils::{is_lint_allowed, match_def_path, paths};
use rustc_ast::ImplPolarity;
use rustc_hir::def_id::DefId;
use rustc_hir::{FieldDef, Item, ItemKind, Node};
use rustc_lint::{LateContext, LateLintPass};
+use rustc_middle::lint::in_external_macro;
use rustc_middle::ty::{self, subst::GenericArgKind, Ty};
use rustc_session::{declare_tool_lint, impl_lint_pass};
use rustc_span::sym;
declare_clippy_lint! {
/// ### What it does
- /// Warns about fields in struct implementing `Send` that are neither `Send` nor `Copy`.
+ /// This lint warns about a `Send` implementation for a type that
+ /// contains fields that are not safe to be sent across threads.
+ /// It tries to detect fields that can cause a soundness issue
+ /// when sent to another thread (e.g., `Rc`) while allowing `!Send` fields
+ /// that are expected to exist in a `Send` type, such as raw pointers.
///
/// ### Why is this bad?
- /// Sending the struct to another thread will transfer the ownership to
- /// the new thread by dropping in the current thread during the transfer.
- /// This causes soundness issues for non-`Send` fields, as they are also
- /// dropped and might not be set up to handle this.
+ /// Sending the struct to another thread effectively sends all of its fields,
+ /// and the fields that do not implement `Send` can lead to soundness bugs
+ /// such as data races when accessed in a thread
+ /// that is different from the thread that created it.
///
/// See:
/// * [*The Rustonomicon* about *Send and Sync*](https://doc.rust-lang.org/nomicon/send-and-sync.html)
/// * [The documentation of `Send`](https://doc.rust-lang.org/std/marker/trait.Send.html)
///
/// ### Known Problems
- /// Data structures that contain raw pointers may cause false positives.
- /// They are sometimes safe to be sent across threads but do not implement
- /// the `Send` trait. This lint has a heuristic to filter out basic cases
- /// such as `Vec<*const T>`, but it's not perfect. Feel free to create an
- /// issue if you have a suggestion on how this heuristic can be improved.
+ /// This lint relies on heuristics to distinguish types that are actually
+ /// unsafe to be sent across threads and `!Send` types that are expected to
+ /// exist in `Send` type. Its rule can filter out basic cases such as
+ /// `Vec<*const T>`, but it's not perfect. Feel free to create an issue if
+ /// you have a suggestion on how this heuristic can be improved.
///
/// ### Example
/// ```rust,ignore
@@ -43,9 +48,10 @@ declare_clippy_lint! {
/// ```
/// Use thread-safe types like [`std::sync::Arc`](https://doc.rust-lang.org/std/sync/struct.Arc.html)
/// or specify correct bounds on generic type parameters (`T: Send`).
+ #[clippy::version = "1.57.0"]
pub NON_SEND_FIELDS_IN_SEND_TY,
- suspicious,
- "there is field that does not implement `Send` in a `Send` struct"
+ nursery,
+ "there is a field that is not safe to be sent to another thread in a `Send` struct"
}
#[derive(Copy, Clone)]
@@ -76,6 +82,7 @@ impl<'tcx> LateLintPass<'tcx> for NonSendFieldInSendTy {
// single `AdtDef` may have multiple `Send` impls due to generic
// parameters, and the lint is much easier to implement in this way.
if_chain! {
+ if !in_external_macro(cx.tcx.sess, item.span);
if let Some(send_trait) = cx.tcx.get_diagnostic_item(sym::Send);
if let ItemKind::Impl(hir_impl) = &item.kind;
if let Some(trait_ref) = &hir_impl.of_trait;
@@ -117,14 +124,14 @@ impl<'tcx> LateLintPass<'tcx> for NonSendFieldInSendTy {
NON_SEND_FIELDS_IN_SEND_TY,
item.span,
&format!(
- "this implementation is unsound, as some fields in `{}` are `!Send`",
+ "some fields in `{}` are not safe to be sent to another thread",
snippet(cx, hir_impl.self_ty.span, "Unknown")
),
|diag| {
for field in non_send_fields {
diag.span_note(
field.def.span,
- &format!("the type of field `{}` is `!Send`", field.def.ident.name),
+ &format!("it is not safe to send field `{}` to another thread", field.def.ident.name),
);
match field.generic_params.len() {
@@ -180,7 +187,7 @@ fn ty_allowed_without_raw_pointer_heuristic<'tcx>(cx: &LateContext<'tcx>, ty: Ty
return true;
}
- if is_copy(cx, ty) && !contains_raw_pointer(cx, ty) {
+ if is_copy(cx, ty) && !contains_pointer_like(cx, ty) {
return true;
}
@@ -200,7 +207,7 @@ fn ty_allowed_with_raw_pointer_heuristic<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'t
.all(|ty| ty_allowed_with_raw_pointer_heuristic(cx, ty, send_trait)),
ty::Array(ty, _) | ty::Slice(ty) => ty_allowed_with_raw_pointer_heuristic(cx, ty, send_trait),
ty::Adt(_, substs) => {
- if contains_raw_pointer(cx, ty) {
+ if contains_pointer_like(cx, ty) {
// descends only if ADT contains any raw pointers
substs.iter().all(|generic_arg| match generic_arg.unpack() {
GenericArgKind::Type(ty) => ty_allowed_with_raw_pointer_heuristic(cx, ty, send_trait),
@@ -217,14 +224,20 @@ fn ty_allowed_with_raw_pointer_heuristic<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'t
}
}
-/// Checks if the type contains any raw pointers in substs (including nested ones).
-fn contains_raw_pointer<'tcx>(cx: &LateContext<'tcx>, target_ty: Ty<'tcx>) -> bool {
+/// Checks if the type contains any pointer-like types in substs (including nested ones)
+fn contains_pointer_like<'tcx>(cx: &LateContext<'tcx>, target_ty: Ty<'tcx>) -> bool {
for ty_node in target_ty.walk(cx.tcx) {
- if_chain! {
- if let GenericArgKind::Type(inner_ty) = ty_node.unpack();
- if let ty::RawPtr(_) = inner_ty.kind();
- then {
- return true;
+ if let GenericArgKind::Type(inner_ty) = ty_node.unpack() {
+ match inner_ty.kind() {
+ ty::RawPtr(_) => {
+ return true;
+ },
+ ty::Adt(adt_def, _) => {
+ if match_def_path(cx, adt_def.did, &paths::PTR_NON_NULL) {
+ return true;
+ }
+ },
+ _ => (),
}
}
}
diff --git a/src/tools/clippy/clippy_lints/src/nonstandard_macro_braces.rs b/src/tools/clippy/clippy_lints/src/nonstandard_macro_braces.rs
index ca660a9250d..a04d589f880 100644
--- a/src/tools/clippy/clippy_lints/src/nonstandard_macro_braces.rs
+++ b/src/tools/clippy/clippy_lints/src/nonstandard_macro_braces.rs
@@ -3,14 +3,16 @@ use std::{
hash::{Hash, Hasher},
};
-use clippy_utils::{diagnostics::span_lint_and_help, in_macro, is_direct_expn_of, source::snippet_opt};
+use clippy_utils::diagnostics::span_lint_and_help;
+use clippy_utils::source::snippet_opt;
use if_chain::if_chain;
use rustc_ast::ast;
use rustc_data_structures::fx::{FxHashMap, FxHashSet};
use rustc_hir::def_id::DefId;
use rustc_lint::{EarlyContext, EarlyLintPass};
use rustc_session::{declare_tool_lint, impl_lint_pass};
-use rustc_span::Span;
+use rustc_span::hygiene::{ExpnKind, MacroKind};
+use rustc_span::{Span, Symbol};
use serde::{de, Deserialize};
declare_clippy_lint! {
@@ -29,6 +31,7 @@ declare_clippy_lint! {
/// ```rust
/// vec![1, 2, 3];
/// ```
+ #[clippy::version = "1.55.0"]
pub NONSTANDARD_MACRO_BRACES,
nursery,
"check consistent use of braces in macro"
@@ -37,7 +40,7 @@ declare_clippy_lint! {
const BRACES: &[(&str, &str)] = &[("(", ")"), ("{", "}"), ("[", "]")];
/// The (name, (open brace, close brace), source snippet)
-type MacroInfo<'a> = (&'a str, &'a (String, String), String);
+type MacroInfo<'a> = (Symbol, &'a (String, String), String);
#[derive(Clone, Debug, Default)]
pub struct MacroBraces {
@@ -93,35 +96,34 @@ impl EarlyLintPass for MacroBraces {
fn is_offending_macro<'a>(cx: &EarlyContext<'_>, span: Span, mac_braces: &'a MacroBraces) -> Option<MacroInfo<'a>> {
let unnested_or_local = || {
- let nested = in_macro(span.ctxt().outer_expn_data().call_site);
- !nested
+ !span.ctxt().outer_expn_data().call_site.from_expansion()
|| span
.macro_backtrace()
.last()
.map_or(false, |e| e.macro_def_id.map_or(false, DefId::is_local))
};
if_chain! {
- // Make sure we are only one level deep otherwise there are to many FP's
- if in_macro(span);
- if let Some((name, braces)) = find_matching_macro(span, &mac_braces.macro_braces);
+ if let ExpnKind::Macro(MacroKind::Bang, mac_name) = span.ctxt().outer_expn_data().kind;
+ let name = &*mac_name.as_str();
+ if let Some(braces) = mac_braces.macro_braces.get(name);
if let Some(snip) = snippet_opt(cx, span.ctxt().outer_expn_data().call_site);
// we must check only invocation sites
// https://github.com/rust-lang/rust-clippy/issues/7422
if snip.starts_with(&format!("{}!", name));
if unnested_or_local();
// make formatting consistent
- let c = snip.replace(" ", "");
+ let c = snip.replace(' ', "");
if !c.starts_with(&format!("{}!{}", name, braces.0));
if !mac_braces.done.contains(&span.ctxt().outer_expn_data().call_site);
then {
- Some((name, braces, snip))
+ Some((mac_name, braces, snip))
} else {
None
}
}
}
-fn emit_help(cx: &EarlyContext<'_>, snip: String, braces: &(String, String), name: &str, span: Span) {
+fn emit_help(cx: &EarlyContext<'_>, snip: String, braces: &(String, String), name: Symbol, span: Span) {
let with_space = &format!("! {}", braces.0);
let without_space = &format!("!{}", braces.0);
let mut help = snip;
@@ -144,15 +146,6 @@ fn emit_help(cx: &EarlyContext<'_>, snip: String, braces: &(String, String), nam
);
}
-fn find_matching_macro(
- span: Span,
- braces: &FxHashMap<String, (String, String)>,
-) -> Option<(&String, &(String, String))> {
- braces
- .iter()
- .find(|(macro_name, _)| is_direct_expn_of(span, macro_name).is_some())
-}
-
fn macro_braces(conf: FxHashSet<MacroMatcher>) -> FxHashMap<String, (String, String)> {
let mut braces = vec![
macro_matcher!(
diff --git a/src/tools/clippy/clippy_lints/src/octal_escapes.rs b/src/tools/clippy/clippy_lints/src/octal_escapes.rs
new file mode 100644
index 00000000000..9c971437645
--- /dev/null
+++ b/src/tools/clippy/clippy_lints/src/octal_escapes.rs
@@ -0,0 +1,150 @@
+use clippy_utils::diagnostics::span_lint_and_then;
+use rustc_ast::ast::{Expr, ExprKind};
+use rustc_ast::token::{Lit, LitKind};
+use rustc_errors::Applicability;
+use rustc_lint::{EarlyContext, EarlyLintPass};
+use rustc_middle::lint::in_external_macro;
+use rustc_session::{declare_lint_pass, declare_tool_lint};
+use rustc_span::Span;
+use std::fmt::Write;
+
+declare_clippy_lint! {
+ /// ### What it does
+ /// Checks for `\0` escapes in string and byte literals that look like octal
+ /// character escapes in C.
+ ///
+ /// ### Why is this bad?
+ ///
+ /// C and other languages support octal character escapes in strings, where
+ /// a backslash is followed by up to three octal digits. For example, `\033`
+ /// stands for the ASCII character 27 (ESC). Rust does not support this
+ /// notation, but has the escape code `\0` which stands for a null
+ /// byte/character, and any following digits do not form part of the escape
+ /// sequence. Therefore, `\033` is not a compiler error but the result may
+ /// be surprising.
+ ///
+ /// ### Known problems
+ /// The actual meaning can be the intended one. `\x00` can be used in these
+ /// cases to be unambigious.
+ ///
+ /// The lint does not trigger for format strings in `print!()`, `write!()`
+ /// and friends since the string is already preprocessed when Clippy lints
+ /// can see it.
+ ///
+ /// # Example
+ /// ```rust
+ /// // Bad
+ /// let one = "\033[1m Bold? \033[0m"; // \033 intended as escape
+ /// let two = "\033\0"; // \033 intended as null-3-3
+ ///
+ /// // Good
+ /// let one = "\x1b[1mWill this be bold?\x1b[0m";
+ /// let two = "\x0033\x00";
+ /// ```
+ #[clippy::version = "1.58.0"]
+ pub OCTAL_ESCAPES,
+ suspicious,
+ "string escape sequences looking like octal characters"
+}
+
+declare_lint_pass!(OctalEscapes => [OCTAL_ESCAPES]);
+
+impl EarlyLintPass for OctalEscapes {
+ fn check_expr(&mut self, cx: &EarlyContext<'tcx>, expr: &Expr) {
+ if in_external_macro(cx.sess, expr.span) {
+ return;
+ }
+
+ if let ExprKind::Lit(lit) = &expr.kind {
+ if matches!(lit.token.kind, LitKind::Str) {
+ check_lit(cx, &lit.token, lit.span, true);
+ } else if matches!(lit.token.kind, LitKind::ByteStr) {
+ check_lit(cx, &lit.token, lit.span, false);
+ }
+ }
+ }
+}
+
+fn check_lit(cx: &EarlyContext<'tcx>, lit: &Lit, span: Span, is_string: bool) {
+ let contents = lit.symbol.as_str();
+ let mut iter = contents.char_indices().peekable();
+ let mut found = vec![];
+
+ // go through the string, looking for \0[0-7][0-7]?
+ while let Some((from, ch)) = iter.next() {
+ if ch == '\\' {
+ if let Some((_, '0')) = iter.next() {
+ // collect up to two further octal digits
+ if let Some((mut to, '0'..='7')) = iter.next() {
+ if let Some((_, '0'..='7')) = iter.peek() {
+ to += 1;
+ }
+ found.push((from, to + 1));
+ }
+ }
+ }
+ }
+
+ if found.is_empty() {
+ return;
+ }
+
+ // construct two suggestion strings, one with \x escapes with octal meaning
+ // as in C, and one with \x00 for null bytes.
+ let mut suggest_1 = if is_string { "\"" } else { "b\"" }.to_string();
+ let mut suggest_2 = suggest_1.clone();
+ let mut index = 0;
+ for (from, to) in found {
+ suggest_1.push_str(&contents[index..from]);
+ suggest_2.push_str(&contents[index..from]);
+
+ // construct a replacement escape
+ // the maximum value is \077, or \x3f, so u8 is sufficient here
+ if let Ok(n) = u8::from_str_radix(&contents[from + 1..to], 8) {
+ write!(&mut suggest_1, "\\x{:02x}", n).unwrap();
+ }
+
+ // append the null byte as \x00 and the following digits literally
+ suggest_2.push_str("\\x00");
+ suggest_2.push_str(&contents[from + 2..to]);
+
+ index = to;
+ }
+ suggest_1.push_str(&contents[index..]);
+ suggest_1.push('"');
+ suggest_2.push_str(&contents[index..]);
+ suggest_2.push('"');
+
+ span_lint_and_then(
+ cx,
+ OCTAL_ESCAPES,
+ span,
+ &format!(
+ "octal-looking escape in {} literal",
+ if is_string { "string" } else { "byte string" }
+ ),
+ |diag| {
+ diag.help(&format!(
+ "octal escapes are not supported, `\\0` is always a null {}",
+ if is_string { "character" } else { "byte" }
+ ));
+ // suggestion 1: equivalent hex escape
+ diag.span_suggestion(
+ span,
+ "if an octal escape was intended, use the hexadecimal representation instead",
+ suggest_1,
+ Applicability::MaybeIncorrect,
+ );
+ // suggestion 2: unambiguous null byte
+ diag.span_suggestion(
+ span,
+ &format!(
+ "if the null {} is intended, disambiguate using",
+ if is_string { "character" } else { "byte" }
+ ),
+ suggest_2,
+ Applicability::MaybeIncorrect,
+ );
+ },
+ );
+}
diff --git a/src/tools/clippy/clippy_lints/src/open_options.rs b/src/tools/clippy/clippy_lints/src/open_options.rs
index 5752342cf62..2c77100bdcf 100644
--- a/src/tools/clippy/clippy_lints/src/open_options.rs
+++ b/src/tools/clippy/clippy_lints/src/open_options.rs
@@ -22,6 +22,7 @@ declare_clippy_lint! {
///
/// OpenOptions::new().read(true).truncate(true);
/// ```
+ #[clippy::version = "pre 1.29.0"]
pub NONSENSICAL_OPEN_OPTIONS,
correctness,
"nonsensical combination of options for opening a file"
diff --git a/src/tools/clippy/clippy_lints/src/option_env_unwrap.rs b/src/tools/clippy/clippy_lints/src/option_env_unwrap.rs
index d7306628030..3f5286ba097 100644
--- a/src/tools/clippy/clippy_lints/src/option_env_unwrap.rs
+++ b/src/tools/clippy/clippy_lints/src/option_env_unwrap.rs
@@ -26,6 +26,7 @@ declare_clippy_lint! {
/// ```rust,no_run
/// let _ = env!("HOME");
/// ```
+ #[clippy::version = "1.43.0"]
pub OPTION_ENV_UNWRAP,
correctness,
"using `option_env!(...).unwrap()` to get environment variable"
diff --git a/src/tools/clippy/clippy_lints/src/option_if_let_else.rs b/src/tools/clippy/clippy_lints/src/option_if_let_else.rs
index cbe1c5d44d5..953de0f72a8 100644
--- a/src/tools/clippy/clippy_lints/src/option_if_let_else.rs
+++ b/src/tools/clippy/clippy_lints/src/option_if_let_else.rs
@@ -1,15 +1,14 @@
use clippy_utils::diagnostics::span_lint_and_sugg;
-use clippy_utils::higher;
use clippy_utils::sugg::Sugg;
use clippy_utils::ty::is_type_diagnostic_item;
use clippy_utils::{
- can_move_expr_to_closure, eager_or_lazy, in_constant, in_macro, is_else_clause, is_lang_ctor, peel_hir_expr_while,
- CaptureKind,
+ can_move_expr_to_closure, eager_or_lazy, higher, in_constant, is_else_clause, is_lang_ctor, peel_blocks,
+ peel_hir_expr_while, CaptureKind,
};
use if_chain::if_chain;
use rustc_errors::Applicability;
use rustc_hir::LangItem::OptionSome;
-use rustc_hir::{def::Res, BindingAnnotation, Block, Expr, ExprKind, Mutability, PatKind, Path, QPath, UnOp};
+use rustc_hir::{def::Res, BindingAnnotation, Expr, ExprKind, Mutability, PatKind, Path, QPath, UnOp};
use rustc_lint::{LateContext, LateLintPass};
use rustc_session::{declare_lint_pass, declare_tool_lint};
use rustc_span::sym;
@@ -59,6 +58,7 @@ declare_clippy_lint! {
/// y*y
/// }, |foo| foo);
/// ```
+ #[clippy::version = "1.47.0"]
pub OPTION_IF_LET_ELSE,
nursery,
"reimplementation of Option::map_or"
@@ -85,32 +85,10 @@ struct OptionIfLetElseOccurence {
none_expr: String,
}
-/// Extracts the body of a given arm. If the arm contains only an expression,
-/// then it returns the expression. Otherwise, it returns the entire block
-fn extract_body_from_expr<'a>(expr: &'a Expr<'a>) -> Option<&'a Expr<'a>> {
- if let ExprKind::Block(
- Block {
- stmts: block_stmts,
- expr: Some(block_expr),
- ..
- },
- _,
- ) = expr.kind
- {
- if let [] = block_stmts {
- Some(block_expr)
- } else {
- Some(expr)
- }
- } else {
- None
- }
-}
-
fn format_option_in_sugg(cx: &LateContext<'_>, cond_expr: &Expr<'_>, as_ref: bool, as_mut: bool) -> String {
format!(
"{}{}",
- Sugg::hir(cx, cond_expr, "..").maybe_par(),
+ Sugg::hir_with_macro_callsite(cx, cond_expr, "..").maybe_par(),
if as_mut {
".as_mut()"
} else if as_ref {
@@ -126,7 +104,7 @@ fn format_option_in_sugg(cx: &LateContext<'_>, cond_expr: &Expr<'_>, as_ref: boo
/// this construct is found, or None if this construct is not found.
fn detect_option_if_let_else<'tcx>(cx: &LateContext<'tcx>, expr: &Expr<'tcx>) -> Option<OptionIfLetElseOccurence> {
if_chain! {
- if !in_macro(expr.span); // Don't lint macros, because it behaves weirdly
+ if !expr.span.from_expansion(); // Don't lint macros, because it behaves weirdly
if !in_constant(cx, expr.hir_id);
if let Some(higher::IfLet { let_pat, let_expr, if_then, if_else: Some(if_else) })
= higher::IfLet::hir(cx, expr);
@@ -134,7 +112,7 @@ fn detect_option_if_let_else<'tcx>(cx: &LateContext<'tcx>, expr: &Expr<'tcx>) ->
if !is_result_ok(cx, let_expr); // Don't lint on Result::ok because a different lint does it already
if let PatKind::TupleStruct(struct_qpath, [inner_pat], _) = &let_pat.kind;
if is_lang_ctor(cx, struct_qpath, OptionSome);
- if let PatKind::Binding(bind_annotation, _, id, _) = &inner_pat.kind;
+ if let PatKind::Binding(bind_annotation, _, id, None) = &inner_pat.kind;
if let Some(some_captures) = can_move_expr_to_closure(cx, if_then);
if let Some(none_captures) = can_move_expr_to_closure(cx, if_else);
if some_captures
@@ -144,13 +122,9 @@ fn detect_option_if_let_else<'tcx>(cx: &LateContext<'tcx>, expr: &Expr<'tcx>) ->
then {
let capture_mut = if bind_annotation == &BindingAnnotation::Mutable { "mut " } else { "" };
- let some_body = extract_body_from_expr(if_then)?;
- let none_body = extract_body_from_expr(if_else)?;
- let method_sugg = if eager_or_lazy::is_eagerness_candidate(cx, none_body) {
- "map_or"
- } else {
- "map_or_else"
- };
+ let some_body = peel_blocks(if_then);
+ let none_body = peel_blocks(if_else);
+ let method_sugg = if eager_or_lazy::switch_to_eager_eval(cx, none_body) { "map_or" } else { "map_or_else" };
let capture_name = id.name.to_ident_string();
let (as_ref, as_mut) = match &let_expr.kind {
ExprKind::AddrOf(_, Mutability::Not, _) => (true, false),
@@ -183,8 +157,8 @@ fn detect_option_if_let_else<'tcx>(cx: &LateContext<'tcx>, expr: &Expr<'tcx>) ->
Some(OptionIfLetElseOccurence {
option: format_option_in_sugg(cx, cond_expr, as_ref, as_mut),
method_sugg: method_sugg.to_string(),
- some_expr: format!("|{}{}| {}", capture_mut, capture_name, Sugg::hir(cx, some_body, "..")),
- none_expr: format!("{}{}", if method_sugg == "map_or" { "" } else { "|| " }, Sugg::hir(cx, none_body, "..")),
+ some_expr: format!("|{}{}| {}", capture_mut, capture_name, Sugg::hir_with_macro_callsite(cx, some_body, "..")),
+ none_expr: format!("{}{}", if method_sugg == "map_or" { "" } else { "|| " }, Sugg::hir_with_macro_callsite(cx, none_body, "..")),
})
} else {
None
diff --git a/src/tools/clippy/clippy_lints/src/overflow_check_conditional.rs b/src/tools/clippy/clippy_lints/src/overflow_check_conditional.rs
index 0f9e5ada3a8..6dabbd48031 100644
--- a/src/tools/clippy/clippy_lints/src/overflow_check_conditional.rs
+++ b/src/tools/clippy/clippy_lints/src/overflow_check_conditional.rs
@@ -19,6 +19,7 @@ declare_clippy_lint! {
/// # let b = 2;
/// a + b < a;
/// ```
+ #[clippy::version = "pre 1.29.0"]
pub OVERFLOW_CHECK_CONDITIONAL,
complexity,
"overflow checks inspired by C which are likely to panic"
diff --git a/src/tools/clippy/clippy_lints/src/panic_in_result_fn.rs b/src/tools/clippy/clippy_lints/src/panic_in_result_fn.rs
index 583c42b6563..8769c045214 100644
--- a/src/tools/clippy/clippy_lints/src/panic_in_result_fn.rs
+++ b/src/tools/clippy/clippy_lints/src/panic_in_result_fn.rs
@@ -30,6 +30,7 @@ declare_clippy_lint! {
/// Err(String::from("error"))
/// }
/// ```
+ #[clippy::version = "1.48.0"]
pub PANIC_IN_RESULT_FN,
restriction,
"functions of type `Result<..>` that contain `panic!()`, `todo!()`, `unreachable()`, `unimplemented()` or assertion"
diff --git a/src/tools/clippy/clippy_lints/src/panic_unimplemented.rs b/src/tools/clippy/clippy_lints/src/panic_unimplemented.rs
index d8d9081d6f1..edfac824ded 100644
--- a/src/tools/clippy/clippy_lints/src/panic_unimplemented.rs
+++ b/src/tools/clippy/clippy_lints/src/panic_unimplemented.rs
@@ -17,6 +17,7 @@ declare_clippy_lint! {
/// ```no_run
/// panic!("even with a good reason");
/// ```
+ #[clippy::version = "1.40.0"]
pub PANIC,
restriction,
"usage of the `panic!` macro"
@@ -33,6 +34,7 @@ declare_clippy_lint! {
/// ```no_run
/// unimplemented!();
/// ```
+ #[clippy::version = "pre 1.29.0"]
pub UNIMPLEMENTED,
restriction,
"`unimplemented!` should not be present in production code"
@@ -49,6 +51,7 @@ declare_clippy_lint! {
/// ```no_run
/// todo!();
/// ```
+ #[clippy::version = "1.40.0"]
pub TODO,
restriction,
"`todo!` should not be present in production code"
@@ -65,6 +68,7 @@ declare_clippy_lint! {
/// ```no_run
/// unreachable!();
/// ```
+ #[clippy::version = "1.40.0"]
pub UNREACHABLE,
restriction,
"usage of the `unreachable!` macro"
diff --git a/src/tools/clippy/clippy_lints/src/partialeq_ne_impl.rs b/src/tools/clippy/clippy_lints/src/partialeq_ne_impl.rs
index 4ec493e5f45..e827cdaae87 100644
--- a/src/tools/clippy/clippy_lints/src/partialeq_ne_impl.rs
+++ b/src/tools/clippy/clippy_lints/src/partialeq_ne_impl.rs
@@ -25,6 +25,7 @@ declare_clippy_lint! {
/// fn ne(&self, other: &Foo) -> bool { !(self == other) }
/// }
/// ```
+ #[clippy::version = "pre 1.29.0"]
pub PARTIALEQ_NE_IMPL,
complexity,
"re-implementing `PartialEq::ne`"
diff --git a/src/tools/clippy/clippy_lints/src/pass_by_ref_or_value.rs b/src/tools/clippy/clippy_lints/src/pass_by_ref_or_value.rs
index 6229b9608b3..3092ab8392a 100644
--- a/src/tools/clippy/clippy_lints/src/pass_by_ref_or_value.rs
+++ b/src/tools/clippy/clippy_lints/src/pass_by_ref_or_value.rs
@@ -65,6 +65,7 @@ declare_clippy_lint! {
/// // Better
/// fn foo(v: u32) {}
/// ```
+ #[clippy::version = "pre 1.29.0"]
pub TRIVIALLY_COPY_PASS_BY_REF,
pedantic,
"functions taking small copyable arguments by reference"
@@ -98,6 +99,7 @@ declare_clippy_lint! {
/// // Good
/// fn foo(v: &TooLarge) {}
/// ```
+ #[clippy::version = "1.49.0"]
pub LARGE_TYPES_PASSED_BY_VALUE,
pedantic,
"functions taking large arguments by value"
diff --git a/src/tools/clippy/clippy_lints/src/path_buf_push_overwrite.rs b/src/tools/clippy/clippy_lints/src/path_buf_push_overwrite.rs
index 3df7a72d295..8ebee9bd04d 100644
--- a/src/tools/clippy/clippy_lints/src/path_buf_push_overwrite.rs
+++ b/src/tools/clippy/clippy_lints/src/path_buf_push_overwrite.rs
@@ -35,6 +35,7 @@ declare_clippy_lint! {
/// x.push("bar");
/// assert_eq!(x, PathBuf::from("/foo/bar"));
/// ```
+ #[clippy::version = "1.36.0"]
pub PATH_BUF_PUSH_OVERWRITE,
nursery,
"calling `push` with file system root on `PathBuf` can overwrite it"
diff --git a/src/tools/clippy/clippy_lints/src/pattern_type_mismatch.rs b/src/tools/clippy/clippy_lints/src/pattern_type_mismatch.rs
index 018e6d611db..be319ee110d 100644
--- a/src/tools/clippy/clippy_lints/src/pattern_type_mismatch.rs
+++ b/src/tools/clippy/clippy_lints/src/pattern_type_mismatch.rs
@@ -1,6 +1,6 @@
use clippy_utils::diagnostics::span_lint_and_help;
use rustc_hir::{
- intravisit, Body, Expr, ExprKind, FnDecl, HirId, LocalSource, Mutability, Pat, PatKind, Stmt, StmtKind,
+ intravisit, Body, Expr, ExprKind, FnDecl, HirId, Let, LocalSource, Mutability, Pat, PatKind, Stmt, StmtKind,
};
use rustc_lint::{LateContext, LateLintPass, LintContext};
use rustc_middle::lint::in_external_macro;
@@ -73,6 +73,7 @@ declare_clippy_lint! {
/// *a += b;
/// }
/// ```
+ #[clippy::version = "1.47.0"]
pub PATTERN_TYPE_MISMATCH,
restriction,
"type of pattern does not match the expression type"
@@ -103,8 +104,8 @@ impl<'tcx> LateLintPass<'tcx> for PatternTypeMismatch {
}
}
}
- if let ExprKind::Let(let_pat, ..) = expr.kind {
- apply_lint(cx, let_pat, DerefPossible::Possible);
+ if let ExprKind::Let(Let { pat, .. }) = expr.kind {
+ apply_lint(cx, pat, DerefPossible::Possible);
}
}
diff --git a/src/tools/clippy/clippy_lints/src/precedence.rs b/src/tools/clippy/clippy_lints/src/precedence.rs
index 1a8da00d9d6..cc0533c9f5d 100644
--- a/src/tools/clippy/clippy_lints/src/precedence.rs
+++ b/src/tools/clippy/clippy_lints/src/precedence.rs
@@ -42,6 +42,7 @@ declare_clippy_lint! {
/// ### Example
/// * `1 << 2 + 3` equals 32, while `(1 << 2) + 3` equals 7
/// * `-1i32.abs()` equals -1, while `(-1i32).abs()` equals 1
+ #[clippy::version = "pre 1.29.0"]
pub PRECEDENCE,
complexity,
"operations where precedence may be unclear"
diff --git a/src/tools/clippy/clippy_lints/src/ptr.rs b/src/tools/clippy/clippy_lints/src/ptr.rs
index 8a36e20fc97..c08a19d520b 100644
--- a/src/tools/clippy/clippy_lints/src/ptr.rs
+++ b/src/tools/clippy/clippy_lints/src/ptr.rs
@@ -70,6 +70,7 @@ declare_clippy_lint! {
/// // Good
/// fn foo(&[u32]) { .. }
/// ```
+ #[clippy::version = "pre 1.29.0"]
pub PTR_ARG,
style,
"fn arguments of the type `&Vec<...>` or `&String`, suggesting to use `&[...]` or `&str` instead, respectively"
@@ -96,6 +97,7 @@ declare_clippy_lint! {
/// ..
/// }
/// ```
+ #[clippy::version = "pre 1.29.0"]
pub CMP_NULL,
style,
"comparing a pointer to a null pointer, suggesting to use `.is_null()` instead"
@@ -121,6 +123,7 @@ declare_clippy_lint! {
/// ```ignore
/// fn foo(&Foo) -> &mut Bar { .. }
/// ```
+ #[clippy::version = "pre 1.29.0"]
pub MUT_FROM_REF,
correctness,
"fns that create mutable refs from immutable ref args"
@@ -143,6 +146,7 @@ declare_clippy_lint! {
/// // Good
/// unsafe { std::slice::from_raw_parts(NonNull::dangling().as_ptr(), 0); }
/// ```
+ #[clippy::version = "1.53.0"]
pub INVALID_NULL_PTR_USAGE,
correctness,
"invalid usage of a null pointer, suggesting `NonNull::dangling()` instead"
diff --git a/src/tools/clippy/clippy_lints/src/ptr_eq.rs b/src/tools/clippy/clippy_lints/src/ptr_eq.rs
index 3258c9fb3fe..3c126fc1ca6 100644
--- a/src/tools/clippy/clippy_lints/src/ptr_eq.rs
+++ b/src/tools/clippy/clippy_lints/src/ptr_eq.rs
@@ -1,5 +1,4 @@
use clippy_utils::diagnostics::span_lint_and_sugg;
-use clippy_utils::in_macro;
use clippy_utils::source::snippet_opt;
use if_chain::if_chain;
use rustc_errors::Applicability;
@@ -30,6 +29,7 @@ declare_clippy_lint! {
///
/// assert!(std::ptr::eq(a, b));
/// ```
+ #[clippy::version = "1.49.0"]
pub PTR_EQ,
style,
"use `std::ptr::eq` when comparing raw pointers"
@@ -41,7 +41,7 @@ static LINT_MSG: &str = "use `std::ptr::eq` when comparing raw pointers";
impl LateLintPass<'_> for PtrEq {
fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
- if in_macro(expr.span) {
+ if expr.span.from_expansion() {
return;
}
diff --git a/src/tools/clippy/clippy_lints/src/ptr_offset_with_cast.rs b/src/tools/clippy/clippy_lints/src/ptr_offset_with_cast.rs
index cfb5287c667..964564b5794 100644
--- a/src/tools/clippy/clippy_lints/src/ptr_offset_with_cast.rs
+++ b/src/tools/clippy/clippy_lints/src/ptr_offset_with_cast.rs
@@ -38,6 +38,7 @@ declare_clippy_lint! {
/// ptr.add(offset);
/// }
/// ```
+ #[clippy::version = "1.30.0"]
pub PTR_OFFSET_WITH_CAST,
complexity,
"unneeded pointer offset cast"
diff --git a/src/tools/clippy/clippy_lints/src/question_mark.rs b/src/tools/clippy/clippy_lints/src/question_mark.rs
index f63ef163bcb..c765c8962cf 100644
--- a/src/tools/clippy/clippy_lints/src/question_mark.rs
+++ b/src/tools/clippy/clippy_lints/src/question_mark.rs
@@ -1,14 +1,13 @@
use clippy_utils::diagnostics::span_lint_and_sugg;
use clippy_utils::higher;
-use clippy_utils::is_lang_ctor;
use clippy_utils::source::snippet_with_applicability;
use clippy_utils::sugg::Sugg;
use clippy_utils::ty::is_type_diagnostic_item;
-use clippy_utils::{eq_expr_value, path_to_local, path_to_local_id};
+use clippy_utils::{eq_expr_value, is_lang_ctor, path_to_local, path_to_local_id, peel_blocks, peel_blocks_with_stmt};
use if_chain::if_chain;
use rustc_errors::Applicability;
use rustc_hir::LangItem::{OptionNone, OptionSome, ResultOk};
-use rustc_hir::{BindingAnnotation, Block, Expr, ExprKind, PatKind, StmtKind};
+use rustc_hir::{BindingAnnotation, Expr, ExprKind, PatKind};
use rustc_lint::{LateContext, LateLintPass};
use rustc_session::{declare_lint_pass, declare_tool_lint};
use rustc_span::sym;
@@ -32,6 +31,7 @@ declare_clippy_lint! {
/// ```ignore
/// option?;
/// ```
+ #[clippy::version = "pre 1.29.0"]
pub QUESTION_MARK,
style,
"checks for expressions that could be replaced by the question mark operator"
@@ -67,14 +67,8 @@ impl QuestionMark {
let receiver_str = &Sugg::hir_with_applicability(cx, subject, "..", &mut applicability);
let mut replacement: Option<String> = None;
if let Some(else_inner) = r#else {
- if_chain! {
- if let ExprKind::Block(block, None) = &else_inner.kind;
- if block.stmts.is_empty();
- if let Some(block_expr) = &block.expr;
- if eq_expr_value(cx, subject, block_expr);
- then {
- replacement = Some(format!("Some({}?)", receiver_str));
- }
+ if eq_expr_value(cx, subject, peel_blocks(else_inner)) {
+ replacement = Some(format!("Some({}?)", receiver_str));
}
} else if Self::moves_by_default(cx, subject)
&& !matches!(subject.kind, ExprKind::Call(..) | ExprKind::MethodCall(..))
@@ -109,10 +103,7 @@ impl QuestionMark {
if let PatKind::Binding(annot, bind_id, _, _) = fields[0].kind;
let by_ref = matches!(annot, BindingAnnotation::Ref | BindingAnnotation::RefMut);
- if let ExprKind::Block(block, None) = if_then.kind;
- if block.stmts.is_empty();
- if let Some(trailing_expr) = &block.expr;
- if path_to_local_id(trailing_expr, bind_id);
+ if path_to_local_id(peel_blocks(if_then), bind_id);
then {
let mut applicability = Applicability::MachineApplicable;
let receiver_str = snippet_with_applicability(cx, let_expr.span, "..", &mut applicability);
@@ -158,14 +149,7 @@ impl QuestionMark {
}
fn expression_returns_none(cx: &LateContext<'_>, expression: &Expr<'_>) -> bool {
- match expression.kind {
- ExprKind::Block(block, _) => {
- if let Some(return_expression) = Self::return_expression(block) {
- return Self::expression_returns_none(cx, return_expression);
- }
-
- false
- },
+ match peel_blocks_with_stmt(expression).kind {
ExprKind::Ret(Some(expr)) => Self::expression_returns_none(cx, expr),
ExprKind::Path(ref qpath) => is_lang_ctor(cx, qpath, OptionNone),
_ => false,
@@ -173,44 +157,12 @@ impl QuestionMark {
}
fn expression_returns_unmodified_err(cx: &LateContext<'_>, expr: &Expr<'_>, cond_expr: &Expr<'_>) -> bool {
- match expr.kind {
- ExprKind::Block(block, _) => {
- if let Some(return_expression) = Self::return_expression(block) {
- return Self::expression_returns_unmodified_err(cx, return_expression, cond_expr);
- }
-
- false
- },
+ match peel_blocks_with_stmt(expr).kind {
ExprKind::Ret(Some(ret_expr)) => Self::expression_returns_unmodified_err(cx, ret_expr, cond_expr),
- ExprKind::Path(_) => path_to_local(expr) == path_to_local(cond_expr),
+ ExprKind::Path(_) => path_to_local(expr).is_some() && path_to_local(expr) == path_to_local(cond_expr),
_ => false,
}
}
-
- fn return_expression<'tcx>(block: &Block<'tcx>) -> Option<&'tcx Expr<'tcx>> {
- // Check if last expression is a return statement. Then, return the expression
- if_chain! {
- if block.stmts.len() == 1;
- if let Some(expr) = block.stmts.iter().last();
- if let StmtKind::Semi(expr) = expr.kind;
- if let ExprKind::Ret(Some(ret_expr)) = expr.kind;
-
- then {
- return Some(ret_expr);
- }
- }
-
- // Check for `return` without a semicolon.
- if_chain! {
- if block.stmts.is_empty();
- if let Some(ExprKind::Ret(Some(ret_expr))) = block.expr.as_ref().map(|e| &e.kind);
- then {
- return Some(ret_expr);
- }
- }
-
- None
- }
}
impl<'tcx> LateLintPass<'tcx> for QuestionMark {
diff --git a/src/tools/clippy/clippy_lints/src/ranges.rs b/src/tools/clippy/clippy_lints/src/ranges.rs
index 4fa361fedaf..52c060bc42c 100644
--- a/src/tools/clippy/clippy_lints/src/ranges.rs
+++ b/src/tools/clippy/clippy_lints/src/ranges.rs
@@ -35,6 +35,7 @@ declare_clippy_lint! {
/// # let x = vec![1];
/// x.iter().enumerate();
/// ```
+ #[clippy::version = "pre 1.29.0"]
pub RANGE_ZIP_WITH_LEN,
complexity,
"zipping iterator with a range when `enumerate()` would do"
@@ -72,6 +73,7 @@ declare_clippy_lint! {
/// ```rust,ignore
/// for x..=y { .. }
/// ```
+ #[clippy::version = "pre 1.29.0"]
pub RANGE_PLUS_ONE,
pedantic,
"`x..(y+1)` reads better as `x..=y`"
@@ -100,6 +102,7 @@ declare_clippy_lint! {
/// ```rust,ignore
/// for x..y { .. }
/// ```
+ #[clippy::version = "pre 1.29.0"]
pub RANGE_MINUS_ONE,
pedantic,
"`x..=(y-1)` reads better as `x..y`"
@@ -132,6 +135,7 @@ declare_clippy_lint! {
/// let sub = &arr[1..3];
/// }
/// ```
+ #[clippy::version = "1.45.0"]
pub REVERSED_EMPTY_RANGES,
correctness,
"reversing the limits of range expressions, resulting in empty ranges"
@@ -158,6 +162,7 @@ declare_clippy_lint! {
///# let x = 6;
/// assert!((3..8).contains(&x));
/// ```
+ #[clippy::version = "1.49.0"]
pub MANUAL_RANGE_CONTAINS,
style,
"manually reimplementing {`Range`, `RangeInclusive`}`::contains`"
diff --git a/src/tools/clippy/clippy_lints/src/redundant_clone.rs b/src/tools/clippy/clippy_lints/src/redundant_clone.rs
index f7711b6fe94..1cf349f8aa7 100644
--- a/src/tools/clippy/clippy_lints/src/redundant_clone.rs
+++ b/src/tools/clippy/clippy_lints/src/redundant_clone.rs
@@ -15,7 +15,7 @@ use rustc_middle::mir::{
Mutability,
};
use rustc_middle::ty::{self, fold::TypeVisitor, Ty, TyCtxt};
-use rustc_mir_dataflow::{Analysis, AnalysisDomain, GenKill, GenKillAnalysis, ResultsCursor};
+use rustc_mir_dataflow::{Analysis, AnalysisDomain, CallReturnPlaces, GenKill, GenKillAnalysis, ResultsCursor};
use rustc_session::{declare_lint_pass, declare_tool_lint};
use rustc_span::source_map::{BytePos, Span};
use rustc_span::sym;
@@ -62,6 +62,7 @@ declare_clippy_lint! {
///
/// Path::new("/a/b").join("c").to_path_buf();
/// ```
+ #[clippy::version = "1.32.0"]
pub REDUNDANT_CLONE,
perf,
"`clone()` of an owned value that is going to be dropped immediately"
@@ -499,11 +500,9 @@ impl<'tcx> GenKillAnalysis<'tcx> for MaybeStorageLive {
fn call_return_effect(
&self,
- _in_out: &mut impl GenKill<Self::Idx>,
+ _trans: &mut impl GenKill<Self::Idx>,
_block: mir::BasicBlock,
- _func: &mir::Operand<'tcx>,
- _args: &[mir::Operand<'tcx>],
- _return_place: mir::Place<'tcx>,
+ _return_places: CallReturnPlaces<'_, 'tcx>,
) {
// Nothing to do when a call returns successfully
}
diff --git a/src/tools/clippy/clippy_lints/src/redundant_closure_call.rs b/src/tools/clippy/clippy_lints/src/redundant_closure_call.rs
index 90e3c3f4b3e..0de282542fc 100644
--- a/src/tools/clippy/clippy_lints/src/redundant_closure_call.rs
+++ b/src/tools/clippy/clippy_lints/src/redundant_closure_call.rs
@@ -30,6 +30,7 @@ declare_clippy_lint! {
/// // Good
/// let a = 42
/// ```
+ #[clippy::version = "pre 1.29.0"]
pub REDUNDANT_CLOSURE_CALL,
complexity,
"throwaway closures called in the expression they are defined"
diff --git a/src/tools/clippy/clippy_lints/src/redundant_else.rs b/src/tools/clippy/clippy_lints/src/redundant_else.rs
index 68b256d2944..93dbe936d58 100644
--- a/src/tools/clippy/clippy_lints/src/redundant_else.rs
+++ b/src/tools/clippy/clippy_lints/src/redundant_else.rs
@@ -36,6 +36,7 @@ declare_clippy_lint! {
/// print!("Moving on...");
/// }
/// ```
+ #[clippy::version = "1.50.0"]
pub REDUNDANT_ELSE,
pedantic,
"`else` branch that can be removed without changing semantics"
diff --git a/src/tools/clippy/clippy_lints/src/redundant_field_names.rs b/src/tools/clippy/clippy_lints/src/redundant_field_names.rs
index 47df4917510..0dea4a784b2 100644
--- a/src/tools/clippy/clippy_lints/src/redundant_field_names.rs
+++ b/src/tools/clippy/clippy_lints/src/redundant_field_names.rs
@@ -30,6 +30,7 @@ declare_clippy_lint! {
/// ```ignore
/// let foo = Foo { bar };
/// ```
+ #[clippy::version = "pre 1.29.0"]
pub REDUNDANT_FIELD_NAMES,
style,
"checks for fields in struct literals where shorthands could be used"
diff --git a/src/tools/clippy/clippy_lints/src/redundant_pub_crate.rs b/src/tools/clippy/clippy_lints/src/redundant_pub_crate.rs
index 919d4e11e5a..2cee3c14d7f 100644
--- a/src/tools/clippy/clippy_lints/src/redundant_pub_crate.rs
+++ b/src/tools/clippy/clippy_lints/src/redundant_pub_crate.rs
@@ -26,6 +26,7 @@ declare_clippy_lint! {
/// pub fn internal_fn() { }
/// }
/// ```
+ #[clippy::version = "1.44.0"]
pub REDUNDANT_PUB_CRATE,
nursery,
"Using `pub(crate)` visibility on items that are not crate visible due to the visibility of the module that contains them."
diff --git a/src/tools/clippy/clippy_lints/src/redundant_slicing.rs b/src/tools/clippy/clippy_lints/src/redundant_slicing.rs
index 290348c4509..b2bd0103d11 100644
--- a/src/tools/clippy/clippy_lints/src/redundant_slicing.rs
+++ b/src/tools/clippy/clippy_lints/src/redundant_slicing.rs
@@ -1,7 +1,7 @@
use clippy_utils::diagnostics::span_lint_and_sugg;
+use clippy_utils::get_parent_expr;
use clippy_utils::source::snippet_with_context;
use clippy_utils::ty::is_type_lang_item;
-use clippy_utils::{get_parent_expr, in_macro};
use if_chain::if_chain;
use rustc_errors::Applicability;
use rustc_hir::{BorrowKind, Expr, ExprKind, LangItem, Mutability};
@@ -34,6 +34,7 @@ declare_clippy_lint! {
/// x
/// }
/// ```
+ #[clippy::version = "1.51.0"]
pub REDUNDANT_SLICING,
complexity,
"redundant slicing of the whole range of a type"
@@ -43,7 +44,7 @@ declare_lint_pass!(RedundantSlicing => [REDUNDANT_SLICING]);
impl LateLintPass<'_> for RedundantSlicing {
fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
- if in_macro(expr.span) {
+ if expr.span.from_expansion() {
return;
}
diff --git a/src/tools/clippy/clippy_lints/src/redundant_static_lifetimes.rs b/src/tools/clippy/clippy_lints/src/redundant_static_lifetimes.rs
index d5a1a61da6b..ea5064217ab 100644
--- a/src/tools/clippy/clippy_lints/src/redundant_static_lifetimes.rs
+++ b/src/tools/clippy/clippy_lints/src/redundant_static_lifetimes.rs
@@ -27,6 +27,7 @@ declare_clippy_lint! {
/// const FOO: &[(&str, &str, fn(&Bar) -> bool)] = &[...]
/// static FOO: &[(&str, &str, fn(&Bar) -> bool)] = &[...]
/// ```
+ #[clippy::version = "1.37.0"]
pub REDUNDANT_STATIC_LIFETIMES,
style,
"Using explicit `'static` lifetime for constants or statics when elision rules would allow omitting them."
diff --git a/src/tools/clippy/clippy_lints/src/ref_option_ref.rs b/src/tools/clippy/clippy_lints/src/ref_option_ref.rs
index d543832e314..909d6971a54 100644
--- a/src/tools/clippy/clippy_lints/src/ref_option_ref.rs
+++ b/src/tools/clippy/clippy_lints/src/ref_option_ref.rs
@@ -28,6 +28,7 @@ declare_clippy_lint! {
/// ```rust,ignore
/// let x: Option<&u32> = Some(&0u32);
/// ```
+ #[clippy::version = "1.49.0"]
pub REF_OPTION_REF,
pedantic,
"use `Option<&T>` instead of `&Option<&T>`"
diff --git a/src/tools/clippy/clippy_lints/src/reference.rs b/src/tools/clippy/clippy_lints/src/reference.rs
index 77b6e60d893..22ae7a291d0 100644
--- a/src/tools/clippy/clippy_lints/src/reference.rs
+++ b/src/tools/clippy/clippy_lints/src/reference.rs
@@ -1,5 +1,4 @@
use clippy_utils::diagnostics::span_lint_and_sugg;
-use clippy_utils::in_macro;
use clippy_utils::source::{snippet_opt, snippet_with_applicability};
use clippy_utils::sugg::Sugg;
use if_chain::if_chain;
@@ -31,6 +30,7 @@ declare_clippy_lint! {
/// let a = f(b);
/// let c = d;
/// ```
+ #[clippy::version = "pre 1.29.0"]
pub DEREF_ADDROF,
complexity,
"use of `*&` or `*&mut` in an expression"
@@ -50,7 +50,7 @@ impl EarlyLintPass for DerefAddrOf {
if_chain! {
if let ExprKind::Unary(UnOp::Deref, ref deref_target) = e.kind;
if let ExprKind::AddrOf(_, ref mutability, ref addrof_target) = without_parens(deref_target).kind;
- if !in_macro(addrof_target.span);
+ if !addrof_target.span.from_expansion();
then {
let mut applicability = Applicability::MachineApplicable;
let sugg = if e.span.from_expansion() {
@@ -125,6 +125,7 @@ declare_clippy_lint! {
/// # let point = Point(30, 20);
/// let x = point.0;
/// ```
+ #[clippy::version = "pre 1.29.0"]
pub REF_IN_DEREF,
complexity,
"Use of reference in auto dereference expression."
diff --git a/src/tools/clippy/clippy_lints/src/regex.rs b/src/tools/clippy/clippy_lints/src/regex.rs
index 5d08aee1e5f..8e5983b4773 100644
--- a/src/tools/clippy/clippy_lints/src/regex.rs
+++ b/src/tools/clippy/clippy_lints/src/regex.rs
@@ -22,6 +22,7 @@ declare_clippy_lint! {
/// ```ignore
/// Regex::new("|")
/// ```
+ #[clippy::version = "pre 1.29.0"]
pub INVALID_REGEX,
correctness,
"invalid regular expressions"
@@ -46,6 +47,7 @@ declare_clippy_lint! {
/// ```ignore
/// Regex::new("^foobar")
/// ```
+ #[clippy::version = "pre 1.29.0"]
pub TRIVIAL_REGEX,
nursery,
"trivial regular expressions"
diff --git a/src/tools/clippy/clippy_lints/src/repeat_once.rs b/src/tools/clippy/clippy_lints/src/repeat_once.rs
index cf94c0e97d9..b5dd2de6337 100644
--- a/src/tools/clippy/clippy_lints/src/repeat_once.rs
+++ b/src/tools/clippy/clippy_lints/src/repeat_once.rs
@@ -1,6 +1,5 @@
use clippy_utils::consts::{constant_context, Constant};
use clippy_utils::diagnostics::span_lint_and_sugg;
-use clippy_utils::in_macro;
use clippy_utils::source::snippet;
use clippy_utils::ty::is_type_diagnostic_item;
use if_chain::if_chain;
@@ -36,6 +35,7 @@ declare_clippy_lint! {
/// let x = String::from("hello world").clone();
/// }
/// ```
+ #[clippy::version = "1.47.0"]
pub REPEAT_ONCE,
complexity,
"using `.repeat(1)` instead of `String.clone()`, `str.to_string()` or `slice.to_vec()` "
@@ -49,7 +49,7 @@ impl<'tcx> LateLintPass<'tcx> for RepeatOnce {
if let ExprKind::MethodCall(path, _, [receiver, count], _) = &expr.kind;
if path.ident.name == sym!(repeat);
if constant_context(cx, cx.typeck_results()).expr(count) == Some(Constant::Int(1));
- if !in_macro(receiver.span);
+ if !receiver.span.from_expansion();
then {
let ty = cx.typeck_results().expr_ty(receiver).peel_refs();
if ty.is_str() {
diff --git a/src/tools/clippy/clippy_lints/src/return_self_not_must_use.rs b/src/tools/clippy/clippy_lints/src/return_self_not_must_use.rs
new file mode 100644
index 00000000000..1118da6c8cb
--- /dev/null
+++ b/src/tools/clippy/clippy_lints/src/return_self_not_must_use.rs
@@ -0,0 +1,105 @@
+use clippy_utils::{diagnostics::span_lint, must_use_attr, nth_arg, return_ty};
+use rustc_hir::def_id::LocalDefId;
+use rustc_hir::intravisit::FnKind;
+use rustc_hir::{Body, FnDecl, HirId, TraitItem, TraitItemKind};
+use rustc_lint::{LateContext, LateLintPass, LintContext};
+use rustc_middle::lint::in_external_macro;
+use rustc_session::{declare_lint_pass, declare_tool_lint};
+use rustc_span::Span;
+
+declare_clippy_lint! {
+ /// ### What it does
+ /// This lint warns when a method returning `Self` doesn't have the `#[must_use]` attribute.
+ ///
+ /// ### Why is this bad?
+ /// It prevents to "forget" to use the newly created value.
+ ///
+ /// ### Limitations
+ /// This lint is only applied on methods taking a `self` argument. It would be mostly noise
+ /// if it was added on constructors for example.
+ ///
+ /// ### Example
+ /// ```rust
+ /// pub struct Bar;
+ ///
+ /// impl Bar {
+ /// // Bad
+ /// pub fn bar(&self) -> Self {
+ /// Self
+ /// }
+ ///
+ /// // Good
+ /// #[must_use]
+ /// pub fn foo(&self) -> Self {
+ /// Self
+ /// }
+ /// }
+ /// ```
+ #[clippy::version = "1.59.0"]
+ pub RETURN_SELF_NOT_MUST_USE,
+ suspicious,
+ "missing `#[must_use]` annotation on a method returning `Self`"
+}
+
+declare_lint_pass!(ReturnSelfNotMustUse => [RETURN_SELF_NOT_MUST_USE]);
+
+fn check_method(cx: &LateContext<'tcx>, decl: &'tcx FnDecl<'tcx>, fn_def: LocalDefId, span: Span, hir_id: HirId) {
+ if_chain! {
+ // If it comes from an external macro, better ignore it.
+ if !in_external_macro(cx.sess(), span);
+ if decl.implicit_self.has_implicit_self();
+ // We only show this warning for public exported methods.
+ if cx.access_levels.is_exported(fn_def);
+ if cx.tcx.visibility(fn_def.to_def_id()).is_public();
+ // No need to warn if the attribute is already present.
+ if must_use_attr(cx.tcx.hir().attrs(hir_id)).is_none();
+ let ret_ty = return_ty(cx, hir_id);
+ let self_arg = nth_arg(cx, hir_id, 0);
+ // If `Self` has the same type as the returned type, then we want to warn.
+ //
+ // For this check, we don't want to remove the reference on the returned type because if
+ // there is one, we shouldn't emit a warning!
+ if self_arg.peel_refs() == ret_ty;
+
+ then {
+ span_lint(
+ cx,
+ RETURN_SELF_NOT_MUST_USE,
+ span,
+ "missing `#[must_use]` attribute on a method returning `Self`",
+ );
+ }
+ }
+}
+
+impl<'tcx> LateLintPass<'tcx> for ReturnSelfNotMustUse {
+ fn check_fn(
+ &mut self,
+ cx: &LateContext<'tcx>,
+ kind: FnKind<'tcx>,
+ decl: &'tcx FnDecl<'tcx>,
+ _: &'tcx Body<'tcx>,
+ span: Span,
+ hir_id: HirId,
+ ) {
+ if_chain! {
+ // We are only interested in methods, not in functions or associated functions.
+ if matches!(kind, FnKind::Method(_, _, _));
+ if let Some(fn_def) = cx.tcx.hir().opt_local_def_id(hir_id);
+ if let Some(impl_def) = cx.tcx.impl_of_method(fn_def.to_def_id());
+ // We don't want this method to be te implementation of a trait because the
+ // `#[must_use]` should be put on the trait definition directly.
+ if cx.tcx.trait_id_of_impl(impl_def).is_none();
+
+ then {
+ check_method(cx, decl, fn_def, span, hir_id);
+ }
+ }
+ }
+
+ fn check_trait_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx TraitItem<'tcx>) {
+ if let TraitItemKind::Fn(ref sig, _) = item.kind {
+ check_method(cx, sig.decl, item.def_id, item.span, item.hir_id());
+ }
+ }
+}
diff --git a/src/tools/clippy/clippy_lints/src/returns.rs b/src/tools/clippy/clippy_lints/src/returns.rs
index ae85b7087e7..494bc7dda18 100644
--- a/src/tools/clippy/clippy_lints/src/returns.rs
+++ b/src/tools/clippy/clippy_lints/src/returns.rs
@@ -1,6 +1,6 @@
use clippy_utils::diagnostics::{span_lint_and_sugg, span_lint_and_then};
use clippy_utils::source::snippet_opt;
-use clippy_utils::{fn_def_id, in_macro, path_to_local_id};
+use clippy_utils::{fn_def_id, path_to_local_id};
use if_chain::if_chain;
use rustc_ast::ast::Attribute;
use rustc_errors::Applicability;
@@ -37,6 +37,7 @@ declare_clippy_lint! {
/// String::new()
/// }
/// ```
+ #[clippy::version = "pre 1.29.0"]
pub LET_AND_RETURN,
style,
"creating a let-binding and then immediately returning it like `let x = expr; x` at the end of a block"
@@ -62,6 +63,7 @@ declare_clippy_lint! {
/// x
/// }
/// ```
+ #[clippy::version = "pre 1.29.0"]
pub NEEDLESS_RETURN,
style,
"using a return statement like `return expr;` where an expression would suffice"
@@ -90,8 +92,7 @@ impl<'tcx> LateLintPass<'tcx> for Return {
if !last_statement_borrows(cx, initexpr);
if !in_external_macro(cx.sess(), initexpr.span);
if !in_external_macro(cx.sess(), retexpr.span);
- if !in_external_macro(cx.sess(), local.span);
- if !in_macro(local.span);
+ if !local.span.from_expansion();
then {
span_lint_and_then(
cx,
diff --git a/src/tools/clippy/clippy_lints/src/same_name_method.rs b/src/tools/clippy/clippy_lints/src/same_name_method.rs
index 737ff634e44..1bbaa104e60 100644
--- a/src/tools/clippy/clippy_lints/src/same_name_method.rs
+++ b/src/tools/clippy/clippy_lints/src/same_name_method.rs
@@ -11,7 +11,7 @@ use std::collections::{BTreeMap, BTreeSet};
declare_clippy_lint! {
/// ### What it does
- /// It lints if a struct has two method with same time:
+ /// It lints if a struct has two methods with the same name:
/// one from a trait, another not from trait.
///
/// ### Why is this bad?
@@ -33,6 +33,7 @@ declare_clippy_lint! {
/// fn foo(&self) {}
/// }
/// ```
+ #[clippy::version = "1.57.0"]
pub SAME_NAME_METHOD,
restriction,
"two method with same name"
@@ -99,7 +100,7 @@ impl<'tcx> LateLintPass<'tcx> for SameNameMethod {
cx,
SAME_NAME_METHOD,
*impl_span,
- "method's name is same to an existing method in a trait",
+ "method's name is the same as an existing method in a trait",
|diag| {
diag.span_note(
trait_method_span,
@@ -138,7 +139,7 @@ impl<'tcx> LateLintPass<'tcx> for SameNameMethod {
cx,
SAME_NAME_METHOD,
impl_span,
- "method's name is same to an existing method in a trait",
+ "method's name is the same as an existing method in a trait",
|diag| {
// TODO should we `span_note` on every trait?
// iterate on trait_spans?
diff --git a/src/tools/clippy/clippy_lints/src/self_assignment.rs b/src/tools/clippy/clippy_lints/src/self_assignment.rs
index fbd65fef7d1..b14f0518bdb 100644
--- a/src/tools/clippy/clippy_lints/src/self_assignment.rs
+++ b/src/tools/clippy/clippy_lints/src/self_assignment.rs
@@ -30,6 +30,7 @@ declare_clippy_lint! {
/// a.y = a.y;
/// }
/// ```
+ #[clippy::version = "1.48.0"]
pub SELF_ASSIGNMENT,
correctness,
"explicit self-assignment"
diff --git a/src/tools/clippy/clippy_lints/src/self_named_constructors.rs b/src/tools/clippy/clippy_lints/src/self_named_constructors.rs
index 4ba5e1a0f53..d386663e498 100644
--- a/src/tools/clippy/clippy_lints/src/self_named_constructors.rs
+++ b/src/tools/clippy/clippy_lints/src/self_named_constructors.rs
@@ -32,6 +32,7 @@ declare_clippy_lint! {
/// }
/// }
/// ```
+ #[clippy::version = "1.55.0"]
pub SELF_NAMED_CONSTRUCTORS,
style,
"method should not have the same name as the type it is implemented for"
@@ -50,7 +51,7 @@ impl<'tcx> LateLintPass<'tcx> for SelfNamedConstructors {
_ => return,
}
- let parent = cx.tcx.hir().get_parent_item(impl_item.hir_id());
+ let parent = cx.tcx.hir().get_parent_did(impl_item.hir_id());
let item = cx.tcx.hir().expect_item(parent);
let self_ty = cx.tcx.type_of(item.def_id);
let ret_ty = return_ty(cx, impl_item.hir_id());
@@ -75,7 +76,7 @@ impl<'tcx> LateLintPass<'tcx> for SelfNamedConstructors {
let self_id = cx.tcx.hir().local_def_id_to_hir_id(self_local_did);
if let Some(Node::Item(x)) = cx.tcx.hir().find(self_id);
let type_name = x.ident.name.as_str().to_lowercase();
- if impl_item.ident.name.as_str() == type_name || impl_item.ident.name.as_str().replace("_", "") == type_name;
+ if impl_item.ident.name.as_str() == type_name || impl_item.ident.name.as_str().replace('_', "") == type_name;
then {
span_lint(
diff --git a/src/tools/clippy/clippy_lints/src/semicolon_if_nothing_returned.rs b/src/tools/clippy/clippy_lints/src/semicolon_if_nothing_returned.rs
index c0e4914efe0..0b3bbbc8155 100644
--- a/src/tools/clippy/clippy_lints/src/semicolon_if_nothing_returned.rs
+++ b/src/tools/clippy/clippy_lints/src/semicolon_if_nothing_returned.rs
@@ -29,6 +29,7 @@ declare_clippy_lint! {
/// println!("Hello world");
/// }
/// ```
+ #[clippy::version = "1.52.0"]
pub SEMICOLON_IF_NOTHING_RETURNED,
pedantic,
"add a semicolon if nothing is returned"
@@ -44,7 +45,7 @@ impl LateLintPass<'_> for SemicolonIfNothingReturned {
let t_expr = cx.typeck_results().expr_ty(expr);
if t_expr.is_unit();
if let snippet = snippet_with_macro_callsite(cx, expr.span, "}");
- if !snippet.ends_with('}');
+ if !snippet.ends_with('}') && !snippet.ends_with(';');
if cx.sess().source_map().is_multiline(block.span);
then {
// filter out the desugared `for` loop
diff --git a/src/tools/clippy/clippy_lints/src/serde_api.rs b/src/tools/clippy/clippy_lints/src/serde_api.rs
index 2cd0f85999c..a38b3c4ab69 100644
--- a/src/tools/clippy/clippy_lints/src/serde_api.rs
+++ b/src/tools/clippy/clippy_lints/src/serde_api.rs
@@ -15,6 +15,7 @@ declare_clippy_lint! {
/// ### Example
/// Implementing `Visitor::visit_string` but not
/// `Visitor::visit_str`.
+ #[clippy::version = "pre 1.29.0"]
pub SERDE_API_MISUSE,
correctness,
"various things that will negatively affect your serde experience"
diff --git a/src/tools/clippy/clippy_lints/src/shadow.rs b/src/tools/clippy/clippy_lints/src/shadow.rs
index 64841f33cc3..f6880af0cab 100644
--- a/src/tools/clippy/clippy_lints/src/shadow.rs
+++ b/src/tools/clippy/clippy_lints/src/shadow.rs
@@ -29,6 +29,7 @@ declare_clippy_lint! {
/// // Good
/// let y = &x; // use different variable name
/// ```
+ #[clippy::version = "pre 1.29.0"]
pub SHADOW_SAME,
restriction,
"rebinding a name to itself, e.g., `let mut x = &mut x`"
@@ -55,6 +56,7 @@ declare_clippy_lint! {
/// let x = 2;
/// let y = x + 1;
/// ```
+ #[clippy::version = "pre 1.29.0"]
pub SHADOW_REUSE,
restriction,
"rebinding a name to an expression that re-uses the original value, e.g., `let x = x + 1`"
@@ -84,6 +86,7 @@ declare_clippy_lint! {
/// // Good
/// let w = z; // use different variable name
/// ```
+ #[clippy::version = "pre 1.29.0"]
pub SHADOW_UNRELATED,
restriction,
"rebinding a name without even using the original value"
@@ -102,11 +105,16 @@ impl<'tcx> LateLintPass<'tcx> for Shadow {
PatKind::Binding(_, hir_id, ident, _) => (hir_id, ident),
_ => return,
};
+
+ if pat.span.desugaring_kind().is_some() {
+ return;
+ }
+
if ident.span.from_expansion() || ident.span.is_dummy() {
return;
}
- let HirId { owner, local_id } = id;
+ let HirId { owner, local_id } = id;
// get (or insert) the list of items for this owner and symbol
let data = self.bindings.last_mut().unwrap();
let items_with_name = data.entry(ident.name).or_default();
diff --git a/src/tools/clippy/clippy_lints/src/single_component_path_imports.rs b/src/tools/clippy/clippy_lints/src/single_component_path_imports.rs
index f6487b8c46b..28d32203da9 100644
--- a/src/tools/clippy/clippy_lints/src/single_component_path_imports.rs
+++ b/src/tools/clippy/clippy_lints/src/single_component_path_imports.rs
@@ -1,5 +1,4 @@
use clippy_utils::diagnostics::{span_lint_and_help, span_lint_and_sugg};
-use clippy_utils::in_macro;
use rustc_ast::{ptr::P, Crate, Item, ItemKind, MacroDef, ModKind, UseTreeKind, VisibilityKind};
use rustc_errors::Applicability;
use rustc_lint::{EarlyContext, EarlyLintPass};
@@ -28,6 +27,7 @@ declare_clippy_lint! {
/// regex::Regex::new(r"^\d{4}-\d{2}-\d{2}$").unwrap();
/// }
/// ```
+ #[clippy::version = "1.43.0"]
pub SINGLE_COMPONENT_PATH_IMPORTS,
style,
"imports with single component path are redundant"
@@ -110,7 +110,7 @@ fn track_uses(
single_use_usages: &mut Vec<(Symbol, Span, bool)>,
macros: &mut Vec<Symbol>,
) {
- if in_macro(item.span) || item.vis.kind.is_pub() {
+ if item.span.from_expansion() || item.vis.kind.is_pub() {
return;
}
diff --git a/src/tools/clippy/clippy_lints/src/size_of_in_element_count.rs b/src/tools/clippy/clippy_lints/src/size_of_in_element_count.rs
index 3e4e4a8d0c0..df1e85afdd7 100644
--- a/src/tools/clippy/clippy_lints/src/size_of_in_element_count.rs
+++ b/src/tools/clippy/clippy_lints/src/size_of_in_element_count.rs
@@ -29,6 +29,7 @@ declare_clippy_lint! {
/// let mut y = [2u8; SIZE];
/// unsafe { copy_nonoverlapping(x.as_ptr(), y.as_mut_ptr(), size_of::<u8>() * SIZE) };
/// ```
+ #[clippy::version = "1.50.0"]
pub SIZE_OF_IN_ELEMENT_COUNT,
correctness,
"using `size_of::<T>` or `size_of_val::<T>` where a count of elements of `T` is expected"
diff --git a/src/tools/clippy/clippy_lints/src/slow_vector_initialization.rs b/src/tools/clippy/clippy_lints/src/slow_vector_initialization.rs
index 3608fe1472d..1ae772ef70b 100644
--- a/src/tools/clippy/clippy_lints/src/slow_vector_initialization.rs
+++ b/src/tools/clippy/clippy_lints/src/slow_vector_initialization.rs
@@ -36,6 +36,7 @@ declare_clippy_lint! {
/// let mut vec1 = vec![0; len];
/// let mut vec2 = vec![0; len];
/// ```
+ #[clippy::version = "1.32.0"]
pub SLOW_VECTOR_INITIALIZATION,
perf,
"slow vector initialization"
diff --git a/src/tools/clippy/clippy_lints/src/stable_sort_primitive.rs b/src/tools/clippy/clippy_lints/src/stable_sort_primitive.rs
index 4ea1293d504..953d21e07a3 100644
--- a/src/tools/clippy/clippy_lints/src/stable_sort_primitive.rs
+++ b/src/tools/clippy/clippy_lints/src/stable_sort_primitive.rs
@@ -28,6 +28,7 @@ declare_clippy_lint! {
/// let mut vec = vec![2, 1, 3];
/// vec.sort_unstable();
/// ```
+ #[clippy::version = "1.47.0"]
pub STABLE_SORT_PRIMITIVE,
perf,
"use of sort() when sort_unstable() is equivalent"
diff --git a/src/tools/clippy/clippy_lints/src/strings.rs b/src/tools/clippy/clippy_lints/src/strings.rs
index 6435107b8b4..73600a8a087 100644
--- a/src/tools/clippy/clippy_lints/src/strings.rs
+++ b/src/tools/clippy/clippy_lints/src/strings.rs
@@ -1,8 +1,8 @@
use clippy_utils::diagnostics::{span_lint, span_lint_and_help, span_lint_and_sugg};
use clippy_utils::source::{snippet, snippet_with_applicability};
use clippy_utils::ty::is_type_diagnostic_item;
-use clippy_utils::SpanlessEq;
use clippy_utils::{get_parent_expr, is_lint_allowed, match_function_call, method_calls, paths};
+use clippy_utils::{peel_blocks, SpanlessEq};
use if_chain::if_chain;
use rustc_errors::Applicability;
use rustc_hir::{BinOpKind, BorrowKind, Expr, ExprKind, LangItem, QPath};
@@ -31,6 +31,7 @@ declare_clippy_lint! {
/// x += ", World";
/// x.push_str(", World");
/// ```
+ #[clippy::version = "pre 1.29.0"]
pub STRING_ADD_ASSIGN,
pedantic,
"using `x = x + ..` where x is a `String` instead of `push_str()`"
@@ -58,6 +59,7 @@ declare_clippy_lint! {
/// let x = "Hello".to_owned();
/// x + ", World";
/// ```
+ #[clippy::version = "pre 1.29.0"]
pub STRING_ADD,
restriction,
"using `x + ..` where x is a `String` instead of `push_str()`"
@@ -102,6 +104,7 @@ declare_clippy_lint! {
/// // Good
/// let bs = b"a byte string";
/// ```
+ #[clippy::version = "pre 1.29.0"]
pub STRING_LIT_AS_BYTES,
nursery,
"calling `as_bytes` on a string literal instead of using a byte string literal"
@@ -125,6 +128,7 @@ declare_clippy_lint! {
/// ```rust,should_panic
/// &"Ölkanne"[1..];
/// ```
+ #[clippy::version = "1.58.0"]
pub STRING_SLICE,
restriction,
"slicing a string"
@@ -197,7 +201,7 @@ fn is_string(cx: &LateContext<'_>, e: &Expr<'_>) -> bool {
}
fn is_add(cx: &LateContext<'_>, src: &Expr<'_>, target: &Expr<'_>) -> bool {
- match src.kind {
+ match peel_blocks(src).kind {
ExprKind::Binary(
Spanned {
node: BinOpKind::Add, ..
@@ -205,9 +209,6 @@ fn is_add(cx: &LateContext<'_>, src: &Expr<'_>, target: &Expr<'_>) -> bool {
left,
_,
) => SpanlessEq::new(cx).eq_expr(target, left),
- ExprKind::Block(block, _) => {
- block.stmts.is_empty() && block.expr.as_ref().map_or(false, |expr| is_add(cx, expr, target))
- },
_ => false,
}
}
@@ -227,6 +228,7 @@ declare_clippy_lint! {
/// ```rust
/// let _ = &"Hello World!"[6..11];
/// ```
+ #[clippy::version = "1.50.0"]
pub STRING_FROM_UTF8_AS_BYTES,
complexity,
"casting string slices to byte slices and back"
@@ -255,7 +257,7 @@ impl<'tcx> LateLintPass<'tcx> for StringLitAsBytes {
if method_names[0] == sym!(as_bytes);
// Check for slicer
- if let ExprKind::Struct(QPath::LangItem(LangItem::Range, _), _, _) = right.kind;
+ if let ExprKind::Struct(QPath::LangItem(LangItem::Range, ..), _, _) = right.kind;
then {
let mut applicability = Applicability::MachineApplicable;
@@ -371,6 +373,7 @@ declare_clippy_lint! {
/// // example code which does not raise clippy warning
/// let _ = "str".to_owned();
/// ```
+ #[clippy::version = "pre 1.29.0"]
pub STR_TO_STRING,
restriction,
"using `to_string()` on a `&str`, which should be `to_owned()`"
@@ -420,6 +423,7 @@ declare_clippy_lint! {
/// let msg = String::from("Hello World");
/// let _ = msg.clone();
/// ```
+ #[clippy::version = "pre 1.29.0"]
pub STRING_TO_STRING,
restriction,
"using `to_string()` on a `String`, which should be `clone()`"
diff --git a/src/tools/clippy/clippy_lints/src/strlen_on_c_strings.rs b/src/tools/clippy/clippy_lints/src/strlen_on_c_strings.rs
index 516fa3d95b4..fee01fb0bd1 100644
--- a/src/tools/clippy/clippy_lints/src/strlen_on_c_strings.rs
+++ b/src/tools/clippy/clippy_lints/src/strlen_on_c_strings.rs
@@ -1,14 +1,14 @@
use clippy_utils::diagnostics::span_lint_and_sugg;
-use clippy_utils::in_macro;
-use clippy_utils::paths;
-use clippy_utils::source::snippet_with_macro_callsite;
-use clippy_utils::ty::{is_type_diagnostic_item, is_type_ref_to_diagnostic_item};
+use clippy_utils::source::snippet_with_context;
+use clippy_utils::ty::is_type_diagnostic_item;
+use clippy_utils::visitors::is_expr_unsafe;
+use clippy_utils::{get_parent_node, match_libc_symbol};
use if_chain::if_chain;
use rustc_errors::Applicability;
-use rustc_hir as hir;
+use rustc_hir::{Block, BlockCheckMode, Expr, ExprKind, Node, UnsafeSource};
use rustc_lint::{LateContext, LateLintPass};
use rustc_session::{declare_lint_pass, declare_tool_lint};
-use rustc_span::symbol::{sym, Symbol};
+use rustc_span::symbol::sym;
declare_clippy_lint! {
/// ### What it does
@@ -31,6 +31,7 @@ declare_clippy_lint! {
/// let cstring = CString::new("foo").expect("CString::new failed");
/// let len = cstring.as_bytes().len();
/// ```
+ #[clippy::version = "1.55.0"]
pub STRLEN_ON_C_STRINGS,
complexity,
"using `libc::strlen` on a `CString` or `CStr` value, while `as_bytes().len()` or `to_bytes().len()` respectively can be used instead"
@@ -39,29 +40,35 @@ declare_clippy_lint! {
declare_lint_pass!(StrlenOnCStrings => [STRLEN_ON_C_STRINGS]);
impl LateLintPass<'tcx> for StrlenOnCStrings {
- fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx hir::Expr<'_>) {
- if in_macro(expr.span) {
- return;
- }
-
+ fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
if_chain! {
- if let hir::ExprKind::Call(func, [recv]) = expr.kind;
- if let hir::ExprKind::Path(hir::QPath::Resolved(_, path)) = func.kind;
-
- if (&paths::LIBC_STRLEN).iter().map(|x| Symbol::intern(x)).eq(
- path.segments.iter().map(|seg| seg.ident.name));
- if let hir::ExprKind::MethodCall(path, _, args, _) = recv.kind;
- if args.len() == 1;
- if !args.iter().any(|e| e.span.from_expansion());
+ if !expr.span.from_expansion();
+ if let ExprKind::Call(func, [recv]) = expr.kind;
+ if let ExprKind::Path(path) = &func.kind;
+ if let Some(did) = cx.qpath_res(path, func.hir_id).opt_def_id();
+ if match_libc_symbol(cx, did, "strlen");
+ if let ExprKind::MethodCall(path, _, [self_arg], _) = recv.kind;
+ if !recv.span.from_expansion();
if path.ident.name == sym::as_ptr;
then {
- let cstring = &args[0];
- let ty = cx.typeck_results().expr_ty(cstring);
- let val_name = snippet_with_macro_callsite(cx, cstring.span, "..");
- let sugg = if is_type_diagnostic_item(cx, ty, sym::cstring_type){
- format!("{}.as_bytes().len()", val_name)
- } else if is_type_ref_to_diagnostic_item(cx, ty, sym::CStr){
- format!("{}.to_bytes().len()", val_name)
+ let ctxt = expr.span.ctxt();
+ let span = match get_parent_node(cx.tcx, expr.hir_id) {
+ Some(Node::Block(&Block {
+ rules: BlockCheckMode::UnsafeBlock(UnsafeSource::UserProvided), span, ..
+ }))
+ if span.ctxt() == ctxt && !is_expr_unsafe(cx, self_arg) => {
+ span
+ }
+ _ => expr.span,
+ };
+
+ let ty = cx.typeck_results().expr_ty(self_arg).peel_refs();
+ let mut app = Applicability::MachineApplicable;
+ let val_name = snippet_with_context(cx, self_arg.span, ctxt, "..", &mut app).0;
+ let method_name = if is_type_diagnostic_item(cx, ty, sym::cstring_type) {
+ "as_bytes"
+ } else if is_type_diagnostic_item(cx, ty, sym::CStr) {
+ "to_bytes"
} else {
return;
};
@@ -69,11 +76,11 @@ impl LateLintPass<'tcx> for StrlenOnCStrings {
span_lint_and_sugg(
cx,
STRLEN_ON_C_STRINGS,
- expr.span,
+ span,
"using `libc::strlen` on a `CString` or `CStr` value",
- "try this (you might also need to get rid of `unsafe` block in some cases):",
- sugg,
- Applicability::Unspecified // Sometimes unnecessary `unsafe` block
+ "try this",
+ format!("{}.{}().len()", val_name, method_name),
+ app,
);
}
}
diff --git a/src/tools/clippy/clippy_lints/src/suspicious_operation_groupings.rs b/src/tools/clippy/clippy_lints/src/suspicious_operation_groupings.rs
index 201aa067824..faf43fd9fc1 100644
--- a/src/tools/clippy/clippy_lints/src/suspicious_operation_groupings.rs
+++ b/src/tools/clippy/clippy_lints/src/suspicious_operation_groupings.rs
@@ -59,6 +59,7 @@ declare_clippy_lint! {
/// }
/// }
/// ```
+ #[clippy::version = "1.50.0"]
pub SUSPICIOUS_OPERATION_GROUPINGS,
nursery,
"groupings of binary operations that look suspiciously like typos"
diff --git a/src/tools/clippy/clippy_lints/src/suspicious_trait_impl.rs b/src/tools/clippy/clippy_lints/src/suspicious_trait_impl.rs
index 682fad00a13..a3195de81d1 100644
--- a/src/tools/clippy/clippy_lints/src/suspicious_trait_impl.rs
+++ b/src/tools/clippy/clippy_lints/src/suspicious_trait_impl.rs
@@ -25,6 +25,7 @@ declare_clippy_lint! {
/// }
/// }
/// ```
+ #[clippy::version = "pre 1.29.0"]
pub SUSPICIOUS_ARITHMETIC_IMPL,
suspicious,
"suspicious use of operators in impl of arithmetic trait"
@@ -46,6 +47,7 @@ declare_clippy_lint! {
/// }
/// }
/// ```
+ #[clippy::version = "pre 1.29.0"]
pub SUSPICIOUS_OP_ASSIGN_IMPL,
suspicious,
"suspicious use of operators in impl of OpAssign trait"
diff --git a/src/tools/clippy/clippy_lints/src/swap.rs b/src/tools/clippy/clippy_lints/src/swap.rs
index ef26de5b6b9..4c10b12437d 100644
--- a/src/tools/clippy/clippy_lints/src/swap.rs
+++ b/src/tools/clippy/clippy_lints/src/swap.rs
@@ -2,7 +2,7 @@ use clippy_utils::diagnostics::{span_lint_and_sugg, span_lint_and_then};
use clippy_utils::source::snippet_with_applicability;
use clippy_utils::sugg::Sugg;
use clippy_utils::ty::is_type_diagnostic_item;
-use clippy_utils::{can_mut_borrow_both, differing_macro_contexts, eq_expr_value};
+use clippy_utils::{can_mut_borrow_both, differing_macro_contexts, eq_expr_value, std_or_core};
use if_chain::if_chain;
use rustc_errors::Applicability;
use rustc_hir::{BinOpKind, Block, Expr, ExprKind, PatKind, QPath, Stmt, StmtKind};
@@ -35,6 +35,7 @@ declare_clippy_lint! {
/// let mut b = 2;
/// std::mem::swap(&mut a, &mut b);
/// ```
+ #[clippy::version = "pre 1.29.0"]
pub MANUAL_SWAP,
complexity,
"manual swap of two variables"
@@ -60,6 +61,7 @@ declare_clippy_lint! {
/// # let mut b = 2;
/// std::mem::swap(&mut a, &mut b);
/// ```
+ #[clippy::version = "pre 1.29.0"]
pub ALMOST_SWAPPED,
correctness,
"`foo = bar; bar = foo` sequence"
@@ -113,6 +115,8 @@ fn generate_swap_warning(cx: &LateContext<'_>, e1: &Expr<'_>, e2: &Expr<'_>, spa
let first = Sugg::hir_with_applicability(cx, e1, "..", &mut applicability);
let second = Sugg::hir_with_applicability(cx, e2, "..", &mut applicability);
+ let Some(sugg) = std_or_core(cx) else { return };
+
span_lint_and_then(
cx,
MANUAL_SWAP,
@@ -122,11 +126,11 @@ fn generate_swap_warning(cx: &LateContext<'_>, e1: &Expr<'_>, e2: &Expr<'_>, spa
diag.span_suggestion(
span,
"try",
- format!("std::mem::swap({}, {})", first.mut_addr(), second.mut_addr()),
+ format!("{}::mem::swap({}, {})", sugg, first.mut_addr(), second.mut_addr()),
applicability,
);
if !is_xor_based {
- diag.note("or maybe you should use `std::mem::replace`?");
+ diag.note(&format!("or maybe you should use `{}::mem::replace`?", sugg));
}
},
);
@@ -187,26 +191,30 @@ fn check_suspicious_swap(cx: &LateContext<'_>, block: &Block<'_>) {
};
let span = first.span.to(second.span);
+ let Some(sugg) = std_or_core(cx) else { return };
span_lint_and_then(cx,
- ALMOST_SWAPPED,
- span,
- &format!("this looks like you are trying to swap{}", what),
- |diag| {
- if !what.is_empty() {
- diag.span_suggestion(
- span,
- "try",
- format!(
- "std::mem::swap({}, {})",
- lhs,
- rhs,
- ),
- Applicability::MaybeIncorrect,
- );
- diag.note("or maybe you should use `std::mem::replace`?");
- }
- });
+ ALMOST_SWAPPED,
+ span,
+ &format!("this looks like you are trying to swap{}", what),
+ |diag| {
+ if !what.is_empty() {
+ diag.span_suggestion(
+ span,
+ "try",
+ format!(
+ "{}::mem::swap({}, {})",
+ sugg,
+ lhs,
+ rhs,
+ ),
+ Applicability::MaybeIncorrect,
+ );
+ diag.note(
+ &format!("or maybe you should use `{}::mem::replace`?", sugg)
+ );
+ }
+ });
}
}
}
diff --git a/src/tools/clippy/clippy_lints/src/tabs_in_doc_comments.rs b/src/tools/clippy/clippy_lints/src/tabs_in_doc_comments.rs
index 4a67cabf323..c9b4b245f4c 100644
--- a/src/tools/clippy/clippy_lints/src/tabs_in_doc_comments.rs
+++ b/src/tools/clippy/clippy_lints/src/tabs_in_doc_comments.rs
@@ -51,6 +51,7 @@ declare_clippy_lint! {
/// second_string: String,
///}
/// ```
+ #[clippy::version = "1.41.0"]
pub TABS_IN_DOC_COMMENTS,
style,
"using tabs in doc comments is not recommended"
diff --git a/src/tools/clippy/clippy_lints/src/temporary_assignment.rs b/src/tools/clippy/clippy_lints/src/temporary_assignment.rs
index a9da690339c..3766b8f8ed1 100644
--- a/src/tools/clippy/clippy_lints/src/temporary_assignment.rs
+++ b/src/tools/clippy/clippy_lints/src/temporary_assignment.rs
@@ -17,6 +17,7 @@ declare_clippy_lint! {
/// ```rust
/// (0, 0).0 = 1
/// ```
+ #[clippy::version = "pre 1.29.0"]
pub TEMPORARY_ASSIGNMENT,
complexity,
"assignments to temporaries"
diff --git a/src/tools/clippy/clippy_lints/src/to_digit_is_some.rs b/src/tools/clippy/clippy_lints/src/to_digit_is_some.rs
index 1c14a919995..5eb58b47838 100644
--- a/src/tools/clippy/clippy_lints/src/to_digit_is_some.rs
+++ b/src/tools/clippy/clippy_lints/src/to_digit_is_some.rs
@@ -28,6 +28,7 @@ declare_clippy_lint! {
/// # let radix = 10;
/// let is_digit = c.is_digit(radix);
/// ```
+ #[clippy::version = "1.41.0"]
pub TO_DIGIT_IS_SOME,
style,
"`char.is_digit()` is clearer"
diff --git a/src/tools/clippy/clippy_lints/src/to_string_in_display.rs b/src/tools/clippy/clippy_lints/src/to_string_in_display.rs
index b7414cec87c..f8b6bdcd3e1 100644
--- a/src/tools/clippy/clippy_lints/src/to_string_in_display.rs
+++ b/src/tools/clippy/clippy_lints/src/to_string_in_display.rs
@@ -39,6 +39,7 @@ declare_clippy_lint! {
/// }
/// }
/// ```
+ #[clippy::version = "1.48.0"]
pub TO_STRING_IN_DISPLAY,
correctness,
"`to_string` method used while implementing `Display` trait"
diff --git a/src/tools/clippy/clippy_lints/src/trailing_empty_array.rs b/src/tools/clippy/clippy_lints/src/trailing_empty_array.rs
index c216a1f81ea..47c0a84cd46 100644
--- a/src/tools/clippy/clippy_lints/src/trailing_empty_array.rs
+++ b/src/tools/clippy/clippy_lints/src/trailing_empty_array.rs
@@ -28,6 +28,7 @@ declare_clippy_lint! {
/// last: [u32; 0],
/// }
/// ```
+ #[clippy::version = "1.58.0"]
pub TRAILING_EMPTY_ARRAY,
nursery,
"struct with a trailing zero-sized array but without `#[repr(C)]` or another `repr` attribute"
diff --git a/src/tools/clippy/clippy_lints/src/trait_bounds.rs b/src/tools/clippy/clippy_lints/src/trait_bounds.rs
index 79367c4230c..fb4abceac25 100644
--- a/src/tools/clippy/clippy_lints/src/trait_bounds.rs
+++ b/src/tools/clippy/clippy_lints/src/trait_bounds.rs
@@ -1,6 +1,6 @@
use clippy_utils::diagnostics::span_lint_and_help;
use clippy_utils::source::{snippet, snippet_with_applicability};
-use clippy_utils::{in_macro, SpanlessHash};
+use clippy_utils::SpanlessHash;
use if_chain::if_chain;
use rustc_data_structures::fx::FxHashMap;
use rustc_data_structures::unhash::UnhashMap;
@@ -28,6 +28,7 @@ declare_clippy_lint! {
/// ```rust
/// pub fn foo<T>(t: T) where T: Copy + Clone {}
/// ```
+ #[clippy::version = "1.38.0"]
pub TYPE_REPETITION_IN_BOUNDS,
pedantic,
"Types are repeated unnecessary in trait bounds use `+` instead of using `T: _, T: _`"
@@ -57,6 +58,7 @@ declare_clippy_lint! {
/// ```rust
/// fn func<T>(arg: T) where T: Clone + Default {}
/// ```
+ #[clippy::version = "1.47.0"]
pub TRAIT_DUPLICATION_IN_BOUNDS,
pedantic,
"Check if the same trait bounds are specified twice during a function declaration"
@@ -93,7 +95,7 @@ fn get_trait_res_span_from_bound(bound: &GenericBound<'_>) -> Option<(Res, Span)
impl TraitBounds {
fn check_type_repetition(self, cx: &LateContext<'_>, gen: &'_ Generics<'_>) {
- if in_macro(gen.span) {
+ if gen.span.from_expansion() {
return;
}
let hash = |ty| -> u64 {
@@ -107,7 +109,7 @@ impl TraitBounds {
if_chain! {
if let WherePredicate::BoundPredicate(ref p) = bound;
if p.bounds.len() as u64 <= self.max_trait_bounds;
- if !in_macro(p.span);
+ if !p.span.from_expansion();
let h = hash(p.bounded_ty);
if let Some(ref v) = map.insert(h, p.bounds.iter().collect::<Vec<_>>());
@@ -151,7 +153,7 @@ impl TraitBounds {
}
fn check_trait_bound_duplication(cx: &LateContext<'_>, gen: &'_ Generics<'_>) {
- if in_macro(gen.span) || gen.params.is_empty() || gen.where_clause.predicates.is_empty() {
+ if gen.span.from_expansion() || gen.params.is_empty() || gen.where_clause.predicates.is_empty() {
return;
}
@@ -170,7 +172,7 @@ fn check_trait_bound_duplication(cx: &LateContext<'_>, gen: &'_ Generics<'_>) {
for predicate in gen.where_clause.predicates {
if_chain! {
if let WherePredicate::BoundPredicate(ref bound_predicate) = predicate;
- if !in_macro(bound_predicate.span);
+ if !bound_predicate.span.from_expansion();
if let TyKind::Path(QPath::Resolved(_, Path { segments, .. })) = bound_predicate.bounded_ty.kind;
if let Some(segment) = segments.first();
if let Some(trait_resolutions_direct) = map.get(&segment.ident);
diff --git a/src/tools/clippy/clippy_lints/src/transmute/mod.rs b/src/tools/clippy/clippy_lints/src/transmute/mod.rs
index e6acf1a94c9..3ad4ec74bf5 100644
--- a/src/tools/clippy/clippy_lints/src/transmute/mod.rs
+++ b/src/tools/clippy/clippy_lints/src/transmute/mod.rs
@@ -36,6 +36,7 @@ declare_clippy_lint! {
/// ```ignore
/// let ptr: *const T = core::intrinsics::transmute('x')
/// ```
+ #[clippy::version = "pre 1.29.0"]
pub WRONG_TRANSMUTE,
correctness,
"transmutes that are confusing at best, undefined behaviour at worst and always useless"
@@ -55,6 +56,7 @@ declare_clippy_lint! {
/// ```rust,ignore
/// core::intrinsics::transmute(t); // where the result type is the same as `t`'s
/// ```
+ #[clippy::version = "pre 1.29.0"]
pub USELESS_TRANSMUTE,
nursery,
"transmutes that have the same to and from types or could be a cast/coercion"
@@ -80,6 +82,7 @@ declare_clippy_lint! {
/// # let p: *const [i32] = &[];
/// p as *const [u16];
/// ```
+ #[clippy::version = "1.47.0"]
pub TRANSMUTES_EXPRESSIBLE_AS_PTR_CASTS,
complexity,
"transmutes that could be a pointer cast"
@@ -98,6 +101,7 @@ declare_clippy_lint! {
/// core::intrinsics::transmute(t) // where the result type is the same as
/// // `*t` or `&t`'s
/// ```
+ #[clippy::version = "pre 1.29.0"]
pub CROSSPOINTER_TRANSMUTE,
complexity,
"transmutes that have to or from types that are a pointer to the other"
@@ -125,6 +129,7 @@ declare_clippy_lint! {
/// // can be written:
/// let _: &T = &*p;
/// ```
+ #[clippy::version = "pre 1.29.0"]
pub TRANSMUTE_PTR_TO_REF,
complexity,
"transmutes from a pointer to a reference type"
@@ -158,6 +163,7 @@ declare_clippy_lint! {
/// // should be:
/// let _ = std::char::from_u32(x).unwrap();
/// ```
+ #[clippy::version = "pre 1.29.0"]
pub TRANSMUTE_INT_TO_CHAR,
complexity,
"transmutes from an integer to a `char`"
@@ -191,6 +197,7 @@ declare_clippy_lint! {
/// // should be:
/// let _ = std::str::from_utf8(b).unwrap();
/// ```
+ #[clippy::version = "pre 1.29.0"]
pub TRANSMUTE_BYTES_TO_STR,
complexity,
"transmutes from a `&[u8]` to a `&str`"
@@ -213,6 +220,7 @@ declare_clippy_lint! {
/// // should be:
/// let _: bool = x != 0;
/// ```
+ #[clippy::version = "pre 1.29.0"]
pub TRANSMUTE_INT_TO_BOOL,
complexity,
"transmutes from an integer to a `bool`"
@@ -235,6 +243,7 @@ declare_clippy_lint! {
/// // should be:
/// let _: f32 = f32::from_bits(1_u32);
/// ```
+ #[clippy::version = "pre 1.29.0"]
pub TRANSMUTE_INT_TO_FLOAT,
complexity,
"transmutes from an integer to a float"
@@ -257,6 +266,7 @@ declare_clippy_lint! {
/// // should be:
/// let _: u32 = 1f32.to_bits();
/// ```
+ #[clippy::version = "1.41.0"]
pub TRANSMUTE_FLOAT_TO_INT,
complexity,
"transmutes from a float to an integer"
@@ -279,6 +289,7 @@ declare_clippy_lint! {
/// // should be
/// let x: [u8; 8] = 0i64.to_ne_bytes();
/// ```
+ #[clippy::version = "1.58.0"]
pub TRANSMUTE_NUM_TO_BYTES,
complexity,
"transmutes from a number to an array of `u8`"
@@ -306,6 +317,7 @@ declare_clippy_lint! {
/// let _ = ptr as *const f32;
/// let _ = unsafe{ &*(&1u32 as *const u32 as *const f32) };
/// ```
+ #[clippy::version = "pre 1.29.0"]
pub TRANSMUTE_PTR_TO_PTR,
pedantic,
"transmutes from a pointer to a pointer / a reference to a reference"
@@ -337,6 +349,7 @@ declare_clippy_lint! {
/// ```rust
/// vec![2_u16].into_iter().map(u32::from).collect::<Vec<_>>();
/// ```
+ #[clippy::version = "1.40.0"]
pub UNSOUND_COLLECTION_TRANSMUTE,
correctness,
"transmute between collections of layout-incompatible types"
diff --git a/src/tools/clippy/clippy_lints/src/transmuting_null.rs b/src/tools/clippy/clippy_lints/src/transmuting_null.rs
index ef80663d1da..7939dfedc3a 100644
--- a/src/tools/clippy/clippy_lints/src/transmuting_null.rs
+++ b/src/tools/clippy/clippy_lints/src/transmuting_null.rs
@@ -25,6 +25,7 @@ declare_clippy_lint! {
/// ```rust
/// let null_ref: &u64 = unsafe { std::mem::transmute(0 as *const u64) };
/// ```
+ #[clippy::version = "1.35.0"]
pub TRANSMUTING_NULL,
correctness,
"transmutes from a null pointer to a reference, which is undefined behavior"
diff --git a/src/tools/clippy/clippy_lints/src/try_err.rs b/src/tools/clippy/clippy_lints/src/try_err.rs
index e9ec120a7f9..4da32c52e75 100644
--- a/src/tools/clippy/clippy_lints/src/try_err.rs
+++ b/src/tools/clippy/clippy_lints/src/try_err.rs
@@ -1,7 +1,7 @@
use clippy_utils::diagnostics::span_lint_and_sugg;
-use clippy_utils::source::{snippet, snippet_with_macro_callsite};
+use clippy_utils::source::snippet_with_applicability;
use clippy_utils::ty::is_type_diagnostic_item;
-use clippy_utils::{differing_macro_contexts, get_parent_expr, in_macro, is_lang_ctor, match_def_path, paths};
+use clippy_utils::{get_parent_expr, is_lang_ctor, match_def_path, paths};
use if_chain::if_chain;
use rustc_errors::Applicability;
use rustc_hir::LangItem::ResultErr;
@@ -10,7 +10,7 @@ use rustc_lint::{LateContext, LateLintPass};
use rustc_middle::lint::in_external_macro;
use rustc_middle::ty::{self, Ty};
use rustc_session::{declare_lint_pass, declare_tool_lint};
-use rustc_span::sym;
+use rustc_span::{hygiene, sym};
declare_clippy_lint! {
/// ### What it does
@@ -41,6 +41,7 @@ declare_clippy_lint! {
/// Ok(0)
/// }
/// ```
+ #[clippy::version = "1.38.0"]
pub TRY_ERR,
style,
"return errors explicitly rather than hiding them behind a `?`"
@@ -64,7 +65,7 @@ impl<'tcx> LateLintPass<'tcx> for TryErr {
if let ExprKind::Match(match_arg, _, MatchSource::TryDesugar) = expr.kind;
if let ExprKind::Call(match_fun, try_args) = match_arg.kind;
if let ExprKind::Path(ref match_fun_path) = match_fun.kind;
- if matches!(match_fun_path, QPath::LangItem(LangItem::TryTraitBranch, _));
+ if matches!(match_fun_path, QPath::LangItem(LangItem::TryTraitBranch, ..));
if let Some(try_arg) = try_args.get(0);
if let ExprKind::Call(err_fun, err_args) = try_arg.kind;
if let Some(err_arg) = err_args.get(0);
@@ -93,15 +94,9 @@ impl<'tcx> LateLintPass<'tcx> for TryErr {
};
let expr_err_ty = cx.typeck_results().expr_ty(err_arg);
- let differing_contexts = differing_macro_contexts(expr.span, err_arg.span);
-
- let origin_snippet = if in_macro(expr.span) && in_macro(err_arg.span) && differing_contexts {
- snippet(cx, err_arg.span.ctxt().outer_expn_data().call_site, "_")
- } else if err_arg.span.from_expansion() && !in_macro(expr.span) {
- snippet_with_macro_callsite(cx, err_arg.span, "_")
- } else {
- snippet(cx, err_arg.span, "_")
- };
+ let span = hygiene::walk_chain(err_arg.span, try_arg.span.ctxt());
+ let mut applicability = Applicability::MachineApplicable;
+ let origin_snippet = snippet_with_applicability(cx, span, "_", &mut applicability);
let ret_prefix = if get_parent_expr(cx, expr).map_or(false, |e| matches!(e.kind, ExprKind::Ret(_))) {
"" // already returns
} else {
@@ -120,7 +115,7 @@ impl<'tcx> LateLintPass<'tcx> for TryErr {
"returning an `Err(_)` with the `?` operator",
"try this",
suggestion,
- Applicability::MachineApplicable
+ applicability,
);
}
}
diff --git a/src/tools/clippy/clippy_lints/src/types/mod.rs b/src/tools/clippy/clippy_lints/src/types/mod.rs
index bbe07db5358..481e5957435 100644
--- a/src/tools/clippy/clippy_lints/src/types/mod.rs
+++ b/src/tools/clippy/clippy_lints/src/types/mod.rs
@@ -43,6 +43,7 @@ declare_clippy_lint! {
/// values: Vec<Foo>,
/// }
/// ```
+ #[clippy::version = "1.57.0"]
pub BOX_COLLECTION,
perf,
"usage of `Box<Vec<T>>`, vector elements are already on the heap"
@@ -75,6 +76,7 @@ declare_clippy_lint! {
/// values: Vec<i32>,
/// }
/// ```
+ #[clippy::version = "1.33.0"]
pub VEC_BOX,
complexity,
"usage of `Vec<Box<T>>` where T: Sized, vector elements are already on the heap"
@@ -113,6 +115,7 @@ declare_clippy_lint! {
/// Contents::None
/// }
/// ```
+ #[clippy::version = "pre 1.29.0"]
pub OPTION_OPTION,
pedantic,
"usage of `Option<Option<T>>`"
@@ -152,6 +155,7 @@ declare_clippy_lint! {
/// # use std::collections::LinkedList;
/// let x: LinkedList<usize> = LinkedList::new();
/// ```
+ #[clippy::version = "pre 1.29.0"]
pub LINKEDLIST,
pedantic,
"usage of LinkedList, usually a vector is faster, or a more specialized data structure like a `VecDeque`"
@@ -176,6 +180,7 @@ declare_clippy_lint! {
/// ```rust,ignore
/// fn foo(bar: &T) { ... }
/// ```
+ #[clippy::version = "pre 1.29.0"]
pub BORROWED_BOX,
complexity,
"a borrow of a boxed type"
@@ -200,6 +205,7 @@ declare_clippy_lint! {
/// ```rust
/// fn foo(bar: &usize) {}
/// ```
+ #[clippy::version = "1.44.0"]
pub REDUNDANT_ALLOCATION,
perf,
"redundant allocation"
@@ -234,6 +240,7 @@ declare_clippy_lint! {
/// ```rust,ignore
/// fn foo(interned: Rc<str>) { ... }
/// ```
+ #[clippy::version = "1.48.0"]
pub RC_BUFFER,
restriction,
"shared ownership of a buffer type"
@@ -255,6 +262,7 @@ declare_clippy_lint! {
/// inner: Rc<Vec<Vec<Box<(u32, u32, u32, u32)>>>>,
/// }
/// ```
+ #[clippy::version = "pre 1.29.0"]
pub TYPE_COMPLEXITY,
complexity,
"usage of very complex types that might be better factored into `type` definitions"
@@ -287,6 +295,7 @@ declare_clippy_lint! {
/// use std::cell::RefCell
/// fn foo(interned: Rc<RefCell<i32>>) { ... }
/// ```
+ #[clippy::version = "1.55.0"]
pub RC_MUTEX,
restriction,
"usage of `Rc<Mutex<T>>`"
@@ -341,16 +350,28 @@ impl<'tcx> LateLintPass<'tcx> for Types {
fn check_impl_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx ImplItem<'_>) {
match item.kind {
- ImplItemKind::Const(ty, _) | ImplItemKind::TyAlias(ty) => self.check_ty(
- cx,
- ty,
- CheckTyContext {
- is_in_trait_impl: true,
- ..CheckTyContext::default()
- },
- ),
- // methods are covered by check_fn
- ImplItemKind::Fn(..) => (),
+ ImplItemKind::Const(ty, _) => {
+ let is_in_trait_impl = if let Some(hir::Node::Item(item)) =
+ cx.tcx.hir().find(cx.tcx.hir().get_parent_item(item.hir_id()))
+ {
+ matches!(item.kind, ItemKind::Impl(hir::Impl { of_trait: Some(_), .. }))
+ } else {
+ false
+ };
+
+ self.check_ty(
+ cx,
+ ty,
+ CheckTyContext {
+ is_in_trait_impl,
+ ..CheckTyContext::default()
+ },
+ );
+ },
+ // Methods are covered by check_fn.
+ // Type aliases are ignored because oftentimes it's impossible to
+ // make type alias declaration in trait simpler, see #1013
+ ImplItemKind::Fn(..) | ImplItemKind::TyAlias(..) => (),
}
}
@@ -408,6 +429,14 @@ impl Types {
}
fn check_fn_decl(&mut self, cx: &LateContext<'_>, decl: &FnDecl<'_>, context: CheckTyContext) {
+ // Ignore functions in trait implementations as they are usually forced by the trait definition.
+ //
+ // FIXME: idially we would like to warn *if the compicated type can be simplified*, but it's hard to
+ // check.
+ if context.is_in_trait_impl {
+ return;
+ }
+
for input in decl.inputs {
self.check_ty(cx, input, context);
}
@@ -426,12 +455,12 @@ impl Types {
return;
}
- if !context.is_nested_call && type_complexity::check(cx, hir_ty, self.type_complexity_threshold) {
+ // Skip trait implementations; see issue #605.
+ if context.is_in_trait_impl {
return;
}
- // Skip trait implementations; see issue #605.
- if context.is_in_trait_impl {
+ if !context.is_nested_call && type_complexity::check(cx, hir_ty, self.type_complexity_threshold) {
return;
}
diff --git a/src/tools/clippy/clippy_lints/src/undocumented_unsafe_blocks.rs b/src/tools/clippy/clippy_lints/src/undocumented_unsafe_blocks.rs
index 11aef50991b..ccc49caf47c 100644
--- a/src/tools/clippy/clippy_lints/src/undocumented_unsafe_blocks.rs
+++ b/src/tools/clippy/clippy_lints/src/undocumented_unsafe_blocks.rs
@@ -1,6 +1,6 @@
use clippy_utils::diagnostics::{span_lint_and_help, span_lint_and_sugg};
+use clippy_utils::is_lint_allowed;
use clippy_utils::source::{indent_of, reindent_multiline, snippet};
-use clippy_utils::{in_macro, is_lint_allowed};
use rustc_errors::Applicability;
use rustc_hir::intravisit::{walk_expr, NestedVisitorMap, Visitor};
use rustc_hir::{Block, BlockCheckMode, Expr, ExprKind, HirId, Local, UnsafeSource};
@@ -39,6 +39,7 @@ declare_clippy_lint! {
/// // Safety: references are guaranteed to be non-null.
/// let ptr = unsafe { NonNull::new_unchecked(a) };
/// ```
+ #[clippy::version = "1.58.0"]
pub UNDOCUMENTED_UNSAFE_BLOCKS,
restriction,
"creating an unsafe block without explaining why it is safe"
@@ -134,12 +135,12 @@ impl UndocumentedUnsafeBlocks {
let enclosing_scope_span = map.opt_span(enclosing_hir_id)?;
- let between_span = if in_macro(block_span) {
+ let between_span = if block_span.from_expansion() {
self.macro_expansion = true;
- enclosing_scope_span.with_hi(block_span.hi())
+ enclosing_scope_span.with_hi(block_span.hi()).source_callsite()
} else {
self.macro_expansion = false;
- enclosing_scope_span.to(block_span)
+ enclosing_scope_span.to(block_span).source_callsite()
};
let file_name = source_map.span_to_filename(between_span);
@@ -149,6 +150,8 @@ impl UndocumentedUnsafeBlocks {
let lex_end = (between_span.hi().0 - source_file.start_pos.0) as usize;
let src_str = source_file.src.as_ref()?[lex_start..lex_end].to_string();
+ let source_start_pos = source_file.start_pos.0 as usize + lex_start;
+
let mut pos = 0;
let mut comment = false;
@@ -171,7 +174,7 @@ impl UndocumentedUnsafeBlocks {
if comment {
// Get the line number of the "comment" (really wherever the trailing whitespace ended)
let comment_line_num = source_file
- .lookup_file_pos_with_col_display(BytePos((lex_start + pos).try_into().unwrap()))
+ .lookup_file_pos(BytePos((source_start_pos + pos).try_into().unwrap()))
.0;
// Find the block/local's line number
let block_line_num = tcx.sess.source_map().lookup_char_pos(block_span.lo()).line;
diff --git a/src/tools/clippy/clippy_lints/src/undropped_manually_drops.rs b/src/tools/clippy/clippy_lints/src/undropped_manually_drops.rs
index 09570616593..c58fa67a023 100644
--- a/src/tools/clippy/clippy_lints/src/undropped_manually_drops.rs
+++ b/src/tools/clippy/clippy_lints/src/undropped_manually_drops.rs
@@ -28,6 +28,7 @@ declare_clippy_lint! {
/// std::mem::ManuallyDrop::drop(&mut std::mem::ManuallyDrop::new(S));
/// }
/// ```
+ #[clippy::version = "1.49.0"]
pub UNDROPPED_MANUALLY_DROPS,
correctness,
"use of safe `std::mem::drop` function to drop a std::mem::ManuallyDrop, which will not drop the inner value"
diff --git a/src/tools/clippy/clippy_lints/src/unicode.rs b/src/tools/clippy/clippy_lints/src/unicode.rs
index f49ce696a04..afd7be89a4e 100644
--- a/src/tools/clippy/clippy_lints/src/unicode.rs
+++ b/src/tools/clippy/clippy_lints/src/unicode.rs
@@ -20,6 +20,7 @@ declare_clippy_lint! {
/// ### Example
/// You don't see it, but there may be a zero-width space or soft hyphen
/// some­where in this text.
+ #[clippy::version = "1.49.0"]
pub INVISIBLE_CHARACTERS,
correctness,
"using an invisible character in a string literal, which is confusing"
@@ -27,7 +28,7 @@ declare_clippy_lint! {
declare_clippy_lint! {
/// ### What it does
- /// Checks for non-ASCII characters in string literals.
+ /// Checks for non-ASCII characters in string and char literals.
///
/// ### Why is this bad?
/// Yeah, we know, the 90's called and wanted their charset
@@ -44,6 +45,7 @@ declare_clippy_lint! {
/// ```rust
/// let x = String::from("\u{20ac}");
/// ```
+ #[clippy::version = "pre 1.29.0"]
pub NON_ASCII_LITERAL,
restriction,
"using any literal non-ASCII chars in a string literal instead of using the `\\u` escape"
@@ -62,6 +64,7 @@ declare_clippy_lint! {
/// ### Example
/// You may not see it, but "à"" and "à"" aren't the same string. The
/// former when escaped is actually `"a\u{300}"` while the latter is `"\u{e0}"`.
+ #[clippy::version = "pre 1.29.0"]
pub UNICODE_NOT_NFC,
pedantic,
"using a Unicode literal not in NFC normal form (see [Unicode tr15](http://www.unicode.org/reports/tr15/) for further information)"
@@ -72,7 +75,7 @@ declare_lint_pass!(Unicode => [INVISIBLE_CHARACTERS, NON_ASCII_LITERAL, UNICODE_
impl LateLintPass<'_> for Unicode {
fn check_expr(&mut self, cx: &LateContext<'_>, expr: &'_ Expr<'_>) {
if let ExprKind::Lit(ref lit) = expr.kind {
- if let LitKind::Str(_, _) = lit.node {
+ if let LitKind::Str(_, _) | LitKind::Char(_) = lit.node {
check_str(cx, lit.span, expr.hir_id);
}
}
@@ -103,9 +106,9 @@ fn check_str(cx: &LateContext<'_>, span: Span, id: HirId) {
"invisible character detected",
"consider replacing the string with",
string
- .replace("\u{200B}", "\\u{200B}")
- .replace("\u{ad}", "\\u{AD}")
- .replace("\u{2060}", "\\u{2060}"),
+ .replace('\u{200B}', "\\u{200B}")
+ .replace('\u{ad}', "\\u{AD}")
+ .replace('\u{2060}', "\\u{2060}"),
Applicability::MachineApplicable,
);
}
diff --git a/src/tools/clippy/clippy_lints/src/uninit_vec.rs b/src/tools/clippy/clippy_lints/src/uninit_vec.rs
index f3e8b688105..46cc76b150e 100644
--- a/src/tools/clippy/clippy_lints/src/uninit_vec.rs
+++ b/src/tools/clippy/clippy_lints/src/uninit_vec.rs
@@ -52,6 +52,7 @@ declare_clippy_lint! {
/// // perform initialization with `remaining`
/// vec.set_len(...); // Safe to call `set_len()` on initialized part
/// ```
+ #[clippy::version = "1.58.0"]
pub UNINIT_VEC,
correctness,
"Vec with uninitialized data"
diff --git a/src/tools/clippy/clippy_lints/src/unit_hash.rs b/src/tools/clippy/clippy_lints/src/unit_hash.rs
index a3a3f2d41c7..26b4e0f58a8 100644
--- a/src/tools/clippy/clippy_lints/src/unit_hash.rs
+++ b/src/tools/clippy/clippy_lints/src/unit_hash.rs
@@ -39,6 +39,7 @@ declare_clippy_lint! {
/// WithValue(x) => x.hash(&mut state),
/// }
/// ```
+ #[clippy::version = "1.58.0"]
pub UNIT_HASH,
correctness,
"hashing a unit value, which does nothing"
diff --git a/src/tools/clippy/clippy_lints/src/unit_return_expecting_ord.rs b/src/tools/clippy/clippy_lints/src/unit_return_expecting_ord.rs
index db0f412f2a1..fe35ff33d35 100644
--- a/src/tools/clippy/clippy_lints/src/unit_return_expecting_ord.rs
+++ b/src/tools/clippy/clippy_lints/src/unit_return_expecting_ord.rs
@@ -30,6 +30,7 @@ declare_clippy_lint! {
/// let mut twins = vec!((1, 1), (2, 2));
/// twins.sort_by_key(|x| { x.1; });
/// ```
+ #[clippy::version = "1.47.0"]
pub UNIT_RETURN_EXPECTING_ORD,
correctness,
"fn arguments of type Fn(...) -> Ord returning the unit type ()."
@@ -168,7 +169,7 @@ impl<'tcx> LateLintPass<'tcx> for UnitReturnExpectingOrd {
trait_name
),
Some(last_semi),
- &"probably caused by this trailing semicolon".to_string(),
+ "probably caused by this trailing semicolon",
);
},
None => {},
diff --git a/src/tools/clippy/clippy_lints/src/unit_types/mod.rs b/src/tools/clippy/clippy_lints/src/unit_types/mod.rs
index 66b1abbe50b..d9f5b53b413 100644
--- a/src/tools/clippy/clippy_lints/src/unit_types/mod.rs
+++ b/src/tools/clippy/clippy_lints/src/unit_types/mod.rs
@@ -21,6 +21,7 @@ declare_clippy_lint! {
/// 1;
/// };
/// ```
+ #[clippy::version = "pre 1.29.0"]
pub LET_UNIT_VALUE,
pedantic,
"creating a `let` binding to a value of unit type, which usually can't be used afterwards"
@@ -68,6 +69,7 @@ declare_clippy_lint! {
/// assert_eq!({ foo(); }, { bar(); });
/// ```
/// will always succeed
+ #[clippy::version = "pre 1.29.0"]
pub UNIT_CMP,
correctness,
"comparing unit values"
@@ -88,6 +90,7 @@ declare_clippy_lint! {
/// baz(a);
/// })
/// ```
+ #[clippy::version = "pre 1.29.0"]
pub UNIT_ARG,
complexity,
"passing unit to a function"
diff --git a/src/tools/clippy/clippy_lints/src/unnamed_address.rs b/src/tools/clippy/clippy_lints/src/unnamed_address.rs
index 1eafdee0352..0bcafde658a 100644
--- a/src/tools/clippy/clippy_lints/src/unnamed_address.rs
+++ b/src/tools/clippy/clippy_lints/src/unnamed_address.rs
@@ -24,6 +24,7 @@ declare_clippy_lint! {
/// // ...
/// }
/// ```
+ #[clippy::version = "1.44.0"]
pub FN_ADDRESS_COMPARISONS,
correctness,
"comparison with an address of a function item"
@@ -47,6 +48,7 @@ declare_clippy_lint! {
/// ...
/// }
/// ```
+ #[clippy::version = "1.44.0"]
pub VTABLE_ADDRESS_COMPARISONS,
correctness,
"comparison with an address of a trait vtable"
diff --git a/src/tools/clippy/clippy_lints/src/unnecessary_self_imports.rs b/src/tools/clippy/clippy_lints/src/unnecessary_self_imports.rs
index 4cfd2df551f..839a4bdab09 100644
--- a/src/tools/clippy/clippy_lints/src/unnecessary_self_imports.rs
+++ b/src/tools/clippy/clippy_lints/src/unnecessary_self_imports.rs
@@ -26,6 +26,7 @@ declare_clippy_lint! {
/// ```rust
/// use std::io;
/// ```
+ #[clippy::version = "1.53.0"]
pub UNNECESSARY_SELF_IMPORTS,
restriction,
"imports ending in `::{self}`, which can be omitted"
diff --git a/src/tools/clippy/clippy_lints/src/unnecessary_sort_by.rs b/src/tools/clippy/clippy_lints/src/unnecessary_sort_by.rs
index 26b56e0f2f3..d024577f485 100644
--- a/src/tools/clippy/clippy_lints/src/unnecessary_sort_by.rs
+++ b/src/tools/clippy/clippy_lints/src/unnecessary_sort_by.rs
@@ -39,6 +39,7 @@ declare_clippy_lint! {
/// # let mut vec: Vec<A> = Vec::new();
/// vec.sort_by_key(|a| a.foo());
/// ```
+ #[clippy::version = "1.46.0"]
pub UNNECESSARY_SORT_BY,
complexity,
"Use of `Vec::sort_by` when `Vec::sort_by_key` or `Vec::sort` would be clearer"
diff --git a/src/tools/clippy/clippy_lints/src/unnecessary_wraps.rs b/src/tools/clippy/clippy_lints/src/unnecessary_wraps.rs
index c940cf077d1..1728533f18b 100644
--- a/src/tools/clippy/clippy_lints/src/unnecessary_wraps.rs
+++ b/src/tools/clippy/clippy_lints/src/unnecessary_wraps.rs
@@ -1,6 +1,6 @@
use clippy_utils::diagnostics::span_lint_and_then;
use clippy_utils::source::snippet;
-use clippy_utils::{contains_return, in_macro, is_lang_ctor, return_ty, visitors::find_all_ret_expressions};
+use clippy_utils::{contains_return, is_lang_ctor, return_ty, visitors::find_all_ret_expressions};
use if_chain::if_chain;
use rustc_errors::Applicability;
use rustc_hir::intravisit::FnKind;
@@ -49,6 +49,7 @@ declare_clippy_lint! {
/// }
/// }
/// ```
+ #[clippy::version = "1.50.0"]
pub UNNECESSARY_WRAPS,
pedantic,
"functions that only return `Ok` or `Some`"
@@ -116,7 +117,7 @@ impl<'tcx> LateLintPass<'tcx> for UnnecessaryWraps {
let mut suggs = Vec::new();
let can_sugg = find_all_ret_expressions(cx, &body.value, |ret_expr| {
if_chain! {
- if !in_macro(ret_expr.span);
+ if !ret_expr.span.from_expansion();
// Check if a function call.
if let ExprKind::Call(func, [arg]) = ret_expr.kind;
// Check if OPTION_SOME or RESULT_OK, depending on return type.
diff --git a/src/tools/clippy/clippy_lints/src/unnested_or_patterns.rs b/src/tools/clippy/clippy_lints/src/unnested_or_patterns.rs
index d6cf7190abb..0bd151fed91 100644
--- a/src/tools/clippy/clippy_lints/src/unnested_or_patterns.rs
+++ b/src/tools/clippy/clippy_lints/src/unnested_or_patterns.rs
@@ -39,6 +39,7 @@ declare_clippy_lint! {
/// if let Some(0 | 2) = Some(0) {}
/// }
/// ```
+ #[clippy::version = "1.46.0"]
pub UNNESTED_OR_PATTERNS,
pedantic,
"unnested or-patterns, e.g., `Foo(Bar) | Foo(Baz) instead of `Foo(Bar | Baz)`"
diff --git a/src/tools/clippy/clippy_lints/src/unsafe_removed_from_name.rs b/src/tools/clippy/clippy_lints/src/unsafe_removed_from_name.rs
index 3c694af2b9d..44b1989dbc6 100644
--- a/src/tools/clippy/clippy_lints/src/unsafe_removed_from_name.rs
+++ b/src/tools/clippy/clippy_lints/src/unsafe_removed_from_name.rs
@@ -21,6 +21,7 @@ declare_clippy_lint! {
/// extern crate crossbeam;
/// use crossbeam::{spawn_unsafe as spawn};
/// ```
+ #[clippy::version = "pre 1.29.0"]
pub UNSAFE_REMOVED_FROM_NAME,
style,
"`unsafe` removed from API names on import"
diff --git a/src/tools/clippy/clippy_lints/src/unused_async.rs b/src/tools/clippy/clippy_lints/src/unused_async.rs
index f4808682b69..1ccb78425c2 100644
--- a/src/tools/clippy/clippy_lints/src/unused_async.rs
+++ b/src/tools/clippy/clippy_lints/src/unused_async.rs
@@ -29,6 +29,7 @@ declare_clippy_lint! {
/// }
/// let number_future = async { get_random_number_improved() };
/// ```
+ #[clippy::version = "1.54.0"]
pub UNUSED_ASYNC,
pedantic,
"finds async functions with no await statements"
diff --git a/src/tools/clippy/clippy_lints/src/unused_io_amount.rs b/src/tools/clippy/clippy_lints/src/unused_io_amount.rs
index 031b182bd2f..111413e5193 100644
--- a/src/tools/clippy/clippy_lints/src/unused_io_amount.rs
+++ b/src/tools/clippy/clippy_lints/src/unused_io_amount.rs
@@ -29,6 +29,7 @@ declare_clippy_lint! {
/// Ok(())
/// }
/// ```
+ #[clippy::version = "pre 1.29.0"]
pub UNUSED_IO_AMOUNT,
correctness,
"unused written/read amount"
@@ -48,7 +49,7 @@ impl<'tcx> LateLintPass<'tcx> for UnusedIoAmount {
if let hir::ExprKind::Call(func, [ref arg_0, ..]) = res.kind {
if matches!(
func.kind,
- hir::ExprKind::Path(hir::QPath::LangItem(hir::LangItem::TryTraitBranch, _))
+ hir::ExprKind::Path(hir::QPath::LangItem(hir::LangItem::TryTraitBranch, ..))
) {
check_map_error(cx, arg_0, expr);
}
diff --git a/src/tools/clippy/clippy_lints/src/unused_self.rs b/src/tools/clippy/clippy_lints/src/unused_self.rs
index e7e249c79a2..aa105580ee3 100644
--- a/src/tools/clippy/clippy_lints/src/unused_self.rs
+++ b/src/tools/clippy/clippy_lints/src/unused_self.rs
@@ -29,6 +29,7 @@ declare_clippy_lint! {
/// fn method() {}
/// }
/// ```
+ #[clippy::version = "1.40.0"]
pub UNUSED_SELF,
pedantic,
"methods that contain a `self` argument but don't use it"
@@ -41,7 +42,7 @@ impl<'tcx> LateLintPass<'tcx> for UnusedSelf {
if impl_item.span.from_expansion() {
return;
}
- let parent = cx.tcx.hir().get_parent_item(impl_item.hir_id());
+ let parent = cx.tcx.hir().get_parent_did(impl_item.hir_id());
let parent_item = cx.tcx.hir().expect_item(parent);
let assoc_item = cx.tcx.associated_item(impl_item.def_id);
if_chain! {
diff --git a/src/tools/clippy/clippy_lints/src/unused_unit.rs b/src/tools/clippy/clippy_lints/src/unused_unit.rs
index 1164ac4938f..48c17fa2a40 100644
--- a/src/tools/clippy/clippy_lints/src/unused_unit.rs
+++ b/src/tools/clippy/clippy_lints/src/unused_unit.rs
@@ -28,6 +28,7 @@ declare_clippy_lint! {
/// ```rust
/// fn return_unit() {}
/// ```
+ #[clippy::version = "1.31.0"]
pub UNUSED_UNIT,
style,
"needless unit expression"
diff --git a/src/tools/clippy/clippy_lints/src/unwrap.rs b/src/tools/clippy/clippy_lints/src/unwrap.rs
index ebaa9dcbbf8..71771aae44b 100644
--- a/src/tools/clippy/clippy_lints/src/unwrap.rs
+++ b/src/tools/clippy/clippy_lints/src/unwrap.rs
@@ -39,6 +39,7 @@ declare_clippy_lint! {
/// do_something_with(value)
/// }
/// ```
+ #[clippy::version = "pre 1.29.0"]
pub UNNECESSARY_UNWRAP,
complexity,
"checks for calls of `unwrap[_err]()` that cannot fail"
@@ -65,6 +66,7 @@ declare_clippy_lint! {
/// ```
///
/// This code will always panic. The if condition should probably be inverted.
+ #[clippy::version = "pre 1.29.0"]
pub PANICKING_UNWRAP,
correctness,
"checks for calls of `unwrap[_err]()` that will always fail"
@@ -229,8 +231,8 @@ impl<'a, 'tcx> Visitor<'tcx> for UnwrappableVariablesVisitor<'a, 'tcx> {
} else {
// find `unwrap[_err]()` calls:
if_chain! {
- if let ExprKind::MethodCall(method_name, _, args, _) = expr.kind;
- if let Some(id) = path_to_local(&args[0]);
+ if let ExprKind::MethodCall(method_name, _, [self_arg, ..], _) = expr.kind;
+ if let Some(id) = path_to_local(self_arg);
if [sym::unwrap, sym::expect, sym!(unwrap_err)].contains(&method_name.ident.name);
let call_to_unwrap = [sym::unwrap, sym::expect].contains(&method_name.ident.name);
if let Some(unwrappable) = self.unwrappables.iter()
diff --git a/src/tools/clippy/clippy_lints/src/unwrap_in_result.rs b/src/tools/clippy/clippy_lints/src/unwrap_in_result.rs
index 6447e3fa2ca..994df85cb8a 100644
--- a/src/tools/clippy/clippy_lints/src/unwrap_in_result.rs
+++ b/src/tools/clippy/clippy_lints/src/unwrap_in_result.rs
@@ -51,6 +51,7 @@ declare_clippy_lint! {
/// Ok(())
/// }
/// ```
+ #[clippy::version = "1.48.0"]
pub UNWRAP_IN_RESULT,
restriction,
"functions of type `Result<..>` or `Option`<...> that contain `expect()` or `unwrap()`"
diff --git a/src/tools/clippy/clippy_lints/src/upper_case_acronyms.rs b/src/tools/clippy/clippy_lints/src/upper_case_acronyms.rs
index dbf335a70c8..4773e350760 100644
--- a/src/tools/clippy/clippy_lints/src/upper_case_acronyms.rs
+++ b/src/tools/clippy/clippy_lints/src/upper_case_acronyms.rs
@@ -33,6 +33,7 @@ declare_clippy_lint! {
/// ```rust
/// struct HttpResponse;
/// ```
+ #[clippy::version = "1.51.0"]
pub UPPER_CASE_ACRONYMS,
style,
"capitalized acronyms are against the naming convention"
diff --git a/src/tools/clippy/clippy_lints/src/use_self.rs b/src/tools/clippy/clippy_lints/src/use_self.rs
index 9ae50e47ca4..059f7f647f8 100644
--- a/src/tools/clippy/clippy_lints/src/use_self.rs
+++ b/src/tools/clippy/clippy_lints/src/use_self.rs
@@ -1,6 +1,6 @@
use clippy_utils::diagnostics::span_lint_and_sugg;
use clippy_utils::ty::same_type_and_consts;
-use clippy_utils::{in_macro, meets_msrv, msrvs};
+use clippy_utils::{meets_msrv, msrvs};
use if_chain::if_chain;
use rustc_data_structures::fx::FxHashSet;
use rustc_errors::Applicability;
@@ -51,6 +51,7 @@ declare_clippy_lint! {
/// }
/// }
/// ```
+ #[clippy::version = "pre 1.29.0"]
pub USE_SELF,
nursery,
"unnecessary structure name repetition whereas `Self` is applicable"
@@ -197,7 +198,7 @@ impl<'tcx> LateLintPass<'tcx> for UseSelf {
fn check_ty(&mut self, cx: &LateContext<'_>, hir_ty: &hir::Ty<'_>) {
if_chain! {
- if !in_macro(hir_ty.span);
+ if !hir_ty.span.from_expansion();
if meets_msrv(self.msrv.as_ref(), &msrvs::TYPE_ALIAS_ENUM_VARIANTS);
if let Some(&StackItem::Check {
impl_id,
@@ -214,8 +215,8 @@ impl<'tcx> LateLintPass<'tcx> for UseSelf {
};
if same_type_and_consts(ty, cx.tcx.type_of(impl_id));
let hir = cx.tcx.hir();
- let id = hir.get_parent_node(hir_ty.hir_id);
- if !hir.opt_span(id).map_or(false, in_macro);
+ // prevents false positive on `#[derive(serde::Deserialize)]`
+ if !hir.span(hir.get_parent_node(hir_ty.hir_id)).in_derive_expansion();
then {
span_lint(cx, hir_ty.span);
}
@@ -224,7 +225,7 @@ impl<'tcx> LateLintPass<'tcx> for UseSelf {
fn check_expr(&mut self, cx: &LateContext<'_>, expr: &Expr<'_>) {
if_chain! {
- if !in_macro(expr.span);
+ if !expr.span.from_expansion();
if meets_msrv(self.msrv.as_ref(), &msrvs::TYPE_ALIAS_ENUM_VARIANTS);
if let Some(&StackItem::Check { impl_id, .. }) = self.stack.last();
if cx.typeck_results().expr_ty(expr) == cx.tcx.type_of(impl_id);
diff --git a/src/tools/clippy/clippy_lints/src/useless_conversion.rs b/src/tools/clippy/clippy_lints/src/useless_conversion.rs
index 88f11542072..0e4b32541c9 100644
--- a/src/tools/clippy/clippy_lints/src/useless_conversion.rs
+++ b/src/tools/clippy/clippy_lints/src/useless_conversion.rs
@@ -28,6 +28,7 @@ declare_clippy_lint! {
/// // Good
/// let s: String = format!("hello");
/// ```
+ #[clippy::version = "1.45.0"]
pub USELESS_CONVERSION,
complexity,
"calls to `Into`, `TryInto`, `From`, `TryFrom`, or `IntoIter` which perform useless conversions to the same type"
diff --git a/src/tools/clippy/clippy_lints/src/utils/author.rs b/src/tools/clippy/clippy_lints/src/utils/author.rs
index f93d7782e25..c1b811c2174 100644
--- a/src/tools/clippy/clippy_lints/src/utils/author.rs
+++ b/src/tools/clippy/clippy_lints/src/utils/author.rs
@@ -1,16 +1,16 @@
//! A group of attributes that can be attached to Rust code in order
//! to generate a clippy lint detecting said code automatically.
-use clippy_utils::get_attr;
+use clippy_utils::{get_attr, higher};
use rustc_ast::ast::{LitFloatType, LitKind};
-use rustc_ast::walk_list;
+use rustc_ast::LitIntType;
use rustc_data_structures::fx::FxHashMap;
use rustc_hir as hir;
-use rustc_hir::intravisit::{NestedVisitorMap, Visitor};
-use rustc_hir::{Block, Expr, ExprKind, Pat, PatKind, QPath, Stmt, StmtKind, TyKind};
+use rustc_hir::{ExprKind, FnRetTy, HirId, Lit, PatKind, QPath, StmtKind, TyKind};
use rustc_lint::{LateContext, LateLintPass, LintContext};
-use rustc_middle::hir::map::Map;
use rustc_session::{declare_lint_pass, declare_tool_lint};
+use rustc_span::symbol::{Ident, Symbol};
+use std::fmt::{Display, Formatter, Write as _};
declare_clippy_lint! {
/// ### What it does
@@ -53,6 +53,42 @@ declare_clippy_lint! {
declare_lint_pass!(Author => [LINT_AUTHOR]);
+/// Writes a line of output with indentation added
+macro_rules! out {
+ ($($t:tt)*) => {
+ println!(" {}", format_args!($($t)*))
+ };
+}
+
+/// The variables passed in are replaced with `&Binding`s where the `value` field is set
+/// to the original value of the variable. The `name` field is set to the name of the variable
+/// (using `stringify!`) and is adjusted to avoid duplicate names.
+/// Note that the `Binding` may be printed directly to output the `name`.
+macro_rules! bind {
+ ($self:ident $(, $name:ident)+) => {
+ $(let $name = & $self.bind(stringify!($name), $name);)+
+ };
+}
+
+/// Transforms the given `Option<T>` varibles into `OptionPat<Binding<T>>`.
+/// This displays as `Some($name)` or `None` when printed. The name of the inner binding
+/// is set to the name of the variable passed to the macro.
+macro_rules! opt_bind {
+ ($self:ident $(, $name:ident)+) => {
+ $(let $name = OptionPat::new($name.map(|o| $self.bind(stringify!($name), o)));)+
+ };
+}
+
+/// Creates a `Binding` that accesses the field of an existing `Binding`
+macro_rules! field {
+ ($binding:ident.$field:ident) => {
+ &Binding {
+ name: $binding.name.to_string() + stringify!(.$field),
+ value: $binding.value.$field,
+ }
+ };
+}
+
fn prelude() {
println!("if_chain! {{");
}
@@ -66,674 +102,601 @@ fn done() {
impl<'tcx> LateLintPass<'tcx> for Author {
fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx hir::Item<'_>) {
- if !has_attr(cx, item.hir_id()) {
- return;
- }
- prelude();
- PrintVisitor::new("item").visit_item(item);
- done();
+ check_item(cx, item.hir_id());
}
fn check_impl_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx hir::ImplItem<'_>) {
- if !has_attr(cx, item.hir_id()) {
- return;
- }
- prelude();
- PrintVisitor::new("item").visit_impl_item(item);
- done();
+ check_item(cx, item.hir_id());
}
fn check_trait_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx hir::TraitItem<'_>) {
- if !has_attr(cx, item.hir_id()) {
- return;
- }
- prelude();
- PrintVisitor::new("item").visit_trait_item(item);
- done();
+ check_item(cx, item.hir_id());
}
- fn check_variant(&mut self, cx: &LateContext<'tcx>, var: &'tcx hir::Variant<'_>) {
- if !has_attr(cx, var.id) {
- return;
- }
- prelude();
- let parent_hir_id = cx.tcx.hir().get_parent_node(var.id);
- PrintVisitor::new("var").visit_variant(var, &hir::Generics::empty(), parent_hir_id);
- done();
- }
-
- fn check_field_def(&mut self, cx: &LateContext<'tcx>, field: &'tcx hir::FieldDef<'_>) {
- if !has_attr(cx, field.hir_id) {
- return;
- }
- prelude();
- PrintVisitor::new("field").visit_field_def(field);
- done();
+ fn check_arm(&mut self, cx: &LateContext<'tcx>, arm: &'tcx hir::Arm<'_>) {
+ check_node(cx, arm.hir_id, |v| {
+ v.arm(&v.bind("arm", arm));
+ });
}
fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx hir::Expr<'_>) {
- if !has_attr(cx, expr.hir_id) {
- return;
- }
- prelude();
- PrintVisitor::new("expr").visit_expr(expr);
- done();
- }
-
- fn check_arm(&mut self, cx: &LateContext<'tcx>, arm: &'tcx hir::Arm<'_>) {
- if !has_attr(cx, arm.hir_id) {
- return;
- }
- prelude();
- PrintVisitor::new("arm").visit_arm(arm);
- done();
+ check_node(cx, expr.hir_id, |v| {
+ v.expr(&v.bind("expr", expr));
+ });
}
fn check_stmt(&mut self, cx: &LateContext<'tcx>, stmt: &'tcx hir::Stmt<'_>) {
- if !has_attr(cx, stmt.hir_id) {
- return;
- }
match stmt.kind {
StmtKind::Expr(e) | StmtKind::Semi(e) if has_attr(cx, e.hir_id) => return,
_ => {},
}
+ check_node(cx, stmt.hir_id, |v| {
+ v.stmt(&v.bind("stmt", stmt));
+ });
+ }
+}
+
+fn check_item(cx: &LateContext<'_>, hir_id: HirId) {
+ let hir = cx.tcx.hir();
+ if let Some(body_id) = hir.maybe_body_owned_by(hir_id) {
+ check_node(cx, hir_id, |v| {
+ v.expr(&v.bind("expr", &hir.body(body_id).value));
+ });
+ }
+}
+
+fn check_node(cx: &LateContext<'_>, hir_id: HirId, f: impl Fn(&PrintVisitor<'_, '_>)) {
+ if has_attr(cx, hir_id) {
prelude();
- PrintVisitor::new("stmt").visit_stmt(stmt);
+ f(&PrintVisitor::new(cx));
done();
}
+}
- fn check_foreign_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx hir::ForeignItem<'_>) {
- if !has_attr(cx, item.hir_id()) {
- return;
+struct Binding<T> {
+ name: String,
+ value: T,
+}
+
+impl<T> Display for Binding<T> {
+ fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
+ f.write_str(&self.name)
+ }
+}
+
+struct OptionPat<T> {
+ pub opt: Option<T>,
+}
+
+impl<T> OptionPat<T> {
+ fn new(opt: Option<T>) -> Self {
+ Self { opt }
+ }
+
+ fn if_some(&self, f: impl Fn(&T)) {
+ if let Some(t) = &self.opt {
+ f(t);
+ }
+ }
+}
+
+impl<T: Display> Display for OptionPat<T> {
+ fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
+ match &self.opt {
+ None => f.write_str("None"),
+ Some(node) => write!(f, "Some({node})"),
}
- prelude();
- PrintVisitor::new("item").visit_foreign_item(item);
- done();
}
}
-impl PrintVisitor {
- #[must_use]
- fn new(s: &'static str) -> Self {
+struct PrintVisitor<'a, 'tcx> {
+ cx: &'a LateContext<'tcx>,
+ /// Fields are the current index that needs to be appended to pattern
+ /// binding names
+ ids: std::cell::Cell<FxHashMap<&'static str, u32>>,
+}
+
+#[allow(clippy::unused_self)]
+impl<'a, 'tcx> PrintVisitor<'a, 'tcx> {
+ fn new(cx: &'a LateContext<'tcx>) -> Self {
Self {
- ids: FxHashMap::default(),
- current: s.to_owned(),
+ cx,
+ ids: std::cell::Cell::default(),
}
}
- fn next(&mut self, s: &'static str) -> String {
- use std::collections::hash_map::Entry::{Occupied, Vacant};
- match self.ids.entry(s) {
- // already there: start numbering from `1`
- Occupied(mut occ) => {
- let val = occ.get_mut();
- *val += 1;
- format!("{}{}", s, *val)
- },
- // not there: insert and return name as given
- Vacant(vac) => {
- vac.insert(0);
- s.to_owned()
+ fn next(&self, s: &'static str) -> String {
+ let mut ids = self.ids.take();
+ let out = match *ids.entry(s).and_modify(|n| *n += 1).or_default() {
+ // first usage of the name, use it as is
+ 0 => s.to_string(),
+ // append a number starting with 1
+ n => format!("{s}{n}"),
+ };
+ self.ids.set(ids);
+ out
+ }
+
+ fn bind<T>(&self, name: &'static str, value: T) -> Binding<T> {
+ let name = self.next(name);
+ Binding { name, value }
+ }
+
+ fn option<T: Copy>(&self, option: &Binding<Option<T>>, name: &'static str, f: impl Fn(&Binding<T>)) {
+ match option.value {
+ None => out!("if {option}.is_none();"),
+ Some(value) => {
+ let value = &self.bind(name, value);
+ out!("if let Some({value}) = {option};");
+ f(value);
},
}
}
- fn print_qpath(&mut self, path: &QPath<'_>) {
- if let QPath::LangItem(lang_item, _) = *path {
- println!(
- " if matches!({}, QPath::LangItem(LangItem::{:?}, _));",
- self.current, lang_item,
- );
+ fn slice<T>(&self, slice: &Binding<&[T]>, f: impl Fn(&Binding<&T>)) {
+ if slice.value.is_empty() {
+ out!("if {slice}.is_empty();");
} else {
- print!(" if match_qpath({}, &[", self.current);
- print_path(path, &mut true);
- println!("]);");
+ out!("if {slice}.len() == {};", slice.value.len());
+ for (i, value) in slice.value.iter().enumerate() {
+ let name = format!("{slice}[{i}]");
+ f(&Binding { name, value });
+ }
}
}
-}
-struct PrintVisitor {
- /// Fields are the current index that needs to be appended to pattern
- /// binding names
- ids: FxHashMap<&'static str, usize>,
- /// the name that needs to be destructured
- current: String,
-}
+ fn destination(&self, destination: &Binding<hir::Destination>) {
+ self.option(field!(destination.label), "label", |label| {
+ self.ident(field!(label.ident));
+ });
+ }
+
+ fn ident(&self, ident: &Binding<Ident>) {
+ out!("if {ident}.as_str() == {:?};", ident.value.as_str());
+ }
+
+ fn symbol(&self, symbol: &Binding<Symbol>) {
+ out!("if {symbol}.as_str() == {:?};", symbol.value.as_str());
+ }
-impl<'tcx> Visitor<'tcx> for PrintVisitor {
- type Map = Map<'tcx>;
+ fn qpath(&self, qpath: &Binding<&QPath<'_>>) {
+ if let QPath::LangItem(lang_item, ..) = *qpath.value {
+ out!("if matches!({qpath}, QPath::LangItem(LangItem::{lang_item:?}, _));");
+ } else {
+ out!("if match_qpath({qpath}, &[{}]);", path_to_string(qpath.value));
+ }
+ }
+
+ fn lit(&self, lit: &Binding<&Lit>) {
+ let kind = |kind| out!("if let LitKind::{kind} = {lit}.node;");
+ macro_rules! kind {
+ ($($t:tt)*) => (kind(format_args!($($t)*)));
+ }
+
+ match lit.value.node {
+ LitKind::Bool(val) => kind!("Bool({val:?})"),
+ LitKind::Char(c) => kind!("Char({c:?})"),
+ LitKind::Err(val) => kind!("Err({val})"),
+ LitKind::Byte(b) => kind!("Byte({b})"),
+ LitKind::Int(i, suffix) => {
+ let int_ty = match suffix {
+ LitIntType::Signed(int_ty) => format!("LitIntType::Signed(IntTy::{int_ty:?})"),
+ LitIntType::Unsigned(uint_ty) => format!("LitIntType::Unsigned(UintTy::{uint_ty:?})"),
+ LitIntType::Unsuffixed => String::from("LitIntType::Unsuffixed"),
+ };
+ kind!("Int({i}, {int_ty})");
+ },
+ LitKind::Float(_, suffix) => {
+ let float_ty = match suffix {
+ LitFloatType::Suffixed(suffix_ty) => format!("LitFloatType::Suffixed(FloatTy::{suffix_ty:?})"),
+ LitFloatType::Unsuffixed => String::from("LitFloatType::Unsuffixed"),
+ };
+ kind!("Float(_, {float_ty})");
+ },
+ LitKind::ByteStr(ref vec) => {
+ bind!(self, vec);
+ kind!("ByteStr(ref {vec})");
+ out!("if let [{:?}] = **{vec};", vec.value);
+ },
+ LitKind::Str(s, _) => {
+ bind!(self, s);
+ kind!("Str({s}, _)");
+ self.symbol(s);
+ },
+ }
+ }
+
+ fn arm(&self, arm: &Binding<&hir::Arm<'_>>) {
+ self.pat(field!(arm.pat));
+ match arm.value.guard {
+ None => out!("if {arm}.guard.is_none();"),
+ Some(hir::Guard::If(expr)) => {
+ bind!(self, expr);
+ out!("if let Some(Guard::If({expr})) = {arm}.guard;");
+ self.expr(expr);
+ },
+ Some(hir::Guard::IfLet(pat, expr)) => {
+ bind!(self, pat, expr);
+ out!("if let Some(Guard::IfLet({pat}, {expr}) = {arm}.guard;");
+ self.pat(pat);
+ self.expr(expr);
+ },
+ }
+ self.expr(field!(arm.body));
+ }
#[allow(clippy::too_many_lines)]
- fn visit_expr(&mut self, expr: &Expr<'_>) {
- print!(" if let ExprKind::");
- let current = format!("{}.kind", self.current);
- match expr.kind {
- ExprKind::Let(pat, expr, _) => {
- let let_pat = self.next("pat");
- let let_expr = self.next("expr");
- println!(" Let(ref {}, ref {}, _) = {};", let_pat, let_expr, current);
- self.current = let_expr;
- self.visit_expr(expr);
- self.current = let_pat;
- self.visit_pat(pat);
+ fn expr(&self, expr: &Binding<&hir::Expr<'_>>) {
+ if let Some(higher::While { condition, body }) = higher::While::hir(expr.value) {
+ bind!(self, condition, body);
+ out!(
+ "if let Some(higher::While {{ condition: {condition}, body: {body} }}) \
+ = higher::While::hir({expr});"
+ );
+ self.expr(condition);
+ self.expr(body);
+ return;
+ }
+
+ if let Some(higher::WhileLet {
+ let_pat,
+ let_expr,
+ if_then,
+ }) = higher::WhileLet::hir(expr.value)
+ {
+ bind!(self, let_pat, let_expr, if_then);
+ out!(
+ "if let Some(higher::WhileLet {{ let_pat: {let_pat}, let_expr: {let_expr}, if_then: {if_then} }}) \
+ = higher::WhileLet::hir({expr});"
+ );
+ self.pat(let_pat);
+ self.expr(let_expr);
+ self.expr(if_then);
+ return;
+ }
+
+ if let Some(higher::ForLoop { pat, arg, body, .. }) = higher::ForLoop::hir(expr.value) {
+ bind!(self, pat, arg, body);
+ out!(
+ "if let Some(higher::ForLoop {{ pat: {pat}, arg: {arg}, body: {body}, .. }}) \
+ = higher::ForLoop::hir({expr});"
+ );
+ self.pat(pat);
+ self.expr(arg);
+ self.expr(body);
+ return;
+ }
+
+ let kind = |kind| out!("if let ExprKind::{kind} = {expr}.kind;");
+ macro_rules! kind {
+ ($($t:tt)*) => (kind(format_args!($($t)*)));
+ }
+
+ match expr.value.kind {
+ ExprKind::Let(let_expr) => {
+ bind!(self, let_expr);
+ kind!("Let({let_expr})");
+ self.pat(field!(let_expr.pat));
+ // Does what ExprKind::Cast does, only adds a clause for the type
+ // if it's a path
+ if let Some(TyKind::Path(ref qpath)) = let_expr.value.ty.as_ref().map(|ty| &ty.kind) {
+ bind!(self, qpath);
+ out!("if let TyKind::Path(ref {qpath}) = {let_expr}.ty.kind;");
+ self.qpath(qpath);
+ }
+ self.expr(field!(let_expr.init));
},
ExprKind::Box(inner) => {
- let inner_pat = self.next("inner");
- println!("Box(ref {}) = {};", inner_pat, current);
- self.current = inner_pat;
- self.visit_expr(inner);
+ bind!(self, inner);
+ kind!("Box({inner})");
+ self.expr(inner);
},
ExprKind::Array(elements) => {
- let elements_pat = self.next("elements");
- println!("Array(ref {}) = {};", elements_pat, current);
- println!(" if {}.len() == {};", elements_pat, elements.len());
- for (i, element) in elements.iter().enumerate() {
- self.current = format!("{}[{}]", elements_pat, i);
- self.visit_expr(element);
- }
+ bind!(self, elements);
+ kind!("Array({elements})");
+ self.slice(elements, |e| self.expr(e));
},
ExprKind::Call(func, args) => {
- let func_pat = self.next("func");
- let args_pat = self.next("args");
- println!("Call(ref {}, ref {}) = {};", func_pat, args_pat, current);
- self.current = func_pat;
- self.visit_expr(func);
- println!(" if {}.len() == {};", args_pat, args.len());
- for (i, arg) in args.iter().enumerate() {
- self.current = format!("{}[{}]", args_pat, i);
- self.visit_expr(arg);
- }
+ bind!(self, func, args);
+ kind!("Call({func}, {args})");
+ self.expr(func);
+ self.slice(args, |e| self.expr(e));
},
- ExprKind::MethodCall(_method_name, ref _generics, _args, ref _fn_span) => {
- println!(
- "MethodCall(ref method_name, ref generics, ref args, ref fn_span) = {};",
- current
- );
- println!(" // unimplemented: `ExprKind::MethodCall` is not further destructured at the moment");
+ ExprKind::MethodCall(method_name, _, args, _) => {
+ bind!(self, method_name, args);
+ kind!("MethodCall({method_name}, _, {args}, _)");
+ self.ident(field!(method_name.ident));
+ self.slice(args, |e| self.expr(e));
},
ExprKind::Tup(elements) => {
- let elements_pat = self.next("elements");
- println!("Tup(ref {}) = {};", elements_pat, current);
- println!(" if {}.len() == {};", elements_pat, elements.len());
- for (i, element) in elements.iter().enumerate() {
- self.current = format!("{}[{}]", elements_pat, i);
- self.visit_expr(element);
- }
- },
- ExprKind::Binary(ref op, left, right) => {
- let op_pat = self.next("op");
- let left_pat = self.next("left");
- let right_pat = self.next("right");
- println!(
- "Binary(ref {}, ref {}, ref {}) = {};",
- op_pat, left_pat, right_pat, current
- );
- println!(" if BinOpKind::{:?} == {}.node;", op.node, op_pat);
- self.current = left_pat;
- self.visit_expr(left);
- self.current = right_pat;
- self.visit_expr(right);
- },
- ExprKind::Unary(ref op, inner) => {
- let inner_pat = self.next("inner");
- println!("Unary(UnOp::{:?}, ref {}) = {};", op, inner_pat, current);
- self.current = inner_pat;
- self.visit_expr(inner);
+ bind!(self, elements);
+ kind!("Tup({elements})");
+ self.slice(elements, |e| self.expr(e));
+ },
+ ExprKind::Binary(op, left, right) => {
+ bind!(self, op, left, right);
+ kind!("Binary({op}, {left}, {right})");
+ out!("if BinOpKind::{:?} == {op}.node;", op.value.node);
+ self.expr(left);
+ self.expr(right);
+ },
+ ExprKind::Unary(op, inner) => {
+ bind!(self, inner);
+ kind!("Unary(UnOp::{op:?}, {inner})");
+ self.expr(inner);
},
ExprKind::Lit(ref lit) => {
- let lit_pat = self.next("lit");
- println!("Lit(ref {}) = {};", lit_pat, current);
- match lit.node {
- LitKind::Bool(val) => println!(" if let LitKind::Bool({:?}) = {}.node;", val, lit_pat),
- LitKind::Char(c) => println!(" if let LitKind::Char({:?}) = {}.node;", c, lit_pat),
- LitKind::Err(val) => println!(" if let LitKind::Err({}) = {}.node;", val, lit_pat),
- LitKind::Byte(b) => println!(" if let LitKind::Byte({}) = {}.node;", b, lit_pat),
- // FIXME: also check int type
- LitKind::Int(i, _) => println!(" if let LitKind::Int({}, _) = {}.node;", i, lit_pat),
- LitKind::Float(_, LitFloatType::Suffixed(_)) => println!(
- " if let LitKind::Float(_, LitFloatType::Suffixed(_)) = {}.node;",
- lit_pat
- ),
- LitKind::Float(_, LitFloatType::Unsuffixed) => println!(
- " if let LitKind::Float(_, LitFloatType::Unsuffixed) = {}.node;",
- lit_pat
- ),
- LitKind::ByteStr(ref vec) => {
- let vec_pat = self.next("vec");
- println!(" if let LitKind::ByteStr(ref {}) = {}.node;", vec_pat, lit_pat);
- println!(" if let [{:?}] = **{};", vec, vec_pat);
- },
- LitKind::Str(ref text, _) => {
- let str_pat = self.next("s");
- println!(" if let LitKind::Str(ref {}, _) = {}.node;", str_pat, lit_pat);
- println!(" if {}.as_str() == {:?}", str_pat, &*text.as_str());
- },
- }
- },
- ExprKind::Cast(expr, ty) => {
- let cast_pat = self.next("expr");
- let cast_ty = self.next("cast_ty");
- let qp_label = self.next("qp");
-
- println!("Cast(ref {}, ref {}) = {};", cast_pat, cast_ty, current);
- if let TyKind::Path(ref qp) = ty.kind {
- println!(" if let TyKind::Path(ref {}) = {}.kind;", qp_label, cast_ty);
- self.current = qp_label;
- self.print_qpath(qp);
+ bind!(self, lit);
+ kind!("Lit(ref {lit})");
+ self.lit(lit);
+ },
+ ExprKind::Cast(expr, cast_ty) => {
+ bind!(self, expr, cast_ty);
+ kind!("Cast({expr}, {cast_ty})");
+ if let TyKind::Path(ref qpath) = cast_ty.value.kind {
+ bind!(self, qpath);
+ out!("if let TyKind::Path(ref {qpath}) = {cast_ty}.kind;");
+ self.qpath(qpath);
}
- self.current = cast_pat;
- self.visit_expr(expr);
+ self.expr(expr);
},
ExprKind::Type(expr, _ty) => {
- let cast_pat = self.next("expr");
- println!("Type(ref {}, _) = {};", cast_pat, current);
- self.current = cast_pat;
- self.visit_expr(expr);
- },
- ExprKind::Loop(body, _, des, _) => {
- let body_pat = self.next("body");
- let label_pat = self.next("label");
- println!(
- "Loop(ref {}, ref {}, LoopSource::{:?}) = {};",
- body_pat, label_pat, des, current
- );
- self.current = body_pat;
- self.visit_block(body);
- },
- ExprKind::If(cond, then, ref opt_else) => {
- let cond_pat = self.next("cond");
- let then_pat = self.next("then");
- if let Some(else_) = *opt_else {
- let else_pat = self.next("else_");
- println!(
- "If(ref {}, ref {}, Some(ref {})) = {};",
- cond_pat, then_pat, else_pat, current
- );
- self.current = else_pat;
- self.visit_expr(else_);
- } else {
- println!("If(ref {}, ref {}, None) = {};", cond_pat, then_pat, current);
- }
- self.current = cond_pat;
- self.visit_expr(cond);
- self.current = then_pat;
- self.visit_expr(then);
- },
- ExprKind::Match(expr, arms, des) => {
- let expr_pat = self.next("expr");
- let arms_pat = self.next("arms");
- println!(
- "Match(ref {}, ref {}, MatchSource::{:?}) = {};",
- expr_pat, arms_pat, des, current
- );
- self.current = expr_pat;
- self.visit_expr(expr);
- println!(" if {}.len() == {};", arms_pat, arms.len());
- for (i, arm) in arms.iter().enumerate() {
- self.current = format!("{}[{}].body", arms_pat, i);
- self.visit_expr(arm.body);
- if let Some(ref guard) = arm.guard {
- let guard_pat = self.next("guard");
- println!(" if let Some(ref {}) = {}[{}].guard;", guard_pat, arms_pat, i);
- match guard {
- hir::Guard::If(if_expr) => {
- let if_expr_pat = self.next("expr");
- println!(" if let Guard::If(ref {}) = {};", if_expr_pat, guard_pat);
- self.current = if_expr_pat;
- self.visit_expr(if_expr);
- },
- hir::Guard::IfLet(if_let_pat, if_let_expr) => {
- let if_let_pat_pat = self.next("pat");
- let if_let_expr_pat = self.next("expr");
- println!(
- " if let Guard::IfLet(ref {}, ref {}) = {};",
- if_let_pat_pat, if_let_expr_pat, guard_pat
- );
- self.current = if_let_expr_pat;
- self.visit_expr(if_let_expr);
- self.current = if_let_pat_pat;
- self.visit_pat(if_let_pat);
- },
- }
- }
- self.current = format!("{}[{}].pat", arms_pat, i);
- self.visit_pat(arm.pat);
- }
- },
- ExprKind::Closure(ref _capture_clause, _func, _, _, _) => {
- println!("Closure(ref capture_clause, ref func, _, _, _) = {};", current);
- println!(" // unimplemented: `ExprKind::Closure` is not further destructured at the moment");
- },
- ExprKind::Yield(sub, _) => {
- let sub_pat = self.next("sub");
- println!("Yield(ref sub) = {};", current);
- self.current = sub_pat;
- self.visit_expr(sub);
- },
- ExprKind::Block(block, _) => {
- let block_pat = self.next("block");
- println!("Block(ref {}) = {};", block_pat, current);
- self.current = block_pat;
- self.visit_block(block);
+ bind!(self, expr);
+ kind!("Type({expr}, _)");
+ self.expr(expr);
+ },
+ ExprKind::Loop(body, label, des, _) => {
+ bind!(self, body);
+ opt_bind!(self, label);
+ kind!("Loop({body}, {label}, LoopSource::{des:?}, _)");
+ self.block(body);
+ label.if_some(|l| self.ident(field!(l.ident)));
+ },
+ ExprKind::If(cond, then, else_expr) => {
+ bind!(self, cond, then);
+ opt_bind!(self, else_expr);
+ kind!("If({cond}, {then}, {else_expr})");
+ self.expr(cond);
+ self.expr(then);
+ else_expr.if_some(|e| self.expr(e));
+ },
+ ExprKind::Match(scrutinee, arms, des) => {
+ bind!(self, scrutinee, arms);
+ kind!("Match({scrutinee}, {arms}, MatchSource::{des:?})");
+ self.expr(scrutinee);
+ self.slice(arms, |arm| self.arm(arm));
+ },
+ ExprKind::Closure(capture_by, fn_decl, body_id, _, movability) => {
+ let movability = OptionPat::new(movability.map(|m| format!("Movability::{m:?}")));
+
+ let ret_ty = match fn_decl.output {
+ FnRetTy::DefaultReturn(_) => "FnRetTy::DefaultReturn(_)",
+ FnRetTy::Return(_) => "FnRetTy::Return(_ty)",
+ };
+
+ bind!(self, fn_decl, body_id);
+ kind!("Closure(CaptureBy::{capture_by:?}, {fn_decl}, {body_id}, _, {movability})");
+ out!("if let {ret_ty} = {fn_decl}.output;");
+ self.body(body_id);
+ },
+ ExprKind::Yield(sub, source) => {
+ bind!(self, sub);
+ kind!("Yield(sub, YieldSource::{source:?})");
+ self.expr(sub);
+ },
+ ExprKind::Block(block, label) => {
+ bind!(self, block);
+ opt_bind!(self, label);
+ kind!("Block({block}, {label})");
+ self.block(block);
+ label.if_some(|l| self.ident(field!(l.ident)));
},
ExprKind::Assign(target, value, _) => {
- let target_pat = self.next("target");
- let value_pat = self.next("value");
- println!(
- "Assign(ref {}, ref {}, ref _span) = {};",
- target_pat, value_pat, current
- );
- self.current = target_pat;
- self.visit_expr(target);
- self.current = value_pat;
- self.visit_expr(value);
- },
- ExprKind::AssignOp(ref op, target, value) => {
- let op_pat = self.next("op");
- let target_pat = self.next("target");
- let value_pat = self.next("value");
- println!(
- "AssignOp(ref {}, ref {}, ref {}) = {};",
- op_pat, target_pat, value_pat, current
- );
- println!(" if BinOpKind::{:?} == {}.node;", op.node, op_pat);
- self.current = target_pat;
- self.visit_expr(target);
- self.current = value_pat;
- self.visit_expr(value);
- },
- ExprKind::Field(object, ref field_ident) => {
- let obj_pat = self.next("object");
- let field_name_pat = self.next("field_name");
- println!("Field(ref {}, ref {}) = {};", obj_pat, field_name_pat, current);
- println!(" if {}.as_str() == {:?}", field_name_pat, field_ident.as_str());
- self.current = obj_pat;
- self.visit_expr(object);
+ bind!(self, target, value);
+ kind!("Assign({target}, {value}, _span)");
+ self.expr(target);
+ self.expr(value);
+ },
+ ExprKind::AssignOp(op, target, value) => {
+ bind!(self, op, target, value);
+ kind!("AssignOp({op}, {target}, {value})");
+ out!("if BinOpKind::{:?} == {op}.node;", op.value.node);
+ self.expr(target);
+ self.expr(value);
+ },
+ ExprKind::Field(object, field_name) => {
+ bind!(self, object, field_name);
+ kind!("Field({object}, {field_name})");
+ self.ident(field_name);
+ self.expr(object);
},
ExprKind::Index(object, index) => {
- let object_pat = self.next("object");
- let index_pat = self.next("index");
- println!("Index(ref {}, ref {}) = {};", object_pat, index_pat, current);
- self.current = object_pat;
- self.visit_expr(object);
- self.current = index_pat;
- self.visit_expr(index);
- },
- ExprKind::Path(ref path) => {
- let path_pat = self.next("path");
- println!("Path(ref {}) = {};", path_pat, current);
- self.current = path_pat;
- self.print_qpath(path);
+ bind!(self, object, index);
+ kind!("Index({object}, {index})");
+ self.expr(object);
+ self.expr(index);
+ },
+ ExprKind::Path(ref qpath) => {
+ bind!(self, qpath);
+ kind!("Path(ref {qpath})");
+ self.qpath(qpath);
},
ExprKind::AddrOf(kind, mutability, inner) => {
- let inner_pat = self.next("inner");
- println!(
- "AddrOf(BorrowKind::{:?}, Mutability::{:?}, ref {}) = {};",
- kind, mutability, inner_pat, current
- );
- self.current = inner_pat;
- self.visit_expr(inner);
- },
- ExprKind::Break(ref _destination, ref opt_value) => {
- let destination_pat = self.next("destination");
- if let Some(value) = *opt_value {
- let value_pat = self.next("value");
- println!("Break(ref {}, Some(ref {})) = {};", destination_pat, value_pat, current);
- self.current = value_pat;
- self.visit_expr(value);
- } else {
- println!("Break(ref {}, None) = {};", destination_pat, current);
- }
- // FIXME: implement label printing
- },
- ExprKind::Continue(ref _destination) => {
- let destination_pat = self.next("destination");
- println!("Again(ref {}) = {};", destination_pat, current);
- // FIXME: implement label printing
- },
- ExprKind::Ret(ref opt_value) => {
- if let Some(value) = *opt_value {
- let value_pat = self.next("value");
- println!("Ret(Some(ref {})) = {};", value_pat, current);
- self.current = value_pat;
- self.visit_expr(value);
- } else {
- println!("Ret(None) = {};", current);
- }
+ bind!(self, inner);
+ kind!("AddrOf(BorrowKind::{kind:?}, Mutability::{mutability:?}, {inner})");
+ self.expr(inner);
+ },
+ ExprKind::Break(destination, value) => {
+ bind!(self, destination);
+ opt_bind!(self, value);
+ kind!("Break({destination}, {value})");
+ self.destination(destination);
+ value.if_some(|e| self.expr(e));
+ },
+ ExprKind::Continue(destination) => {
+ bind!(self, destination);
+ kind!("Continue({destination})");
+ self.destination(destination);
+ },
+ ExprKind::Ret(value) => {
+ opt_bind!(self, value);
+ kind!("Ret({value})");
+ value.if_some(|e| self.expr(e));
},
ExprKind::InlineAsm(_) => {
- println!("InlineAsm(_) = {};", current);
- println!(" // unimplemented: `ExprKind::InlineAsm` is not further destructured at the moment");
+ kind!("InlineAsm(_)");
+ out!("// unimplemented: `ExprKind::InlineAsm` is not further destructured at the moment");
},
ExprKind::LlvmInlineAsm(_) => {
- println!("LlvmInlineAsm(_) = {};", current);
- println!(" // unimplemented: `ExprKind::LlvmInlineAsm` is not further destructured at the moment");
- },
- ExprKind::Struct(path, fields, ref opt_base) => {
- let path_pat = self.next("path");
- let fields_pat = self.next("fields");
- if let Some(base) = *opt_base {
- let base_pat = self.next("base");
- println!(
- "Struct(ref {}, ref {}, Some(ref {})) = {};",
- path_pat, fields_pat, base_pat, current
- );
- self.current = base_pat;
- self.visit_expr(base);
- } else {
- println!("Struct(ref {}, ref {}, None) = {};", path_pat, fields_pat, current);
- }
- self.current = path_pat;
- self.print_qpath(path);
- println!(" if {}.len() == {};", fields_pat, fields.len());
- println!(" // unimplemented: field checks");
- },
- ExprKind::ConstBlock(_) => {
- let value_pat = self.next("value");
- println!("Const({})", value_pat);
- self.current = value_pat;
- },
- // FIXME: compute length (needs type info)
- ExprKind::Repeat(value, _) => {
- let value_pat = self.next("value");
- println!("Repeat(ref {}, _) = {};", value_pat, current);
- println!("// unimplemented: repeat count check");
- self.current = value_pat;
- self.visit_expr(value);
- },
- ExprKind::Err => {
- println!("Err = {}", current);
- },
+ kind!("LlvmInlineAsm(_)");
+ out!("// unimplemented: `ExprKind::LlvmInlineAsm` is not further destructured at the moment");
+ },
+ ExprKind::Struct(qpath, fields, base) => {
+ bind!(self, qpath, fields);
+ opt_bind!(self, base);
+ kind!("Struct({qpath}, {fields}, {base})");
+ self.qpath(qpath);
+ self.slice(fields, |field| {
+ self.ident(field!(field.ident));
+ self.expr(field!(field.expr));
+ });
+ base.if_some(|e| self.expr(e));
+ },
+ ExprKind::ConstBlock(_) => kind!("ConstBlock(_)"),
+ ExprKind::Repeat(value, length) => {
+ bind!(self, value, length);
+ kind!("Repeat({value}, {length})");
+ self.expr(value);
+ self.body(field!(length.body));
+ },
+ ExprKind::Err => kind!("Err"),
ExprKind::DropTemps(expr) => {
- let expr_pat = self.next("expr");
- println!("DropTemps(ref {}) = {};", expr_pat, current);
- self.current = expr_pat;
- self.visit_expr(expr);
+ bind!(self, expr);
+ kind!("DropTemps({expr})");
+ self.expr(expr);
},
}
}
- fn visit_block(&mut self, block: &Block<'_>) {
- println!(" if {}.stmts.len() == {};", self.current, block.stmts.len());
- let block_name = self.current.clone();
- for (i, stmt) in block.stmts.iter().enumerate() {
- self.current = format!("{}.stmts[{}]", block_name, i);
- self.visit_stmt(stmt);
- }
- if let Some(expr) = block.expr {
- self.current = self.next("trailing_expr");
- println!(" if let Some({}) = &{}.expr;", self.current, block_name);
- self.visit_expr(expr);
- } else {
- println!(" if {}.expr.is_none();", block_name);
- }
+ fn block(&self, block: &Binding<&hir::Block<'_>>) {
+ self.slice(field!(block.stmts), |stmt| self.stmt(stmt));
+ self.option(field!(block.expr), "trailing_expr", |expr| {
+ self.expr(expr);
+ });
}
- #[allow(clippy::too_many_lines)]
- fn visit_pat(&mut self, pat: &Pat<'_>) {
- print!(" if let PatKind::");
- let current = format!("{}.kind", self.current);
- match pat.kind {
- PatKind::Wild => println!("Wild = {};", current),
- PatKind::Binding(anno, .., ident, ref sub) => {
- let anno_pat = &format!("BindingAnnotation::{:?}", anno);
- let name_pat = self.next("name");
- if let Some(sub) = *sub {
- let sub_pat = self.next("sub");
- println!(
- "Binding({}, _, {}, Some(ref {})) = {};",
- anno_pat, name_pat, sub_pat, current
- );
- self.current = sub_pat;
- self.visit_pat(sub);
- } else {
- println!("Binding({}, _, {}, None) = {};", anno_pat, name_pat, current);
- }
- println!(" if {}.as_str() == \"{}\";", name_pat, ident.as_str());
- },
- PatKind::Struct(ref path, fields, ignore) => {
- let path_pat = self.next("path");
- let fields_pat = self.next("fields");
- println!(
- "Struct(ref {}, ref {}, {}) = {};",
- path_pat, fields_pat, ignore, current
- );
- self.current = path_pat;
- self.print_qpath(path);
- println!(" if {}.len() == {};", fields_pat, fields.len());
- println!(" // unimplemented: field checks");
+ fn body(&self, body_id: &Binding<hir::BodyId>) {
+ let expr = &self.cx.tcx.hir().body(body_id.value).value;
+ bind!(self, expr);
+ out!("let {expr} = &cx.tcx.hir().body({body_id}).value;");
+ self.expr(expr);
+ }
+
+ fn pat(&self, pat: &Binding<&hir::Pat<'_>>) {
+ let kind = |kind| out!("if let PatKind::{kind} = {pat}.kind;");
+ macro_rules! kind {
+ ($($t:tt)*) => (kind(format_args!($($t)*)));
+ }
+
+ match pat.value.kind {
+ PatKind::Wild => kind!("Wild"),
+ PatKind::Binding(anno, .., name, sub) => {
+ bind!(self, name);
+ opt_bind!(self, sub);
+ kind!("Binding(BindingAnnotation::{anno:?}, _, {name}, {sub})");
+ self.ident(name);
+ sub.if_some(|p| self.pat(p));
+ },
+ PatKind::Struct(ref qpath, fields, ignore) => {
+ bind!(self, qpath, fields);
+ kind!("Struct(ref {qpath}, {fields}, {ignore})");
+ self.qpath(qpath);
+ self.slice(fields, |field| {
+ self.ident(field!(field.ident));
+ self.pat(field!(field.pat));
+ });
},
PatKind::Or(fields) => {
- let fields_pat = self.next("fields");
- println!("Or(ref {}) = {};", fields_pat, current);
- println!(" if {}.len() == {};", fields_pat, fields.len());
- println!(" // unimplemented: field checks");
- },
- PatKind::TupleStruct(ref path, fields, skip_pos) => {
- let path_pat = self.next("path");
- let fields_pat = self.next("fields");
- println!(
- "TupleStruct(ref {}, ref {}, {:?}) = {};",
- path_pat, fields_pat, skip_pos, current
- );
- self.current = path_pat;
- self.print_qpath(path);
- println!(" if {}.len() == {};", fields_pat, fields.len());
- println!(" // unimplemented: field checks");
- },
- PatKind::Path(ref path) => {
- let path_pat = self.next("path");
- println!("Path(ref {}) = {};", path_pat, current);
- self.current = path_pat;
- self.print_qpath(path);
+ bind!(self, fields);
+ kind!("Or({fields})");
+ self.slice(fields, |pat| self.pat(pat));
+ },
+ PatKind::TupleStruct(ref qpath, fields, skip_pos) => {
+ bind!(self, qpath, fields);
+ kind!("TupleStruct(ref {qpath}, {fields}, {skip_pos:?})");
+ self.qpath(qpath);
+ self.slice(fields, |pat| self.pat(pat));
+ },
+ PatKind::Path(ref qpath) => {
+ bind!(self, qpath);
+ kind!("Path(ref {qpath})");
+ self.qpath(qpath);
},
PatKind::Tuple(fields, skip_pos) => {
- let fields_pat = self.next("fields");
- println!("Tuple(ref {}, {:?}) = {};", fields_pat, skip_pos, current);
- println!(" if {}.len() == {};", fields_pat, fields.len());
- println!(" // unimplemented: field checks");
+ bind!(self, fields);
+ kind!("Tuple({fields}, {skip_pos:?})");
+ self.slice(fields, |field| self.pat(field));
},
PatKind::Box(pat) => {
- let pat_pat = self.next("pat");
- println!("Box(ref {}) = {};", pat_pat, current);
- self.current = pat_pat;
- self.visit_pat(pat);
+ bind!(self, pat);
+ kind!("Box({pat})");
+ self.pat(pat);
},
PatKind::Ref(pat, muta) => {
- let pat_pat = self.next("pat");
- println!("Ref(ref {}, Mutability::{:?}) = {};", pat_pat, muta, current);
- self.current = pat_pat;
- self.visit_pat(pat);
+ bind!(self, pat);
+ kind!("Ref({pat}, Mutability::{muta:?})");
+ self.pat(pat);
},
PatKind::Lit(lit_expr) => {
- let lit_expr_pat = self.next("lit_expr");
- println!("Lit(ref {}) = {}", lit_expr_pat, current);
- self.current = lit_expr_pat;
- self.visit_expr(lit_expr);
- },
- PatKind::Range(ref start, ref end, end_kind) => {
- let start_pat = self.next("start");
- let end_pat = self.next("end");
- println!(
- "Range(ref {}, ref {}, RangeEnd::{:?}) = {};",
- start_pat, end_pat, end_kind, current
- );
- self.current = start_pat;
- walk_list!(self, visit_expr, start);
- self.current = end_pat;
- walk_list!(self, visit_expr, end);
- },
- PatKind::Slice(start, ref middle, end) => {
- let start_pat = self.next("start");
- let end_pat = self.next("end");
- if let Some(middle) = middle {
- let middle_pat = self.next("middle");
- println!(
- "Slice(ref {}, Some(ref {}), ref {}) = {};",
- start_pat, middle_pat, end_pat, current
- );
- self.current = middle_pat;
- self.visit_pat(middle);
- } else {
- println!("Slice(ref {}, None, ref {}) = {};", start_pat, end_pat, current);
- }
- println!(" if {}.len() == {};", start_pat, start.len());
- for (i, pat) in start.iter().enumerate() {
- self.current = format!("{}[{}]", start_pat, i);
- self.visit_pat(pat);
- }
- println!(" if {}.len() == {};", end_pat, end.len());
- for (i, pat) in end.iter().enumerate() {
- self.current = format!("{}[{}]", end_pat, i);
- self.visit_pat(pat);
- }
+ bind!(self, lit_expr);
+ kind!("Lit({lit_expr})");
+ self.expr(lit_expr);
+ },
+ PatKind::Range(start, end, end_kind) => {
+ opt_bind!(self, start, end);
+ kind!("Range({start}, {end}, RangeEnd::{end_kind:?})");
+ start.if_some(|e| self.expr(e));
+ end.if_some(|e| self.expr(e));
+ },
+ PatKind::Slice(start, middle, end) => {
+ bind!(self, start, end);
+ opt_bind!(self, middle);
+ kind!("Slice({start}, {middle}, {end})");
+ middle.if_some(|p| self.pat(p));
+ self.slice(start, |pat| self.pat(pat));
+ self.slice(end, |pat| self.pat(pat));
},
}
}
- fn visit_stmt(&mut self, s: &Stmt<'_>) {
- print!(" if let StmtKind::");
- let current = format!("{}.kind", self.current);
- match s.kind {
- // A local (let) binding:
- StmtKind::Local(local) => {
- let local_pat = self.next("local");
- println!("Local(ref {}) = {};", local_pat, current);
- if let Some(init) = local.init {
- let init_pat = self.next("init");
- println!(" if let Some(ref {}) = {}.init;", init_pat, local_pat);
- self.current = init_pat;
- self.visit_expr(init);
- }
- self.current = format!("{}.pat", local_pat);
- self.visit_pat(local.pat);
- },
- // An item binding:
- StmtKind::Item(_) => {
- println!("Item(item_id) = {};", current);
- },
+ fn stmt(&self, stmt: &Binding<&hir::Stmt<'_>>) {
+ let kind = |kind| out!("if let StmtKind::{kind} = {stmt}.kind;");
+ macro_rules! kind {
+ ($($t:tt)*) => (kind(format_args!($($t)*)));
+ }
- // Expr without trailing semi-colon (must have unit type):
+ match stmt.value.kind {
+ StmtKind::Local(local) => {
+ bind!(self, local);
+ kind!("Local({local})");
+ self.option(field!(local.init), "init", |init| {
+ self.expr(init);
+ });
+ self.pat(field!(local.pat));
+ },
+ StmtKind::Item(_) => kind!("Item(item_id)"),
StmtKind::Expr(e) => {
- let e_pat = self.next("e");
- println!("Expr(ref {}, _) = {}", e_pat, current);
- self.current = e_pat;
- self.visit_expr(e);
+ bind!(self, e);
+ kind!("Expr({e})");
+ self.expr(e);
},
-
- // Expr with trailing semi-colon (may have any type):
StmtKind::Semi(e) => {
- let e_pat = self.next("e");
- println!("Semi(ref {}, _) = {}", e_pat, current);
- self.current = e_pat;
- self.visit_expr(e);
+ bind!(self, e);
+ kind!("Semi({e})");
+ self.expr(e);
},
}
}
-
- fn nested_visit_map(&mut self) -> NestedVisitorMap<Self::Map> {
- NestedVisitorMap::None
- }
}
fn has_attr(cx: &LateContext<'_>, hir_id: hir::HirId) -> bool {
@@ -741,30 +704,29 @@ fn has_attr(cx: &LateContext<'_>, hir_id: hir::HirId) -> bool {
get_attr(cx.sess(), attrs, "author").count() > 0
}
-fn print_path(path: &QPath<'_>, first: &mut bool) {
- match *path {
- QPath::Resolved(_, path) => {
- for segment in path.segments {
- if *first {
- *first = false;
- } else {
- print!(", ");
- }
- print!("{:?}", segment.ident.as_str());
- }
- },
- QPath::TypeRelative(ty, segment) => match ty.kind {
- hir::TyKind::Path(ref inner_path) => {
- print_path(inner_path, first);
- if *first {
- *first = false;
- } else {
- print!(", ");
+fn path_to_string(path: &QPath<'_>) -> String {
+ fn inner(s: &mut String, path: &QPath<'_>) {
+ match *path {
+ QPath::Resolved(_, path) => {
+ for (i, segment) in path.segments.iter().enumerate() {
+ if i > 0 {
+ *s += ", ";
+ }
+ write!(s, "{:?}", segment.ident.as_str()).unwrap();
}
- print!("{:?}", segment.ident.as_str());
},
- ref other => print!("/* unimplemented: {:?}*/", other),
- },
- QPath::LangItem(..) => panic!("print_path: called for lang item qpath"),
+ QPath::TypeRelative(ty, segment) => match &ty.kind {
+ hir::TyKind::Path(inner_path) => {
+ inner(s, inner_path);
+ *s += ", ";
+ write!(s, "{:?}", segment.ident.as_str()).unwrap();
+ },
+ other => write!(s, "/* unimplemented: {:?}*/", other).unwrap(),
+ },
+ QPath::LangItem(..) => panic!("path_to_string: called for lang item qpath"),
+ }
}
+ let mut s = String::new();
+ inner(&mut s, path);
+ s
}
diff --git a/src/tools/clippy/clippy_lints/src/utils/conf.rs b/src/tools/clippy/clippy_lints/src/utils/conf.rs
index 122a5ce3fc8..9c83d30eb9c 100644
--- a/src/tools/clippy/clippy_lints/src/utils/conf.rs
+++ b/src/tools/clippy/clippy_lints/src/utils/conf.rs
@@ -15,7 +15,7 @@ pub struct Rename {
pub rename: String,
}
-/// A single disallowed method, used by the `DISALLOWED_METHOD` lint.
+/// A single disallowed method, used by the `DISALLOWED_METHODS` lint.
#[derive(Clone, Debug, Deserialize)]
#[serde(untagged)]
pub enum DisallowedMethod {
@@ -23,7 +23,7 @@ pub enum DisallowedMethod {
WithReason { path: String, reason: Option<String> },
}
-/// A single disallowed type, used by the `DISALLOWED_TYPE` lint.
+/// A single disallowed type, used by the `DISALLOWED_TYPES` lint.
#[derive(Clone, Debug, Deserialize)]
#[serde(untagged)]
pub enum DisallowedType {
@@ -148,7 +148,7 @@ define_Conf! {
///
/// Suppress lints whenever the suggested change would cause breakage for other crates.
(avoid_breaking_exported_api: bool = true),
- /// Lint: MANUAL_SPLIT_ONCE, MANUAL_STR_REPEAT, CLONED_INSTEAD_OF_COPIED, REDUNDANT_FIELD_NAMES, REDUNDANT_STATIC_LIFETIMES, FILTER_MAP_NEXT, CHECKED_CONVERSIONS, MANUAL_RANGE_CONTAINS, USE_SELF, MEM_REPLACE_WITH_DEFAULT, MANUAL_NON_EXHAUSTIVE, OPTION_AS_REF_DEREF, MAP_UNWRAP_OR, MATCH_LIKE_MATCHES_MACRO, MANUAL_STRIP, MISSING_CONST_FOR_FN, UNNESTED_OR_PATTERNS, FROM_OVER_INTO, PTR_AS_PTR, IF_THEN_SOME_ELSE_NONE, APPROX_CONSTANT.
+ /// Lint: MANUAL_SPLIT_ONCE, MANUAL_STR_REPEAT, CLONED_INSTEAD_OF_COPIED, REDUNDANT_FIELD_NAMES, REDUNDANT_STATIC_LIFETIMES, FILTER_MAP_NEXT, CHECKED_CONVERSIONS, MANUAL_RANGE_CONTAINS, USE_SELF, MEM_REPLACE_WITH_DEFAULT, MANUAL_NON_EXHAUSTIVE, OPTION_AS_REF_DEREF, MAP_UNWRAP_OR, MATCH_LIKE_MATCHES_MACRO, MANUAL_STRIP, MISSING_CONST_FOR_FN, UNNESTED_OR_PATTERNS, FROM_OVER_INTO, PTR_AS_PTR, IF_THEN_SOME_ELSE_NONE, APPROX_CONSTANT, DEPRECATED_CFG_ATTR, INDEX_REFUTABLE_SLICE.
///
/// The minimum rust version that the project supports
(msrv: Option<String> = None),
@@ -256,11 +256,11 @@ define_Conf! {
///
/// Whether to allow certain wildcard imports (prelude, super in tests).
(warn_on_all_wildcard_imports: bool = false),
- /// Lint: DISALLOWED_METHOD.
+ /// Lint: DISALLOWED_METHODS.
///
/// The list of disallowed methods, written as fully qualified paths.
(disallowed_methods: Vec<crate::utils::conf::DisallowedMethod> = Vec::new()),
- /// Lint: DISALLOWED_TYPE.
+ /// Lint: DISALLOWED_TYPES.
///
/// The list of disallowed types, written as fully qualified paths.
(disallowed_types: Vec<crate::utils::conf::DisallowedType> = Vec::new()),
@@ -296,6 +296,12 @@ define_Conf! {
///
/// Whether to apply the raw pointer heuristic to determine if a type is `Send`.
(enable_raw_pointer_heuristic_for_send: bool = true),
+ /// Lint: INDEX_REFUTABLE_SLICE.
+ ///
+ /// When Clippy suggests using a slice pattern, this is the maximum number of elements allowed in
+ /// the slice pattern that is suggested. If more elements would be necessary, the lint is suppressed.
+ /// For example, `[_, _, _, e, ..]` is a slice pattern with 4 elements.
+ (max_suggested_slice_pattern_length: u64 = 3),
}
/// Search for the configuration file.
diff --git a/src/tools/clippy/clippy_lints/src/utils/inspector.rs b/src/tools/clippy/clippy_lints/src/utils/inspector.rs
index 43590cc7862..abf4826a069 100644
--- a/src/tools/clippy/clippy_lints/src/utils/inspector.rs
+++ b/src/tools/clippy/clippy_lints/src/utils/inspector.rs
@@ -142,9 +142,12 @@ fn print_expr(cx: &LateContext<'_>, expr: &hir::Expr<'_>, indent: usize) {
print_expr(cx, arg, indent + 1);
}
},
- hir::ExprKind::Let(pat, expr, _) => {
+ hir::ExprKind::Let(hir::Let { pat, init, ty, .. }) => {
print_pat(cx, pat, indent + 1);
- print_expr(cx, expr, indent + 1);
+ if let Some(ty) = ty {
+ println!("{} type annotation: {:?}", ind, ty);
+ }
+ print_expr(cx, init, indent + 1);
},
hir::ExprKind::MethodCall(path, _, args, _) => {
println!("{}MethodCall", ind);
diff --git a/src/tools/clippy/clippy_lints/src/utils/internal_lints.rs b/src/tools/clippy/clippy_lints/src/utils/internal_lints.rs
index 824ec53ab9c..81e9c2e15c9 100644
--- a/src/tools/clippy/clippy_lints/src/utils/internal_lints.rs
+++ b/src/tools/clippy/clippy_lints/src/utils/internal_lints.rs
@@ -1,13 +1,13 @@
use clippy_utils::consts::{constant_simple, Constant};
use clippy_utils::diagnostics::{span_lint, span_lint_and_help, span_lint_and_sugg, span_lint_and_then};
-use clippy_utils::higher;
use clippy_utils::source::snippet;
use clippy_utils::ty::match_type;
use clippy_utils::{
- is_else_clause, is_expn_of, is_expr_path_def_path, is_lint_allowed, match_def_path, method_calls, path_to_res,
- paths, SpanlessEq,
+ higher, is_else_clause, is_expn_of, is_expr_path_def_path, is_lint_allowed, match_def_path, method_calls,
+ path_to_res, paths, peel_blocks_with_stmt, SpanlessEq,
};
use if_chain::if_chain;
+use rustc_ast as ast;
use rustc_ast::ast::{Crate, ItemKind, LitKind, ModKind, NodeId};
use rustc_ast::visit::FnKind;
use rustc_data_structures::fx::{FxHashMap, FxHashSet};
@@ -25,10 +25,11 @@ use rustc_lint::{EarlyContext, EarlyLintPass, LateContext, LateLintPass, LintCon
use rustc_middle::hir::map::Map;
use rustc_middle::mir::interpret::ConstValue;
use rustc_middle::ty;
+use rustc_semver::RustcVersion;
use rustc_session::{declare_lint_pass, declare_tool_lint, impl_lint_pass};
use rustc_span::source_map::Spanned;
use rustc_span::symbol::{Symbol, SymbolStr};
-use rustc_span::{BytePos, Span};
+use rustc_span::{sym, BytePos, Span};
use rustc_typeck::hir_ty_to_ty;
use std::borrow::{Borrow, Cow};
@@ -314,6 +315,27 @@ declare_clippy_lint! {
"non-idiomatic `if_chain!` usage"
}
+declare_clippy_lint! {
+ /// ### What it does
+ /// Checks for invalid `clippy::version` attributes.
+ ///
+ /// Valid values are:
+ /// * "pre 1.29.0"
+ /// * any valid semantic version
+ pub INVALID_CLIPPY_VERSION_ATTRIBUTE,
+ internal,
+ "found an invalid `clippy::version` attribute"
+}
+
+declare_clippy_lint! {
+ /// ### What it does
+ /// Checks for declared clippy lints without the `clippy::version` attribute.
+ ///
+ pub MISSING_CLIPPY_VERSION_ATTRIBUTE,
+ internal,
+ "found clippy lint without `clippy::version` attribute"
+}
+
declare_lint_pass!(ClippyLintsInternal => [CLIPPY_LINTS_INTERNAL]);
impl EarlyLintPass for ClippyLintsInternal {
@@ -351,7 +373,7 @@ pub struct LintWithoutLintPass {
registered_lints: FxHashSet<Symbol>,
}
-impl_lint_pass!(LintWithoutLintPass => [DEFAULT_LINT, LINT_WITHOUT_LINT_PASS]);
+impl_lint_pass!(LintWithoutLintPass => [DEFAULT_LINT, LINT_WITHOUT_LINT_PASS, INVALID_CLIPPY_VERSION_ATTRIBUTE, MISSING_CLIPPY_VERSION_ATTRIBUTE]);
impl<'tcx> LateLintPass<'tcx> for LintWithoutLintPass {
fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx Item<'_>) {
@@ -361,6 +383,8 @@ impl<'tcx> LateLintPass<'tcx> for LintWithoutLintPass {
if let hir::ItemKind::Static(ty, Mutability::Not, body_id) = item.kind {
if is_lint_ref_type(cx, ty) {
+ check_invalid_clippy_version_attribute(cx, item);
+
let expr = &cx.tcx.hir().body(body_id).value;
if_chain! {
if let ExprKind::AddrOf(_, _, inner_exp) = expr.kind;
@@ -458,6 +482,57 @@ fn is_lint_ref_type<'tcx>(cx: &LateContext<'tcx>, ty: &Ty<'_>) -> bool {
false
}
+fn check_invalid_clippy_version_attribute(cx: &LateContext<'_>, item: &'_ Item<'_>) {
+ if let Some(value) = extract_clippy_version_value(cx, item) {
+ // The `sym!` macro doesn't work as it only expects a single token.
+ // It's better to keep it this way and have a direct `Symbol::intern` call here.
+ if value == Symbol::intern("pre 1.29.0") {
+ return;
+ }
+
+ if RustcVersion::parse(&*value.as_str()).is_err() {
+ span_lint_and_help(
+ cx,
+ INVALID_CLIPPY_VERSION_ATTRIBUTE,
+ item.span,
+ "this item has an invalid `clippy::version` attribute",
+ None,
+ "please use a valid sematic version, see `doc/adding_lints.md`",
+ );
+ }
+ } else {
+ span_lint_and_help(
+ cx,
+ MISSING_CLIPPY_VERSION_ATTRIBUTE,
+ item.span,
+ "this lint is missing the `clippy::version` attribute or version value",
+ None,
+ "please use a `clippy::version` attribute, see `doc/adding_lints.md`",
+ );
+ }
+}
+
+/// This function extracts the version value of a `clippy::version` attribute if the given value has
+/// one
+fn extract_clippy_version_value(cx: &LateContext<'_>, item: &'_ Item<'_>) -> Option<Symbol> {
+ let attrs = cx.tcx.hir().attrs(item.hir_id());
+ attrs.iter().find_map(|attr| {
+ if_chain! {
+ // Identify attribute
+ if let ast::AttrKind::Normal(ref attr_kind, _) = &attr.kind;
+ if let [tool_name, attr_name] = &attr_kind.path.segments[..];
+ if tool_name.ident.name == sym::clippy;
+ if attr_name.ident.name == sym::version;
+ if let Some(version) = attr.value_str();
+ then {
+ Some(version)
+ } else {
+ None
+ }
+ }
+ })
+}
+
struct LintCollector<'a, 'tcx> {
output: &'a mut FxHashSet<Symbol>,
cx: &'a LateContext<'tcx>,
@@ -586,10 +661,7 @@ impl<'tcx> LateLintPass<'tcx> for CollapsibleCalls {
if and_then_args.len() == 5;
if let ExprKind::Closure(_, _, body_id, _, _) = &and_then_args[4].kind;
let body = cx.tcx.hir().body(*body_id);
- if let ExprKind::Block(block, _) = &body.value.kind;
- let stmts = &block.stmts;
- if stmts.len() == 1 && block.expr.is_none();
- if let StmtKind::Semi(only_expr) = &stmts[0].kind;
+ let only_expr = peel_blocks_with_stmt(&body.value);
if let ExprKind::MethodCall(ps, _, span_call_args, _) = &only_expr.kind;
then {
let and_then_snippets = get_and_then_snippets(cx, and_then_args);
diff --git a/src/tools/clippy/clippy_lints/src/utils/internal_lints/metadata_collector.rs b/src/tools/clippy/clippy_lints/src/utils/internal_lints/metadata_collector.rs
index 99cf4c1ed40..7707eebd622 100644
--- a/src/tools/clippy/clippy_lints/src/utils/internal_lints/metadata_collector.rs
+++ b/src/tools/clippy/clippy_lints/src/utils/internal_lints/metadata_collector.rs
@@ -8,6 +8,11 @@
//! during any comparison or mapping. (Please take care of this, it's not fun to spend time on such
//! a simple mistake)
+use crate::utils::internal_lints::{extract_clippy_version_value, is_lint_ref_type};
+
+use clippy_utils::diagnostics::span_lint;
+use clippy_utils::ty::{match_type, walk_ptrs_ty_depth};
+use clippy_utils::{last_path_segment, match_def_path, match_function_call, match_path, paths};
use if_chain::if_chain;
use rustc_ast as ast;
use rustc_data_structures::fx::FxHashMap;
@@ -25,12 +30,6 @@ use std::fs::{self, OpenOptions};
use std::io::prelude::*;
use std::path::Path;
-use crate::utils::internal_lints::is_lint_ref_type;
-use clippy_utils::{
- diagnostics::span_lint, last_path_segment, match_def_path, match_function_call, match_path, paths, ty::match_type,
- ty::walk_ptrs_ty_depth,
-};
-
/// This is the output file of the lint collector.
const OUTPUT_FILE: &str = "../util/gh-pages/lints.json";
/// These lints are excluded from the export.
@@ -116,6 +115,8 @@ const DEPRECATED_LINT_TYPE: [&str; 3] = ["clippy_lints", "deprecated_lints", "Cl
const APPLICABILITY_NAME_INDEX: usize = 2;
/// This applicability will be set for unresolved applicability values.
const APPLICABILITY_UNRESOLVED_STR: &str = "Unresolved";
+/// The version that will be displayed if none has been defined
+const VERION_DEFAULT_STR: &str = "Unknown";
declare_clippy_lint! {
/// ### What it does
@@ -144,6 +145,7 @@ declare_clippy_lint! {
/// "docs": " ### What it does\nCollects metadata about clippy lints for the website. [...] "
/// }
/// ```
+ #[clippy::version = "1.56.0"]
pub INTERNAL_METADATA_COLLECTOR,
internal_warn,
"A busy bee collection metadata about lints"
@@ -215,18 +217,27 @@ struct LintMetadata {
group: String,
level: String,
docs: String,
+ version: String,
/// This field is only used in the output and will only be
/// mapped shortly before the actual output.
applicability: Option<ApplicabilityInfo>,
}
impl LintMetadata {
- fn new(id: String, id_span: SerializableSpan, group: String, level: &'static str, docs: String) -> Self {
+ fn new(
+ id: String,
+ id_span: SerializableSpan,
+ group: String,
+ level: &'static str,
+ version: String,
+ docs: String,
+ ) -> Self {
Self {
id,
id_span,
group,
level: level.to_string(),
+ version,
docs,
applicability: None,
}
@@ -410,12 +421,14 @@ impl<'hir> LateLintPass<'hir> for MetadataCollector {
if let Some(configuration_section) = self.get_lint_configs(&lint_name) {
docs.push_str(&configuration_section);
}
+ let version = get_lint_version(cx, item);
self.lints.push(LintMetadata::new(
lint_name,
SerializableSpan::from_item(cx, item),
group,
level,
+ version,
docs,
));
}
@@ -429,11 +442,14 @@ impl<'hir> LateLintPass<'hir> for MetadataCollector {
// Metadata the little we can get from a deprecated lint
if let Some(docs) = extract_attr_docs_or_lint(cx, item);
then {
+ let version = get_lint_version(cx, item);
+
self.lints.push(LintMetadata::new(
lint_name,
SerializableSpan::from_item(cx, item),
DEPRECATED_LINT_GROUP_STR.to_string(),
DEPRECATED_LINT_LEVEL,
+ version,
docs,
));
}
@@ -552,6 +568,13 @@ fn extract_attr_docs(cx: &LateContext<'_>, item: &Item<'_>) -> Option<String> {
Some(docs)
}
+fn get_lint_version(cx: &LateContext<'_>, item: &Item<'_>) -> String {
+ extract_clippy_version_value(cx, item).map_or_else(
+ || VERION_DEFAULT_STR.to_string(),
+ |version| version.as_str().to_string(),
+ )
+}
+
fn get_lint_group_and_level_or_lint(
cx: &LateContext<'_>,
lint_name: &str,
@@ -663,7 +686,6 @@ fn extract_emission_info<'hir>(
applicability = resolve_applicability(cx, arg);
} else if arg_ty.is_closure() {
multi_part |= check_is_multi_part(cx, arg);
- // TODO xFrednet 2021-03-01: don't use or_else but rather a comparison
applicability = applicability.or_else(|| resolve_applicability(cx, arg));
}
}
diff --git a/src/tools/clippy/clippy_lints/src/vec.rs b/src/tools/clippy/clippy_lints/src/vec.rs
index d3234b5758a..79e7410c3a8 100644
--- a/src/tools/clippy/clippy_lints/src/vec.rs
+++ b/src/tools/clippy/clippy_lints/src/vec.rs
@@ -36,6 +36,7 @@ declare_clippy_lint! {
/// // Good
/// foo(&[1, 2]);
/// ```
+ #[clippy::version = "pre 1.29.0"]
pub USELESS_VEC,
perf,
"useless `vec!`"
diff --git a/src/tools/clippy/clippy_lints/src/vec_init_then_push.rs b/src/tools/clippy/clippy_lints/src/vec_init_then_push.rs
index b92b6ca4f43..1bc0eb6303c 100644
--- a/src/tools/clippy/clippy_lints/src/vec_init_then_push.rs
+++ b/src/tools/clippy/clippy_lints/src/vec_init_then_push.rs
@@ -27,6 +27,7 @@ declare_clippy_lint! {
/// ```rust
/// let v = vec![0];
/// ```
+ #[clippy::version = "1.51.0"]
pub VEC_INIT_THEN_PUSH,
perf,
"`push` immediately after `Vec` creation"
diff --git a/src/tools/clippy/clippy_lints/src/vec_resize_to_zero.rs b/src/tools/clippy/clippy_lints/src/vec_resize_to_zero.rs
index 5c0429db6b8..3441d9ccdfa 100644
--- a/src/tools/clippy/clippy_lints/src/vec_resize_to_zero.rs
+++ b/src/tools/clippy/clippy_lints/src/vec_resize_to_zero.rs
@@ -20,6 +20,7 @@ declare_clippy_lint! {
/// ```rust
/// vec!(1, 2, 3, 4, 5).resize(0, 5)
/// ```
+ #[clippy::version = "1.46.0"]
pub VEC_RESIZE_TO_ZERO,
correctness,
"emptying a vector with `resize(0, an_int)` instead of `clear()` is probably an argument inversion mistake"
diff --git a/src/tools/clippy/clippy_lints/src/verbose_file_reads.rs b/src/tools/clippy/clippy_lints/src/verbose_file_reads.rs
index e07c12f4f16..ebdaff1e676 100644
--- a/src/tools/clippy/clippy_lints/src/verbose_file_reads.rs
+++ b/src/tools/clippy/clippy_lints/src/verbose_file_reads.rs
@@ -27,6 +27,7 @@ declare_clippy_lint! {
/// # use std::fs;
/// let mut bytes = fs::read("foo.txt").unwrap();
/// ```
+ #[clippy::version = "1.44.0"]
pub VERBOSE_FILE_READS,
restriction,
"use of `File::read_to_end` or `File::read_to_string`"
diff --git a/src/tools/clippy/clippy_lints/src/wildcard_dependencies.rs b/src/tools/clippy/clippy_lints/src/wildcard_dependencies.rs
index d0c98b6bd79..80d7b8a1b6d 100644
--- a/src/tools/clippy/clippy_lints/src/wildcard_dependencies.rs
+++ b/src/tools/clippy/clippy_lints/src/wildcard_dependencies.rs
@@ -20,6 +20,7 @@ declare_clippy_lint! {
/// [dependencies]
/// regex = "*"
/// ```
+ #[clippy::version = "1.32.0"]
pub WILDCARD_DEPENDENCIES,
cargo,
"wildcard dependencies being used"
diff --git a/src/tools/clippy/clippy_lints/src/wildcard_imports.rs b/src/tools/clippy/clippy_lints/src/wildcard_imports.rs
index bafb9d3e3b1..832da66a536 100644
--- a/src/tools/clippy/clippy_lints/src/wildcard_imports.rs
+++ b/src/tools/clippy/clippy_lints/src/wildcard_imports.rs
@@ -1,6 +1,6 @@
use clippy_utils::diagnostics::span_lint_and_sugg;
+use clippy_utils::is_test_module_or_function;
use clippy_utils::source::{snippet, snippet_with_applicability};
-use clippy_utils::{in_macro, is_test_module_or_function};
use if_chain::if_chain;
use rustc_errors::Applicability;
use rustc_hir::{
@@ -34,6 +34,7 @@ declare_clippy_lint! {
/// use std::cmp::Ordering;
/// foo(Ordering::Less)
/// ```
+ #[clippy::version = "pre 1.29.0"]
pub ENUM_GLOB_USE,
pedantic,
"use items that import all variants of an enum"
@@ -86,6 +87,7 @@ declare_clippy_lint! {
///
/// foo();
/// ```
+ #[clippy::version = "1.43.0"]
pub WILDCARD_IMPORTS,
pedantic,
"lint `use _::*` statements"
@@ -196,7 +198,7 @@ impl LateLintPass<'_> for WildcardImports {
impl WildcardImports {
fn check_exceptions(&self, item: &Item<'_>, segments: &[PathSegment<'_>]) -> bool {
- in_macro(item.span)
+ item.span.from_expansion()
|| is_prelude_import(segments)
|| (is_super_only_import(segments) && self.test_modules_deep > 0)
}
diff --git a/src/tools/clippy/clippy_lints/src/write.rs b/src/tools/clippy/clippy_lints/src/write.rs
index b412e15ae4f..5bf0cffdbad 100644
--- a/src/tools/clippy/clippy_lints/src/write.rs
+++ b/src/tools/clippy/clippy_lints/src/write.rs
@@ -31,6 +31,7 @@ declare_clippy_lint! {
/// // Good
/// println!();
/// ```
+ #[clippy::version = "pre 1.29.0"]
pub PRINTLN_EMPTY_STRING,
style,
"using `println!(\"\")` with an empty string"
@@ -55,6 +56,7 @@ declare_clippy_lint! {
/// # let name = "World";
/// println!("Hello {}!", name);
/// ```
+ #[clippy::version = "pre 1.29.0"]
pub PRINT_WITH_NEWLINE,
style,
"using `print!()` with a format string that ends in a single newline"
@@ -70,12 +72,19 @@ declare_clippy_lint! {
/// application and might forget to remove those prints afterward.
///
/// ### Known problems
- /// Only catches `print!` and `println!` calls.
+ /// * Only catches `print!` and `println!` calls.
+ /// * The lint level is unaffected by crate attributes. The level can still
+ /// be set for functions, modules and other items. To change the level for
+ /// the entire crate, please use command line flags. More information and a
+ /// configuration example can be found in [clippy#6610].
+ ///
+ /// [clippy#6610]: https://github.com/rust-lang/rust-clippy/issues/6610#issuecomment-977120558
///
/// ### Example
/// ```rust
/// println!("Hello world!");
/// ```
+ #[clippy::version = "pre 1.29.0"]
pub PRINT_STDOUT,
restriction,
"printing on stdout"
@@ -91,12 +100,19 @@ declare_clippy_lint! {
/// application and might forget to remove those prints afterward.
///
/// ### Known problems
- /// Only catches `eprint!` and `eprintln!` calls.
+ /// * Only catches `eprint!` and `eprintln!` calls.
+ /// * The lint level is unaffected by crate attributes. The level can still
+ /// be set for functions, modules and other items. To change the level for
+ /// the entire crate, please use command line flags. More information and a
+ /// configuration example can be found in [clippy#6610].
+ ///
+ /// [clippy#6610]: https://github.com/rust-lang/rust-clippy/issues/6610#issuecomment-977120558
///
/// ### Example
/// ```rust
/// eprintln!("Hello world!");
/// ```
+ #[clippy::version = "1.50.0"]
pub PRINT_STDERR,
restriction,
"printing on stderr"
@@ -116,6 +132,7 @@ declare_clippy_lint! {
/// # let foo = "bar";
/// println!("{:?}", foo);
/// ```
+ #[clippy::version = "pre 1.29.0"]
pub USE_DEBUG,
restriction,
"use of `Debug`-based formatting"
@@ -142,6 +159,7 @@ declare_clippy_lint! {
/// ```rust
/// println!("foo");
/// ```
+ #[clippy::version = "pre 1.29.0"]
pub PRINT_LITERAL,
style,
"printing a literal with a format string"
@@ -165,6 +183,7 @@ declare_clippy_lint! {
/// // Good
/// writeln!(buf);
/// ```
+ #[clippy::version = "pre 1.29.0"]
pub WRITELN_EMPTY_STRING,
style,
"using `writeln!(buf, \"\")` with an empty string"
@@ -191,6 +210,7 @@ declare_clippy_lint! {
/// // Good
/// writeln!(buf, "Hello {}!", name);
/// ```
+ #[clippy::version = "pre 1.29.0"]
pub WRITE_WITH_NEWLINE,
style,
"using `write!()` with a format string that ends in a single newline"
@@ -219,6 +239,7 @@ declare_clippy_lint! {
/// // Good
/// writeln!(buf, "foo");
/// ```
+ #[clippy::version = "pre 1.29.0"]
pub WRITE_LITERAL,
style,
"writing a literal with a format string"
@@ -562,10 +583,10 @@ impl Write {
let replacement: String = match lit.token.kind {
LitKind::Integer | LitKind::Float | LitKind::Err => continue,
LitKind::StrRaw(_) | LitKind::ByteStrRaw(_) if matches!(fmtstr.style, StrStyle::Raw(_)) => {
- lit.token.symbol.as_str().replace("{", "{{").replace("}", "}}")
+ lit.token.symbol.as_str().replace('{', "{{").replace('}', "}}")
},
LitKind::Str | LitKind::ByteStr if matches!(fmtstr.style, StrStyle::Cooked) => {
- lit.token.symbol.as_str().replace("{", "{{").replace("}", "}}")
+ lit.token.symbol.as_str().replace('{', "{{").replace('}', "}}")
},
LitKind::StrRaw(_) | LitKind::Str | LitKind::ByteStrRaw(_) | LitKind::ByteStr => continue,
LitKind::Byte | LitKind::Char => match &*lit.token.symbol.as_str() {
diff --git a/src/tools/clippy/clippy_lints/src/zero_div_zero.rs b/src/tools/clippy/clippy_lints/src/zero_div_zero.rs
index e0746ce4d81..641681185a2 100644
--- a/src/tools/clippy/clippy_lints/src/zero_div_zero.rs
+++ b/src/tools/clippy/clippy_lints/src/zero_div_zero.rs
@@ -20,6 +20,7 @@ declare_clippy_lint! {
/// // Good
/// let nan = f32::NAN;
/// ```
+ #[clippy::version = "pre 1.29.0"]
pub ZERO_DIVIDED_BY_ZERO,
complexity,
"usage of `0.0 / 0.0` to obtain NaN instead of `f32::NAN` or `f64::NAN`"
diff --git a/src/tools/clippy/clippy_lints/src/zero_sized_map_values.rs b/src/tools/clippy/clippy_lints/src/zero_sized_map_values.rs
index aa6b2614bbc..eb8436a501d 100644
--- a/src/tools/clippy/clippy_lints/src/zero_sized_map_values.rs
+++ b/src/tools/clippy/clippy_lints/src/zero_sized_map_values.rs
@@ -36,6 +36,7 @@ declare_clippy_lint! {
/// todo!();
/// }
/// ```
+ #[clippy::version = "1.50.0"]
pub ZERO_SIZED_MAP_VALUES,
pedantic,
"usage of map with zero-sized value type"
diff --git a/src/tools/clippy/clippy_utils/Cargo.toml b/src/tools/clippy/clippy_utils/Cargo.toml
index d99a3d9359e..0ba0b59ed13 100644
--- a/src/tools/clippy/clippy_utils/Cargo.toml
+++ b/src/tools/clippy/clippy_utils/Cargo.toml
@@ -1,6 +1,6 @@
[package]
name = "clippy_utils"
-version = "0.1.58"
+version = "0.1.59"
edition = "2021"
publish = false
diff --git a/src/tools/clippy/clippy_utils/src/ast_utils.rs b/src/tools/clippy/clippy_utils/src/ast_utils.rs
index 1b05a8a3504..8400bfbbd99 100644
--- a/src/tools/clippy/clippy_utils/src/ast_utils.rs
+++ b/src/tools/clippy/clippy_utils/src/ast_utils.rs
@@ -243,6 +243,7 @@ pub fn eq_item<K>(l: &Item<K>, r: &Item<K>, mut eq_kind: impl FnMut(&K, &K) -> b
eq_id(l.ident, r.ident) && over(&l.attrs, &r.attrs, eq_attr) && eq_vis(&l.vis, &r.vis) && eq_kind(&l.kind, &r.kind)
}
+#[allow(clippy::too_many_lines)] // Just a big match statement
pub fn eq_item_kind(l: &ItemKind, r: &ItemKind) -> bool {
use ItemKind::*;
match (l, r) {
@@ -250,8 +251,20 @@ pub fn eq_item_kind(l: &ItemKind, r: &ItemKind) -> bool {
(Use(l), Use(r)) => eq_use_tree(l, r),
(Static(lt, lm, le), Static(rt, rm, re)) => lm == rm && eq_ty(lt, rt) && eq_expr_opt(le, re),
(Const(ld, lt, le), Const(rd, rt, re)) => eq_defaultness(*ld, *rd) && eq_ty(lt, rt) && eq_expr_opt(le, re),
- (Fn(box ast::Fn { defaultness: ld, sig: lf, generics: lg, body: lb }),
- Fn(box ast::Fn { defaultness: rd, sig: rf, generics: rg, body: rb })) => {
+ (
+ Fn(box ast::Fn {
+ defaultness: ld,
+ sig: lf,
+ generics: lg,
+ body: lb,
+ }),
+ Fn(box ast::Fn {
+ defaultness: rd,
+ sig: rf,
+ generics: rg,
+ body: rb,
+ }),
+ ) => {
eq_defaultness(*ld, *rd) && eq_fn_sig(lf, rf) && eq_generics(lg, rg) && both(lb, rb, |l, r| eq_block(l, r))
},
(Mod(lu, lmk), Mod(ru, rmk)) => {
@@ -267,8 +280,20 @@ pub fn eq_item_kind(l: &ItemKind, r: &ItemKind) -> bool {
(ForeignMod(l), ForeignMod(r)) => {
both(&l.abi, &r.abi, eq_str_lit) && over(&l.items, &r.items, |l, r| eq_item(l, r, eq_foreign_item_kind))
},
- (TyAlias(box ast::TyAlias { defaultness: ld, generics: lg, bounds: lb, ty: lt }),
- TyAlias(box ast::TyAlias { defaultness: rd, generics: rg, bounds: rb, ty: rt })) => {
+ (
+ TyAlias(box ast::TyAlias {
+ defaultness: ld,
+ generics: lg,
+ bounds: lb,
+ ty: lt,
+ }),
+ TyAlias(box ast::TyAlias {
+ defaultness: rd,
+ generics: rg,
+ bounds: rb,
+ ty: rt,
+ }),
+ ) => {
eq_defaultness(*ld, *rd)
&& eq_generics(lg, rg)
&& over(lb, rb, eq_generic_bound)
@@ -278,8 +303,22 @@ pub fn eq_item_kind(l: &ItemKind, r: &ItemKind) -> bool {
(Struct(lv, lg), Struct(rv, rg)) | (Union(lv, lg), Union(rv, rg)) => {
eq_variant_data(lv, rv) && eq_generics(lg, rg)
},
- (Trait(box ast::Trait { is_auto: la, unsafety: lu, generics: lg, bounds: lb, items: li }),
- Trait(box ast::Trait { is_auto: ra, unsafety: ru, generics: rg, bounds: rb, items: ri })) => {
+ (
+ Trait(box ast::Trait {
+ is_auto: la,
+ unsafety: lu,
+ generics: lg,
+ bounds: lb,
+ items: li,
+ }),
+ Trait(box ast::Trait {
+ is_auto: ra,
+ unsafety: ru,
+ generics: rg,
+ bounds: rb,
+ items: ri,
+ }),
+ ) => {
la == ra
&& matches!(lu, Unsafe::No) == matches!(ru, Unsafe::No)
&& eq_generics(lg, rg)
@@ -328,12 +367,36 @@ pub fn eq_foreign_item_kind(l: &ForeignItemKind, r: &ForeignItemKind) -> bool {
use ForeignItemKind::*;
match (l, r) {
(Static(lt, lm, le), Static(rt, rm, re)) => lm == rm && eq_ty(lt, rt) && eq_expr_opt(le, re),
- (Fn(box ast::Fn { defaultness: ld, sig: lf, generics: lg, body: lb }),
- Fn(box ast::Fn { defaultness: rd, sig: rf, generics: rg, body: rb })) => {
+ (
+ Fn(box ast::Fn {
+ defaultness: ld,
+ sig: lf,
+ generics: lg,
+ body: lb,
+ }),
+ Fn(box ast::Fn {
+ defaultness: rd,
+ sig: rf,
+ generics: rg,
+ body: rb,
+ }),
+ ) => {
eq_defaultness(*ld, *rd) && eq_fn_sig(lf, rf) && eq_generics(lg, rg) && both(lb, rb, |l, r| eq_block(l, r))
},
- (TyAlias(box ast::TyAlias { defaultness: ld, generics: lg, bounds: lb, ty: lt }),
- TyAlias(box ast::TyAlias { defaultness: rd, generics: rg, bounds: rb, ty: rt })) => {
+ (
+ TyAlias(box ast::TyAlias {
+ defaultness: ld,
+ generics: lg,
+ bounds: lb,
+ ty: lt,
+ }),
+ TyAlias(box ast::TyAlias {
+ defaultness: rd,
+ generics: rg,
+ bounds: rb,
+ ty: rt,
+ }),
+ ) => {
eq_defaultness(*ld, *rd)
&& eq_generics(lg, rg)
&& over(lb, rb, eq_generic_bound)
@@ -348,12 +411,36 @@ pub fn eq_assoc_item_kind(l: &AssocItemKind, r: &AssocItemKind) -> bool {
use AssocItemKind::*;
match (l, r) {
(Const(ld, lt, le), Const(rd, rt, re)) => eq_defaultness(*ld, *rd) && eq_ty(lt, rt) && eq_expr_opt(le, re),
- (Fn(box ast::Fn { defaultness: ld, sig: lf, generics: lg, body: lb }),
- Fn(box ast::Fn { defaultness: rd, sig: rf, generics: rg, body: rb })) => {
+ (
+ Fn(box ast::Fn {
+ defaultness: ld,
+ sig: lf,
+ generics: lg,
+ body: lb,
+ }),
+ Fn(box ast::Fn {
+ defaultness: rd,
+ sig: rf,
+ generics: rg,
+ body: rb,
+ }),
+ ) => {
eq_defaultness(*ld, *rd) && eq_fn_sig(lf, rf) && eq_generics(lg, rg) && both(lb, rb, |l, r| eq_block(l, r))
},
- (TyAlias(box ast::TyAlias { defaultness: ld, generics: lg, bounds: lb, ty: lt }),
- TyAlias(box ast::TyAlias { defaultness: rd, generics: rg, bounds: rb, ty: rt })) => {
+ (
+ TyAlias(box ast::TyAlias {
+ defaultness: ld,
+ generics: lg,
+ bounds: lb,
+ ty: lt,
+ }),
+ TyAlias(box ast::TyAlias {
+ defaultness: rd,
+ generics: rg,
+ bounds: rb,
+ ty: rt,
+ }),
+ ) => {
eq_defaultness(*ld, *rd)
&& eq_generics(lg, rg)
&& over(lb, rb, eq_generic_bound)
diff --git a/src/tools/clippy/clippy_utils/src/attrs.rs b/src/tools/clippy/clippy_utils/src/attrs.rs
index c19b558cd8c..7ae9615d560 100644
--- a/src/tools/clippy/clippy_utils/src/attrs.rs
+++ b/src/tools/clippy/clippy_utils/src/attrs.rs
@@ -14,15 +14,14 @@ pub enum DeprecationStatus {
None,
}
+#[rustfmt::skip]
pub const BUILTIN_ATTRIBUTES: &[(&str, DeprecationStatus)] = &[
- ("author", DeprecationStatus::None),
- ("cognitive_complexity", DeprecationStatus::None),
- (
- "cyclomatic_complexity",
- DeprecationStatus::Replaced("cognitive_complexity"),
- ),
- ("dump", DeprecationStatus::None),
- ("msrv", DeprecationStatus::None),
+ ("author", DeprecationStatus::None),
+ ("version", DeprecationStatus::None),
+ ("cognitive_complexity", DeprecationStatus::None),
+ ("cyclomatic_complexity", DeprecationStatus::Replaced("cognitive_complexity")),
+ ("dump", DeprecationStatus::None),
+ ("msrv", DeprecationStatus::None),
];
pub struct LimitStack {
diff --git a/src/tools/clippy/clippy_utils/src/eager_or_lazy.rs b/src/tools/clippy/clippy_utils/src/eager_or_lazy.rs
index 1ea7ccfb752..c2645ac730a 100644
--- a/src/tools/clippy/clippy_utils/src/eager_or_lazy.rs
+++ b/src/tools/clippy/clippy_utils/src/eager_or_lazy.rs
@@ -9,128 +9,227 @@
//! - or-fun-call
//! - option-if-let-else
-use crate::is_ctor_or_promotable_const_function;
-use crate::ty::is_type_diagnostic_item;
+use crate::ty::{all_predicates_of, is_copy};
+use crate::visitors::is_const_evaluatable;
use rustc_hir::def::{DefKind, Res};
-
-use rustc_hir::intravisit;
-use rustc_hir::intravisit::{NestedVisitorMap, Visitor};
-
-use rustc_hir::{Block, Expr, ExprKind, Path, QPath};
+use rustc_hir::intravisit::{walk_expr, ErasedMap, NestedVisitorMap, Visitor};
+use rustc_hir::{def_id::DefId, Block, Expr, ExprKind, QPath, UnOp};
use rustc_lint::LateContext;
-use rustc_middle::hir::map::Map;
-use rustc_span::sym;
-
-/// Is the expr pure (is it free from side-effects)?
-/// This function is named so to stress that it isn't exhaustive and returns FNs.
-fn identify_some_pure_patterns(expr: &Expr<'_>) -> bool {
- match expr.kind {
- ExprKind::Lit(..) | ExprKind::ConstBlock(..) | ExprKind::Path(..) | ExprKind::Field(..) => true,
- ExprKind::AddrOf(_, _, addr_of_expr) => identify_some_pure_patterns(addr_of_expr),
- ExprKind::Tup(tup_exprs) => tup_exprs.iter().all(identify_some_pure_patterns),
- ExprKind::Struct(_, fields, expr) => {
- fields.iter().all(|f| identify_some_pure_patterns(f.expr)) && expr.map_or(true, identify_some_pure_patterns)
- },
- ExprKind::Call(
- &Expr {
- kind:
- ExprKind::Path(QPath::Resolved(
- _,
- Path {
- res: Res::Def(DefKind::Ctor(..) | DefKind::Variant, ..),
- ..
- },
- )),
- ..
- },
- args,
- ) => args.iter().all(identify_some_pure_patterns),
- ExprKind::Block(
- &Block {
- stmts,
- expr: Some(expr),
- ..
- },
- _,
- ) => stmts.is_empty() && identify_some_pure_patterns(expr),
- ExprKind::Box(..)
- | ExprKind::Array(..)
- | ExprKind::Call(..)
- | ExprKind::MethodCall(..)
- | ExprKind::Binary(..)
- | ExprKind::Unary(..)
- | ExprKind::Let(..)
- | ExprKind::Cast(..)
- | ExprKind::Type(..)
- | ExprKind::DropTemps(..)
- | ExprKind::Loop(..)
- | ExprKind::If(..)
- | ExprKind::Match(..)
- | ExprKind::Closure(..)
- | ExprKind::Block(..)
- | ExprKind::Assign(..)
- | ExprKind::AssignOp(..)
- | ExprKind::Index(..)
- | ExprKind::Break(..)
- | ExprKind::Continue(..)
- | ExprKind::Ret(..)
- | ExprKind::InlineAsm(..)
- | ExprKind::LlvmInlineAsm(..)
- | ExprKind::Repeat(..)
- | ExprKind::Yield(..)
- | ExprKind::Err => false,
+use rustc_middle::ty::{self, PredicateKind};
+use rustc_span::{sym, Symbol};
+use std::cmp;
+use std::ops;
+
+#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
+enum EagernessSuggestion {
+ // The expression is cheap and should be evaluated eagerly
+ Eager,
+ // The expression may be cheap, so don't suggested lazy evaluation; or the expression may not be safe to switch to
+ // eager evaluation.
+ NoChange,
+ // The expression is likely expensive and should be evaluated lazily.
+ Lazy,
+ // The expression cannot be placed into a closure.
+ ForceNoChange,
+}
+impl ops::BitOr for EagernessSuggestion {
+ type Output = Self;
+ fn bitor(self, rhs: Self) -> Self {
+ cmp::max(self, rhs)
}
}
-
-/// Identify some potentially computationally expensive patterns.
-/// This function is named so to stress that its implementation is non-exhaustive.
-/// It returns FNs and FPs.
-fn identify_some_potentially_expensive_patterns<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>) -> bool {
- // Searches an expression for method calls or function calls that aren't ctors
- struct FunCallFinder<'a, 'tcx> {
- cx: &'a LateContext<'tcx>,
- found: bool,
+impl ops::BitOrAssign for EagernessSuggestion {
+ fn bitor_assign(&mut self, rhs: Self) {
+ *self = *self | rhs;
}
+}
- impl<'a, 'tcx> intravisit::Visitor<'tcx> for FunCallFinder<'a, 'tcx> {
- type Map = Map<'tcx>;
-
- fn visit_expr(&mut self, expr: &'tcx Expr<'tcx>) {
- let call_found = match &expr.kind {
- // ignore enum and struct constructors
- ExprKind::Call(..) => !is_ctor_or_promotable_const_function(self.cx, expr),
- ExprKind::Index(obj, _) => {
- let ty = self.cx.typeck_results().expr_ty(obj);
- is_type_diagnostic_item(self.cx, ty, sym::HashMap)
- || is_type_diagnostic_item(self.cx, ty, sym::BTreeMap)
- },
- ExprKind::MethodCall(..) => true,
- _ => false,
- };
+/// Determine the eagerness of the given function call.
+fn fn_eagerness(cx: &LateContext<'tcx>, fn_id: DefId, name: Symbol, args: &'tcx [Expr<'_>]) -> EagernessSuggestion {
+ use EagernessSuggestion::{Eager, Lazy, NoChange};
+ let name = &*name.as_str();
- if call_found {
- self.found |= true;
- }
+ let ty = match cx.tcx.impl_of_method(fn_id) {
+ Some(id) => cx.tcx.type_of(id),
+ None => return Lazy,
+ };
- if !self.found {
- intravisit::walk_expr(self, expr);
+ if (name.starts_with("as_") || name == "len" || name == "is_empty") && args.len() == 1 {
+ if matches!(
+ cx.tcx.crate_name(fn_id.krate),
+ sym::std | sym::core | sym::alloc | sym::proc_macro
+ ) {
+ Eager
+ } else {
+ NoChange
+ }
+ } else if let ty::Adt(def, subs) = ty.kind() {
+ // Types where the only fields are generic types (or references to) with no trait bounds other
+ // than marker traits.
+ // Due to the limited operations on these types functions should be fairly cheap.
+ if def
+ .variants
+ .iter()
+ .flat_map(|v| v.fields.iter())
+ .any(|x| matches!(cx.tcx.type_of(x.did).peel_refs().kind(), ty::Param(_)))
+ && all_predicates_of(cx.tcx, fn_id).all(|(pred, _)| match pred.kind().skip_binder() {
+ PredicateKind::Trait(pred) => cx.tcx.trait_def(pred.trait_ref.def_id).is_marker,
+ _ => true,
+ })
+ && subs.types().all(|x| matches!(x.peel_refs().kind(), ty::Param(_)))
+ {
+ // Limit the function to either `(self) -> bool` or `(&self) -> bool`
+ match &**cx.tcx.fn_sig(fn_id).skip_binder().inputs_and_output {
+ [arg, res] if !arg.is_mutable_ptr() && arg.peel_refs() == ty && res.is_bool() => NoChange,
+ _ => Lazy,
}
+ } else {
+ Lazy
}
+ } else {
+ Lazy
+ }
+}
+#[allow(clippy::too_many_lines)]
+fn expr_eagerness(cx: &LateContext<'tcx>, e: &'tcx Expr<'_>) -> EagernessSuggestion {
+ struct V<'cx, 'tcx> {
+ cx: &'cx LateContext<'tcx>,
+ eagerness: EagernessSuggestion,
+ }
+
+ impl<'cx, 'tcx> Visitor<'tcx> for V<'cx, 'tcx> {
+ type Map = ErasedMap<'tcx>;
fn nested_visit_map(&mut self) -> NestedVisitorMap<Self::Map> {
NestedVisitorMap::None
}
+
+ fn visit_expr(&mut self, e: &'tcx Expr<'_>) {
+ use EagernessSuggestion::{ForceNoChange, Lazy, NoChange};
+ if self.eagerness == ForceNoChange {
+ return;
+ }
+ match e.kind {
+ ExprKind::Call(
+ &Expr {
+ kind: ExprKind::Path(ref path),
+ hir_id,
+ ..
+ },
+ args,
+ ) => match self.cx.qpath_res(path, hir_id) {
+ Res::Def(DefKind::Ctor(..) | DefKind::Variant, _) | Res::SelfCtor(_) => (),
+ Res::Def(_, id) if self.cx.tcx.is_promotable_const_fn(id) => (),
+ // No need to walk the arguments here, `is_const_evaluatable` already did
+ Res::Def(..) if is_const_evaluatable(self.cx, e) => {
+ self.eagerness |= NoChange;
+ return;
+ },
+ Res::Def(_, id) => match path {
+ QPath::Resolved(_, p) => {
+ self.eagerness |= fn_eagerness(self.cx, id, p.segments.last().unwrap().ident.name, args);
+ },
+ QPath::TypeRelative(_, name) => {
+ self.eagerness |= fn_eagerness(self.cx, id, name.ident.name, args);
+ },
+ QPath::LangItem(..) => self.eagerness = Lazy,
+ },
+ _ => self.eagerness = Lazy,
+ },
+ // No need to walk the arguments here, `is_const_evaluatable` already did
+ ExprKind::MethodCall(..) if is_const_evaluatable(self.cx, e) => {
+ self.eagerness |= NoChange;
+ return;
+ },
+ ExprKind::MethodCall(name, _, args, _) => {
+ self.eagerness |= self
+ .cx
+ .typeck_results()
+ .type_dependent_def_id(e.hir_id)
+ .map_or(Lazy, |id| fn_eagerness(self.cx, id, name.ident.name, args));
+ },
+ ExprKind::Index(_, e) => {
+ let ty = self.cx.typeck_results().expr_ty_adjusted(e);
+ if is_copy(self.cx, ty) && !ty.is_ref() {
+ self.eagerness |= NoChange;
+ } else {
+ self.eagerness = Lazy;
+ }
+ },
+
+ // Dereferences should be cheap, but dereferencing a raw pointer earlier may not be safe.
+ ExprKind::Unary(UnOp::Deref, e) if !self.cx.typeck_results().expr_ty(e).is_unsafe_ptr() => (),
+ ExprKind::Unary(UnOp::Deref, _) => self.eagerness |= NoChange,
+
+ ExprKind::Unary(_, e)
+ if matches!(
+ self.cx.typeck_results().expr_ty(e).kind(),
+ ty::Bool | ty::Int(_) | ty::Uint(_),
+ ) => {},
+ ExprKind::Binary(_, lhs, rhs)
+ if self.cx.typeck_results().expr_ty(lhs).is_primitive()
+ && self.cx.typeck_results().expr_ty(rhs).is_primitive() => {},
+
+ // Can't be moved into a closure
+ ExprKind::Break(..)
+ | ExprKind::Continue(_)
+ | ExprKind::Ret(_)
+ | ExprKind::InlineAsm(_)
+ | ExprKind::LlvmInlineAsm(_)
+ | ExprKind::Yield(..)
+ | ExprKind::Err => {
+ self.eagerness = ForceNoChange;
+ return;
+ },
+
+ // Memory allocation, custom operator, loop, or call to an unknown function
+ ExprKind::Box(_)
+ | ExprKind::Unary(..)
+ | ExprKind::Binary(..)
+ | ExprKind::Loop(..)
+ | ExprKind::Call(..) => self.eagerness = Lazy,
+
+ ExprKind::ConstBlock(_)
+ | ExprKind::Array(_)
+ | ExprKind::Tup(_)
+ | ExprKind::Lit(_)
+ | ExprKind::Cast(..)
+ | ExprKind::Type(..)
+ | ExprKind::DropTemps(_)
+ | ExprKind::Let(..)
+ | ExprKind::If(..)
+ | ExprKind::Match(..)
+ | ExprKind::Closure(..)
+ | ExprKind::Field(..)
+ | ExprKind::Path(_)
+ | ExprKind::AddrOf(..)
+ | ExprKind::Struct(..)
+ | ExprKind::Repeat(..)
+ | ExprKind::Block(Block { stmts: [], .. }, _) => (),
+
+ // Assignment might be to a local defined earlier, so don't eagerly evaluate.
+ // Blocks with multiple statements might be expensive, so don't eagerly evaluate.
+ // TODO: Actually check if either of these are true here.
+ ExprKind::Assign(..) | ExprKind::AssignOp(..) | ExprKind::Block(..) => self.eagerness |= NoChange,
+ }
+ walk_expr(self, e);
+ }
}
- let mut finder = FunCallFinder { cx, found: false };
- finder.visit_expr(expr);
- finder.found
+ let mut v = V {
+ cx,
+ eagerness: EagernessSuggestion::Eager,
+ };
+ v.visit_expr(e);
+ v.eagerness
}
-pub fn is_eagerness_candidate<'a, 'tcx>(cx: &'a LateContext<'tcx>, expr: &'tcx Expr<'tcx>) -> bool {
- !identify_some_potentially_expensive_patterns(cx, expr) && identify_some_pure_patterns(expr)
+/// Whether the given expression should be changed to evaluate eagerly
+pub fn switch_to_eager_eval(cx: &'_ LateContext<'tcx>, expr: &'tcx Expr<'_>) -> bool {
+ expr_eagerness(cx, expr) == EagernessSuggestion::Eager
}
-pub fn is_lazyness_candidate<'a, 'tcx>(cx: &'a LateContext<'tcx>, expr: &'tcx Expr<'tcx>) -> bool {
- identify_some_potentially_expensive_patterns(cx, expr)
+/// Whether the given expression should be changed to evaluate lazily
+pub fn switch_to_lazy_eval(cx: &'_ LateContext<'tcx>, expr: &'tcx Expr<'_>) -> bool {
+ expr_eagerness(cx, expr) == EagernessSuggestion::Lazy
}
diff --git a/src/tools/clippy/clippy_utils/src/higher.rs b/src/tools/clippy/clippy_utils/src/higher.rs
index 7297265d08c..c764c35d444 100644
--- a/src/tools/clippy/clippy_utils/src/higher.rs
+++ b/src/tools/clippy/clippy_utils/src/higher.rs
@@ -101,7 +101,12 @@ impl<'hir> IfLet<'hir> {
pub fn hir(cx: &LateContext<'_>, expr: &Expr<'hir>) -> Option<Self> {
if let ExprKind::If(
Expr {
- kind: ExprKind::Let(let_pat, let_expr, _),
+ kind:
+ ExprKind::Let(hir::Let {
+ pat: let_pat,
+ init: let_expr,
+ ..
+ }),
..
},
if_then,
@@ -218,7 +223,7 @@ impl<'a> Range<'a> {
hir::ExprKind::Call(path, args)
if matches!(
path.kind,
- hir::ExprKind::Path(hir::QPath::LangItem(hir::LangItem::RangeInclusiveNew, _))
+ hir::ExprKind::Path(hir::QPath::LangItem(hir::LangItem::RangeInclusiveNew, ..))
) =>
{
Some(Range {
@@ -228,27 +233,27 @@ impl<'a> Range<'a> {
})
},
hir::ExprKind::Struct(path, fields, None) => match &path {
- hir::QPath::LangItem(hir::LangItem::RangeFull, _) => Some(Range {
+ hir::QPath::LangItem(hir::LangItem::RangeFull, ..) => Some(Range {
start: None,
end: None,
limits: ast::RangeLimits::HalfOpen,
}),
- hir::QPath::LangItem(hir::LangItem::RangeFrom, _) => Some(Range {
+ hir::QPath::LangItem(hir::LangItem::RangeFrom, ..) => Some(Range {
start: Some(get_field("start", fields)?),
end: None,
limits: ast::RangeLimits::HalfOpen,
}),
- hir::QPath::LangItem(hir::LangItem::Range, _) => Some(Range {
+ hir::QPath::LangItem(hir::LangItem::Range, ..) => Some(Range {
start: Some(get_field("start", fields)?),
end: Some(get_field("end", fields)?),
limits: ast::RangeLimits::HalfOpen,
}),
- hir::QPath::LangItem(hir::LangItem::RangeToInclusive, _) => Some(Range {
+ hir::QPath::LangItem(hir::LangItem::RangeToInclusive, ..) => Some(Range {
start: None,
end: Some(get_field("end", fields)?),
limits: ast::RangeLimits::Closed,
}),
- hir::QPath::LangItem(hir::LangItem::RangeTo, _) => Some(Range {
+ hir::QPath::LangItem(hir::LangItem::RangeTo, ..) => Some(Range {
start: None,
end: Some(get_field("end", fields)?),
limits: ast::RangeLimits::HalfOpen,
@@ -368,7 +373,12 @@ impl<'hir> WhileLet<'hir> {
kind:
ExprKind::If(
Expr {
- kind: ExprKind::Let(let_pat, let_expr, _),
+ kind:
+ ExprKind::Let(hir::Let {
+ pat: let_pat,
+ init: let_expr,
+ ..
+ }),
..
},
if_then,
diff --git a/src/tools/clippy/clippy_utils/src/hir_utils.rs b/src/tools/clippy/clippy_utils/src/hir_utils.rs
index 7438b6eabf9..ad50759effa 100644
--- a/src/tools/clippy/clippy_utils/src/hir_utils.rs
+++ b/src/tools/clippy/clippy_utils/src/hir_utils.rs
@@ -7,7 +7,7 @@ use rustc_hir::def::Res;
use rustc_hir::HirIdMap;
use rustc_hir::{
BinOpKind, Block, BodyId, Expr, ExprField, ExprKind, FnRetTy, GenericArg, GenericArgs, Guard, HirId,
- InlineAsmOperand, Lifetime, LifetimeName, ParamName, Pat, PatField, PatKind, Path, PathSegment, QPath, Stmt,
+ InlineAsmOperand, Let, Lifetime, LifetimeName, ParamName, Pat, PatField, PatKind, Path, PathSegment, QPath, Stmt,
StmtKind, Ty, TyKind, TypeBinding,
};
use rustc_lexer::{tokenize, TokenKind};
@@ -41,6 +41,7 @@ impl<'a, 'tcx> SpanlessEq<'a, 'tcx> {
}
/// Consider expressions containing potential side effects as not equal.
+ #[must_use]
pub fn deny_side_effects(self) -> Self {
Self {
allow_side_effects: false,
@@ -48,6 +49,7 @@ impl<'a, 'tcx> SpanlessEq<'a, 'tcx> {
}
}
+ #[must_use]
pub fn expr_fallback(self, expr_fallback: impl FnMut(&Expr<'_>, &Expr<'_>) -> bool + 'a) -> Self {
Self {
expr_fallback: Some(Box::new(expr_fallback)),
@@ -232,7 +234,9 @@ impl HirEqInterExpr<'_, '_, '_> {
(&ExprKind::If(lc, lt, ref le), &ExprKind::If(rc, rt, ref re)) => {
self.eq_expr(lc, rc) && self.eq_expr(&**lt, &**rt) && both(le, re, |l, r| self.eq_expr(l, r))
},
- (&ExprKind::Let(lp, le, _), &ExprKind::Let(rp, re, _)) => self.eq_pat(lp, rp) && self.eq_expr(le, re),
+ (&ExprKind::Let(l), &ExprKind::Let(r)) => {
+ self.eq_pat(l.pat, r.pat) && both(&l.ty, &r.ty, |l, r| self.eq_ty(l, r)) && self.eq_expr(l.init, r.init)
+ },
(&ExprKind::Lit(ref l), &ExprKind::Lit(ref r)) => l.node == r.node,
(&ExprKind::Loop(lb, ref ll, ref lls, _), &ExprKind::Loop(rb, ref rl, ref rls, _)) => {
lls == rls && self.eq_block(lb, rb) && both(ll, rl, |l, r| l.ident.name == r.ident.name)
@@ -346,7 +350,7 @@ impl HirEqInterExpr<'_, '_, '_> {
(&QPath::TypeRelative(lty, lseg), &QPath::TypeRelative(rty, rseg)) => {
self.eq_ty(lty, rty) && self.eq_path_segment(lseg, rseg)
},
- (&QPath::LangItem(llang_item, _), &QPath::LangItem(rlang_item, _)) => llang_item == rlang_item,
+ (&QPath::LangItem(llang_item, ..), &QPath::LangItem(rlang_item, ..)) => llang_item == rlang_item,
_ => false,
}
}
@@ -666,8 +670,11 @@ impl<'a, 'tcx> SpanlessHash<'a, 'tcx> {
}
}
},
- ExprKind::Let(pat, expr, _) => {
- self.hash_expr(expr);
+ ExprKind::Let(Let { pat, init, ty, .. }) => {
+ self.hash_expr(init);
+ if let Some(ty) = ty {
+ self.hash_ty(ty);
+ }
self.hash_pat(pat);
},
ExprKind::LlvmInlineAsm(..) | ExprKind::Err => {},
diff --git a/src/tools/clippy/clippy_utils/src/lib.rs b/src/tools/clippy/clippy_utils/src/lib.rs
index 086fbc9d3dd..7e054a54c3c 100644
--- a/src/tools/clippy/clippy_utils/src/lib.rs
+++ b/src/tools/clippy/clippy_utils/src/lib.rs
@@ -1,6 +1,6 @@
#![feature(box_patterns)]
#![feature(in_band_lifetimes)]
-#![feature(iter_zip)]
+#![feature(let_else)]
#![feature(rustc_private)]
#![feature(control_flow_enum)]
#![recursion_limit = "512"]
@@ -68,14 +68,14 @@ use rustc_hir as hir;
use rustc_hir::def::{DefKind, Res};
use rustc_hir::def_id::DefId;
use rustc_hir::hir_id::{HirIdMap, HirIdSet};
-use rustc_hir::intravisit::{self, walk_expr, ErasedMap, FnKind, NestedVisitorMap, Visitor};
+use rustc_hir::intravisit::{walk_expr, ErasedMap, FnKind, NestedVisitorMap, Visitor};
use rustc_hir::itemlikevisit::ItemLikeVisitor;
use rustc_hir::LangItem::{OptionNone, ResultErr, ResultOk};
use rustc_hir::{
- def, Arm, BindingAnnotation, Block, Body, Constness, Destination, Expr, ExprKind, FnDecl, ForeignItem, GenericArgs,
- HirId, Impl, ImplItem, ImplItemKind, IsAsync, Item, ItemKind, LangItem, Local, MatchSource, Mutability, Node,
- Param, Pat, PatKind, Path, PathSegment, PrimTy, QPath, Stmt, StmtKind, TraitItem, TraitItemKind, TraitRef, TyKind,
- UnOp,
+ def, Arm, BindingAnnotation, Block, BlockCheckMode, Body, Constness, Destination, Expr, ExprKind, FnDecl,
+ ForeignItem, GenericArgs, HirId, Impl, ImplItem, ImplItemKind, IsAsync, Item, ItemKind, LangItem, Local,
+ MatchSource, Mutability, Node, Param, Pat, PatKind, Path, PathSegment, PrimTy, QPath, Stmt, StmtKind, TraitItem,
+ TraitItemKind, TraitRef, TyKind, UnOp,
};
use rustc_lint::{LateContext, Level, Lint, LintContext};
use rustc_middle::hir::exports::Export;
@@ -96,6 +96,7 @@ use rustc_target::abi::Integer;
use crate::consts::{constant, Constant};
use crate::ty::{can_partially_move_ty, is_copy, is_recursively_primitive_type};
+use crate::visitors::expr_visitor_no_bodies;
pub fn parse_msrv(msrv: &str, sess: Option<&Session>, span: Option<Span>) -> Option<RustcVersion> {
if let Ok(version) = RustcVersion::parse(msrv) {
@@ -250,12 +251,6 @@ pub fn is_lang_ctor(cx: &LateContext<'_>, qpath: &QPath<'_>, lang_item: LangItem
false
}
-/// Returns `true` if this `span` was expanded by any macro.
-#[must_use]
-pub fn in_macro(span: Span) -> bool {
- span.from_expansion() && !matches!(span.ctxt().outer_expn_data().kind, ExpnKind::Desugaring(..))
-}
-
pub fn is_unit_expr(expr: &Expr<'_>) -> bool {
matches!(
expr.kind,
@@ -875,8 +870,8 @@ pub fn capture_local_usage(cx: &LateContext<'tcx>, e: &Expr<'_>) -> CaptureKind
capture_expr_ty = e;
}
},
- ExprKind::Let(pat, ..) => {
- let mutability = match pat_capture_kind(cx, pat) {
+ ExprKind::Let(let_expr) => {
+ let mutability = match pat_capture_kind(cx, let_expr.pat) {
CaptureKind::Value => Mutability::Not,
CaptureKind::Ref(m) => m,
};
@@ -1113,63 +1108,30 @@ pub fn contains_name(name: Symbol, expr: &Expr<'_>) -> bool {
/// Returns `true` if `expr` contains a return expression
pub fn contains_return(expr: &hir::Expr<'_>) -> bool {
- struct RetCallFinder {
- found: bool,
- }
-
- impl<'tcx> hir::intravisit::Visitor<'tcx> for RetCallFinder {
- type Map = Map<'tcx>;
-
- fn visit_expr(&mut self, expr: &'tcx hir::Expr<'_>) {
- if self.found {
- return;
- }
+ let mut found = false;
+ expr_visitor_no_bodies(|expr| {
+ if !found {
if let hir::ExprKind::Ret(..) = &expr.kind {
- self.found = true;
- } else {
- hir::intravisit::walk_expr(self, expr);
+ found = true;
}
}
-
- fn nested_visit_map(&mut self) -> hir::intravisit::NestedVisitorMap<Self::Map> {
- hir::intravisit::NestedVisitorMap::None
- }
- }
-
- let mut visitor = RetCallFinder { found: false };
- visitor.visit_expr(expr);
- visitor.found
-}
-
-struct FindMacroCalls<'a, 'b> {
- names: &'a [&'b str],
- result: Vec<Span>,
-}
-
-impl<'a, 'b, 'tcx> Visitor<'tcx> for FindMacroCalls<'a, 'b> {
- type Map = Map<'tcx>;
-
- fn visit_expr(&mut self, expr: &'tcx Expr<'_>) {
- if self.names.iter().any(|fun| is_expn_of(expr.span, fun).is_some()) {
- self.result.push(expr.span);
- }
- // and check sub-expressions
- intravisit::walk_expr(self, expr);
- }
-
- fn nested_visit_map(&mut self) -> NestedVisitorMap<Self::Map> {
- NestedVisitorMap::None
- }
+ !found
+ })
+ .visit_expr(expr);
+ found
}
/// Finds calls of the specified macros in a function body.
pub fn find_macro_calls(names: &[&str], body: &Body<'_>) -> Vec<Span> {
- let mut fmc = FindMacroCalls {
- names,
- result: Vec::new(),
- };
- fmc.visit_expr(&body.value);
- fmc.result
+ let mut result = Vec::new();
+ expr_visitor_no_bodies(|expr| {
+ if names.iter().any(|fun| is_expn_of(expr.span, fun).is_some()) {
+ result.push(expr.span);
+ }
+ true
+ })
+ .visit_expr(&body.value);
+ result
}
/// Extends the span to the beginning of the spans line, incl. whitespaces.
@@ -1261,6 +1223,70 @@ pub fn get_parent_as_impl(tcx: TyCtxt<'_>, id: HirId) -> Option<&Impl<'_>> {
}
}
+/// Removes blocks around an expression, only if the block contains just one expression
+/// and no statements. Unsafe blocks are not removed.
+///
+/// Examples:
+/// * `{}` -> `{}`
+/// * `{ x }` -> `x`
+/// * `{{ x }}` -> `x`
+/// * `{ x; }` -> `{ x; }`
+/// * `{ x; y }` -> `{ x; y }`
+/// * `{ unsafe { x } }` -> `unsafe { x }`
+pub fn peel_blocks<'a>(mut expr: &'a Expr<'a>) -> &'a Expr<'a> {
+ while let ExprKind::Block(
+ Block {
+ stmts: [],
+ expr: Some(inner),
+ rules: BlockCheckMode::DefaultBlock,
+ ..
+ },
+ _,
+ ) = expr.kind
+ {
+ expr = inner;
+ }
+ expr
+}
+
+/// Removes blocks around an expression, only if the block contains just one expression
+/// or just one expression statement with a semicolon. Unsafe blocks are not removed.
+///
+/// Examples:
+/// * `{}` -> `{}`
+/// * `{ x }` -> `x`
+/// * `{ x; }` -> `x`
+/// * `{{ x; }}` -> `x`
+/// * `{ x; y }` -> `{ x; y }`
+/// * `{ unsafe { x } }` -> `unsafe { x }`
+pub fn peel_blocks_with_stmt<'a>(mut expr: &'a Expr<'a>) -> &'a Expr<'a> {
+ while let ExprKind::Block(
+ Block {
+ stmts: [],
+ expr: Some(inner),
+ rules: BlockCheckMode::DefaultBlock,
+ ..
+ }
+ | Block {
+ stmts:
+ [
+ Stmt {
+ kind: StmtKind::Expr(inner) | StmtKind::Semi(inner),
+ ..
+ },
+ ],
+ expr: None,
+ rules: BlockCheckMode::DefaultBlock,
+ ..
+ },
+ _,
+ ) = expr.kind
+ {
+ expr = inner;
+ }
+ expr
+}
+
/// Checks if the given expression is the else clause of either an `if` or `if let` expression.
pub fn is_else_clause(tcx: TyCtxt<'_>, expr: &Expr<'_>) -> bool {
let mut iter = tcx.hir().parent_iter(expr.hir_id);
@@ -1366,6 +1392,13 @@ pub fn return_ty<'tcx>(cx: &LateContext<'tcx>, fn_item: hir::HirId) -> Ty<'tcx>
cx.tcx.erase_late_bound_regions(ret_ty)
}
+/// Convenience function to get the nth argument type of a function.
+pub fn nth_arg<'tcx>(cx: &LateContext<'tcx>, fn_item: hir::HirId, nth: usize) -> Ty<'tcx> {
+ let fn_def_id = cx.tcx.hir().local_def_id(fn_item);
+ let arg = cx.tcx.fn_sig(fn_def_id).input(nth);
+ cx.tcx.erase_late_bound_regions(arg)
+}
+
/// Checks if an expression is constructing a tuple-like enum variant or struct
pub fn is_ctor_or_promotable_const_function(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool {
if let ExprKind::Call(fun, _) = expr.kind {
@@ -1439,21 +1472,7 @@ pub fn recurse_or_patterns<'tcx, F: FnMut(&'tcx Pat<'tcx>)>(pat: &'tcx Pat<'tcx>
/// Checks for the `#[automatically_derived]` attribute all `#[derive]`d
/// implementations have.
pub fn is_automatically_derived(attrs: &[ast::Attribute]) -> bool {
- attrs.iter().any(|attr| attr.has_name(sym::automatically_derived))
-}
-
-/// Remove blocks around an expression.
-///
-/// Ie. `x`, `{ x }` and `{{{{ x }}}}` all give `x`. `{ x; y }` and `{}` return
-/// themselves.
-pub fn remove_blocks<'tcx>(mut expr: &'tcx Expr<'tcx>) -> &'tcx Expr<'tcx> {
- while let ExprKind::Block(block, ..) = expr.kind {
- match (block.stmts.is_empty(), block.expr.as_ref()) {
- (true, Some(e)) => expr = e,
- _ => break,
- }
- }
- expr
+ has_attr(attrs, sym::automatically_derived)
}
pub fn is_self(slf: &Param<'_>) -> bool {
@@ -1561,20 +1580,29 @@ pub fn clip(tcx: TyCtxt<'_>, u: u128, ity: rustc_ty::UintTy) -> u128 {
(u << amt) >> amt
}
-pub fn any_parent_is_automatically_derived(tcx: TyCtxt<'_>, node: HirId) -> bool {
+pub fn has_attr(attrs: &[ast::Attribute], symbol: Symbol) -> bool {
+ attrs.iter().any(|attr| attr.has_name(symbol))
+}
+
+pub fn any_parent_has_attr(tcx: TyCtxt<'_>, node: HirId, symbol: Symbol) -> bool {
let map = &tcx.hir();
let mut prev_enclosing_node = None;
let mut enclosing_node = node;
while Some(enclosing_node) != prev_enclosing_node {
- if is_automatically_derived(map.attrs(enclosing_node)) {
+ if has_attr(map.attrs(enclosing_node), symbol) {
return true;
}
prev_enclosing_node = Some(enclosing_node);
enclosing_node = map.get_parent_item(enclosing_node);
}
+
false
}
+pub fn any_parent_is_automatically_derived(tcx: TyCtxt<'_>, node: HirId) -> bool {
+ any_parent_has_attr(tcx, node, sym::automatically_derived)
+}
+
/// Matches a function call with the given path and returns the arguments.
///
/// Usage:
@@ -1625,6 +1653,14 @@ pub fn match_def_path<'tcx>(cx: &LateContext<'tcx>, did: DefId, syms: &[&str]) -
syms.iter().map(|x| Symbol::intern(x)).eq(path.iter().copied())
}
+/// Checks if the given `DefId` matches the `libc` item.
+pub fn match_libc_symbol(cx: &LateContext<'_>, did: DefId, name: &str) -> bool {
+ let path = cx.get_def_path(did);
+ // libc is meant to be used as a flat list of names, but they're all actually defined in different
+ // modules based on the target platform. Ignore everything but crate name and the item name.
+ path.first().map_or(false, |s| s.as_str() == "libc") && path.last().map_or(false, |s| s.as_str() == name)
+}
+
pub fn match_panic_call(cx: &LateContext<'_>, expr: &'tcx Expr<'_>) -> Option<&'tcx Expr<'tcx>> {
if let ExprKind::Call(func, [arg]) = expr.kind {
expr_path_res(cx, func)
@@ -1837,6 +1873,16 @@ pub fn is_expr_final_block_expr(tcx: TyCtxt<'_>, expr: &Expr<'_>) -> bool {
matches!(get_parent_node(tcx, expr.hir_id), Some(Node::Block(..)))
}
+pub fn std_or_core(cx: &LateContext<'_>) -> Option<&'static str> {
+ if !is_no_std_crate(cx) {
+ Some("std")
+ } else if !is_no_core_crate(cx) {
+ Some("core")
+ } else {
+ None
+ }
+}
+
pub fn is_no_std_crate(cx: &LateContext<'_>) -> bool {
cx.tcx.hir().attrs(hir::CRATE_HIR_ID).iter().any(|attr| {
if let ast::AttrKind::Normal(ref attr, _) = attr.kind {
@@ -1847,6 +1893,16 @@ pub fn is_no_std_crate(cx: &LateContext<'_>) -> bool {
})
}
+pub fn is_no_core_crate(cx: &LateContext<'_>) -> bool {
+ cx.tcx.hir().attrs(hir::CRATE_HIR_ID).iter().any(|attr| {
+ if let ast::AttrKind::Normal(ref attr, _) = attr.kind {
+ attr.path == sym::no_core
+ } else {
+ false
+ }
+ })
+}
+
/// Check if parent of a hir node is a trait implementation block.
/// For example, `f` in
/// ```rust,ignore
diff --git a/src/tools/clippy/clippy_utils/src/msrvs.rs b/src/tools/clippy/clippy_utils/src/msrvs.rs
index fa57dfbb57e..0cec7d6a5e4 100644
--- a/src/tools/clippy/clippy_utils/src/msrvs.rs
+++ b/src/tools/clippy/clippy_utils/src/msrvs.rs
@@ -19,7 +19,7 @@ msrv_aliases! {
1,46,0 { CONST_IF_MATCH }
1,45,0 { STR_STRIP_PREFIX }
1,43,0 { LOG2_10, LOG10_2 }
- 1,42,0 { MATCHES_MACRO }
+ 1,42,0 { MATCHES_MACRO, SLICE_PATTERNS }
1,41,0 { RE_REBALANCING_COHERENCE, RESULT_MAP_OR_ELSE }
1,40,0 { MEM_TAKE, NON_EXHAUSTIVE, OPTION_AS_DEREF }
1,38,0 { POINTER_CAST }
@@ -27,7 +27,8 @@ msrv_aliases! {
1,36,0 { ITERATOR_COPIED }
1,35,0 { OPTION_COPIED, RANGE_CONTAINS }
1,34,0 { TRY_FROM }
- 1,30,0 { ITERATOR_FIND_MAP }
+ 1,30,0 { ITERATOR_FIND_MAP, TOOL_ATTRIBUTES }
+ 1,28,0 { FROM_BOOL }
1,17,0 { FIELD_INIT_SHORTHAND, STATIC_IN_CONST }
1,16,0 { STR_REPEAT }
}
diff --git a/src/tools/clippy/clippy_utils/src/paths.rs b/src/tools/clippy/clippy_utils/src/paths.rs
index 501b08a47f1..6171823abbb 100644
--- a/src/tools/clippy/clippy_utils/src/paths.rs
+++ b/src/tools/clippy/clippy_utils/src/paths.rs
@@ -28,6 +28,7 @@ pub const ASREF_TRAIT: [&str; 3] = ["core", "convert", "AsRef"];
pub(super) const BEGIN_PANIC: [&str; 3] = ["std", "panicking", "begin_panic"];
/// Preferably use the diagnostic item `sym::Borrow` where possible
pub const BORROW_TRAIT: [&str; 3] = ["core", "borrow", "Borrow"];
+pub const BORROW_MUT_TRAIT: [&str; 3] = ["core", "borrow", "BorrowMut"];
pub const BTREEMAP_CONTAINS_KEY: [&str; 6] = ["alloc", "collections", "btree", "map", "BTreeMap", "contains_key"];
pub const BTREEMAP_ENTRY: [&str; 6] = ["alloc", "collections", "btree", "map", "entry", "Entry"];
pub const BTREEMAP_INSERT: [&str; 6] = ["alloc", "collections", "btree", "map", "BTreeMap", "insert"];
@@ -85,7 +86,6 @@ pub const ITERTOOLS_NEXT_TUPLE: [&str; 3] = ["itertools", "Itertools", "next_tup
pub const KW_MODULE: [&str; 3] = ["rustc_span", "symbol", "kw"];
#[cfg(feature = "internal-lints")]
pub const LATE_CONTEXT: [&str; 2] = ["rustc_lint", "LateContext"];
-pub const LIBC_STRLEN: [&str; 2] = ["libc", "strlen"];
#[cfg(any(feature = "internal-lints", feature = "metadata-collector-lint"))]
pub const LINT: [&str; 2] = ["rustc_lint_defs", "Lint"];
pub const MEM_DISCRIMINANT: [&str; 3] = ["core", "mem", "discriminant"];
@@ -110,6 +110,8 @@ pub(super) const PANICKING_PANIC: [&str; 3] = ["core", "panicking", "panic"];
pub(super) const PANICKING_PANIC_FMT: [&str; 3] = ["core", "panicking", "panic_fmt"];
pub(super) const PANICKING_PANIC_STR: [&str; 3] = ["core", "panicking", "panic_str"];
pub(super) const PANIC_ANY: [&str; 3] = ["std", "panic", "panic_any"];
+pub const PARKING_LOT_RAWMUTEX: [&str; 3] = ["parking_lot", "raw_mutex", "RawMutex"];
+pub const PARKING_LOT_RAWRWLOCK: [&str; 3] = ["parking_lot", "raw_rwlock", "RawRwLock"];
pub const PARKING_LOT_MUTEX_GUARD: [&str; 2] = ["parking_lot", "MutexGuard"];
pub const PARKING_LOT_RWLOCK_READ_GUARD: [&str; 2] = ["parking_lot", "RwLockReadGuard"];
pub const PARKING_LOT_RWLOCK_WRITE_GUARD: [&str; 2] = ["parking_lot", "RwLockWriteGuard"];
@@ -204,3 +206,4 @@ pub const WEAK_RC: [&str; 3] = ["alloc", "rc", "Weak"];
pub const WRITE_MACRO: [&str; 3] = ["core", "macros", "write"];
#[allow(clippy::invalid_paths)] // `check_path` does not seem to work for macros
pub const WRITELN_MACRO: [&str; 3] = ["core", "macros", "writeln"];
+pub const PTR_NON_NULL: [&str; 4] = ["core", "ptr", "non_null", "NonNull"];
diff --git a/src/tools/clippy/clippy_utils/src/ptr.rs b/src/tools/clippy/clippy_utils/src/ptr.rs
index 8adb6915952..17d9a505bc9 100644
--- a/src/tools/clippy/clippy_utils/src/ptr.rs
+++ b/src/tools/clippy/clippy_utils/src/ptr.rs
@@ -1,9 +1,9 @@
use crate::source::snippet;
+use crate::visitors::expr_visitor_no_bodies;
use crate::{path_to_local_id, strip_pat_refs};
-use rustc_hir::intravisit::{walk_expr, NestedVisitorMap, Visitor};
-use rustc_hir::{Body, BodyId, Expr, ExprKind, HirId, PatKind};
+use rustc_hir::intravisit::Visitor;
+use rustc_hir::{Body, BodyId, ExprKind, HirId, PatKind};
use rustc_lint::LateContext;
-use rustc_middle::hir::map::Map;
use rustc_span::Span;
use std::borrow::Cow;
@@ -30,50 +30,28 @@ fn extract_clone_suggestions<'tcx>(
replace: &[(&'static str, &'static str)],
body: &'tcx Body<'_>,
) -> Option<Vec<(Span, Cow<'static, str>)>> {
- let mut visitor = PtrCloneVisitor {
- cx,
- id,
- replace,
- spans: vec![],
- abort: false,
- };
- visitor.visit_body(body);
- if visitor.abort { None } else { Some(visitor.spans) }
-}
-
-struct PtrCloneVisitor<'a, 'tcx> {
- cx: &'a LateContext<'tcx>,
- id: HirId,
- replace: &'a [(&'static str, &'static str)],
- spans: Vec<(Span, Cow<'static, str>)>,
- abort: bool,
-}
-
-impl<'a, 'tcx> Visitor<'tcx> for PtrCloneVisitor<'a, 'tcx> {
- type Map = Map<'tcx>;
-
- fn visit_expr(&mut self, expr: &'tcx Expr<'_>) {
- if self.abort {
- return;
+ let mut abort = false;
+ let mut spans = Vec::new();
+ expr_visitor_no_bodies(|expr| {
+ if abort {
+ return false;
}
if let ExprKind::MethodCall(seg, _, [recv], _) = expr.kind {
- if path_to_local_id(recv, self.id) {
+ if path_to_local_id(recv, id) {
if seg.ident.name.as_str() == "capacity" {
- self.abort = true;
- return;
+ abort = true;
+ return false;
}
- for &(fn_name, suffix) in self.replace {
+ for &(fn_name, suffix) in replace {
if seg.ident.name.as_str() == fn_name {
- self.spans.push((expr.span, snippet(self.cx, recv.span, "_") + suffix));
- return;
+ spans.push((expr.span, snippet(cx, recv.span, "_") + suffix));
+ return false;
}
}
}
}
- walk_expr(self, expr);
- }
-
- fn nested_visit_map(&mut self) -> NestedVisitorMap<Self::Map> {
- NestedVisitorMap::None
- }
+ !abort
+ })
+ .visit_body(body);
+ if abort { None } else { Some(spans) }
}
diff --git a/src/tools/clippy/clippy_utils/src/source.rs b/src/tools/clippy/clippy_utils/src/source.rs
index 789079510c5..d928317259d 100644
--- a/src/tools/clippy/clippy_utils/src/source.rs
+++ b/src/tools/clippy/clippy_utils/src/source.rs
@@ -128,7 +128,7 @@ pub fn reindent_multiline(s: Cow<'_, str>, ignore_first: bool, indent: Option<us
fn reindent_multiline_inner(s: &str, ignore_first: bool, indent: Option<usize>, ch: char) -> String {
let x = s
.lines()
- .skip(ignore_first as usize)
+ .skip(usize::from(ignore_first))
.filter_map(|l| {
if l.is_empty() {
None
@@ -155,14 +155,22 @@ fn reindent_multiline_inner(s: &str, ignore_first: bool, indent: Option<usize>,
.join("\n")
}
-/// Converts a span to a code snippet if available, otherwise use default.
+/// Converts a span to a code snippet if available, otherwise returns the default.
///
/// This is useful if you want to provide suggestions for your lint or more generally, if you want
-/// to convert a given `Span` to a `str`.
+/// to convert a given `Span` to a `str`. To create suggestions consider using
+/// [`snippet_with_applicability`] to ensure that the applicability stays correct.
///
/// # Example
/// ```rust,ignore
-/// snippet(cx, expr.span, "..")
+/// // Given two spans one for `value` and one for the `init` expression.
+/// let value = Vec::new();
+/// // ^^^^^ ^^^^^^^^^^
+/// // span1 span2
+///
+/// // The snipped call would return the corresponding code snippet
+/// snippet(cx, span1, "..") // -> "value"
+/// snippet(cx, span2, "..") // -> "Vec::new()"
/// ```
pub fn snippet<'a, T: LintContext>(cx: &T, span: Span, default: &'a str) -> Cow<'a, str> {
snippet_opt(cx, span).map_or_else(|| Cow::Borrowed(default), From::from)
diff --git a/src/tools/clippy/clippy_utils/src/sugg.rs b/src/tools/clippy/clippy_utils/src/sugg.rs
index 01fb944cc36..586934df460 100644
--- a/src/tools/clippy/clippy_utils/src/sugg.rs
+++ b/src/tools/clippy/clippy_utils/src/sugg.rs
@@ -1,19 +1,27 @@
//! Contains utility functions to generate suggestions.
#![deny(clippy::missing_docs_in_private_items)]
-use crate::higher;
-use crate::source::{snippet, snippet_opt, snippet_with_context, snippet_with_macro_callsite};
+use crate::source::{
+ snippet, snippet_opt, snippet_with_applicability, snippet_with_context, snippet_with_macro_callsite,
+};
+use crate::{get_parent_expr_for_hir, higher};
use rustc_ast::util::parser::AssocOp;
use rustc_ast::{ast, token};
use rustc_ast_pretty::pprust::token_kind_to_string;
use rustc_errors::Applicability;
use rustc_hir as hir;
+use rustc_hir::{ExprKind, HirId, MutTy, TyKind};
+use rustc_infer::infer::TyCtxtInferExt;
use rustc_lint::{EarlyContext, LateContext, LintContext};
-use rustc_span::source_map::{CharPos, Span};
-use rustc_span::{BytePos, Pos, SyntaxContext};
+use rustc_middle::hir::place::ProjectionKind;
+use rustc_middle::mir::{FakeReadCause, Mutability};
+use rustc_middle::ty;
+use rustc_span::source_map::{BytePos, CharPos, Pos, Span, SyntaxContext};
+use rustc_typeck::expr_use_visitor::{Delegate, ExprUseVisitor, PlaceBase, PlaceWithHirId};
use std::borrow::Cow;
use std::convert::TryInto;
use std::fmt::Display;
+use std::iter;
use std::ops::{Add, Neg, Not, Sub};
/// A helper type to build suggestion correctly handling parentheses.
@@ -286,6 +294,7 @@ impl<'a> Sugg<'a> {
/// Adds parentheses to any expression that might need them. Suitable to the
/// `self` argument of a method call
/// (e.g., to build `bar.foo()` or `(1 + 2).foo()`).
+ #[must_use]
pub fn maybe_par(self) -> Self {
match self {
Sugg::NonParen(..) => self,
@@ -716,6 +725,267 @@ impl<T: LintContext> DiagnosticBuilderExt<T> for rustc_errors::DiagnosticBuilder
}
}
+/// Suggestion results for handling closure
+/// args dereferencing and borrowing
+pub struct DerefClosure {
+ /// confidence on the built suggestion
+ pub applicability: Applicability,
+ /// gradually built suggestion
+ pub suggestion: String,
+}
+
+/// Build suggestion gradually by handling closure arg specific usages,
+/// such as explicit deref and borrowing cases.
+/// Returns `None` if no such use cases have been triggered in closure body
+///
+/// note: this only works on single line immutable closures with exactly one input parameter.
+pub fn deref_closure_args<'tcx>(cx: &LateContext<'_>, closure: &'tcx hir::Expr<'_>) -> Option<DerefClosure> {
+ if let hir::ExprKind::Closure(_, fn_decl, body_id, ..) = closure.kind {
+ let closure_body = cx.tcx.hir().body(body_id);
+ // is closure arg a type annotated double reference (i.e.: `|x: &&i32| ...`)
+ // a type annotation is present if param `kind` is different from `TyKind::Infer`
+ let closure_arg_is_type_annotated_double_ref = if let TyKind::Rptr(_, MutTy { ty, .. }) = fn_decl.inputs[0].kind
+ {
+ matches!(ty.kind, TyKind::Rptr(_, MutTy { .. }))
+ } else {
+ false
+ };
+
+ let mut visitor = DerefDelegate {
+ cx,
+ closure_span: closure.span,
+ closure_arg_is_type_annotated_double_ref,
+ next_pos: closure.span.lo(),
+ suggestion_start: String::new(),
+ applicability: Applicability::MaybeIncorrect,
+ };
+
+ let fn_def_id = cx.tcx.hir().local_def_id(closure.hir_id);
+ cx.tcx.infer_ctxt().enter(|infcx| {
+ ExprUseVisitor::new(&mut visitor, &infcx, fn_def_id, cx.param_env, cx.typeck_results())
+ .consume_body(closure_body);
+ });
+
+ if !visitor.suggestion_start.is_empty() {
+ return Some(DerefClosure {
+ applicability: visitor.applicability,
+ suggestion: visitor.finish(),
+ });
+ }
+ }
+ None
+}
+
+/// Visitor struct used for tracking down
+/// dereferencing and borrowing of closure's args
+struct DerefDelegate<'a, 'tcx> {
+ /// The late context of the lint
+ cx: &'a LateContext<'tcx>,
+ /// The span of the input closure to adapt
+ closure_span: Span,
+ /// Indicates if the arg of the closure is a type annotated double reference
+ closure_arg_is_type_annotated_double_ref: bool,
+ /// last position of the span to gradually build the suggestion
+ next_pos: BytePos,
+ /// starting part of the gradually built suggestion
+ suggestion_start: String,
+ /// confidence on the built suggestion
+ applicability: Applicability,
+}
+
+impl DerefDelegate<'_, 'tcx> {
+ /// build final suggestion:
+ /// - create the ending part of suggestion
+ /// - concatenate starting and ending parts
+ /// - potentially remove needless borrowing
+ pub fn finish(&mut self) -> String {
+ let end_span = Span::new(self.next_pos, self.closure_span.hi(), self.closure_span.ctxt(), None);
+ let end_snip = snippet_with_applicability(self.cx, end_span, "..", &mut self.applicability);
+ let sugg = format!("{}{}", self.suggestion_start, end_snip);
+ if self.closure_arg_is_type_annotated_double_ref {
+ sugg.replacen('&', "", 1)
+ } else {
+ sugg
+ }
+ }
+
+ /// indicates whether the function from `parent_expr` takes its args by double reference
+ fn func_takes_arg_by_double_ref(&self, parent_expr: &'tcx hir::Expr<'_>, cmt_hir_id: HirId) -> bool {
+ let (call_args, inputs) = match parent_expr.kind {
+ ExprKind::MethodCall(_, _, call_args, _) => {
+ if let Some(method_did) = self.cx.typeck_results().type_dependent_def_id(parent_expr.hir_id) {
+ (call_args, self.cx.tcx.fn_sig(method_did).skip_binder().inputs())
+ } else {
+ return false;
+ }
+ },
+ ExprKind::Call(func, call_args) => {
+ let typ = self.cx.typeck_results().expr_ty(func);
+ (call_args, typ.fn_sig(self.cx.tcx).skip_binder().inputs())
+ },
+ _ => return false,
+ };
+
+ iter::zip(call_args, inputs)
+ .any(|(arg, ty)| arg.hir_id == cmt_hir_id && matches!(ty.kind(), ty::Ref(_, inner, _) if inner.is_ref()))
+ }
+}
+
+impl<'tcx> Delegate<'tcx> for DerefDelegate<'_, 'tcx> {
+ fn consume(&mut self, _: &PlaceWithHirId<'tcx>, _: HirId) {}
+
+ #[allow(clippy::too_many_lines)]
+ fn borrow(&mut self, cmt: &PlaceWithHirId<'tcx>, _: HirId, _: ty::BorrowKind) {
+ if let PlaceBase::Local(id) = cmt.place.base {
+ let map = self.cx.tcx.hir();
+ let span = map.span(cmt.hir_id);
+ let start_span = Span::new(self.next_pos, span.lo(), span.ctxt(), None);
+ let mut start_snip = snippet_with_applicability(self.cx, start_span, "..", &mut self.applicability);
+
+ // identifier referring to the variable currently triggered (i.e.: `fp`)
+ let ident_str = map.name(id).to_string();
+ // full identifier that includes projection (i.e.: `fp.field`)
+ let ident_str_with_proj = snippet(self.cx, span, "..").to_string();
+
+ if cmt.place.projections.is_empty() {
+ // handle item without any projection, that needs an explicit borrowing
+ // i.e.: suggest `&x` instead of `x`
+ self.suggestion_start.push_str(&format!("{}&{}", start_snip, ident_str));
+ } else {
+ // cases where a parent `Call` or `MethodCall` is using the item
+ // i.e.: suggest `.contains(&x)` for `.find(|x| [1, 2, 3].contains(x)).is_none()`
+ //
+ // Note about method calls:
+ // - compiler automatically dereference references if the target type is a reference (works also for
+ // function call)
+ // - `self` arguments in the case of `x.is_something()` are also automatically (de)referenced, and
+ // no projection should be suggested
+ if let Some(parent_expr) = get_parent_expr_for_hir(self.cx, cmt.hir_id) {
+ match &parent_expr.kind {
+ // given expression is the self argument and will be handled completely by the compiler
+ // i.e.: `|x| x.is_something()`
+ ExprKind::MethodCall(_, _, [self_expr, ..], _) if self_expr.hir_id == cmt.hir_id => {
+ self.suggestion_start
+ .push_str(&format!("{}{}", start_snip, ident_str_with_proj));
+ self.next_pos = span.hi();
+ return;
+ },
+ // item is used in a call
+ // i.e.: `Call`: `|x| please(x)` or `MethodCall`: `|x| [1, 2, 3].contains(x)`
+ ExprKind::Call(_, [call_args @ ..]) | ExprKind::MethodCall(_, _, [_, call_args @ ..], _) => {
+ let expr = self.cx.tcx.hir().expect_expr(cmt.hir_id);
+ let arg_ty_kind = self.cx.typeck_results().expr_ty(expr).kind();
+
+ if matches!(arg_ty_kind, ty::Ref(_, _, Mutability::Not)) {
+ // suggest ampersand if call function is taking args by double reference
+ let takes_arg_by_double_ref =
+ self.func_takes_arg_by_double_ref(parent_expr, cmt.hir_id);
+
+ // compiler will automatically dereference field or index projection, so no need
+ // to suggest ampersand, but full identifier that includes projection is required
+ let has_field_or_index_projection =
+ cmt.place.projections.iter().any(|proj| {
+ matches!(proj.kind, ProjectionKind::Field(..) | ProjectionKind::Index)
+ });
+
+ // no need to bind again if the function doesn't take arg by double ref
+ // and if the item is already a double ref
+ let ident_sugg = if !call_args.is_empty()
+ && !takes_arg_by_double_ref
+ && (self.closure_arg_is_type_annotated_double_ref || has_field_or_index_projection)
+ {
+ let ident = if has_field_or_index_projection {
+ ident_str_with_proj
+ } else {
+ ident_str
+ };
+ format!("{}{}", start_snip, ident)
+ } else {
+ format!("{}&{}", start_snip, ident_str)
+ };
+ self.suggestion_start.push_str(&ident_sugg);
+ self.next_pos = span.hi();
+ return;
+ }
+
+ self.applicability = Applicability::Unspecified;
+ },
+ _ => (),
+ }
+ }
+
+ let mut replacement_str = ident_str;
+ let mut projections_handled = false;
+ cmt.place.projections.iter().enumerate().for_each(|(i, proj)| {
+ match proj.kind {
+ // Field projection like `|v| v.foo`
+ // no adjustment needed here, as field projections are handled by the compiler
+ ProjectionKind::Field(..) => match cmt.place.ty_before_projection(i).kind() {
+ ty::Adt(..) | ty::Tuple(_) => {
+ replacement_str = ident_str_with_proj.clone();
+ projections_handled = true;
+ },
+ _ => (),
+ },
+ // Index projection like `|x| foo[x]`
+ // the index is dropped so we can't get it to build the suggestion,
+ // so the span is set-up again to get more code, using `span.hi()` (i.e.: `foo[x]`)
+ // instead of `span.lo()` (i.e.: `foo`)
+ ProjectionKind::Index => {
+ let start_span = Span::new(self.next_pos, span.hi(), span.ctxt(), None);
+ start_snip = snippet_with_applicability(self.cx, start_span, "..", &mut self.applicability);
+ replacement_str.clear();
+ projections_handled = true;
+ },
+ // note: unable to trigger `Subslice` kind in tests
+ ProjectionKind::Subslice => (),
+ ProjectionKind::Deref => {
+ // Explicit derefs are typically handled later on, but
+ // some items do not need explicit deref, such as array accesses,
+ // so we mark them as already processed
+ // i.e.: don't suggest `*sub[1..4].len()` for `|sub| sub[1..4].len() == 3`
+ if let ty::Ref(_, inner, _) = cmt.place.ty_before_projection(i).kind() {
+ if matches!(inner.kind(), ty::Ref(_, innermost, _) if innermost.is_array()) {
+ projections_handled = true;
+ }
+ }
+ },
+ }
+ });
+
+ // handle `ProjectionKind::Deref` by removing one explicit deref
+ // if no special case was detected (i.e.: suggest `*x` instead of `**x`)
+ if !projections_handled {
+ let last_deref = cmt
+ .place
+ .projections
+ .iter()
+ .rposition(|proj| proj.kind == ProjectionKind::Deref);
+
+ if let Some(pos) = last_deref {
+ let mut projections = cmt.place.projections.clone();
+ projections.truncate(pos);
+
+ for item in projections {
+ if item.kind == ProjectionKind::Deref {
+ replacement_str = format!("*{}", replacement_str);
+ }
+ }
+ }
+ }
+
+ self.suggestion_start
+ .push_str(&format!("{}{}", start_snip, replacement_str));
+ }
+ self.next_pos = span.hi();
+ }
+ }
+
+ fn mutate(&mut self, _: &PlaceWithHirId<'tcx>, _: HirId) {}
+
+ fn fake_read(&mut self, _: rustc_typeck::expr_use_visitor::Place<'tcx>, _: FakeReadCause, _: HirId) {}
+}
+
#[cfg(test)]
mod test {
use super::Sugg;
diff --git a/src/tools/clippy/clippy_utils/src/ty.rs b/src/tools/clippy/clippy_utils/src/ty.rs
index ca64ac7de3e..6d191d4a59b 100644
--- a/src/tools/clippy/clippy_utils/src/ty.rs
+++ b/src/tools/clippy/clippy_utils/src/ty.rs
@@ -10,15 +10,16 @@ use rustc_hir::{TyKind, Unsafety};
use rustc_infer::infer::TyCtxtInferExt;
use rustc_lint::LateContext;
use rustc_middle::ty::subst::{GenericArg, GenericArgKind};
-use rustc_middle::ty::{self, AdtDef, IntTy, Ty, TyCtxt, TypeFoldable, UintTy};
-use rustc_span::sym;
-use rustc_span::symbol::{Ident, Symbol};
-use rustc_span::DUMMY_SP;
+use rustc_middle::ty::{self, AdtDef, IntTy, Predicate, Ty, TyCtxt, TypeFoldable, UintTy};
+use rustc_span::symbol::Ident;
+use rustc_span::{sym, Span, Symbol, DUMMY_SP};
use rustc_trait_selection::infer::InferCtxtExt;
use rustc_trait_selection::traits::query::normalize::AtExt;
+use std::iter;
use crate::{match_def_path, must_use_attr};
+// Checks if the given type implements copy.
pub fn is_copy<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>) -> bool {
ty.is_copy_modulo_regions(cx.tcx.at(DUMMY_SP), cx.param_env)
}
@@ -57,14 +58,20 @@ pub fn contains_adt_constructor<'tcx>(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>, adt: &'tc
pub fn get_iterator_item_ty<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>) -> Option<Ty<'tcx>> {
cx.tcx
.get_diagnostic_item(sym::Iterator)
- .and_then(|iter_did| {
- cx.tcx.associated_items(iter_did).find_by_name_and_kind(
- cx.tcx,
- Ident::from_str("Item"),
- ty::AssocKind::Type,
- iter_did,
- )
- })
+ .and_then(|iter_did| get_associated_type(cx, ty, iter_did, "Item"))
+}
+
+/// Returns the associated type `name` for `ty` as an implementation of `trait_id`.
+/// Do not invoke without first verifying that the type implements the trait.
+pub fn get_associated_type<'tcx>(
+ cx: &LateContext<'tcx>,
+ ty: Ty<'tcx>,
+ trait_id: DefId,
+ name: &str,
+) -> Option<Ty<'tcx>> {
+ cx.tcx
+ .associated_items(trait_id)
+ .find_by_name_and_kind(cx.tcx, Ident::from_str(name), ty::AssocKind::Type, trait_id)
.map(|assoc| {
let proj = cx.tcx.mk_projection(assoc.def_id, cx.tcx.mk_substs_trait(ty, &[]));
cx.tcx.normalize_erasing_regions(cx.param_env, proj)
@@ -114,7 +121,12 @@ pub fn has_iter_method(cx: &LateContext<'_>, probably_ref_ty: Ty<'_>) -> Option<
/// Checks whether a type implements a trait.
/// The function returns false in case the type contains an inference variable.
-/// See also [`get_trait_def_id`](super::get_trait_def_id).
+///
+/// See:
+/// * [`get_trait_def_id`](super::get_trait_def_id) to get a trait [`DefId`].
+/// * [Common tools for writing lints] for an example how to use this function and other options.
+///
+/// [Common tools for writing lints]: https://github.com/rust-lang/rust-clippy/blob/master/doc/common_tools_writing_lints.md#checking-if-a-type-implements-a-specific-trait
pub fn implements_trait<'tcx>(
cx: &LateContext<'tcx>,
ty: Ty<'tcx>,
@@ -254,9 +266,17 @@ pub fn is_type_ref_to_diagnostic_item(cx: &LateContext<'_>, ty: Ty<'_>, diag_ite
}
}
-/// Checks if the type is equal to a diagnostic item
+/// Checks if the type is equal to a diagnostic item. To check if a type implements a
+/// trait marked with a diagnostic item use [`implements_trait`].
+///
+/// For a further exploitation what diagnostic items are see [diagnostic items] in
+/// rustc-dev-guide.
+///
+/// ---
///
/// If you change the signature, remember to update the internal lint `MatchTypeOnDiagItem`
+///
+/// [Diagnostic Items]: https://rustc-dev-guide.rust-lang.org/diagnostics/diagnostic-items.html
pub fn is_type_diagnostic_item(cx: &LateContext<'_>, ty: Ty<'_>, diag_item: Symbol) -> bool {
match ty.kind() {
ty::Adt(adt, _) => cx.tcx.is_diagnostic_item(diag_item, adt.did),
@@ -377,3 +397,16 @@ pub fn is_uninit_value_valid_for_ty(cx: &LateContext<'_>, ty: Ty<'_>) -> bool {
_ => false,
}
}
+
+/// Gets an iterator over all predicates which apply to the given item.
+pub fn all_predicates_of(tcx: TyCtxt<'_>, id: DefId) -> impl Iterator<Item = &(Predicate<'_>, Span)> {
+ let mut next_id = Some(id);
+ iter::from_fn(move || {
+ next_id.take().map(|id| {
+ let preds = tcx.predicates_of(id);
+ next_id = preds.parent;
+ preds.predicates.iter()
+ })
+ })
+ .flatten()
+}
diff --git a/src/tools/clippy/clippy_utils/src/usage.rs b/src/tools/clippy/clippy_utils/src/usage.rs
index 34206b5ae2b..2066915e1d1 100644
--- a/src/tools/clippy/clippy_utils/src/usage.rs
+++ b/src/tools/clippy/clippy_utils/src/usage.rs
@@ -1,7 +1,7 @@
use crate as utils;
+use crate::visitors::{expr_visitor, expr_visitor_no_bodies};
use rustc_hir as hir;
-use rustc_hir::intravisit;
-use rustc_hir::intravisit::{NestedVisitorMap, Visitor};
+use rustc_hir::intravisit::{self, Visitor};
use rustc_hir::HirIdSet;
use rustc_hir::{Expr, ExprKind, HirId};
use rustc_infer::infer::TyCtxtInferExt;
@@ -78,7 +78,7 @@ impl<'tcx> Delegate<'tcx> for MutVarsDelegate {
}
pub struct ParamBindingIdCollector {
- binding_hir_ids: Vec<hir::HirId>,
+ pub binding_hir_ids: Vec<hir::HirId>,
}
impl<'tcx> ParamBindingIdCollector {
fn collect_binding_hir_ids(body: &'tcx hir::Body<'tcx>) -> Vec<hir::HirId> {
@@ -148,96 +148,47 @@ impl<'a, 'tcx> intravisit::Visitor<'tcx> for BindingUsageFinder<'a, 'tcx> {
}
}
-struct ReturnBreakContinueMacroVisitor {
- seen_return_break_continue: bool,
-}
-
-impl ReturnBreakContinueMacroVisitor {
- fn new() -> ReturnBreakContinueMacroVisitor {
- ReturnBreakContinueMacroVisitor {
- seen_return_break_continue: false,
- }
- }
-}
-
-impl<'tcx> Visitor<'tcx> for ReturnBreakContinueMacroVisitor {
- type Map = Map<'tcx>;
- fn nested_visit_map(&mut self) -> NestedVisitorMap<Self::Map> {
- NestedVisitorMap::None
- }
-
- fn visit_expr(&mut self, ex: &'tcx Expr<'tcx>) {
- if self.seen_return_break_continue {
- // No need to look farther if we've already seen one of them
- return;
+pub fn contains_return_break_continue_macro(expression: &Expr<'_>) -> bool {
+ let mut seen_return_break_continue = false;
+ expr_visitor_no_bodies(|ex| {
+ if seen_return_break_continue {
+ return false;
}
match &ex.kind {
ExprKind::Ret(..) | ExprKind::Break(..) | ExprKind::Continue(..) => {
- self.seen_return_break_continue = true;
+ seen_return_break_continue = true;
},
// Something special could be done here to handle while or for loop
// desugaring, as this will detect a break if there's a while loop
// or a for loop inside the expression.
_ => {
- if utils::in_macro(ex.span) {
- self.seen_return_break_continue = true;
- } else {
- rustc_hir::intravisit::walk_expr(self, ex);
+ if ex.span.from_expansion() {
+ seen_return_break_continue = true;
}
},
}
- }
-}
-
-pub fn contains_return_break_continue_macro(expression: &Expr<'_>) -> bool {
- let mut recursive_visitor = ReturnBreakContinueMacroVisitor::new();
- recursive_visitor.visit_expr(expression);
- recursive_visitor.seen_return_break_continue
-}
-
-pub struct UsedAfterExprVisitor<'a, 'tcx> {
- cx: &'a LateContext<'tcx>,
- expr: &'tcx Expr<'tcx>,
- definition: HirId,
- past_expr: bool,
- used_after_expr: bool,
-}
-impl<'a, 'tcx> UsedAfterExprVisitor<'a, 'tcx> {
- pub fn is_found(cx: &'a LateContext<'tcx>, expr: &'tcx Expr<'_>) -> bool {
- utils::path_to_local(expr).map_or(false, |definition| {
- let mut visitor = UsedAfterExprVisitor {
- cx,
- expr,
- definition,
- past_expr: false,
- used_after_expr: false,
- };
- utils::get_enclosing_block(cx, definition).map_or(false, |block| {
- visitor.visit_block(block);
- visitor.used_after_expr
- })
- })
- }
-}
-
-impl<'a, 'tcx> intravisit::Visitor<'tcx> for UsedAfterExprVisitor<'a, 'tcx> {
- type Map = Map<'tcx>;
-
- fn nested_visit_map(&mut self) -> NestedVisitorMap<Self::Map> {
- NestedVisitorMap::OnlyBodies(self.cx.tcx.hir())
- }
-
- fn visit_expr(&mut self, expr: &'tcx Expr<'tcx>) {
- if self.used_after_expr {
- return;
+ !seen_return_break_continue
+ })
+ .visit_expr(expression);
+ seen_return_break_continue
+}
+
+pub fn local_used_after_expr(cx: &LateContext<'_>, local_id: HirId, after: &Expr<'_>) -> bool {
+ let Some(block) = utils::get_enclosing_block(cx, local_id) else { return false };
+ let mut used_after_expr = false;
+ let mut past_expr = false;
+ expr_visitor(cx, |expr| {
+ if used_after_expr {
+ return false;
}
- if expr.hir_id == self.expr.hir_id {
- self.past_expr = true;
- } else if self.past_expr && utils::path_to_local_id(expr, self.definition) {
- self.used_after_expr = true;
- } else {
- intravisit::walk_expr(self, expr);
+ if expr.hir_id == after.hir_id {
+ past_expr = true;
+ } else if past_expr && utils::path_to_local_id(expr, local_id) {
+ used_after_expr = true;
}
- }
+ !used_after_expr
+ })
+ .visit_block(block);
+ used_after_expr
}
diff --git a/src/tools/clippy/clippy_utils/src/visitors.rs b/src/tools/clippy/clippy_utils/src/visitors.rs
index 503effbdad5..4bfd3c64b9c 100644
--- a/src/tools/clippy/clippy_utils/src/visitors.rs
+++ b/src/tools/clippy/clippy_utils/src/visitors.rs
@@ -1,38 +1,70 @@
use crate::path_to_local_id;
use rustc_hir as hir;
-use rustc_hir::intravisit::{self, walk_expr, ErasedMap, NestedVisitorMap, Visitor};
-use rustc_hir::{def::Res, Arm, Block, Body, BodyId, Destination, Expr, ExprKind, HirId, Stmt};
+use rustc_hir::def::{DefKind, Res};
+use rustc_hir::intravisit::{self, walk_block, walk_expr, NestedVisitorMap, Visitor};
+use rustc_hir::{
+ Arm, Block, BlockCheckMode, Body, BodyId, Expr, ExprKind, HirId, ItemId, ItemKind, Stmt, UnOp, Unsafety,
+};
use rustc_lint::LateContext;
use rustc_middle::hir::map::Map;
-use std::ops::ControlFlow;
+use rustc_middle::ty;
-/// returns `true` if expr contains match expr desugared from try
-fn contains_try(expr: &hir::Expr<'_>) -> bool {
- struct TryFinder {
- found: bool,
+/// Convenience method for creating a `Visitor` with just `visit_expr` overridden and nested
+/// bodies (i.e. closures) are visited.
+/// If the callback returns `true`, the expr just provided to the callback is walked.
+#[must_use]
+pub fn expr_visitor<'tcx>(cx: &LateContext<'tcx>, f: impl FnMut(&'tcx Expr<'tcx>) -> bool) -> impl Visitor<'tcx> {
+ struct V<'tcx, F> {
+ hir: Map<'tcx>,
+ f: F,
}
+ impl<'tcx, F: FnMut(&'tcx Expr<'tcx>) -> bool> Visitor<'tcx> for V<'tcx, F> {
+ type Map = Map<'tcx>;
+ fn nested_visit_map(&mut self) -> NestedVisitorMap<Self::Map> {
+ NestedVisitorMap::OnlyBodies(self.hir)
+ }
- impl<'hir> intravisit::Visitor<'hir> for TryFinder {
- type Map = Map<'hir>;
+ fn visit_expr(&mut self, expr: &'tcx Expr<'tcx>) {
+ if (self.f)(expr) {
+ walk_expr(self, expr);
+ }
+ }
+ }
+ V { hir: cx.tcx.hir(), f }
+}
- fn nested_visit_map(&mut self) -> intravisit::NestedVisitorMap<Self::Map> {
- intravisit::NestedVisitorMap::None
+/// Convenience method for creating a `Visitor` with just `visit_expr` overridden and nested
+/// bodies (i.e. closures) are not visited.
+/// If the callback returns `true`, the expr just provided to the callback is walked.
+#[must_use]
+pub fn expr_visitor_no_bodies<'tcx>(f: impl FnMut(&'tcx Expr<'tcx>) -> bool) -> impl Visitor<'tcx> {
+ struct V<F>(F);
+ impl<'tcx, F: FnMut(&'tcx Expr<'tcx>) -> bool> Visitor<'tcx> for V<F> {
+ type Map = intravisit::ErasedMap<'tcx>;
+ fn nested_visit_map(&mut self) -> NestedVisitorMap<Self::Map> {
+ NestedVisitorMap::None
}
- fn visit_expr(&mut self, expr: &'hir hir::Expr<'hir>) {
- if self.found {
- return;
- }
- match expr.kind {
- hir::ExprKind::Match(_, _, hir::MatchSource::TryDesugar) => self.found = true,
- _ => intravisit::walk_expr(self, expr),
+ fn visit_expr(&mut self, e: &'tcx Expr<'_>) {
+ if (self.0)(e) {
+ walk_expr(self, e);
}
}
}
+ V(f)
+}
- let mut visitor = TryFinder { found: false };
- visitor.visit_expr(expr);
- visitor.found
+/// returns `true` if expr contains match expr desugared from try
+fn contains_try(expr: &hir::Expr<'_>) -> bool {
+ let mut found = false;
+ expr_visitor_no_bodies(|e| {
+ if !found {
+ found = matches!(e.kind, hir::ExprKind::Match(_, _, hir::MatchSource::TryDesugar));
+ }
+ !found
+ })
+ .visit_expr(expr);
+ found
}
pub fn find_all_ret_expressions<'hir, F>(_cx: &LateContext<'_>, expr: &'hir hir::Expr<'hir>, callback: F) -> bool
@@ -165,103 +197,186 @@ visitable_ref!(Stmt, visit_stmt);
// }
// }
-/// Calls the given function for each break expression.
-pub fn visit_break_exprs<'tcx>(
- node: impl Visitable<'tcx>,
- f: impl FnMut(&'tcx Expr<'tcx>, Destination, Option<&'tcx Expr<'tcx>>),
-) {
- struct V<F>(F);
- impl<'tcx, F: FnMut(&'tcx Expr<'tcx>, Destination, Option<&'tcx Expr<'tcx>>)> Visitor<'tcx> for V<F> {
- type Map = ErasedMap<'tcx>;
- fn nested_visit_map(&mut self) -> NestedVisitorMap<Self::Map> {
- NestedVisitorMap::None
+/// Checks if the given resolved path is used in the given body.
+pub fn is_res_used(cx: &LateContext<'_>, res: Res, body: BodyId) -> bool {
+ let mut found = false;
+ expr_visitor(cx, |e| {
+ if found {
+ return false;
}
- fn visit_expr(&mut self, e: &'tcx Expr<'_>) {
- if let ExprKind::Break(dest, sub_expr) = e.kind {
- self.0(e, dest, sub_expr);
+ if let ExprKind::Path(p) = &e.kind {
+ if cx.qpath_res(p, e.hir_id) == res {
+ found = true;
}
- walk_expr(self, e);
}
- }
+ !found
+ })
+ .visit_expr(&cx.tcx.hir().body(body).value);
+ found
+}
- node.visit(&mut V(f));
+/// Checks if the given local is used.
+pub fn is_local_used(cx: &LateContext<'tcx>, visitable: impl Visitable<'tcx>, id: HirId) -> bool {
+ let mut is_used = false;
+ let mut visitor = expr_visitor(cx, |expr| {
+ if !is_used {
+ is_used = path_to_local_id(expr, id);
+ }
+ !is_used
+ });
+ visitable.visit(&mut visitor);
+ drop(visitor);
+ is_used
}
-/// Checks if the given resolved path is used in the given body.
-pub fn is_res_used(cx: &LateContext<'_>, res: Res, body: BodyId) -> bool {
+/// Checks if the given expression is a constant.
+pub fn is_const_evaluatable(cx: &LateContext<'tcx>, e: &'tcx Expr<'_>) -> bool {
struct V<'a, 'tcx> {
cx: &'a LateContext<'tcx>,
- res: Res,
- found: bool,
+ is_const: bool,
}
- impl Visitor<'tcx> for V<'_, 'tcx> {
+ impl<'tcx> Visitor<'tcx> for V<'_, 'tcx> {
type Map = Map<'tcx>;
fn nested_visit_map(&mut self) -> NestedVisitorMap<Self::Map> {
NestedVisitorMap::OnlyBodies(self.cx.tcx.hir())
}
fn visit_expr(&mut self, e: &'tcx Expr<'_>) {
- if self.found {
+ if !self.is_const {
return;
}
+ match e.kind {
+ ExprKind::ConstBlock(_) => return,
+ ExprKind::Call(
+ &Expr {
+ kind: ExprKind::Path(ref p),
+ hir_id,
+ ..
+ },
+ _,
+ ) if self
+ .cx
+ .qpath_res(p, hir_id)
+ .opt_def_id()
+ .map_or(false, |id| self.cx.tcx.is_const_fn_raw(id)) => {},
+ ExprKind::MethodCall(..)
+ if self
+ .cx
+ .typeck_results()
+ .type_dependent_def_id(e.hir_id)
+ .map_or(false, |id| self.cx.tcx.is_const_fn_raw(id)) => {},
+ ExprKind::Binary(_, lhs, rhs)
+ if self.cx.typeck_results().expr_ty(lhs).peel_refs().is_primitive_ty()
+ && self.cx.typeck_results().expr_ty(rhs).peel_refs().is_primitive_ty() => {},
+ ExprKind::Unary(UnOp::Deref, e) if self.cx.typeck_results().expr_ty(e).is_ref() => (),
+ ExprKind::Unary(_, e) if self.cx.typeck_results().expr_ty(e).peel_refs().is_primitive_ty() => (),
+ ExprKind::Index(base, _)
+ if matches!(
+ self.cx.typeck_results().expr_ty(base).peel_refs().kind(),
+ ty::Slice(_) | ty::Array(..)
+ ) => {},
+ ExprKind::Path(ref p)
+ if matches!(
+ self.cx.qpath_res(p, e.hir_id),
+ Res::Def(
+ DefKind::Const
+ | DefKind::AssocConst
+ | DefKind::AnonConst
+ | DefKind::ConstParam
+ | DefKind::Ctor(..)
+ | DefKind::Fn
+ | DefKind::AssocFn,
+ _
+ ) | Res::SelfCtor(_)
+ ) => {},
- if let ExprKind::Path(p) = &e.kind {
- if self.cx.qpath_res(p, e.hir_id) == self.res {
- self.found = true;
- }
- } else {
- walk_expr(self, e);
+ ExprKind::AddrOf(..)
+ | ExprKind::Array(_)
+ | ExprKind::Block(..)
+ | ExprKind::Cast(..)
+ | ExprKind::DropTemps(_)
+ | ExprKind::Field(..)
+ | ExprKind::If(..)
+ | ExprKind::Let(..)
+ | ExprKind::Lit(_)
+ | ExprKind::Match(..)
+ | ExprKind::Repeat(..)
+ | ExprKind::Struct(..)
+ | ExprKind::Tup(_)
+ | ExprKind::Type(..) => (),
+
+ _ => {
+ self.is_const = false;
+ return;
+ },
}
+ walk_expr(self, e);
}
}
- let mut v = V { cx, res, found: false };
- v.visit_expr(&cx.tcx.hir().body(body).value);
- v.found
+ let mut v = V { cx, is_const: true };
+ v.visit_expr(e);
+ v.is_const
}
-/// Calls the given function for each usage of the given local.
-pub fn for_each_local_usage<'tcx, B>(
- cx: &LateContext<'tcx>,
- visitable: impl Visitable<'tcx>,
- id: HirId,
- f: impl FnMut(&'tcx Expr<'tcx>) -> ControlFlow<B>,
-) -> ControlFlow<B> {
- struct V<'tcx, B, F> {
- map: Map<'tcx>,
- id: HirId,
- f: F,
- res: ControlFlow<B>,
+/// Checks if the given expression performs an unsafe operation outside of an unsafe block.
+pub fn is_expr_unsafe(cx: &LateContext<'tcx>, e: &'tcx Expr<'_>) -> bool {
+ struct V<'a, 'tcx> {
+ cx: &'a LateContext<'tcx>,
+ is_unsafe: bool,
}
- impl<'tcx, B, F: FnMut(&'tcx Expr<'tcx>) -> ControlFlow<B>> Visitor<'tcx> for V<'tcx, B, F> {
+ impl<'tcx> Visitor<'tcx> for V<'_, 'tcx> {
type Map = Map<'tcx>;
fn nested_visit_map(&mut self) -> NestedVisitorMap<Self::Map> {
- NestedVisitorMap::OnlyBodies(self.map)
+ NestedVisitorMap::OnlyBodies(self.cx.tcx.hir())
}
-
fn visit_expr(&mut self, e: &'tcx Expr<'_>) {
- if self.res.is_continue() {
- if path_to_local_id(e, self.id) {
- self.res = (self.f)(e);
- } else {
- walk_expr(self, e);
- }
+ if self.is_unsafe {
+ return;
+ }
+ match e.kind {
+ ExprKind::Unary(UnOp::Deref, e) if self.cx.typeck_results().expr_ty(e).is_unsafe_ptr() => {
+ self.is_unsafe = true;
+ },
+ ExprKind::MethodCall(..)
+ if self
+ .cx
+ .typeck_results()
+ .type_dependent_def_id(e.hir_id)
+ .map_or(false, |id| self.cx.tcx.fn_sig(id).unsafety() == Unsafety::Unsafe) =>
+ {
+ self.is_unsafe = true;
+ },
+ ExprKind::Call(func, _) => match *self.cx.typeck_results().expr_ty(func).peel_refs().kind() {
+ ty::FnDef(id, _) if self.cx.tcx.fn_sig(id).unsafety() == Unsafety::Unsafe => self.is_unsafe = true,
+ ty::FnPtr(sig) if sig.unsafety() == Unsafety::Unsafe => self.is_unsafe = true,
+ _ => walk_expr(self, e),
+ },
+ ExprKind::Path(ref p)
+ if self
+ .cx
+ .qpath_res(p, e.hir_id)
+ .opt_def_id()
+ .map_or(false, |id| self.cx.tcx.is_mutable_static(id)) =>
+ {
+ self.is_unsafe = true;
+ },
+ _ => walk_expr(self, e),
+ }
+ }
+ fn visit_block(&mut self, b: &'tcx Block<'_>) {
+ if !matches!(b.rules, BlockCheckMode::UnsafeBlock(_)) {
+ walk_block(self, b);
+ }
+ }
+ fn visit_nested_item(&mut self, id: ItemId) {
+ if let ItemKind::Impl(i) = &self.cx.tcx.hir().item(id).kind {
+ self.is_unsafe = i.unsafety == Unsafety::Unsafe;
}
}
}
-
- let mut v = V {
- map: cx.tcx.hir(),
- id,
- f,
- res: ControlFlow::CONTINUE,
- };
- visitable.visit(&mut v);
- v.res
-}
-
-/// Checks if the given local is used.
-pub fn is_local_used(cx: &LateContext<'tcx>, visitable: impl Visitable<'tcx>, id: HirId) -> bool {
- for_each_local_usage(cx, visitable, id, |_| ControlFlow::BREAK).is_break()
+ let mut v = V { cx, is_unsafe: false };
+ v.visit_expr(e);
+ v.is_unsafe
}
diff --git a/src/tools/clippy/doc/adding_lints.md b/src/tools/clippy/doc/adding_lints.md
index bd32696d6db..cf16a1d5d3d 100644
--- a/src/tools/clippy/doc/adding_lints.md
+++ b/src/tools/clippy/doc/adding_lints.md
@@ -157,7 +157,7 @@ Manually testing against an example file can be useful if you have added some
your local modifications, run
```
-env __CLIPPY_INTERNAL_TESTS=true cargo run --bin clippy-driver -- -L ./target/debug input.rs
+cargo dev lint input.rs
```
from the working copy root. With tests in place, let's have a look at
@@ -189,6 +189,7 @@ declare_clippy_lint! {
/// ```rust
/// // example code
/// ```
+ #[clippy::version = "1.29.0"]
pub FOO_FUNCTIONS,
pedantic,
"function named `foo`, which is not a descriptive name"
@@ -199,6 +200,10 @@ declare_clippy_lint! {
section. This is the default documentation style and will be displayed
[like this][example_lint_page]. To render and open this documentation locally
in a browser, run `cargo dev serve`.
+* The `#[clippy::version]` attribute will be rendered as part of the lint documentation.
+ The value should be set to the current Rust version that the lint is developed in,
+ it can be retrieved by running `rustc -vV` in the rust-clippy directory. The version
+ is listed under *release*. (Use the version without the `-nightly`) suffix.
* `FOO_FUNCTIONS` is the name of our lint. Be sure to follow the
[lint naming guidelines][lint_naming] here when naming your lint.
In short, the name should state the thing that is being checked for and
@@ -503,6 +508,7 @@ declare_clippy_lint! {
/// // Good
/// Insert a short example of improved code that doesn't trigger the lint
/// ```
+ #[clippy::version = "1.29.0"]
pub FOO_FUNCTIONS,
pedantic,
"function named `foo`, which is not a descriptive name"
@@ -634,7 +640,7 @@ in the following steps:
Here are some pointers to things you are likely going to need for every lint:
* [Clippy utils][utils] - Various helper functions. Maybe the function you need
- is already in here (`implements_trait`, `match_def_path`, `snippet`, etc)
+ is already in here ([`is_type_diagnostic_item`], [`implements_trait`], [`snippet`], etc)
* [Clippy diagnostics][diagnostics]
* [The `if_chain` macro][if_chain]
* [`from_expansion`][from_expansion] and [`in_external_macro`][in_external_macro]
@@ -660,7 +666,10 @@ documentation currently. This is unfortunate, but in most cases you can probably
get away with copying things from existing similar lints. If you are stuck,
don't hesitate to ask on [Zulip] or in the issue/PR.
-[utils]: https://github.com/rust-lang/rust-clippy/blob/master/clippy_utils/src/lib.rs
+[utils]: https://doc.rust-lang.org/nightly/nightly-rustc/clippy_utils/index.html
+[`is_type_diagnostic_item`]: https://doc.rust-lang.org/nightly/nightly-rustc/clippy_utils/ty/fn.is_type_diagnostic_item.html
+[`implements_trait`]: https://doc.rust-lang.org/nightly/nightly-rustc/clippy_utils/ty/fn.implements_trait.html
+[`snippet`]: https://doc.rust-lang.org/nightly/nightly-rustc/clippy_utils/source/fn.snippet.html
[if_chain]: https://docs.rs/if_chain/*/if_chain/
[from_expansion]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_span/struct.Span.html#method.from_expansion
[in_external_macro]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_middle/lint/fn.in_external_macro.html
diff --git a/src/tools/clippy/doc/changelog_update.md b/src/tools/clippy/doc/changelog_update.md
index 115848c4804..0cbad2c0924 100644
--- a/src/tools/clippy/doc/changelog_update.md
+++ b/src/tools/clippy/doc/changelog_update.md
@@ -32,7 +32,7 @@ bullet points might be helpful:
need to check out the Rust release tag of the stable release.
[Link][rust_stable_tools]
-Usually you want to wirte the changelog of the **upcoming stable release**. Make
+Usually you want to write the changelog of the **upcoming stable release**. Make
sure though, that `beta` was already branched in the Rust repository.
To find the commit hash, issue the following command when in a `rust-lang/rust` checkout:
diff --git a/src/tools/clippy/doc/common_tools_writing_lints.md b/src/tools/clippy/doc/common_tools_writing_lints.md
index 1a6b7c8cb47..c7e51d53f51 100644
--- a/src/tools/clippy/doc/common_tools_writing_lints.md
+++ b/src/tools/clippy/doc/common_tools_writing_lints.md
@@ -4,10 +4,11 @@ You may need following tooltips to catch up with common operations.
- [Common tools for writing lints](#common-tools-for-writing-lints)
- [Retrieving the type of an expression](#retrieving-the-type-of-an-expression)
- - [Checking if an expression is calling a specific method](#checking-if-an-expr-is-calling-a-specific-method)
+ - [Checking if an expr is calling a specific method](#checking-if-an-expr-is-calling-a-specific-method)
+ - [Checking for a specific type](#checking-for-a-specific-type)
- [Checking if a type implements a specific trait](#checking-if-a-type-implements-a-specific-trait)
- [Checking if a type defines a specific method](#checking-if-a-type-defines-a-specific-method)
- - [Dealing with macros](#dealing-with-macros)
+ - [Dealing with macros](#dealing-with-macros-and-expansions)
Useful Rustc dev guide links:
- [Stages of compilation](https://rustc-dev-guide.rust-lang.org/compiler-src.html#the-main-stages-of-compilation)
@@ -15,7 +16,7 @@ Useful Rustc dev guide links:
- [Type checking](https://rustc-dev-guide.rust-lang.org/type-checking.html)
- [Ty module](https://rustc-dev-guide.rust-lang.org/ty.html)
-# Retrieving the type of an expression
+## Retrieving the type of an expression
Sometimes you may want to retrieve the type `Ty` of an expression `Expr`, for example to answer following questions:
@@ -54,7 +55,7 @@ Two noticeable items here:
created by type checking step, it includes useful information such as types
of expressions, ways to resolve methods and so on.
-# Checking if an expr is calling a specific method
+## Checking if an expr is calling a specific method
Starting with an `expr`, you can check whether it is calling a specific method `some_method`:
@@ -63,9 +64,11 @@ impl LateLintPass<'_> for MyStructLint {
fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx hir::Expr<'_>) {
if_chain! {
// Check our expr is calling a method
- if let hir::ExprKind::MethodCall(path, _, _args, _) = &expr.kind;
+ if let hir::ExprKind::MethodCall(path, _, [_self_arg, ..], _) = &expr.kind;
// Check the name of this method is `some_method`
if path.ident.name == sym!(some_method);
+ // Optionally, check the type of the self argument.
+ // - See "Checking for a specific type"
then {
// ...
}
@@ -74,7 +77,45 @@ impl LateLintPass<'_> for MyStructLint {
}
```
-# Checking if a type implements a specific trait
+## Checking for a specific type
+
+There are three ways to check if an expression type is a specific type we want to check for.
+All of these methods only check for the base type, generic arguments have to be checked separately.
+
+```rust
+use clippy_utils::ty::{is_type_diagnostic_item, is_type_lang_item};
+use clippy_utils::{paths, match_def_path};
+use rustc_span::symbol::sym;
+use rustc_hir::LangItem;
+
+impl LateLintPass<'_> for MyStructLint {
+ fn check_expr(&mut self, cx: &LateContext<'_>, expr: &Expr<'_>) {
+ // Getting the expression type
+ let ty = cx.typeck_results().expr_ty(expr);
+
+ // 1. Using diagnostic items
+ // The last argument is the diagnostic item to check for
+ if is_type_diagnostic_item(cx, ty, sym::Option) {
+ // The type is an `Option`
+ }
+
+ // 2. Using lang items
+ if is_type_lang_item(cx, ty, LangItem::RangeFull) {
+ // The type is a full range like `.drain(..)`
+ }
+
+ // 3. Using the type path
+ // This method should be avoided if possible
+ if match_def_path(cx, def_id, &paths::RESULT) {
+ // The type is a `core::result::Result`
+ }
+ }
+}
+```
+
+Prefer using diagnostic items and lang items where possible.
+
+## Checking if a type implements a specific trait
There are three ways to do this, depending on if the target trait has a diagnostic item, lang item or neither.
@@ -102,6 +143,7 @@ impl LateLintPass<'_> for MyStructLint {
// 3. Using the type path with the expression
// we use `match_trait_method` function from Clippy's utils
+ // (This method should be avoided if possible)
if match_trait_method(cx, expr, &paths::INTO) {
// `expr` implements `Into` trait
}
@@ -114,7 +156,7 @@ impl LateLintPass<'_> for MyStructLint {
We access lang items through the type context `tcx`. `tcx` is of type [`TyCtxt`][TyCtxt] and is defined in the `rustc_middle` crate.
A list of defined paths for Clippy can be found in [paths.rs][paths]
-# Checking if a type defines a specific method
+## Checking if a type defines a specific method
To check if our type defines a method called `some_method`:
@@ -140,64 +182,78 @@ impl<'tcx> LateLintPass<'tcx> for MyTypeImpl {
}
```
-# Dealing with macros
+## Dealing with macros and expansions
-There are several helpers in [`clippy_utils`][utils] to deal with macros:
+Keep in mind that macros are already expanded and desugaring is already applied
+to the code representation that you are working with in Clippy. This unfortunately causes a lot of
+false positives because macro expansions are "invisible" unless you actively check for them.
+Generally speaking, code with macro expansions should just be ignored by Clippy because that code can be
+dynamic in ways that are difficult or impossible to see.
+Use the following functions to deal with macros:
-- `in_macro()`: detect if the given span is expanded by a macro
+- `span.from_expansion()`: detects if a span is from macro expansion or desugaring.
+ Checking this is a common first step in a lint.
-You may want to use this for example to not start linting in any macro.
+ ```rust
+ if expr.span.from_expansion() {
+ // just forget it
+ return;
+ }
+ ```
-```rust
-macro_rules! foo {
- ($param:expr) => {
- match $param {
- "bar" => println!("whatever"),
- _ => ()
- }
- };
-}
+- `span.ctxt()`: the span's context represents whether it is from expansion, and if so, which macro call expanded it.
+ It is sometimes useful to check if the context of two spans are equal.
-foo!("bar");
+ ```rust
+ // expands to `1 + 0`, but don't lint
+ 1 + mac!()
+ ```
+ ```rust
+ if left.span.ctxt() != right.span.ctxt() {
+ // the coder most likely cannot modify this expression
+ return;
+ }
+ ```
+ Note: Code that is not from expansion is in the "root" context. So any spans where `from_expansion` returns `true` can
+ be assumed to have the same context. And so just using `span.from_expansion()` is often good enough.
-// if we lint the `match` of `foo` call and test its span
-assert_eq!(in_macro(match_span), true);
-```
-- `in_external_macro()`: detect if the given span is from an external macro, defined in a foreign crate
+- `in_external_macro(span)`: detect if the given span is from a macro defined in a foreign crate.
+ If you want the lint to work with macro-generated code, this is the next line of defense to avoid macros
+ not defined in the current crate. It doesn't make sense to lint code that the coder can't change.
-You may want to use it for example to not start linting in macros from other crates
+ You may want to use it for example to not start linting in macros from other crates
-```rust
-#[macro_use]
-extern crate a_crate_with_macros;
+ ```rust
+ #[macro_use]
+ extern crate a_crate_with_macros;
-// `foo` is defined in `a_crate_with_macros`
-foo!("bar");
+ // `foo` is defined in `a_crate_with_macros`
+ foo!("bar");
-// if we lint the `match` of `foo` call and test its span
-assert_eq!(in_external_macro(cx.sess(), match_span), true);
-```
+ // if we lint the `match` of `foo` call and test its span
+ assert_eq!(in_external_macro(cx.sess(), match_span), true);
+ ```
- `differing_macro_contexts()`: returns true if the two given spans are not from the same context
-```rust
-macro_rules! m {
- ($a:expr, $b:expr) => {
- if $a.is_some() {
- $b;
- }
- }
-}
+ ```rust
+ macro_rules! m {
+ ($a:expr, $b:expr) => {
+ if $a.is_some() {
+ $b;
+ }
+ }
+ }
-let x: Option<u32> = Some(42);
-m!(x, x.unwrap());
+ let x: Option<u32> = Some(42);
+ m!(x, x.unwrap());
-// These spans are not from the same context
-// x.is_some() is from inside the macro
-// x.unwrap() is from outside the macro
-assert_eq!(differing_macro_contexts(x_is_some_span, x_unwrap_span), true);
-```
+ // These spans are not from the same context
+ // x.is_some() is from inside the macro
+ // x.unwrap() is from outside the macro
+ assert_eq!(differing_macro_contexts(x_is_some_span, x_unwrap_span), true);
+ ```
[TyS]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_middle/ty/struct.TyS.html
[TyKind]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_middle/ty/enum.TyKind.html
@@ -207,4 +263,3 @@ assert_eq!(differing_macro_contexts(x_is_some_span, x_unwrap_span), true);
[TyCtxt]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_middle/ty/context/struct.TyCtxt.html
[pat_ty]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_middle/ty/context/struct.TypeckResults.html#method.pat_ty
[paths]: ../clippy_utils/src/paths.rs
-[utils]: https://github.com/rust-lang/rust-clippy/blob/master/clippy_utils/src/lib.rs
diff --git a/src/tools/clippy/lintcheck-logs/lintcheck_crates_logs.txt b/src/tools/clippy/lintcheck-logs/lintcheck_crates_logs.txt
deleted file mode 100644
index 8f22bd65683..00000000000
--- a/src/tools/clippy/lintcheck-logs/lintcheck_crates_logs.txt
+++ /dev/null
@@ -1,3862 +0,0 @@
-clippy 0.1.53 (0b7671963 2021-03-31)
-
-target/lintcheck/sources/anyhow-1.0.38/build.rs:1:null clippy::cargo_common_metadata "package `anyhow` is missing `package.keywords` metadata"
-target/lintcheck/sources/anyhow-1.0.38/src/error.rs:350:5 clippy::missing_panics_doc "docs for function which may panic missing `# Panics` section"
-target/lintcheck/sources/anyhow-1.0.38/src/lib.rs:1:null clippy::cargo_common_metadata "package `anyhow` is missing `package.keywords` metadata"
-target/lintcheck/sources/async-trait-0.1.42/src/expand.rs:130:1 clippy::too_many_lines "this function has too many lines (104/100)"
-target/lintcheck/sources/async-trait-0.1.42/src/expand.rs:156:26 clippy::default_trait_access "calling `syn::token::Where::default()` is more clear than this expression"
-target/lintcheck/sources/async-trait-0.1.42/src/expand.rs:259:1 clippy::too_many_lines "this function has too many lines (204/100)"
-target/lintcheck/sources/async-trait-0.1.42/src/expand.rs:387:17 clippy::match_wildcard_for_single_variants "wildcard matches only a single variant and will also match any future added variants"
-target/lintcheck/sources/async-trait-0.1.42/src/expand.rs:414:35 clippy::shadow_unrelated "`generics` is being shadowed"
-target/lintcheck/sources/async-trait-0.1.42/src/expand.rs:464:32 clippy::if_not_else "unnecessary `!=` operation"
-target/lintcheck/sources/async-trait-0.1.42/src/lib.rs:102:7 clippy::doc_markdown "you should put `async_trait` between ticks in the documentation"
-target/lintcheck/sources/async-trait-0.1.42/src/lib.rs:159:64 clippy::doc_markdown "you should put `async_trait` between ticks in the documentation"
-target/lintcheck/sources/async-trait-0.1.42/src/lib.rs:1:null clippy::cargo_common_metadata "package `async-trait` is missing `package.categories` metadata"
-target/lintcheck/sources/async-trait-0.1.42/src/lib.rs:1:null clippy::cargo_common_metadata "package `async-trait` is missing `package.keywords` metadata"
-target/lintcheck/sources/async-trait-0.1.42/src/lib.rs:240:15 clippy::doc_markdown "you should put `async_trait` between ticks in the documentation"
-target/lintcheck/sources/async-trait-0.1.42/src/lifetime.rs:5:1 clippy::module_name_repetitions "item name ends with its containing module's name"
-target/lintcheck/sources/async-trait-0.1.42/src/receiver.rs:102:34 clippy::similar_names "binding's name is too similar to existing binding"
-target/lintcheck/sources/async-trait-0.1.42/src/receiver.rs:107:29 clippy::similar_names "binding's name is too similar to existing binding"
-target/lintcheck/sources/async-trait-0.1.42/src/receiver.rs:137:38 clippy::default_trait_access "calling `syn::token::Colon2::default()` is more clear than this expression"
-target/lintcheck/sources/async-trait-0.1.42/src/receiver.rs:162:55 clippy::default_trait_access "calling `syn::token::Colon2::default()` is more clear than this expression"
-target/lintcheck/sources/async-trait-0.1.42/src/receiver.rs:167:42 clippy::default_trait_access "calling `syn::token::Colon2::default()` is more clear than this expression"
-target/lintcheck/sources/async-trait-0.1.42/src/receiver.rs:73:1 clippy::module_name_repetitions "item name ends with its containing module's name"
-target/lintcheck/sources/async-trait-0.1.42/src/receiver.rs:97:34 clippy::similar_names "binding's name is too similar to existing binding"
-target/lintcheck/sources/cargo-0.49.0/build.rs:1:null clippy::cargo_common_metadata "package `cargo` is missing `package.categories` metadata"
-target/lintcheck/sources/cargo-0.49.0/build.rs:1:null clippy::cargo_common_metadata "package `cargo` is missing `package.keywords` metadata"
-target/lintcheck/sources/cargo-0.49.0/src/bin/cargo/cli.rs:104:34 clippy::single_match_else "you seem to be trying to use `match` for destructuring a single pattern. Consider using `if let`"
-target/lintcheck/sources/cargo-0.49.0/src/bin/cargo/cli.rs:121:5 clippy::single_char_add_str "calling `push_str()` using a single-character string literal"
-target/lintcheck/sources/cargo-0.49.0/src/bin/cargo/cli.rs:157:30 clippy::redundant_closure_for_method_calls "redundant closure"
-target/lintcheck/sources/cargo-0.49.0/src/bin/cargo/cli.rs:184:41 clippy::cast_possible_truncation "casting `u64` to `u32` may truncate the value"
-target/lintcheck/sources/cargo-0.49.0/src/bin/cargo/cli.rs:196:42 clippy::redundant_closure_for_method_calls "redundant closure"
-target/lintcheck/sources/cargo-0.49.0/src/bin/cargo/cli.rs:200:39 clippy::redundant_closure_for_method_calls "redundant closure"
-target/lintcheck/sources/cargo-0.49.0/src/bin/cargo/cli.rs:231:1 clippy::struct_excessive_bools "more than 3 bools in a struct"
-target/lintcheck/sources/cargo-0.49.0/src/bin/cargo/cli.rs:23:56 clippy::implicit_clone "implicitly cloning a `String` by calling `to_owned` on its dereferenced type"
-target/lintcheck/sources/cargo-0.49.0/src/bin/cargo/cli.rs:245:22 clippy::cast_possible_truncation "casting `u64` to `u32` may truncate the value"
-target/lintcheck/sources/cargo-0.49.0/src/bin/cargo/cli.rs:247:47 clippy::redundant_closure_for_method_calls "redundant closure"
-target/lintcheck/sources/cargo-0.49.0/src/bin/cargo/cli.rs:257:22 clippy::redundant_closure_for_method_calls "redundant closure"
-target/lintcheck/sources/cargo-0.49.0/src/bin/cargo/cli.rs:26:20 clippy::redundant_else "redundant else block"
-target/lintcheck/sources/cargo-0.49.0/src/bin/cargo/cli.rs:7:5 clippy::wildcard_imports "usage of wildcard import"
-target/lintcheck/sources/cargo-0.49.0/src/bin/cargo/commands/bench.rs:1:5 clippy::wildcard_imports "usage of wildcard import"
-target/lintcheck/sources/cargo-0.49.0/src/bin/cargo/commands/bench.rs:76:59 clippy::redundant_closure_for_method_calls "redundant closure"
-target/lintcheck/sources/cargo-0.49.0/src/bin/cargo/commands/build.rs:1:5 clippy::wildcard_imports "usage of wildcard import"
-target/lintcheck/sources/cargo-0.49.0/src/bin/cargo/commands/check.rs:1:5 clippy::wildcard_imports "usage of wildcard import"
-target/lintcheck/sources/cargo-0.49.0/src/bin/cargo/commands/clean.rs:1:5 clippy::wildcard_imports "usage of wildcard import"
-target/lintcheck/sources/cargo-0.49.0/src/bin/cargo/commands/doc.rs:1:5 clippy::wildcard_imports "usage of wildcard import"
-target/lintcheck/sources/cargo-0.49.0/src/bin/cargo/commands/fetch.rs:1:5 clippy::wildcard_imports "usage of wildcard import"
-target/lintcheck/sources/cargo-0.49.0/src/bin/cargo/commands/fetch.rs:22:5 clippy::let_underscore_drop "non-binding `let` on a type that implements `Drop`"
-target/lintcheck/sources/cargo-0.49.0/src/bin/cargo/commands/fix.rs:1:5 clippy::wildcard_imports "usage of wildcard import"
-target/lintcheck/sources/cargo-0.49.0/src/bin/cargo/commands/generate_lockfile.rs:1:5 clippy::wildcard_imports "usage of wildcard import"
-target/lintcheck/sources/cargo-0.49.0/src/bin/cargo/commands/git_checkout.rs:1:5 clippy::wildcard_imports "usage of wildcard import"
-target/lintcheck/sources/cargo-0.49.0/src/bin/cargo/commands/help.rs:20:1 clippy::module_name_repetitions "item name ends with its containing module's name"
-target/lintcheck/sources/cargo-0.49.0/src/bin/cargo/commands/init.rs:1:5 clippy::wildcard_imports "usage of wildcard import"
-target/lintcheck/sources/cargo-0.49.0/src/bin/cargo/commands/install.rs:1:5 clippy::wildcard_imports "usage of wildcard import"
-target/lintcheck/sources/cargo-0.49.0/src/bin/cargo/commands/install.rs:97:16 clippy::option_if_let_else "use Option::map_or instead of an if let/else"
-target/lintcheck/sources/cargo-0.49.0/src/bin/cargo/commands/locate_project.rs:1:5 clippy::wildcard_imports "usage of wildcard import"
-target/lintcheck/sources/cargo-0.49.0/src/bin/cargo/commands/login.rs:1:5 clippy::wildcard_imports "usage of wildcard import"
-target/lintcheck/sources/cargo-0.49.0/src/bin/cargo/commands/metadata.rs:1:5 clippy::wildcard_imports "usage of wildcard import"
-target/lintcheck/sources/cargo-0.49.0/src/bin/cargo/commands/mod.rs:1:5 clippy::wildcard_imports "usage of wildcard import"
-target/lintcheck/sources/cargo-0.49.0/src/bin/cargo/commands/new.rs:1:5 clippy::wildcard_imports "usage of wildcard import"
-target/lintcheck/sources/cargo-0.49.0/src/bin/cargo/commands/new.rs:20:24 clippy::option_if_let_else "use Option::map_or instead of an if let/else"
-target/lintcheck/sources/cargo-0.49.0/src/bin/cargo/commands/owner.rs:1:5 clippy::wildcard_imports "usage of wildcard import"
-target/lintcheck/sources/cargo-0.49.0/src/bin/cargo/commands/owner.rs:38:43 clippy::redundant_closure_for_method_calls "redundant closure"
-target/lintcheck/sources/cargo-0.49.0/src/bin/cargo/commands/owner.rs:39:43 clippy::redundant_closure_for_method_calls "redundant closure"
-target/lintcheck/sources/cargo-0.49.0/src/bin/cargo/commands/owner.rs:40:43 clippy::redundant_closure_for_method_calls "redundant closure"
-target/lintcheck/sources/cargo-0.49.0/src/bin/cargo/commands/owner.rs:43:30 clippy::redundant_closure_for_method_calls "redundant closure"
-target/lintcheck/sources/cargo-0.49.0/src/bin/cargo/commands/owner.rs:46:30 clippy::redundant_closure_for_method_calls "redundant closure"
-target/lintcheck/sources/cargo-0.49.0/src/bin/cargo/commands/package.rs:1:5 clippy::wildcard_imports "usage of wildcard import"
-target/lintcheck/sources/cargo-0.49.0/src/bin/cargo/commands/pkgid.rs:1:5 clippy::wildcard_imports "usage of wildcard import"
-target/lintcheck/sources/cargo-0.49.0/src/bin/cargo/commands/publish.rs:1:5 clippy::wildcard_imports "usage of wildcard import"
-target/lintcheck/sources/cargo-0.49.0/src/bin/cargo/commands/publish.rs:40:47 clippy::redundant_closure_for_method_calls "redundant closure"
-target/lintcheck/sources/cargo-0.49.0/src/bin/cargo/commands/read_manifest.rs:1:5 clippy::wildcard_imports "usage of wildcard import"
-target/lintcheck/sources/cargo-0.49.0/src/bin/cargo/commands/run.rs:1:5 clippy::wildcard_imports "usage of wildcard import"
-target/lintcheck/sources/cargo-0.49.0/src/bin/cargo/commands/rustc.rs:1:5 clippy::wildcard_imports "usage of wildcard import"
-target/lintcheck/sources/cargo-0.49.0/src/bin/cargo/commands/rustdoc.rs:3:5 clippy::wildcard_imports "usage of wildcard import"
-target/lintcheck/sources/cargo-0.49.0/src/bin/cargo/commands/search.rs:1:5 clippy::wildcard_imports "usage of wildcard import"
-target/lintcheck/sources/cargo-0.49.0/src/bin/cargo/commands/test.rs:127:54 clippy::redundant_closure_for_method_calls "redundant closure"
-target/lintcheck/sources/cargo-0.49.0/src/bin/cargo/commands/test.rs:1:5 clippy::wildcard_imports "usage of wildcard import"
-target/lintcheck/sources/cargo-0.49.0/src/bin/cargo/commands/tree.rs:149:49 clippy::redundant_closure_for_method_calls "redundant closure"
-target/lintcheck/sources/cargo-0.49.0/src/bin/cargo/commands/tree.rs:2:5 clippy::wildcard_imports "usage of wildcard import"
-target/lintcheck/sources/cargo-0.49.0/src/bin/cargo/commands/uninstall.rs:1:5 clippy::wildcard_imports "usage of wildcard import"
-target/lintcheck/sources/cargo-0.49.0/src/bin/cargo/commands/update.rs:1:5 clippy::wildcard_imports "usage of wildcard import"
-target/lintcheck/sources/cargo-0.49.0/src/bin/cargo/commands/vendor.rs:1:5 clippy::wildcard_imports "usage of wildcard import"
-target/lintcheck/sources/cargo-0.49.0/src/bin/cargo/commands/vendor.rs:96:16 clippy::map_unwrap_or "called `map(<f>).unwrap_or_else(<g>)` on an `Option` value. This can be done more directly by calling `map_or_else(<g>, <f>)` instead"
-target/lintcheck/sources/cargo-0.49.0/src/bin/cargo/commands/verify_project.rs:1:5 clippy::wildcard_imports "usage of wildcard import"
-target/lintcheck/sources/cargo-0.49.0/src/bin/cargo/commands/version.rs:2:5 clippy::wildcard_imports "usage of wildcard import"
-target/lintcheck/sources/cargo-0.49.0/src/bin/cargo/commands/yank.rs:1:5 clippy::wildcard_imports "usage of wildcard import"
-target/lintcheck/sources/cargo-0.49.0/src/bin/cargo/commands/yank.rs:32:36 clippy::redundant_closure_for_method_calls "redundant closure"
-target/lintcheck/sources/cargo-0.49.0/src/bin/cargo/commands/yank.rs:33:35 clippy::redundant_closure_for_method_calls "redundant closure"
-target/lintcheck/sources/cargo-0.49.0/src/bin/cargo/commands/yank.rs:34:36 clippy::redundant_closure_for_method_calls "redundant closure"
-target/lintcheck/sources/cargo-0.49.0/src/bin/cargo/commands/yank.rs:35:36 clippy::redundant_closure_for_method_calls "redundant closure"
-target/lintcheck/sources/cargo-0.49.0/src/bin/cargo/main.rs:118:41 clippy::redundant_closure_for_method_calls "redundant closure"
-target/lintcheck/sources/cargo-0.49.0/src/bin/cargo/main.rs:137:43 clippy::redundant_closure_for_method_calls "redundant closure"
-target/lintcheck/sources/cargo-0.49.0/src/bin/cargo/main.rs:148:19 clippy::single_match_else "you seem to be trying to use `match` for destructuring a single pattern. Consider using `if let`"
-target/lintcheck/sources/cargo-0.49.0/src/bin/cargo/main.rs:174:57 clippy::redundant_closure_for_method_calls "redundant closure"
-target/lintcheck/sources/cargo-0.49.0/src/bin/cargo/main.rs:18:5 clippy::wildcard_imports "usage of wildcard import"
-target/lintcheck/sources/cargo-0.49.0/src/bin/cargo/main.rs:1:null clippy::cargo_common_metadata "package `cargo` is missing `package.categories` metadata"
-target/lintcheck/sources/cargo-0.49.0/src/bin/cargo/main.rs:1:null clippy::cargo_common_metadata "package `cargo` is missing `package.keywords` metadata"
-target/lintcheck/sources/cargo-0.49.0/src/bin/cargo/main.rs:1:null clippy::multiple_crate_versions "multiple versions for dependency `crossbeam-utils`: 0.6.6, 0.7.2"
-target/lintcheck/sources/cargo-0.49.0/src/bin/cargo/main.rs:1:null clippy::multiple_crate_versions "multiple versions for dependency `hex`: 0.3.2, 0.4.0"
-target/lintcheck/sources/cargo-0.49.0/src/bin/cargo/main.rs:1:null clippy::multiple_crate_versions "multiple versions for dependency `humantime`: 1.3.0, 2.0.0"
-target/lintcheck/sources/cargo-0.49.0/src/bin/cargo/main.rs:72:22 clippy::redundant_closure_for_method_calls "redundant closure"
-target/lintcheck/sources/cargo-0.49.0/src/bin/cargo/main.rs:79:40 clippy::manual_map "manual implementation of `Option::map`"
-target/lintcheck/sources/cargo-0.49.0/src/bin/cargo/main.rs:98:60 clippy::redundant_closure_for_method_calls "redundant closure"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/core/compiler/build_config.rs:155:13 clippy::enum_glob_use "usage of wildcard import for enum variants"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/core/compiler/build_config.rs:170:5 clippy::must_use_candidate "this method could have a `#[must_use]` attribute"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/core/compiler/build_config.rs:175:5 clippy::must_use_candidate "this method could have a `#[must_use]` attribute"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/core/compiler/build_config.rs:180:5 clippy::must_use_candidate "this method could have a `#[must_use]` attribute"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/core/compiler/build_config.rs:186:5 clippy::must_use_candidate "this method could have a `#[must_use]` attribute"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/core/compiler/build_config.rs:197:5 clippy::must_use_candidate "this method could have a `#[must_use]` attribute"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/core/compiler/build_config.rs:205:5 clippy::must_use_candidate "this method could have a `#[must_use]` attribute"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/core/compiler/build_config.rs:51:5 clippy::missing_errors_doc "docs for function returning `Result` missing `# Errors` section"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/core/compiler/build_config.rs:69:48 clippy::cast_possible_truncation "casting `usize` to `u32` may truncate the value on targets with 64-bit wide pointers"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/core/compiler/build_config.rs:96:5 clippy::missing_errors_doc "docs for function returning `Result` missing `# Errors` section"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/core/compiler/build_context/mod.rs:44:5 clippy::missing_errors_doc "docs for function returning `Result` missing `# Errors` section"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/core/compiler/build_context/mod.rs:83:20 clippy::doc_markdown "you should put `x86_64` between ticks in the documentation"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/core/compiler/build_context/target_info.rs:108:5 clippy::must_use_candidate "this method could have a `#[must_use]` attribute"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/core/compiler/build_context/target_info.rs:121:5 clippy::missing_errors_doc "docs for function returning `Result` missing `# Errors` section"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/core/compiler/build_context/target_info.rs:149:9 clippy::items_after_statements "adding items after statements is confusing, since items exist from the start of the scope"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/core/compiler/build_context/target_info.rs:411:9 clippy::needless_question_mark "question mark operator is useless here"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/core/compiler/build_context/target_info.rs:420:69 clippy::doc_markdown "you should put `mode/target_kind` between ticks in the documentation"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/core/compiler/build_context/target_info.rs:423:19 clippy::doc_markdown "you should put `CrateTypes` between ticks in the documentation"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/core/compiler/build_context/target_info.rs:424:5 clippy::missing_errors_doc "docs for function returning `Result` missing `# Errors` section"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/core/compiler/build_context/target_info.rs:469:58 clippy::redundant_closure_for_method_calls "redundant closure"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/core/compiler/build_context/target_info.rs:603:19 clippy::redundant_closure_for_method_calls "redundant closure"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/core/compiler/build_context/target_info.rs:665:5 clippy::missing_errors_doc "docs for function returning `Result` missing `# Errors` section"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/core/compiler/build_context/target_info.rs:697:12 clippy::inconsistent_struct_constructor "struct constructor field order is inconsistent with struct definition field order"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/core/compiler/build_context/target_info.rs:82:31 clippy::doc_markdown "you should put `FileType` between ticks in the documentation"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/core/compiler/build_context/target_info.rs:83:5 clippy::must_use_candidate "this method could have a `#[must_use]` attribute"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/core/compiler/build_context/target_info.rs:84:9 clippy::single_match_else "you seem to be trying to use `match` for destructuring a single pattern. Consider using `if let`"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/core/compiler/build_context/target_info.rs:96:31 clippy::doc_markdown "you should put `FileType` between ticks in the documentation"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/core/compiler/build_context/target_info.rs:98:5 clippy::must_use_candidate "this method could have a `#[must_use]` attribute"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/core/compiler/build_plan.rs:4:9 clippy::doc_markdown "you should put `BuildPlan` between ticks in the documentation"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/core/compiler/build_plan.rs:5:66 clippy::doc_markdown "you should put `BuildPlan` between ticks in the documentation"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/core/compiler/build_plan.rs:66:40 clippy::ptr_arg "writing `&PathBuf` instead of `&Path` involves a new object where a slice will do"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/core/compiler/compilation.rs:150:5 clippy::missing_errors_doc "docs for function returning `Result` missing `# Errors` section"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/core/compiler/compilation.rs:150:5 clippy::missing_panics_doc "docs for function which may panic missing `# Panics` section"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/core/compiler/compilation.rs:169:5 clippy::missing_errors_doc "docs for function returning `Result` missing `# Errors` section"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/core/compiler/compilation.rs:185:5 clippy::missing_errors_doc "docs for function returning `Result` missing `# Errors` section"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/core/compiler/compilation.rs:193:5 clippy::must_use_candidate "this method could have a `#[must_use]` attribute"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/core/compiler/compilation.rs:194:49 clippy::redundant_closure_for_method_calls "redundant closure"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/core/compiler/compilation.rs:198:5 clippy::missing_errors_doc "docs for function returning `Result` missing `# Errors` section"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/core/compiler/compilation.rs:314:16 clippy::doc_markdown "you should put `rustc_tool` between ticks in the documentation"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/core/compiler/compilation.rs:91:5 clippy::missing_errors_doc "docs for function returning `Result` missing `# Errors` section"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/core/compiler/compile_kind.rs:118:5 clippy::missing_errors_doc "docs for function returning `Result` missing `# Errors` section"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/core/compiler/compile_kind.rs:123:18 clippy::case_sensitive_file_extension_comparisons "case-sensitive file extension comparison"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/core/compiler/compile_kind.rs:147:5 clippy::must_use_candidate "this method could have a `#[must_use]` attribute"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/core/compiler/compile_kind.rs:157:5 clippy::missing_panics_doc "docs for function which may panic missing `# Panics` section"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/core/compiler/compile_kind.rs:157:5 clippy::must_use_candidate "this method could have a `#[must_use]` attribute"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/core/compiler/compile_kind.rs:29:5 clippy::must_use_candidate "this method could have a `#[must_use]` attribute"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/core/compiler/compile_kind.rs:33:5 clippy::must_use_candidate "this method could have a `#[must_use]` attribute"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/core/compiler/compile_kind.rs:49:5 clippy::missing_errors_doc "docs for function returning `Result` missing `# Errors` section"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/core/compiler/compile_kind.rs:69:48 clippy::case_sensitive_file_extension_comparisons "case-sensitive file extension comparison"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/core/compiler/context/compilation_files.rs:204:9 clippy::single_match_else "you seem to be trying to use `match` for destructuring a single pattern. Consider using `if let`"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/core/compiler/context/compilation_files.rs:277:22 clippy::doc_markdown "you should put `OUT_DIR` between ticks in the documentation"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/core/compiler/context/compilation_files.rs:324:66 clippy::doc_markdown "you should put `FileType` between ticks in the documentation"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/core/compiler/context/compilation_files.rs:393:37 clippy::match_same_arms "this `match` has identical arm bodies"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/core/compiler/context/compilation_files.rs:426:71 clippy::redundant_closure_for_method_calls "redundant closure"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/core/compiler/context/mod.rs:125:5 clippy::missing_errors_doc "docs for function returning `Result` missing `# Errors` section"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/core/compiler/context/mod.rs:125:5 clippy::missing_panics_doc "docs for function which may panic missing `# Panics` section"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/core/compiler/context/mod.rs:125:5 clippy::too_many_lines "this function has too many lines (107/100)"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/core/compiler/context/mod.rs:270:5 clippy::missing_errors_doc "docs for function returning `Result` missing `# Errors` section"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/core/compiler/context/mod.rs:286:5 clippy::missing_errors_doc "docs for function returning `Result` missing `# Errors` section"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/core/compiler/context/mod.rs:308:5 clippy::missing_errors_doc "docs for function returning `Result` missing `# Errors` section"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/core/compiler/context/mod.rs:308:5 clippy::missing_panics_doc "docs for function which may panic missing `# Panics` section"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/core/compiler/context/mod.rs:340:5 clippy::missing_panics_doc "docs for function which may panic missing `# Panics` section"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/core/compiler/context/mod.rs:340:5 clippy::must_use_candidate "this method could have a `#[must_use]` attribute"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/core/compiler/context/mod.rs:349:5 clippy::missing_errors_doc "docs for function returning `Result` missing `# Errors` section"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/core/compiler/context/mod.rs:349:5 clippy::missing_panics_doc "docs for function which may panic missing `# Panics` section"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/core/compiler/context/mod.rs:354:5 clippy::must_use_candidate "this method could have a `#[must_use]` attribute"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/core/compiler/context/mod.rs:358:21 clippy::doc_markdown "you should put `RunCustomBuild` between ticks in the documentation"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/core/compiler/context/mod.rs:361:5 clippy::must_use_candidate "this method could have a `#[must_use]` attribute"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/core/compiler/context/mod.rs:374:43 clippy::doc_markdown "you should put `RunCustomBuild` between ticks in the documentation"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/core/compiler/context/mod.rs:378:5 clippy::must_use_candidate "this method could have a `#[must_use]` attribute"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/core/compiler/context/mod.rs:383:41 clippy::doc_markdown "you should put `RunCustomBuild` between ticks in the documentation"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/core/compiler/context/mod.rs:384:5 clippy::must_use_candidate "this method could have a `#[must_use]` attribute"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/core/compiler/context/mod.rs:391:5 clippy::must_use_candidate "this method could have a `#[must_use]` attribute"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/core/compiler/context/mod.rs:397:5 clippy::missing_errors_doc "docs for function returning `Result` missing `# Errors` section"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/core/compiler/context/mod.rs:523:5 clippy::must_use_candidate "this method could have a `#[must_use]` attribute"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/core/compiler/context/mod.rs:538:5 clippy::must_use_candidate "this method could have a `#[must_use]` attribute"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/core/compiler/context/mod.rs:542:5 clippy::missing_errors_doc "docs for function returning `Result` missing `# Errors` section"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/core/compiler/context/mod.rs:83:5 clippy::missing_errors_doc "docs for function returning `Result` missing `# Errors` section"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/core/compiler/context/mod.rs:92:25 clippy::single_match_else "you seem to be trying to use `match` for destructuring a single pattern. Consider using `if let`"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/core/compiler/crate_type.rs:16:5 clippy::must_use_candidate "this method could have a `#[must_use]` attribute"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/core/compiler/crate_type.rs:29:5 clippy::must_use_candidate "this method could have a `#[must_use]` attribute"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/core/compiler/crate_type.rs:40:5 clippy::must_use_candidate "this method could have a `#[must_use]` attribute"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/core/compiler/crate_type.rs:49:5 clippy::must_use_candidate "this method could have a `#[must_use]` attribute"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/core/compiler/crate_type.rs:60:5 clippy::must_use_candidate "this method could have a `#[must_use]` attribute"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/core/compiler/custom_build.rs:150:1 clippy::too_many_lines "this function has too many lines (230/100)"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/core/compiler/custom_build.rs:353:56 clippy::manual_strip "stripping a prefix manually"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/core/compiler/custom_build.rs:448:27 clippy::needless_pass_by_value "this argument is passed by value, but not consumed in the function body"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/core/compiler/custom_build.rs:464:5 clippy::missing_errors_doc "docs for function returning `Result` missing `# Errors` section"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/core/compiler/custom_build.rs:481:5 clippy::missing_errors_doc "docs for function returning `Result` missing `# Errors` section"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/core/compiler/custom_build.rs:481:5 clippy::missing_panics_doc "docs for function which may panic missing `# Panics` section"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/core/compiler/custom_build.rs:48:56 clippy::doc_markdown "you should put `RunCustomBuild` between ticks in the documentation"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/core/compiler/custom_build.rs:561:5 clippy::missing_errors_doc "docs for function returning `Result` missing `# Errors` section"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/core/compiler/custom_build.rs:567:20 clippy::redundant_closure_for_method_calls "redundant closure"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/core/compiler/custom_build.rs:576:28 clippy::shadow_unrelated "`mut value` is being shadowed"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/core/compiler/custom_build.rs:606:5 clippy::missing_errors_doc "docs for function returning `Result` missing `# Errors` section"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/core/compiler/custom_build.rs:688:5 clippy::items_after_statements "adding items after statements is confusing, since items exist from the start of the scope"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/core/compiler/custom_build.rs:756:5 clippy::items_after_statements "adding items after statements is confusing, since items exist from the start of the scope"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/core/compiler/custom_build.rs:762:5 clippy::items_after_statements "adding items after statements is confusing, since items exist from the start of the scope"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/core/compiler/custom_build.rs:762:5 clippy::unnecessary_wraps "this function's return value is unnecessary"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/core/compiler/custom_build.rs:823:5 clippy::must_use_candidate "this method could have a `#[must_use]` attribute"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/core/compiler/fingerprint.rs:1021:51 clippy::redundant_closure_for_method_calls "redundant closure"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/core/compiler/fingerprint.rs:1656:16 clippy::single_match_else "you seem to be trying to use `match` for destructuring a single pattern. Consider using `if let`"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/core/compiler/fingerprint.rs:1664:5 clippy::field_reassign_with_default "field assignment outside of initializer for an instance created with Default::default()"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/core/compiler/fingerprint.rs:1787:5 clippy::similar_names "binding's name is too similar to existing binding"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/core/compiler/fingerprint.rs:1795:5 clippy::field_reassign_with_default "field assignment outside of initializer for an instance created with Default::default()"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/core/compiler/fingerprint.rs:1882:17 clippy::similar_names "binding's name is too similar to existing binding"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/core/compiler/fingerprint.rs:1894:17 clippy::similar_names "binding's name is too similar to existing binding"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/core/compiler/fingerprint.rs:1906:9 clippy::items_after_statements "adding items after statements is confusing, since items exist from the start of the scope"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/core/compiler/fingerprint.rs:1917:9 clippy::items_after_statements "adding items after statements is confusing, since items exist from the start of the scope"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/core/compiler/fingerprint.rs:1923:9 clippy::items_after_statements "adding items after statements is confusing, since items exist from the start of the scope"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/core/compiler/fingerprint.rs:1956:9 clippy::items_after_statements "adding items after statements is confusing, since items exist from the start of the scope"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/core/compiler/fingerprint.rs:1962:9 clippy::items_after_statements "adding items after statements is confusing, since items exist from the start of the scope"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/core/compiler/fingerprint.rs:1963:22 clippy::cast_possible_truncation "casting `usize` to `u8` may truncate the value"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/core/compiler/fingerprint.rs:1964:22 clippy::cast_possible_truncation "casting `usize` to `u8` may truncate the value"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/core/compiler/fingerprint.rs:1965:22 clippy::cast_possible_truncation "casting `usize` to `u8` may truncate the value"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/core/compiler/fingerprint.rs:1966:22 clippy::cast_possible_truncation "casting `usize` to `u8` may truncate the value"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/core/compiler/fingerprint.rs:1980:17 clippy::similar_names "binding's name is too similar to existing binding"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/core/compiler/fingerprint.rs:1980:24 clippy::manual_strip "stripping a prefix manually"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/core/compiler/fingerprint.rs:1986:17 clippy::similar_names "binding's name is too similar to existing binding"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/core/compiler/fingerprint.rs:2016:5 clippy::items_after_statements "adding items after statements is confusing, since items exist from the start of the scope"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/core/compiler/fingerprint.rs:61:5 clippy::doc_markdown "you should put `CompileMode` between ticks in the documentation"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/core/compiler/fingerprint.rs:63:12 clippy::doc_markdown "you should put `CompileKind` between ticks in the documentation"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/core/compiler/fingerprint.rs:67:7 clippy::doc_markdown "you should put `CARGO_DEFAULT_LIB_METADATA[^4` between ticks in the documentation"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/core/compiler/fingerprint.rs:68:5 clippy::doc_markdown "you should put `package_id` between ticks in the documentation"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/core/compiler/fingerprint.rs:71:19 clippy::doc_markdown "you should put `test/bench/for_host/edition` between ticks in the documentation"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/core/compiler/fingerprint.rs:755:52 clippy::match_same_arms "this `match` has identical arm bodies"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/core/compiler/fingerprint.rs:77:5 clippy::doc_markdown "you should put `is_std` between ticks in the documentation"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/core/compiler/fingerprint.rs:816:5 clippy::too_many_lines "this function has too many lines (127/100)"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/core/compiler/fingerprint.rs:863:64 clippy::similar_names "binding's name is too similar to existing binding"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/core/compiler/fingerprint.rs:875:33 clippy::similar_names "binding's name is too similar to existing binding"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/core/compiler/fingerprint.rs:876:32 clippy::similar_names "binding's name is too similar to existing binding"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/core/compiler/fingerprint.rs:896:30 clippy::similar_names "binding's name is too similar to existing binding"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/core/compiler/fingerprint.rs:897:30 clippy::similar_names "binding's name is too similar to existing binding"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/core/compiler/fingerprint.rs:991:37 clippy::single_match_else "you seem to be trying to use `match` for destructuring a single pattern. Consider using `if let`"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/core/compiler/job_queue.rs:12:5 clippy::doc_markdown "you should put `src/librustc_jobserver/lib.rs` between ticks in the documentation"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/core/compiler/job_queue.rs:329:13 clippy::items_after_statements "adding items after statements is confusing, since items exist from the start of the scope"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/core/compiler/job_queue.rs:332:23 clippy::needless_pass_by_value "this argument is passed by value, but not consumed in the function body"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/core/compiler/job_queue.rs:34:53 clippy::doc_markdown "you should put `NeedsToken` between ticks in the documentation"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/core/compiler/job_queue.rs:35:6 clippy::doc_markdown "you should put `ReleaseToken` between ticks in the documentation"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/core/compiler/job_queue.rs:37:6 clippy::doc_markdown "you should put `NeedsToken` between ticks in the documentation"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/core/compiler/job_queue.rs:40:5 clippy::doc_markdown "you should put `NeedsToken` between ticks in the documentation"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/core/compiler/job_queue.rs:40:56 clippy::doc_markdown "you should put `NeedsToken` between ticks in the documentation"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/core/compiler/job_queue.rs:43:6 clippy::doc_markdown "you should put `ReleaseToken` between ticks in the documentation"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/core/compiler/job_queue.rs:748:16 clippy::collapsible_else_if "this `else { if .. }` block can be collapsed"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/core/compiler/job_queue.rs:749:13 clippy::if_not_else "unnecessary boolean `not` operation"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/core/compiler/job_queue.rs:786:26 clippy::unused_self "unused `self` argument"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/core/compiler/job_queue.rs:81:61 clippy::doc_markdown "you should put `DrainState` between ticks in the documentation"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/core/compiler/job_queue.rs:865:13 clippy::items_after_statements "adding items after statements is confusing, since items exist from the start of the scope"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/core/compiler/job_queue.rs:871:13 clippy::items_after_statements "adding items after statements is confusing, since items exist from the start of the scope"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/core/compiler/job_queue.rs:890:9 clippy::unused_self "unused `self` argument"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/core/compiler/job_queue.rs:93:24 clippy::doc_markdown "you should put `JobQueue` between ticks in the documentation"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/core/compiler/links.rs:8:1 clippy::module_name_repetitions "item name ends with its containing module's name"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/core/compiler/lto.rs:130:13 clippy::unnested_or_patterns "unnested or-patterns"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/core/compiler/lto.rs:135:13 clippy::unnested_or_patterns "unnested or-patterns"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/core/compiler/mod.rs:1016:1 clippy::missing_errors_doc "docs for function returning `Result` missing `# Errors` section"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/core/compiler/mod.rs:1094:19 clippy::redundant_closure_for_method_calls "redundant closure"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/core/compiler/mod.rs:1131:1 clippy::unnecessary_wraps "this function's return value is unnecessary"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/core/compiler/mod.rs:1268:34 clippy::case_sensitive_file_extension_comparisons "case-sensitive file extension comparison"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/core/compiler/mod.rs:1277:5 clippy::items_after_statements "adding items after statements is confusing, since items exist from the start of the scope"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/core/compiler/mod.rs:179:1 clippy::too_many_lines "this function has too many lines (162/100)"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/core/compiler/mod.rs:198:78 clippy::redundant_closure_for_method_calls "redundant closure"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/core/compiler/mod.rs:201:25 clippy::single_match_else "you seem to be trying to use `match` for destructuring a single pattern. Consider using `if let`"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/core/compiler/mod.rs:267:9 clippy::items_after_statements "adding items after statements is confusing, since items exist from the start of the scope"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/core/compiler/mod.rs:324:5 clippy::items_after_statements "adding items after statements is confusing, since items exist from the start of the scope"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/core/compiler/mod.rs:364:5 clippy::items_after_statements "adding items after statements is confusing, since items exist from the start of the scope"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/core/compiler/mod.rs:364:5 clippy::unnecessary_wraps "this function's return value is unnecessary"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/core/compiler/mod.rs:392:45 clippy::redundant_closure_for_method_calls "redundant closure"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/core/compiler/mod.rs:415:23 clippy::single_match_else "you seem to be trying to use `match` for destructuring a single pattern. Consider using `if let`"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/core/compiler/mod.rs:464:18 clippy::ptr_arg "writing `&PathBuf` instead of `&Path` involves a new object where a slice will do"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/core/compiler/mod.rs:488:61 clippy::ptr_arg "writing `&PathBuf` instead of `&Path` involves a new object where a slice will do"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/core/compiler/mod.rs:498:21 clippy::unnested_or_patterns "unnested or-patterns"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/core/compiler/mod.rs:654:46 clippy::implicit_clone "implicitly cloning a `PathBuf` by calling `to_path_buf` on its dereferenced type"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/core/compiler/mod.rs:667:15 clippy::similar_names "binding's name is too similar to existing binding"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/core/compiler/mod.rs:693:1 clippy::unnecessary_wraps "this function's return value is unnecessary"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/core/compiler/mod.rs:725:42 clippy::match_same_arms "this `match` has identical arm bodies"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/core/compiler/mod.rs:736:1 clippy::too_many_lines "this function has too many lines (141/100)"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/core/compiler/mod.rs:73:5 clippy::missing_errors_doc "docs for function returning `Result` missing `# Errors` section"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/core/compiler/mod.rs:777:12 clippy::if_not_else "unnecessary boolean `not` operation"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/core/compiler/mod.rs:873:5 clippy::items_after_statements "adding items after statements is confusing, since items exist from the start of the scope"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/core/compiler/rustdoc.rs:16:1 clippy::module_name_repetitions "item name starts with its containing module's name"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/core/compiler/rustdoc.rs:57:1 clippy::module_name_repetitions "item name starts with its containing module's name"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/core/compiler/rustdoc.rs:72:1 clippy::missing_errors_doc "docs for function returning `Result` missing `# Errors` section"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/core/compiler/standard_lib.rs:134:1 clippy::missing_errors_doc "docs for function returning `Result` missing `# Errors` section"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/core/compiler/standard_lib.rs:16:1 clippy::must_use_candidate "this function could have a `#[must_use]` attribute"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/core/compiler/standard_lib.rs:30:28 clippy::redundant_closure_for_method_calls "redundant closure"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/core/compiler/standard_lib.rs:34:1 clippy::missing_errors_doc "docs for function returning `Result` missing `# Errors` section"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/core/compiler/standard_lib.rs:34:1 clippy::missing_panics_doc "docs for function which may panic missing `# Panics` section"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/core/compiler/timings.rs:16:1 clippy::struct_excessive_bools "more than 3 bools in a struct"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/core/compiler/timings.rs:192:64 clippy::needless_pass_by_value "this argument is passed by value, but not consumed in the function body"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/core/compiler/timings.rs:212:58 clippy::needless_pass_by_value "this argument is passed by value, but not consumed in the function body"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/core/compiler/timings.rs:234:13 clippy::let_underscore_drop "non-binding `let` on a type that implements `Drop`"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/core/compiler/timings.rs:355:13 clippy::cast_possible_truncation "casting `f64` to `u32` may truncate the value"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/core/compiler/timings.rs:355:13 clippy::cast_sign_loss "casting `f64` to `u32` may lose the sign of the value"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/core/compiler/timings.rs:397:38 clippy::cast_possible_truncation "casting `f64` to `u32` may truncate the value"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/core/compiler/timings.rs:397:38 clippy::cast_sign_loss "casting `f64` to `u32` may lose the sign of the value"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/core/compiler/timings.rs:484:9 clippy::items_after_statements "adding items after statements is confusing, since items exist from the start of the scope"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/core/compiler/timings.rs:605:38 clippy::doc_markdown "you should put `rmeta_time` between ticks in the documentation"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/core/compiler/timings.rs:605:50 clippy::doc_markdown "you should put `codegen_time` between ticks in the documentation"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/core/compiler/timings.rs:641:26 clippy::non_ascii_literal "literal non-ASCII character detected"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/core/compiler/unit.rs:100:5 clippy::must_use_candidate "this method could have a `#[must_use]` attribute"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/core/compiler/unit.rs:151:1 clippy::module_name_repetitions "item name starts with its containing module's name"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/core/compiler/unit.rs:161:5 clippy::must_use_candidate "this method could have a `#[must_use]` attribute"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/core/compiler/unit.rs:35:1 clippy::module_name_repetitions "item name starts with its containing module's name"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/core/compiler/unit_dependencies.rs:154:29 clippy::doc_markdown "you should put `state.unit_dependencies` between ticks in the documentation"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/core/compiler/unit_dependencies.rs:213:1 clippy::too_many_lines "this function has too many lines (110/100)"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/core/compiler/unit_dependencies.rs:52:1 clippy::missing_errors_doc "docs for function returning `Result` missing `# Errors` section"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/core/compiler/unit_dependencies.rs:52:1 clippy::module_name_repetitions "item name ends with its containing module's name"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/core/compiler/unit_graph.rs:65:1 clippy::missing_errors_doc "docs for function returning `Result` missing `# Errors` section"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/core/compiler/unit_graph.rs:65:1 clippy::module_name_repetitions "item name ends with its containing module's name"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/core/dependency.rs:157:5 clippy::missing_errors_doc "docs for function returning `Result` missing `# Errors` section"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/core/dependency.rs:182:5 clippy::missing_errors_doc "docs for function returning `Result` missing `# Errors` section"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/core/dependency.rs:203:5 clippy::must_use_candidate "this method could have a `#[must_use]` attribute"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/core/dependency.rs:224:5 clippy::must_use_candidate "this method could have a `#[must_use]` attribute"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/core/dependency.rs:23:1 clippy::struct_excessive_bools "more than 3 bools in a struct"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/core/dependency.rs:248:5 clippy::must_use_candidate "this method could have a `#[must_use]` attribute"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/core/dependency.rs:270:5 clippy::must_use_candidate "this method could have a `#[must_use]` attribute"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/core/dependency.rs:274:5 clippy::must_use_candidate "this method could have a `#[must_use]` attribute"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/core/dependency.rs:278:5 clippy::must_use_candidate "this method could have a `#[must_use]` attribute"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/core/dependency.rs:287:5 clippy::must_use_candidate "this method could have a `#[must_use]` attribute"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/core/dependency.rs:291:5 clippy::must_use_candidate "this method could have a `#[must_use]` attribute"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/core/dependency.rs:305:5 clippy::must_use_candidate "this method could have a `#[must_use]` attribute"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/core/dependency.rs:311:5 clippy::must_use_candidate "this method could have a `#[must_use]` attribute"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/core/dependency.rs:319:5 clippy::must_use_candidate "this method could have a `#[must_use]` attribute"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/core/dependency.rs:337:75 clippy::redundant_closure_for_method_calls "redundant closure"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/core/dependency.rs:397:56 clippy::redundant_closure_for_method_calls "redundant closure"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/core/dependency.rs:403:5 clippy::must_use_candidate "this method could have a `#[must_use]` attribute"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/core/dependency.rs:408:5 clippy::must_use_candidate "this method could have a `#[must_use]` attribute"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/core/dependency.rs:415:5 clippy::must_use_candidate "this method could have a `#[must_use]` attribute"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/core/dependency.rs:419:5 clippy::must_use_candidate "this method could have a `#[must_use]` attribute"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/core/dependency.rs:424:5 clippy::must_use_candidate "this method could have a `#[must_use]` attribute"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/core/dependency.rs:428:5 clippy::must_use_candidate "this method could have a `#[must_use]` attribute"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/core/dependency.rs:433:5 clippy::must_use_candidate "this method could have a `#[must_use]` attribute"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/core/dependency.rs:438:5 clippy::must_use_candidate "this method could have a `#[must_use]` attribute"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/core/dependency.rs:443:5 clippy::must_use_candidate "this method could have a `#[must_use]` attribute"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/core/dependency.rs:449:5 clippy::must_use_candidate "this method could have a `#[must_use]` attribute"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/core/dependency.rs:450:9 clippy::if_not_else "unnecessary `!=` operation"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/core/features.rs:119:17 clippy::must_use_candidate "this method could have a `#[must_use]` attribute"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/core/features.rs:229:5 clippy::missing_errors_doc "docs for function returning `Result` missing `# Errors` section"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/core/features.rs:274:5 clippy::must_use_candidate "this method could have a `#[must_use]` attribute"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/core/features.rs:278:5 clippy::missing_errors_doc "docs for function returning `Result` missing `# Errors` section"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/core/features.rs:306:5 clippy::must_use_candidate "this method could have a `#[must_use]` attribute"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/core/features.rs:338:1 clippy::struct_excessive_bools "more than 3 bools in a struct"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/core/features.rs:362:25 clippy::option_option "consider using `Option<T>` instead of `Option<Option<T>>` or a custom enum if you need to distinguish all 3 cases"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/core/features.rs:380:5 clippy::missing_errors_doc "docs for function returning `Result` missing `# Errors` section"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/core/features.rs:401:9 clippy::items_after_statements "adding items after statements is confusing, since items exist from the start of the scope"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/core/features.rs:409:9 clippy::items_after_statements "adding items after statements is confusing, since items exist from the start of the scope"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/core/features.rs:412:45 clippy::redundant_closure_for_method_calls "redundant closure"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/core/features.rs:416:9 clippy::items_after_statements "adding items after statements is confusing, since items exist from the start of the scope"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/core/features.rs:419:45 clippy::redundant_closure_for_method_calls "redundant closure"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/core/features.rs:424:9 clippy::items_after_statements "adding items after statements is confusing, since items exist from the start of the scope"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/core/features.rs:431:9 clippy::items_after_statements "adding items after statements is confusing, since items exist from the start of the scope"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/core/features.rs:477:5 clippy::missing_errors_doc "docs for function returning `Result` missing `# Errors` section"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/core/features.rs:509:1 clippy::must_use_candidate "this function could have a `#[must_use]` attribute"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/core/features.rs:518:5 clippy::map_unwrap_or "called `map(<f>).unwrap_or_else(<g>)` on an `Option` value. This can be done more directly by calling `map_or_else(<g>, <f>)` instead"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/core/features.rs:542:1 clippy::must_use_candidate "this function could have a `#[must_use]` attribute"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/core/features.rs:543:37 clippy::redundant_closure_for_method_calls "redundant closure"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/core/features.rs:547:60 clippy::redundant_closure_for_method_calls "redundant closure"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/core/features.rs:556:1 clippy::module_name_repetitions "item name ends with its containing module's name"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/core/features.rs:563:1 clippy::module_name_repetitions "item name ends with its containing module's name"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/core/manifest.rs:116:13 clippy::enum_glob_use "usage of wildcard import for enum variants"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/core/manifest.rs:118:58 clippy::redundant_closure_for_method_calls "redundant closure"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/core/manifest.rs:130:13 clippy::enum_glob_use "usage of wildcard import for enum variants"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/core/manifest.rs:143:5 clippy::must_use_candidate "this method could have a `#[must_use]` attribute"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/core/manifest.rs:159:5 clippy::must_use_candidate "this method could have a `#[must_use]` attribute"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/core/manifest.rs:162:34 clippy::redundant_closure_for_method_calls "redundant closure"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/core/manifest.rs:169:5 clippy::must_use_candidate "this method could have a `#[must_use]` attribute"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/core/manifest.rs:17:5 clippy::wildcard_imports "usage of wildcard import"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/core/manifest.rs:189:1 clippy::struct_excessive_bools "more than 3 bools in a struct"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/core/manifest.rs:215:5 clippy::must_use_candidate "this method could have a `#[must_use]` attribute"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/core/manifest.rs:222:5 clippy::must_use_candidate "this method could have a `#[must_use]` attribute"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/core/manifest.rs:22:1 clippy::module_name_repetitions "item name ends with its containing module's name"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/core/manifest.rs:320:46 clippy::implicit_clone "implicitly cloning a `PathBuf` by calling `to_path_buf` on its dereferenced type"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/core/manifest.rs:360:5 clippy::must_use_candidate "this method could have a `#[must_use]` attribute"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/core/manifest.rs:407:5 clippy::must_use_candidate "this method could have a `#[must_use]` attribute"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/core/manifest.rs:410:5 clippy::must_use_candidate "this method could have a `#[must_use]` attribute"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/core/manifest.rs:413:5 clippy::must_use_candidate "this method could have a `#[must_use]` attribute"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/core/manifest.rs:416:5 clippy::must_use_candidate "this method could have a `#[must_use]` attribute"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/core/manifest.rs:419:5 clippy::must_use_candidate "this method could have a `#[must_use]` attribute"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/core/manifest.rs:422:5 clippy::must_use_candidate "this method could have a `#[must_use]` attribute"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/core/manifest.rs:425:5 clippy::must_use_candidate "this method could have a `#[must_use]` attribute"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/core/manifest.rs:431:5 clippy::must_use_candidate "this method could have a `#[must_use]` attribute"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/core/manifest.rs:438:5 clippy::must_use_candidate "this method could have a `#[must_use]` attribute"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/core/manifest.rs:444:5 clippy::must_use_candidate "this method could have a `#[must_use]` attribute"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/core/manifest.rs:447:5 clippy::must_use_candidate "this method could have a `#[must_use]` attribute"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/core/manifest.rs:450:5 clippy::must_use_candidate "this method could have a `#[must_use]` attribute"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/core/manifest.rs:453:5 clippy::must_use_candidate "this method could have a `#[must_use]` attribute"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/core/manifest.rs:456:5 clippy::must_use_candidate "this method could have a `#[must_use]` attribute"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/core/manifest.rs:459:5 clippy::must_use_candidate "this method could have a `#[must_use]` attribute"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/core/manifest.rs:462:5 clippy::must_use_candidate "this method could have a `#[must_use]` attribute"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/core/manifest.rs:466:5 clippy::must_use_candidate "this method could have a `#[must_use]` attribute"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/core/manifest.rs:470:5 clippy::must_use_candidate "this method could have a `#[must_use]` attribute"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/core/manifest.rs:477:5 clippy::must_use_candidate "this method could have a `#[must_use]` attribute"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/core/manifest.rs:481:5 clippy::must_use_candidate "this method could have a `#[must_use]` attribute"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/core/manifest.rs:488:5 clippy::missing_errors_doc "docs for function returning `Result` missing `# Errors` section"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/core/manifest.rs:512:5 clippy::must_use_candidate "this method could have a `#[must_use]` attribute"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/core/manifest.rs:516:5 clippy::must_use_candidate "this method could have a `#[must_use]` attribute"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/core/manifest.rs:520:5 clippy::must_use_candidate "this method could have a `#[must_use]` attribute"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/core/manifest.rs:524:5 clippy::must_use_candidate "this method could have a `#[must_use]` attribute"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/core/manifest.rs:528:5 clippy::must_use_candidate "this method could have a `#[must_use]` attribute"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/core/manifest.rs:538:5 clippy::must_use_candidate "this method could have a `#[must_use]` attribute"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/core/manifest.rs:557:5 clippy::must_use_candidate "this method could have a `#[must_use]` attribute"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/core/manifest.rs:561:5 clippy::must_use_candidate "this method could have a `#[must_use]` attribute"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/core/manifest.rs:565:5 clippy::must_use_candidate "this method could have a `#[must_use]` attribute"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/core/manifest.rs:569:5 clippy::must_use_candidate "this method could have a `#[must_use]` attribute"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/core/manifest.rs:577:5 clippy::must_use_candidate "this method could have a `#[must_use]` attribute"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/core/manifest.rs:581:5 clippy::must_use_candidate "this method could have a `#[must_use]` attribute"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/core/manifest.rs:588:5 clippy::must_use_candidate "this method could have a `#[must_use]` attribute"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/core/manifest.rs:617:5 clippy::must_use_candidate "this method could have a `#[must_use]` attribute"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/core/manifest.rs:632:5 clippy::must_use_candidate "this method could have a `#[must_use]` attribute"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/core/manifest.rs:648:5 clippy::must_use_candidate "this method could have a `#[must_use]` attribute"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/core/manifest.rs:659:5 clippy::must_use_candidate "this method could have a `#[must_use]` attribute"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/core/manifest.rs:66:1 clippy::module_name_repetitions "item name ends with its containing module's name"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/core/manifest.rs:670:5 clippy::must_use_candidate "this method could have a `#[must_use]` attribute"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/core/manifest.rs:693:5 clippy::must_use_candidate "this method could have a `#[must_use]` attribute"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/core/manifest.rs:708:5 clippy::must_use_candidate "this method could have a `#[must_use]` attribute"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/core/manifest.rs:723:5 clippy::must_use_candidate "this method could have a `#[must_use]` attribute"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/core/manifest.rs:726:5 clippy::must_use_candidate "this method could have a `#[must_use]` attribute"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/core/manifest.rs:729:5 clippy::must_use_candidate "this method could have a `#[must_use]` attribute"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/core/manifest.rs:735:5 clippy::must_use_candidate "this method could have a `#[must_use]` attribute"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/core/manifest.rs:738:5 clippy::must_use_candidate "this method could have a `#[must_use]` attribute"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/core/manifest.rs:741:5 clippy::must_use_candidate "this method could have a `#[must_use]` attribute"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/core/manifest.rs:744:5 clippy::must_use_candidate "this method could have a `#[must_use]` attribute"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/core/manifest.rs:747:5 clippy::must_use_candidate "this method could have a `#[must_use]` attribute"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/core/manifest.rs:751:5 clippy::must_use_candidate "this method could have a `#[must_use]` attribute"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/core/manifest.rs:754:5 clippy::must_use_candidate "this method could have a `#[must_use]` attribute"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/core/manifest.rs:757:5 clippy::must_use_candidate "this method could have a `#[must_use]` attribute"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/core/manifest.rs:760:5 clippy::must_use_candidate "this method could have a `#[must_use]` attribute"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/core/manifest.rs:763:5 clippy::must_use_candidate "this method could have a `#[must_use]` attribute"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/core/manifest.rs:767:5 clippy::must_use_candidate "this method could have a `#[must_use]` attribute"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/core/manifest.rs:776:5 clippy::must_use_candidate "this method could have a `#[must_use]` attribute"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/core/manifest.rs:780:5 clippy::must_use_candidate "this method could have a `#[must_use]` attribute"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/core/manifest.rs:787:5 clippy::must_use_candidate "this method could have a `#[must_use]` attribute"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/core/manifest.rs:798:5 clippy::must_use_candidate "this method could have a `#[must_use]` attribute"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/core/manifest.rs:800:56 clippy::redundant_closure_for_method_calls "redundant closure"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/core/manifest.rs:805:5 clippy::must_use_candidate "this method could have a `#[must_use]` attribute"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/core/manifest.rs:809:5 clippy::must_use_candidate "this method could have a `#[must_use]` attribute"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/core/manifest.rs:818:5 clippy::must_use_candidate "this method could have a `#[must_use]` attribute"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/core/manifest.rs:823:5 clippy::must_use_candidate "this method could have a `#[must_use]` attribute"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/core/manifest.rs:828:5 clippy::must_use_candidate "this method could have a `#[must_use]` attribute"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/core/manifest.rs:831:5 clippy::must_use_candidate "this method could have a `#[must_use]` attribute"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/core/manifest.rs:834:5 clippy::must_use_candidate "this method could have a `#[must_use]` attribute"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/core/manifest.rs:839:5 clippy::must_use_candidate "this method could have a `#[must_use]` attribute"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/core/manifest.rs:85:1 clippy::module_name_repetitions "item name starts with its containing module's name"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/core/manifest.rs:888:5 clippy::must_use_candidate "this method could have a `#[must_use]` attribute"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/core/manifest.rs:936:5 clippy::must_use_candidate "this method could have a `#[must_use]` attribute"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/core/package.rs:1075:28 clippy::redundant_closure_for_method_calls "redundant closure"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/core/package.rs:160:5 clippy::must_use_candidate "this method could have a `#[must_use]` attribute"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/core/package.rs:170:5 clippy::must_use_candidate "this method could have a `#[must_use]` attribute"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/core/package.rs:174:5 clippy::must_use_candidate "this method could have a `#[must_use]` attribute"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/core/package.rs:182:5 clippy::must_use_candidate "this method could have a `#[must_use]` attribute"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/core/package.rs:186:5 clippy::must_use_candidate "this method could have a `#[must_use]` attribute"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/core/package.rs:190:5 clippy::must_use_candidate "this method could have a `#[must_use]` attribute"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/core/package.rs:194:5 clippy::missing_panics_doc "docs for function which may panic missing `# Panics` section"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/core/package.rs:194:5 clippy::must_use_candidate "this method could have a `#[must_use]` attribute"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/core/package.rs:198:5 clippy::must_use_candidate "this method could have a `#[must_use]` attribute"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/core/package.rs:202:5 clippy::must_use_candidate "this method could have a `#[must_use]` attribute"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/core/package.rs:206:5 clippy::must_use_candidate "this method could have a `#[must_use]` attribute"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/core/package.rs:210:5 clippy::must_use_candidate "this method could have a `#[must_use]` attribute"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/core/package.rs:217:5 clippy::must_use_candidate "this method could have a `#[must_use]` attribute"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/core/package.rs:221:5 clippy::must_use_candidate "this method could have a `#[must_use]` attribute"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/core/package.rs:222:35 clippy::redundant_closure_for_method_calls "redundant closure"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/core/package.rs:226:5 clippy::must_use_candidate "this method could have a `#[must_use]` attribute"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/core/package.rs:227:35 clippy::redundant_closure_for_method_calls "redundant closure"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/core/package.rs:230:5 clippy::must_use_candidate "this method could have a `#[must_use]` attribute"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/core/package.rs:239:5 clippy::missing_errors_doc "docs for function returning `Result` missing `# Errors` section"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/core/package.rs:249:5 clippy::must_use_candidate "this method could have a `#[must_use]` attribute"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/core/package.rs:287:1 clippy::module_name_repetitions "item name starts with its containing module's name"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/core/package.rs:385:5 clippy::missing_errors_doc "docs for function returning `Result` missing `# Errors` section"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/core/package.rs:421:5 clippy::needless_lifetimes "explicit lifetimes given in parameter types where they could be elided (or replaced with `'_` if needed by type declaration)"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/core/package.rs:425:5 clippy::missing_errors_doc "docs for function returning `Result` missing `# Errors` section"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/core/package.rs:452:5 clippy::missing_errors_doc "docs for function returning `Result` missing `# Errors` section"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/core/package.rs:453:60 clippy::redundant_closure_for_method_calls "redundant closure"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/core/package.rs:459:5 clippy::missing_errors_doc "docs for function returning `Result` missing `# Errors` section"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/core/package.rs:473:5 clippy::missing_errors_doc "docs for function returning `Result` missing `# Errors` section"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/core/package.rs:587:5 clippy::missing_errors_doc "docs for function returning `Result` missing `# Errors` section"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/core/package.rs:588:9 clippy::needless_question_mark "question mark operator is useless here"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/core/package.rs:682:46 clippy::cast_possible_truncation "casting `f64` to `u64` may truncate the value"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/core/package.rs:682:46 clippy::cast_sign_loss "casting `f64` to `u64` may lose the sign of the value"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/core/package.rs:682:63 clippy::cast_possible_truncation "casting `f64` to `u64` may truncate the value"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/core/package.rs:682:63 clippy::cast_sign_loss "casting `f64` to `u64` may lose the sign of the value"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/core/package.rs:731:5 clippy::missing_errors_doc "docs for function returning `Result` missing `# Errors` section"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/core/package.rs:790:13 clippy::single_match_else "you seem to be trying to use `match` for destructuring a single pattern. Consider using `if let`"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/core/package.rs:988:9 clippy::single_match_else "you seem to be trying to use `match` for destructuring a single pattern. Consider using `if let`"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/core/package_id.rs:115:5 clippy::missing_errors_doc "docs for function returning `Result` missing `# Errors` section"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/core/package_id.rs:124:5 clippy::missing_panics_doc "docs for function which may panic missing `# Panics` section"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/core/package_id.rs:124:5 clippy::must_use_candidate "this method could have a `#[must_use]` attribute"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/core/package_id.rs:139:5 clippy::must_use_candidate "this method could have a `#[must_use]` attribute"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/core/package_id.rs:142:5 clippy::must_use_candidate "this method could have a `#[must_use]` attribute"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/core/package_id.rs:145:5 clippy::must_use_candidate "this method could have a `#[must_use]` attribute"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/core/package_id.rs:149:5 clippy::must_use_candidate "this method could have a `#[must_use]` attribute"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/core/package_id.rs:157:5 clippy::must_use_candidate "this method could have a `#[must_use]` attribute"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/core/package_id.rs:161:5 clippy::must_use_candidate "this method could have a `#[must_use]` attribute"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/core/package_id.rs:169:5 clippy::must_use_candidate "this method could have a `#[must_use]` attribute"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/core/package_id.rs:174:1 clippy::module_name_repetitions "item name starts with its containing module's name"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/core/package_id_spec.rs:101:39 clippy::redundant_closure_for_method_calls "redundant closure"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/core/package_id_spec.rs:143:5 clippy::must_use_candidate "this method could have a `#[must_use]` attribute"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/core/package_id_spec.rs:147:5 clippy::must_use_candidate "this method could have a `#[must_use]` attribute"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/core/package_id_spec.rs:151:5 clippy::must_use_candidate "this method could have a `#[must_use]` attribute"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/core/package_id_spec.rs:160:5 clippy::must_use_candidate "this method could have a `#[must_use]` attribute"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/core/package_id_spec.rs:179:5 clippy::missing_errors_doc "docs for function returning `Result` missing `# Errors` section"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/core/package_id_spec.rs:212:9 clippy::items_after_statements "adding items after statements is confusing, since items exist from the start of the scope"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/core/package_id_spec.rs:231:9 clippy::single_match_else "you seem to be trying to use `match` for destructuring a single pattern. Consider using `if let`"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/core/package_id_spec.rs:51:5 clippy::missing_errors_doc "docs for function returning `Result` missing `# Errors` section"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/core/package_id_spec.rs:51:5 clippy::missing_panics_doc "docs for function which may panic missing `# Panics` section"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/core/package_id_spec.rs:77:5 clippy::missing_errors_doc "docs for function returning `Result` missing `# Errors` section"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/core/package_id_spec.rs:88:5 clippy::must_use_candidate "this method could have a `#[must_use]` attribute"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/core/profiles.rs:1004:5 clippy::must_use_candidate "this method could have a `#[must_use]` attribute"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/core/profiles.rs:1014:5 clippy::must_use_candidate "this method could have a `#[must_use]` attribute"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/core/profiles.rs:1018:5 clippy::must_use_candidate "this method could have a `#[must_use]` attribute"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/core/profiles.rs:1028:5 clippy::must_use_candidate "this method could have a `#[must_use]` attribute"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/core/profiles.rs:106:9 clippy::items_after_statements "adding items after statements is confusing, since items exist from the start of the scope"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/core/profiles.rs:143:5 clippy::unnecessary_wraps "this function's return value is unnecessary"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/core/profiles.rs:204:54 clippy::implicit_clone "implicitly cloning a `InternedString` by calling `to_owned` on its dereferenced type"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/core/profiles.rs:286:5 clippy::missing_panics_doc "docs for function which may panic missing `# Panics` section"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/core/profiles.rs:286:5 clippy::must_use_candidate "this method could have a `#[must_use]` attribute"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/core/profiles.rs:294:40 clippy::if_not_else "unnecessary boolean `not` operation"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/core/profiles.rs:30:5 clippy::missing_errors_doc "docs for function returning `Result` missing `# Errors` section"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/core/profiles.rs:342:25 clippy::shadow_unrelated "`maker` is being shadowed"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/core/profiles.rs:370:41 clippy::unused_self "unused `self` argument"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/core/profiles.rs:370:5 clippy::must_use_candidate "this method could have a `#[must_use]` attribute"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/core/profiles.rs:372:9 clippy::field_reassign_with_default "field assignment outside of initializer for an instance created with Default::default()"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/core/profiles.rs:382:5 clippy::missing_panics_doc "docs for function which may panic missing `# Panics` section"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/core/profiles.rs:382:5 clippy::must_use_candidate "this method could have a `#[must_use]` attribute"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/core/profiles.rs:383:28 clippy::if_not_else "unnecessary boolean `not` operation"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/core/profiles.rs:397:5 clippy::must_use_candidate "this method could have a `#[must_use]` attribute"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/core/profiles.rs:405:5 clippy::missing_errors_doc "docs for function returning `Result` missing `# Errors` section"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/core/profiles.rs:607:1 clippy::struct_excessive_bools "more than 3 bools in a struct"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/core/profiles.rs:909:5 clippy::must_use_candidate "this method could have a `#[must_use]` attribute"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/core/profiles.rs:923:5 clippy::must_use_candidate "this method could have a `#[must_use]` attribute"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/core/profiles.rs:934:5 clippy::must_use_candidate "this method could have a `#[must_use]` attribute"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/core/profiles.rs:987:5 clippy::must_use_candidate "this method could have a `#[must_use]` attribute"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/core/registry.rs:111:5 clippy::missing_errors_doc "docs for function returning `Result` missing `# Errors` section"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/core/registry.rs:127:5 clippy::missing_errors_doc "docs for function returning `Result` missing `# Errors` section"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/core/registry.rs:168:5 clippy::missing_errors_doc "docs for function returning `Result` missing `# Errors` section"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/core/registry.rs:19:5 clippy::missing_errors_doc "docs for function returning `Result` missing `# Errors` section"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/core/registry.rs:240:5 clippy::missing_errors_doc "docs for function returning `Result` missing `# Errors` section"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/core/registry.rs:26:5 clippy::missing_errors_doc "docs for function returning `Result` missing `# Errors` section"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/core/registry.rs:344:49 clippy::redundant_closure_for_method_calls "redundant closure"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/core/registry.rs:369:5 clippy::must_use_candidate "this method could have a `#[must_use]` attribute"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/core/registry.rs:424:5 clippy::must_use_candidate "this method could have a `#[must_use]` attribute"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/core/registry.rs:49:1 clippy::module_name_repetitions "item name ends with its containing module's name"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/core/registry.rs:520:17 clippy::single_match_else "you seem to be trying to use `match` for destructuring a single pattern. Consider using `if let`"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/core/registry.rs:763:53 clippy::redundant_closure_for_method_calls "redundant closure"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/core/registry.rs:765:53 clippy::redundant_closure_for_method_calls "redundant closure"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/core/registry.rs:807:14 clippy::redundant_closure_for_method_calls "redundant closure"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/core/registry.rs:814:53 clippy::redundant_closure_for_method_calls "redundant closure"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/core/resolver/conflict_cache.rs:197:29 clippy::redundant_closure_for_method_calls "redundant closure"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/core/resolver/conflict_cache.rs:41:38 clippy::map_unwrap_or "called `map(<f>).unwrap_or_else(<g>)` on an `Option` value. This can be done more directly by calling `map_or_else(<g>, <f>)` instead"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/core/resolver/context.rs:274:53 clippy::redundant_closure_for_method_calls "redundant closure"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/core/resolver/context.rs:42:1 clippy::module_name_repetitions "item name starts with its containing module's name"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/core/resolver/context.rs:74:5 clippy::must_use_candidate "this method could have a `#[must_use]` attribute"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/core/resolver/encode.rs:156:5 clippy::missing_errors_doc "docs for function returning `Result` missing `# Errors` section"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/core/resolver/encode.rs:156:5 clippy::too_many_lines "this function has too many lines (164/100)"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/core/resolver/encode.rs:438:5 clippy::items_after_statements "adding items after statements is confusing, since items exist from the start of the scope"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/core/resolver/encode.rs:449:5 clippy::items_after_statements "adding items after statements is confusing, since items exist from the start of the scope"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/core/resolver/encode.rs:529:34 clippy::redundant_closure_for_method_calls "redundant closure"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/core/resolver/encode.rs:602:59 clippy::redundant_closure_for_method_calls "redundant closure"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/core/resolver/encode.rs:623:1 clippy::module_name_repetitions "item name starts with its containing module's name"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/core/resolver/encode.rs:652:27 clippy::single_match_else "you seem to be trying to use `match` for destructuring a single pattern. Consider using `if let`"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/core/resolver/encode.rs:674:51 clippy::redundant_closure_for_method_calls "redundant closure"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/core/resolver/errors.rs:103:22 clippy::redundant_closure_for_method_calls "redundant closure"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/core/resolver/errors.rs:104:22 clippy::redundant_closure_for_method_calls "redundant closure"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/core/resolver/errors.rs:206:9 clippy::if_not_else "unnecessary boolean `not` operation"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/core/resolver/errors.rs:257:45 clippy::redundant_closure_for_method_calls "redundant closure"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/core/resolver/errors.rs:27:5 clippy::must_use_candidate "this method could have a `#[must_use]` attribute"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/core/resolver/errors.rs:305:17 clippy::single_char_add_str "calling `push_str()` using a single-character string literal"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/core/resolver/errors.rs:70:1 clippy::too_many_lines "this function has too many lines (207/100)"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/core/resolver/features.rs:104:1 clippy::module_name_repetitions "item name starts with its containing module's name"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/core/resolver/features.rs:111:5 clippy::must_use_candidate "this method could have a `#[must_use]` attribute"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/core/resolver/features.rs:162:56 clippy::redundant_closure_for_method_calls "redundant closure"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/core/resolver/features.rs:179:1 clippy::module_name_repetitions "item name ends with its containing module's name"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/core/resolver/features.rs:186:23 clippy::doc_markdown "you should put `RequestedFeatures` between ticks in the documentation"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/core/resolver/features.rs:187:5 clippy::must_use_candidate "this method could have a `#[must_use]` attribute"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/core/resolver/features.rs:199:23 clippy::doc_markdown "you should put `RequestedFeatures` between ticks in the documentation"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/core/resolver/features.rs:200:5 clippy::must_use_candidate "this method could have a `#[must_use]` attribute"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/core/resolver/features.rs:221:5 clippy::must_use_candidate "this method could have a `#[must_use]` attribute"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/core/resolver/features.rs:231:21 clippy::doc_markdown "you should put `pkg_id/is_build` between ticks in the documentation"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/core/resolver/features.rs:233:5 clippy::must_use_candidate "this method could have a `#[must_use]` attribute"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/core/resolver/features.rs:247:58 clippy::redundant_closure_for_method_calls "redundant closure"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/core/resolver/features.rs:278:5 clippy::missing_errors_doc "docs for function returning `Result` missing `# Errors` section"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/core/resolver/features.rs:394:27 clippy::doc_markdown "you should put `FeatureValue` between ticks in the documentation"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/core/resolver/features.rs:460:19 clippy::single_match_else "you seem to be trying to use `match` for destructuring a single pattern. Consider using `if let`"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/core/resolver/features.rs:480:24 clippy::doc_markdown "you should put `FeatureValues` between ticks in the documentation"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/core/resolver/features.rs:496:24 clippy::doc_markdown "you should put `FeatureValues` between ticks in the documentation"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/core/resolver/features.rs:58:1 clippy::module_name_repetitions "item name ends with its containing module's name"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/core/resolver/features.rs:67:1 clippy::struct_excessive_bools "more than 3 bools in a struct"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/core/resolver/mod.rs:1017:5 clippy::items_after_statements "adding items after statements is confusing, since items exist from the start of the scope"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/core/resolver/mod.rs:1045:57 clippy::redundant_closure_for_method_calls "redundant closure"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/core/resolver/mod.rs:122:1 clippy::missing_errors_doc "docs for function returning `Result` missing `# Errors` section"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/core/resolver/mod.rs:142:44 clippy::redundant_closure_for_method_calls "redundant closure"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/core/resolver/mod.rs:180:1 clippy::too_many_lines "this function has too many lines (225/100)"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/core/resolver/mod.rs:311:17 clippy::single_match_else "you seem to be trying to use `match` for destructuring a single pattern. Consider using `if let`"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/core/resolver/mod.rs:421:52 clippy::filter_map_next "called `filter_map(..).next()` on an `Iterator`. This is more succinctly expressed by calling `.find_map(..)` instead"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/core/resolver/mod.rs:457:69 clippy::filter_map_next "called `filter_map(..).next()` on an `Iterator`. This is more succinctly expressed by calling `.find_map(..)` instead"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/core/resolver/mod.rs:470:37 clippy::similar_names "binding's name is too similar to existing binding"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/core/resolver/mod.rs:607:11 clippy::needless_pass_by_value "this argument is passed by value, but not consumed in the function body"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/core/resolver/mod.rs:631:21 clippy::single_match_else "you seem to be trying to use `match` for destructuring a single pattern. Consider using `if let`"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/core/resolver/mod.rs:942:15 clippy::if_not_else "unnecessary boolean `not` operation"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/core/resolver/mod.rs:988:20 clippy::redundant_else "redundant else block"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/core/resolver/resolve.rs:120:5 clippy::must_use_candidate "this method could have a `#[must_use]` attribute"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/core/resolver/resolve.rs:132:5 clippy::missing_errors_doc "docs for function returning `Result` missing `# Errors` section"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/core/resolver/resolve.rs:199:24 clippy::redundant_else "redundant else block"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/core/resolver/resolve.rs:235:5 clippy::must_use_candidate "this method could have a `#[must_use]` attribute"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/core/resolver/resolve.rs:239:5 clippy::needless_lifetimes "explicit lifetimes given in parameter types where they could be elided (or replaced with `'_` if needed by type declaration)"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/core/resolver/resolve.rs:255:5 clippy::must_use_candidate "this method could have a `#[must_use]` attribute"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/core/resolver/resolve.rs:259:5 clippy::must_use_candidate "this method could have a `#[must_use]` attribute"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/core/resolver/resolve.rs:263:5 clippy::must_use_candidate "this method could have a `#[must_use]` attribute"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/core/resolver/resolve.rs:269:5 clippy::must_use_candidate "this method could have a `#[must_use]` attribute"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/core/resolver/resolve.rs:273:5 clippy::must_use_candidate "this method could have a `#[must_use]` attribute"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/core/resolver/resolve.rs:274:9 clippy::map_unwrap_or "called `map(<f>).unwrap_or_else(<g>)` on an `Option` value. This can be done more directly by calling `map_or_else(<g>, <f>)` instead"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/core/resolver/resolve.rs:280:5 clippy::missing_errors_doc "docs for function returning `Result` missing `# Errors` section"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/core/resolver/resolve.rs:284:5 clippy::missing_errors_doc "docs for function returning `Result` missing `# Errors` section"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/core/resolver/resolve.rs:288:5 clippy::must_use_candidate "this method could have a `#[must_use]` attribute"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/core/resolver/resolve.rs:292:5 clippy::must_use_candidate "this method could have a `#[must_use]` attribute"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/core/resolver/resolve.rs:296:5 clippy::must_use_candidate "this method could have a `#[must_use]` attribute"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/core/resolver/resolve.rs:300:5 clippy::missing_errors_doc "docs for function returning `Result` missing `# Errors` section"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/core/resolver/resolve.rs:315:13 clippy::map_unwrap_or "called `map(<f>).unwrap_or_else(<g>)` on an `Option` value. This can be done more directly by calling `map_or_else(<g>, <f>)` instead"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/core/resolver/resolve.rs:354:5 clippy::must_use_candidate "this method could have a `#[must_use]` attribute"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/core/resolver/resolve.rs:362:5 clippy::must_use_candidate "this method could have a `#[must_use]` attribute"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/core/resolver/resolve.rs:60:1 clippy::module_name_repetitions "item name starts with its containing module's name"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/core/resolver/resolve.rs:76:5 clippy::must_use_candidate "this method could have a `#[must_use]` attribute"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/core/resolver/types.rs:111:5 clippy::missing_errors_doc "docs for function returning `Result` missing `# Errors` section"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/core/resolver/types.rs:121:5 clippy::must_use_candidate "this method could have a `#[must_use]` attribute"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/core/resolver/types.rs:141:19 clippy::doc_markdown "you should put `ResolveOpts` between ticks in the documentation"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/core/resolver/types.rs:142:5 clippy::must_use_candidate "this method could have a `#[must_use]` attribute"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/core/resolver/types.rs:149:5 clippy::must_use_candidate "this method could have a `#[must_use]` attribute"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/core/resolver/types.rs:181:9 clippy::map_unwrap_or "called `map(<f>).unwrap_or(<a>)` on an `Option` value. This can be done more directly by calling `map_or(<a>, <f>)` instead"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/core/resolver/types.rs:187:5 clippy::needless_lifetimes "explicit lifetimes given in parameter types where they could be elided (or replaced with `'_` if needed by type declaration)"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/core/resolver/types.rs:261:5 clippy::needless_lifetimes "explicit lifetimes given in parameter types where they could be elided (or replaced with `'_` if needed by type declaration)"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/core/shell.rs:113:5 clippy::must_use_candidate "this method could have a `#[must_use]` attribute"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/core/shell.rs:130:9 clippy::single_match_else "you seem to be trying to use `match` for an equality check. Consider using `if`"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/core/shell.rs:148:5 clippy::must_use_candidate "this method could have a `#[must_use]` attribute"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/core/shell.rs:153:5 clippy::must_use_candidate "this method could have a `#[must_use]` attribute"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/core/shell.rs:163:5 clippy::must_use_candidate "this method could have a `#[must_use]` attribute"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/core/shell.rs:166:13 clippy::match_wildcard_for_single_variants "wildcard matches only a single variant and will also match any future added variants"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/core/shell.rs:18:5 clippy::must_use_candidate "this method could have a `#[must_use]` attribute"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/core/shell.rs:198:5 clippy::missing_errors_doc "docs for function returning `Result` missing `# Errors` section"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/core/shell.rs:206:5 clippy::missing_errors_doc "docs for function returning `Result` missing `# Errors` section"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/core/shell.rs:214:5 clippy::missing_errors_doc "docs for function returning `Result` missing `# Errors` section"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/core/shell.rs:228:5 clippy::missing_errors_doc "docs for function returning `Result` missing `# Errors` section"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/core/shell.rs:239:5 clippy::missing_errors_doc "docs for function returning `Result` missing `# Errors` section"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/core/shell.rs:250:5 clippy::missing_errors_doc "docs for function returning `Result` missing `# Errors` section"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/core/shell.rs:259:5 clippy::missing_errors_doc "docs for function returning `Result` missing `# Errors` section"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/core/shell.rs:267:5 clippy::missing_errors_doc "docs for function returning `Result` missing `# Errors` section"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/core/shell.rs:26:5 clippy::must_use_candidate "this method could have a `#[must_use]` attribute"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/core/shell.rs:277:5 clippy::must_use_candidate "this method could have a `#[must_use]` attribute"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/core/shell.rs:282:5 clippy::missing_errors_doc "docs for function returning `Result` missing `# Errors` section"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/core/shell.rs:314:5 clippy::must_use_candidate "this method could have a `#[must_use]` attribute"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/core/shell.rs:322:5 clippy::must_use_candidate "this method could have a `#[must_use]` attribute"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/core/shell.rs:330:5 clippy::missing_errors_doc "docs for function returning `Result` missing `# Errors` section"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/core/shell.rs:345:5 clippy::missing_panics_doc "docs for function which may panic missing `# Panics` section"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/core/shell.rs:459:9 clippy::let_underscore_drop "non-binding `let` on a type that implements `Drop`"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/core/shell.rs:98:5 clippy::must_use_candidate "this method could have a `#[must_use]` attribute"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/core/source/mod.rs:103:5 clippy::missing_errors_doc "docs for function returning `Result` missing `# Errors` section"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/core/source/mod.rs:247:1 clippy::module_name_repetitions "item name starts with its containing module's name"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/core/source/mod.rs:261:5 clippy::must_use_candidate "this method could have a `#[must_use]` attribute"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/core/source/mod.rs:268:5 clippy::must_use_candidate "this method could have a `#[must_use]` attribute"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/core/source/mod.rs:273:5 clippy::must_use_candidate "this method could have a `#[must_use]` attribute"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/core/source/mod.rs:291:5 clippy::must_use_candidate "this method could have a `#[must_use]` attribute"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/core/source/mod.rs:302:5 clippy::must_use_candidate "this method could have a `#[must_use]` attribute"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/core/source/mod.rs:307:5 clippy::must_use_candidate "this method could have a `#[must_use]` attribute"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/core/source/mod.rs:31:5 clippy::missing_errors_doc "docs for function returning `Result` missing `# Errors` section"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/core/source/mod.rs:37:5 clippy::missing_errors_doc "docs for function returning `Result` missing `# Errors` section"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/core/source/mod.rs:39:5 clippy::missing_errors_doc "docs for function returning `Result` missing `# Errors` section"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/core/source/mod.rs:47:5 clippy::missing_errors_doc "docs for function returning `Result` missing `# Errors` section"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/core/source/mod.rs:50:5 clippy::missing_errors_doc "docs for function returning `Result` missing `# Errors` section"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/core/source/mod.rs:52:5 clippy::missing_errors_doc "docs for function returning `Result` missing `# Errors` section"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/core/source/mod.rs:63:5 clippy::missing_errors_doc "docs for function returning `Result` missing `# Errors` section"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/core/source/mod.rs:74:5 clippy::missing_errors_doc "docs for function returning `Result` missing `# Errors` section"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/core/source/mod.rs:83:5 clippy::missing_errors_doc "docs for function returning `Result` missing `# Errors` section"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/core/source/source_id.rs:107:5 clippy::missing_errors_doc "docs for function returning `Result` missing `# Errors` section"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/core/source/source_id.rs:107:5 clippy::missing_panics_doc "docs for function which may panic missing `# Panics` section"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/core/source/source_id.rs:128:50 clippy::redundant_closure_for_method_calls "redundant closure"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/core/source/source_id.rs:147:5 clippy::must_use_candidate "this method could have a `#[must_use]` attribute"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/core/source/source_id.rs:156:5 clippy::missing_errors_doc "docs for function returning `Result` missing `# Errors` section"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/core/source/source_id.rs:162:5 clippy::missing_errors_doc "docs for function returning `Result` missing `# Errors` section"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/core/source/source_id.rs:166:19 clippy::doc_markdown "you should put `SourceId` between ticks in the documentation"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/core/source/source_id.rs:167:5 clippy::missing_errors_doc "docs for function returning `Result` missing `# Errors` section"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/core/source/source_id.rs:171:19 clippy::doc_markdown "you should put `SourceId` between ticks in the documentation"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/core/source/source_id.rs:172:5 clippy::missing_errors_doc "docs for function returning `Result` missing `# Errors` section"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/core/source/source_id.rs:178:5 clippy::missing_errors_doc "docs for function returning `Result` missing `# Errors` section"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/core/source/source_id.rs:187:5 clippy::missing_errors_doc "docs for function returning `Result` missing `# Errors` section"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/core/source/source_id.rs:187:5 clippy::missing_panics_doc "docs for function which may panic missing `# Panics` section"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/core/source/source_id.rs:18:74 clippy::default_trait_access "calling `std::sync::Mutex::default()` is more clear than this expression"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/core/source/source_id.rs:195:5 clippy::missing_errors_doc "docs for function returning `Result` missing `# Errors` section"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/core/source/source_id.rs:207:5 clippy::must_use_candidate "this method could have a `#[must_use]` attribute"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/core/source/source_id.rs:213:5 clippy::must_use_candidate "this method could have a `#[must_use]` attribute"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/core/source/source_id.rs:217:5 clippy::must_use_candidate "this method could have a `#[must_use]` attribute"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/core/source/source_id.rs:225:5 clippy::must_use_candidate "this method could have a `#[must_use]` attribute"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/core/source/source_id.rs:228:16 clippy::option_if_let_else "use Option::map_or_else instead of an if let/else"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/core/source/source_id.rs:236:5 clippy::must_use_candidate "this method could have a `#[must_use]` attribute"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/core/source/source_id.rs:241:5 clippy::must_use_candidate "this method could have a `#[must_use]` attribute"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/core/source/source_id.rs:252:5 clippy::must_use_candidate "this method could have a `#[must_use]` attribute"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/core/source/source_id.rs:257:5 clippy::must_use_candidate "this method could have a `#[must_use]` attribute"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/core/source/source_id.rs:262:5 clippy::missing_errors_doc "docs for function returning `Result` missing `# Errors` section"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/core/source/source_id.rs:305:5 clippy::must_use_candidate "this method could have a `#[must_use]` attribute"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/core/source/source_id.rs:310:5 clippy::must_use_candidate "this method could have a `#[must_use]` attribute"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/core/source/source_id.rs:318:5 clippy::must_use_candidate "this method could have a `#[must_use]` attribute"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/core/source/source_id.rs:326:5 clippy::must_use_candidate "this method could have a `#[must_use]` attribute"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/core/source/source_id.rs:338:5 clippy::missing_panics_doc "docs for function which may panic missing `# Panics` section"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/core/source/source_id.rs:355:5 clippy::must_use_candidate "this method could have a `#[must_use]` attribute"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/core/source/source_id.rs:393:61 clippy::match_same_arms "this `match` has identical arm bodies"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/core/source/source_id.rs:394:42 clippy::match_same_arms "this `match` has identical arm bodies"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/core/source/source_id.rs:395:42 clippy::match_same_arms "this `match` has identical arm bodies"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/core/source/source_id.rs:397:71 clippy::match_same_arms "this `match` has identical arm bodies"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/core/source/source_id.rs:397:71 clippy::match_same_arms "this `match` has identical arm bodies"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/core/source/source_id.rs:398:47 clippy::match_same_arms "this `match` has identical arm bodies"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/core/source/source_id.rs:398:47 clippy::match_same_arms "this `match` has identical arm bodies"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/core/source/source_id.rs:399:47 clippy::match_same_arms "this `match` has identical arm bodies"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/core/source/source_id.rs:399:47 clippy::match_same_arms "this `match` has identical arm bodies"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/core/source/source_id.rs:401:63 clippy::match_same_arms "this `match` has identical arm bodies"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/core/source/source_id.rs:401:63 clippy::match_same_arms "this `match` has identical arm bodies"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/core/source/source_id.rs:401:63 clippy::match_same_arms "this `match` has identical arm bodies"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/core/source/source_id.rs:402:43 clippy::match_same_arms "this `match` has identical arm bodies"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/core/source/source_id.rs:402:43 clippy::match_same_arms "this `match` has identical arm bodies"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/core/source/source_id.rs:402:43 clippy::match_same_arms "this `match` has identical arm bodies"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/core/source/source_id.rs:403:43 clippy::match_same_arms "this `match` has identical arm bodies"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/core/source/source_id.rs:403:43 clippy::match_same_arms "this `match` has identical arm bodies"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/core/source/source_id.rs:403:43 clippy::match_same_arms "this `match` has identical arm bodies"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/core/source/source_id.rs:406:21 clippy::enum_glob_use "usage of wildcard import for enum variants"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/core/source/source_id.rs:412:41 clippy::match_same_arms "this `match` has identical arm bodies"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/core/source/source_id.rs:413:36 clippy::match_same_arms "this `match` has identical arm bodies"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/core/source/source_id.rs:414:36 clippy::match_same_arms "this `match` has identical arm bodies"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/core/source/source_id.rs:420:47 clippy::match_same_arms "this `match` has identical arm bodies"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/core/source/source_id.rs:420:47 clippy::match_same_arms "this `match` has identical arm bodies"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/core/source/source_id.rs:512:17 clippy::unseparated_literal_suffix "integer type suffix should be separated by an underscore"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/core/source/source_id.rs:513:17 clippy::unseparated_literal_suffix "integer type suffix should be separated by an underscore"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/core/source/source_id.rs:517:17 clippy::unseparated_literal_suffix "integer type suffix should be separated by an underscore"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/core/source/source_id.rs:518:17 clippy::unseparated_literal_suffix "integer type suffix should be separated by an underscore"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/core/source/source_id.rs:525:17 clippy::unseparated_literal_suffix "integer type suffix should be separated by an underscore"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/core/source/source_id.rs:526:17 clippy::unseparated_literal_suffix "integer type suffix should be separated by an underscore"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/core/source/source_id.rs:530:17 clippy::unseparated_literal_suffix "integer type suffix should be separated by an underscore"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/core/source/source_id.rs:531:17 clippy::unseparated_literal_suffix "integer type suffix should be separated by an underscore"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/core/source/source_id.rs:535:33 clippy::unseparated_literal_suffix "integer type suffix should be separated by an underscore"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/core/source/source_id.rs:536:37 clippy::unseparated_literal_suffix "integer type suffix should be separated by an underscore"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/core/source/source_id.rs:537:42 clippy::unseparated_literal_suffix "integer type suffix should be separated by an underscore"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/core/source/source_id.rs:538:38 clippy::unseparated_literal_suffix "integer type suffix should be separated by an underscore"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/core/source/source_id.rs:548:1 clippy::module_name_repetitions "item name starts with its containing module's name"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/core/source/source_id.rs:597:5 clippy::must_use_candidate "this method could have a `#[must_use]` attribute"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/core/summary.rs:103:5 clippy::must_use_candidate "this method could have a `#[must_use]` attribute"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/core/summary.rs:123:5 clippy::must_use_candidate "this method could have a `#[must_use]` attribute"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/core/summary.rs:150:1 clippy::too_many_lines "this function has too many lines (141/100)"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/core/summary.rs:158:9 clippy::enum_glob_use "usage of wildcard import for enum variants"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/core/summary.rs:181:21 clippy::if_not_else "unnecessary boolean `not` operation"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/core/summary.rs:192:28 clippy::redundant_else "redundant else block"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/core/summary.rs:258:32 clippy::redundant_else "redundant else block"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/core/summary.rs:281:28 clippy::redundant_else "redundant else block"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/core/summary.rs:303:28 clippy::redundant_else "redundant else block"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/core/summary.rs:321:51 clippy::match_same_arms "this `match` has identical arm bodies"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/core/summary.rs:344:5 clippy::doc_markdown "you should put `FeatureValue` between ticks in the documentation"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/core/summary.rs:350:85 clippy::doc_markdown "you should put `FeatureValue` between ticks in the documentation"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/core/summary.rs:36:5 clippy::missing_errors_doc "docs for function returning `Result` missing `# Errors` section"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/core/summary.rs:378:5 clippy::must_use_candidate "this method could have a `#[must_use]` attribute"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/core/summary.rs:386:5 clippy::must_use_candidate "this method could have a `#[must_use]` attribute"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/core/summary.rs:387:13 clippy::enum_glob_use "usage of wildcard import for enum variants"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/core/summary.rs:407:13 clippy::enum_glob_use "usage of wildcard import for enum variants"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/core/summary.rs:69:34 clippy::redundant_closure_for_method_calls "redundant closure"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/core/summary.rs:75:5 clippy::must_use_candidate "this method could have a `#[must_use]` attribute"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/core/summary.rs:78:5 clippy::must_use_candidate "this method could have a `#[must_use]` attribute"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/core/summary.rs:81:5 clippy::must_use_candidate "this method could have a `#[must_use]` attribute"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/core/summary.rs:84:5 clippy::must_use_candidate "this method could have a `#[must_use]` attribute"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/core/summary.rs:87:5 clippy::must_use_candidate "this method could have a `#[must_use]` attribute"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/core/summary.rs:90:5 clippy::must_use_candidate "this method could have a `#[must_use]` attribute"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/core/summary.rs:93:5 clippy::must_use_candidate "this method could have a `#[must_use]` attribute"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/core/summary.rs:96:5 clippy::must_use_candidate "this method could have a `#[must_use]` attribute"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/core/summary.rs:99:5 clippy::must_use_candidate "this method could have a `#[must_use]` attribute"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/core/workspace.rs:1056:5 clippy::unnecessary_wraps "this function's return value is unnecessarily wrapped by `Result`"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/core/workspace.rs:113:1 clippy::module_name_repetitions "item name starts with its containing module's name"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/core/workspace.rs:1157:5 clippy::must_use_candidate "this method could have a `#[must_use]` attribute"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/core/workspace.rs:128:1 clippy::module_name_repetitions "item name starts with its containing module's name"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/core/workspace.rs:150:5 clippy::missing_errors_doc "docs for function returning `Result` missing `# Errors` section"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/core/workspace.rs:159:16 clippy::redundant_else "redundant else block"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/core/workspace.rs:197:5 clippy::missing_errors_doc "docs for function returning `Result` missing `# Errors` section"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/core/workspace.rs:225:5 clippy::missing_errors_doc "docs for function returning `Result` missing `# Errors` section"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/core/workspace.rs:225:5 clippy::missing_panics_doc "docs for function which may panic missing `# Panics` section"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/core/workspace.rs:255:5 clippy::missing_errors_doc "docs for function returning `Result` missing `# Errors` section"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/core/workspace.rs:267:5 clippy::missing_errors_doc "docs for function returning `Result` missing `# Errors` section"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/core/workspace.rs:317:5 clippy::missing_panics_doc "docs for function which may panic missing `# Panics` section"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/core/workspace.rs:329:37 clippy::doc_markdown "you should put `VirtualManifest` between ticks in the documentation"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/core/workspace.rs:410:5 clippy::missing_errors_doc "docs for function returning `Result` missing `# Errors` section"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/core/workspace.rs:420:17 clippy::match_wildcard_for_single_variants "wildcard matches only a single variant and will also match any future added variants"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/core/workspace.rs:440:9 clippy::unnecessary_wraps "this function's return value is unnecessarily wrapped by `Result`"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/core/workspace.rs:511:32 clippy::single_match_else "you seem to be trying to use `match` for destructuring a single pattern. Consider using `if let`"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/core/workspace.rs:561:25 clippy::non_ascii_literal "literal non-ASCII character detected"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/core/workspace.rs:613:13 clippy::filter_map "called `filter_map(..).map(..)` on an `Iterator`"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/core/workspace.rs:615:22 clippy::redundant_closure_for_method_calls "redundant closure"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/core/workspace.rs:762:27 clippy::single_match_else "you seem to be trying to use `match` for destructuring a single pattern. Consider using `if let`"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/core/workspace.rs:784:17 clippy::if_not_else "unnecessary boolean `not` operation"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/core/workspace.rs:849:5 clippy::missing_errors_doc "docs for function returning `Result` missing `# Errors` section"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/core/workspace.rs:849:5 clippy::missing_panics_doc "docs for function which may panic missing `# Panics` section"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/core/workspace.rs:893:5 clippy::missing_errors_doc "docs for function returning `Result` missing `# Errors` section"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/core/workspace.rs:906:24 clippy::redundant_else "redundant else block"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/core/workspace.rs:932:5 clippy::missing_errors_doc "docs for function returning `Result` missing `# Errors` section"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/lib.rs:177:1 clippy::missing_panics_doc "docs for function which may panic missing `# Panics` section"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/lib.rs:177:1 clippy::must_use_candidate "this function could have a `#[must_use]` attribute"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/lib.rs:180:36 clippy::redundant_closure_for_method_calls "redundant closure"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/lib.rs:180:36 clippy::redundant_closure_for_method_calls "redundant closure"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/lib.rs:180:36 clippy::redundant_closure_for_method_calls "redundant closure"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/lib.rs:180:36 clippy::redundant_closure_for_method_calls "redundant closure"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/lib.rs:180:36 clippy::redundant_closure_for_method_calls "redundant closure"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/lib.rs:1:null clippy::cargo_common_metadata "package `cargo` is missing `package.categories` metadata"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/lib.rs:1:null clippy::cargo_common_metadata "package `cargo` is missing `package.keywords` metadata"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/lib.rs:1:null clippy::multiple_crate_versions "multiple versions for dependency `crossbeam-utils`: 0.6.6, 0.7.2"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/lib.rs:1:null clippy::multiple_crate_versions "multiple versions for dependency `hex`: 0.3.2, 0.4.0"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/lib.rs:1:null clippy::multiple_crate_versions "multiple versions for dependency `humantime`: 1.3.0, 2.0.0"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/ops/cargo_clean.rs:205:23 clippy::redundant_closure_for_method_calls "redundant closure"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/ops/cargo_clean.rs:27:1 clippy::missing_errors_doc "docs for function returning `Result` missing `# Errors` section"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/ops/cargo_clean.rs:27:1 clippy::too_many_lines "this function has too many lines (120/100)"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/ops/cargo_compile.rs:1078:14 clippy::redundant_closure_for_method_calls "redundant closure"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/ops/cargo_compile.rs:109:5 clippy::missing_errors_doc "docs for function returning `Result` missing `# Errors` section"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/ops/cargo_compile.rs:119:5 clippy::missing_errors_doc "docs for function returning `Result` missing `# Errors` section"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/ops/cargo_compile.rs:1227:17 clippy::needless_pass_by_value "this argument is passed by value, but not consumed in the function body"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/ops/cargo_compile.rs:127:35 clippy::from_iter_instead_of_collect "usage of `FromIterator::from_iter`"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/ops/cargo_compile.rs:173:5 clippy::missing_errors_doc "docs for function returning `Result` missing `# Errors` section"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/ops/cargo_compile.rs:205:36 clippy::match_same_arms "this `match` has identical arm bodies"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/ops/cargo_compile.rs:242:1 clippy::missing_errors_doc "docs for function returning `Result` missing `# Errors` section"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/ops/cargo_compile.rs:249:1 clippy::missing_errors_doc "docs for function returning `Result` missing `# Errors` section"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/ops/cargo_compile.rs:258:1 clippy::missing_errors_doc "docs for function returning `Result` missing `# Errors` section"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/ops/cargo_compile.rs:267:16 clippy::needless_question_mark "question mark operator is useless here"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/ops/cargo_compile.rs:275:1 clippy::missing_errors_doc "docs for function returning `Result` missing `# Errors` section"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/ops/cargo_compile.rs:275:1 clippy::too_many_lines "this function has too many lines (219/100)"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/ops/cargo_compile.rs:468:9 clippy::default_trait_access "calling `std::collections::HashMap::default()` is more clear than this expression"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/ops/cargo_compile.rs:548:5 clippy::must_use_candidate "this method could have a `#[must_use]` attribute"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/ops/cargo_compile.rs:556:5 clippy::must_use_candidate "this method could have a `#[must_use]` attribute"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/ops/cargo_compile.rs:574:5 clippy::must_use_candidate "this method could have a `#[must_use]` attribute"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/ops/cargo_compile.rs:583:21 clippy::doc_markdown "you should put `CompileFilter` between ticks in the documentation"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/ops/cargo_compile.rs:584:5 clippy::fn_params_excessive_bools "more than 3 bools in function parameters"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/ops/cargo_compile.rs:584:5 clippy::must_use_candidate "this method could have a `#[must_use]` attribute"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/ops/cargo_compile.rs:592:9 clippy::similar_names "binding's name is too similar to existing binding"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/ops/cargo_compile.rs:593:9 clippy::similar_names "binding's name is too similar to existing binding"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/ops/cargo_compile.rs:607:13 clippy::similar_names "binding's name is too similar to existing binding"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/ops/cargo_compile.rs:612:21 clippy::doc_markdown "you should put `CompileFilter` between ticks in the documentation"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/ops/cargo_compile.rs:613:5 clippy::must_use_candidate "this method could have a `#[must_use]` attribute"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/ops/cargo_compile.rs:618:9 clippy::similar_names "binding's name is too similar to existing binding"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/ops/cargo_compile.rs:641:5 clippy::must_use_candidate "this method could have a `#[must_use]` attribute"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/ops/cargo_compile.rs:652:5 clippy::must_use_candidate "this method could have a `#[must_use]` attribute"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/ops/cargo_compile.rs:655:50 clippy::match_same_arms "this `match` has identical arm bodies"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/ops/cargo_compile.rs:673:5 clippy::must_use_candidate "this method could have a `#[must_use]` attribute"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/ops/cargo_compile.rs:692:49 clippy::match_same_arms "this `match` has identical arm bodies"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/ops/cargo_compile.rs:703:5 clippy::must_use_candidate "this method could have a `#[must_use]` attribute"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/ops/cargo_compile.rs:729:1 clippy::too_many_lines "this function has too many lines (205/100)"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/ops/cargo_compile.rs:82:5 clippy::missing_errors_doc "docs for function returning `Result` missing `# Errors` section"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/ops/cargo_compile.rs:874:69 clippy::redundant_closure_for_method_calls "redundant closure"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/ops/cargo_doc.rs:20:1 clippy::missing_errors_doc "docs for function returning `Result` missing `# Errors` section"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/ops/cargo_fetch.rs:15:1 clippy::missing_errors_doc "docs for function returning `Result` missing `# Errors` section"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/ops/cargo_fetch.rs:27:46 clippy::redundant_closure_for_method_calls "redundant closure"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/ops/cargo_generate_lockfile.rs:160:5 clippy::items_after_statements "adding items after statements is confusing, since items exist from the start of the scope"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/ops/cargo_generate_lockfile.rs:175:5 clippy::items_after_statements "adding items after statements is confusing, since items exist from the start of the scope"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/ops/cargo_generate_lockfile.rs:22:1 clippy::missing_errors_doc "docs for function returning `Result` missing `# Errors` section"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/ops/cargo_generate_lockfile.rs:37:1 clippy::missing_errors_doc "docs for function returning `Result` missing `# Errors` section"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/ops/cargo_generate_lockfile.rs:37:1 clippy::missing_panics_doc "docs for function which may panic missing `# Panics` section"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/ops/cargo_generate_lockfile.rs:37:1 clippy::too_many_lines "this function has too many lines (171/100)"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/ops/cargo_install.rs:13:5 clippy::wildcard_imports "usage of wildcard import"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/ops/cargo_install.rs:148:1 clippy::fn_params_excessive_bools "more than 3 bools in function parameters"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/ops/cargo_install.rs:148:1 clippy::too_many_lines "this function has too many lines (316/100)"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/ops/cargo_install.rs:178:24 clippy::collapsible_else_if "this `else { if .. }` block can be collapsed"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/ops/cargo_install.rs:202:17 clippy::redundant_closure_for_method_calls "redundant closure"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/ops/cargo_install.rs:236:16 clippy::collapsible_else_if "this `else { if .. }` block can be collapsed"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/ops/cargo_install.rs:312:64 clippy::redundant_closure_for_method_calls "redundant closure"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/ops/cargo_install.rs:32:13 clippy::let_underscore_drop "non-binding `let` on a type that implements `Drop`"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/ops/cargo_install.rs:339:12 clippy::collapsible_else_if "this `else { if .. }` block can be collapsed"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/ops/cargo_install.rs:37:1 clippy::missing_errors_doc "docs for function returning `Result` missing `# Errors` section"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/ops/cargo_install.rs:454:22 clippy::redundant_closure_for_method_calls "redundant closure"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/ops/cargo_install.rs:483:5 clippy::items_after_statements "adding items after statements is confusing, since items exist from the start of the scope"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/ops/cargo_install.rs:683:1 clippy::missing_errors_doc "docs for function returning `Result` missing `# Errors` section"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/ops/cargo_install.rs:708:5 clippy::manual_flatten "unnecessary `if let` since only the `Some` variant of the iterator element is used"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/ops/cargo_new.rs:101:5 clippy::missing_errors_doc "docs for function returning `Result` missing `# Errors` section"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/ops/cargo_new.rs:245:5 clippy::items_after_statements "adding items after statements is confusing, since items exist from the start of the scope"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/ops/cargo_new.rs:251:5 clippy::items_after_statements "adding items after statements is confusing, since items exist from the start of the scope"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/ops/cargo_new.rs:367:1 clippy::missing_errors_doc "docs for function returning `Result` missing `# Errors` section"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/ops/cargo_new.rs:405:1 clippy::missing_errors_doc "docs for function returning `Result` missing `# Errors` section"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/ops/cargo_new.rs:489:5 clippy::doc_markdown "you should put `IgnoreList` between ticks in the documentation"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/ops/cargo_new.rs:525:47 clippy::doc_markdown "you should put `IgnoreList` between ticks in the documentation"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/ops/cargo_new.rs:525:9 clippy::doc_markdown "you should put `format_existing` between ticks in the documentation"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/ops/cargo_new.rs:572:34 clippy::match_same_arms "this `match` has identical arm bodies"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/ops/cargo_new.rs:623:1 clippy::too_many_lines "this function has too many lines (130/100)"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/ops/cargo_new.rs:781:5 clippy::filter_map_next "called `filter_map(..).next()` on an `Iterator`. This is more succinctly expressed by calling `.find_map(..)` instead"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/ops/cargo_new.rs:800:16 clippy::single_match_else "you seem to be trying to use `match` for destructuring a single pattern. Consider using `if let`"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/ops/cargo_output_metadata.rs:163:36 clippy::redundant_closure_for_method_calls "redundant closure"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/ops/cargo_output_metadata.rs:27:1 clippy::missing_errors_doc "docs for function returning `Result` missing `# Errors` section"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/ops/cargo_output_metadata.rs:45:45 clippy::redundant_closure_for_method_calls "redundant closure"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/ops/cargo_package.rs:144:1 clippy::too_many_lines "this function has too many lines (112/100)"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/ops/cargo_package.rs:207:13 clippy::single_match_else "you seem to be trying to use `match` for destructuring a single pattern. Consider using `if let`"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/ops/cargo_package.rs:25:1 clippy::struct_excessive_bools "more than 3 bools in a struct"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/ops/cargo_package.rs:307:54 clippy::redundant_closure_for_method_calls "redundant closure"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/ops/cargo_package.rs:394:5 clippy::items_after_statements "adding items after statements is confusing, since items exist from the start of the scope"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/ops/cargo_package.rs:425:61 clippy::redundant_closure_for_method_calls "redundant closure"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/ops/cargo_package.rs:459:5 clippy::items_after_statements "adding items after statements is confusing, since items exist from the start of the scope"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/ops/cargo_package.rs:66:1 clippy::missing_errors_doc "docs for function returning `Result` missing `# Errors` section"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/ops/cargo_package.rs:69:9 clippy::let_underscore_drop "non-binding `let` on a type that implements `Drop`"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/ops/cargo_package.rs:93:20 clippy::if_not_else "unnecessary boolean `not` operation"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/ops/cargo_pkgid.rs:5:1 clippy::missing_errors_doc "docs for function returning `Result` missing `# Errors` section"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/ops/cargo_read_manifest.rs:14:1 clippy::missing_errors_doc "docs for function returning `Result` missing `# Errors` section"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/ops/cargo_read_manifest.rs:171:5 clippy::items_after_statements "adding items after statements is confusing, since items exist from the start of the scope"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/ops/cargo_read_manifest.rs:37:1 clippy::missing_errors_doc "docs for function returning `Result` missing `# Errors` section"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/ops/cargo_read_manifest.rs:37:1 clippy::missing_panics_doc "docs for function which may panic missing `# Panics` section"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/ops/cargo_read_manifest.rs:57:49 clippy::redundant_closure_for_method_calls "redundant closure"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/ops/cargo_read_manifest.rs:69:37 clippy::redundant_closure_for_method_calls "redundant closure"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/ops/cargo_run.rs:25:24 clippy::if_not_else "unnecessary boolean `not` operation"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/ops/cargo_run.rs:35:9 clippy::if_not_else "unnecessary boolean `not` operation"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/ops/cargo_run.rs:37:16 clippy::redundant_else "redundant else block"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/ops/cargo_run.rs:53:9 clippy::if_not_else "unnecessary boolean `not` operation"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/ops/cargo_run.rs:65:16 clippy::redundant_else "redundant else block"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/ops/cargo_run.rs:82:23 clippy::implicit_clone "implicitly cloning a `PathBuf` by calling `to_path_buf` on its dereferenced type"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/ops/cargo_run.rs:9:1 clippy::missing_errors_doc "docs for function returning `Result` missing `# Errors` section"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/ops/cargo_test.rs:16:1 clippy::missing_errors_doc "docs for function returning `Result` missing `# Errors` section"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/ops/cargo_test.rs:43:1 clippy::missing_errors_doc "docs for function returning `Result` missing `# Errors` section"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/ops/cargo_test.rs:84:17 clippy::similar_names "binding's name is too similar to existing binding"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/ops/cargo_uninstall.rs:14:1 clippy::missing_errors_doc "docs for function returning `Result` missing `# Errors` section"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/ops/cargo_uninstall.rs:7:5 clippy::wildcard_imports "usage of wildcard import"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/ops/common_for_install_and_uninstall.rs:147:9 clippy::doc_markdown "you should put `PackageId` between ticks in the documentation"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/ops/common_for_install_and_uninstall.rs:233:21 clippy::single_char_add_str "calling `push_str()` using a single-character string literal"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/ops/common_for_install_and_uninstall.rs:244:22 clippy::doc_markdown "you should put `PackageId` between ticks in the documentation"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/ops/common_for_install_and_uninstall.rs:244:63 clippy::doc_markdown "you should put `PackageId` between ticks in the documentation"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/ops/common_for_install_and_uninstall.rs:253:17 clippy::if_not_else "unnecessary boolean `not` operation"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/ops/common_for_install_and_uninstall.rs:370:5 clippy::unnecessary_wraps "this function's return value is unnecessary"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/ops/common_for_install_and_uninstall.rs:505:8 clippy::map_unwrap_or "called `map(<f>).unwrap_or_else(<g>)` on an `Option` value. This can be done more directly by calling `map_or_else(<g>, <f>)` instead"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/ops/common_for_install_and_uninstall.rs:525:10 clippy::needless_pass_by_value "this argument is passed by value, but not consumed in the function body"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/ops/common_for_install_and_uninstall.rs:542:27 clippy::redundant_closure_for_method_calls "redundant closure"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/ops/common_for_install_and_uninstall.rs:542:5 clippy::single_match_else "you seem to be trying to use `match` for destructuring a single pattern. Consider using `if let`"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/ops/common_for_install_and_uninstall.rs:561:20 clippy::redundant_else "redundant else block"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/ops/common_for_install_and_uninstall.rs:613:5 clippy::items_after_statements "adding items after statements is confusing, since items exist from the start of the scope"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/ops/common_for_install_and_uninstall.rs:645:41 clippy::doc_markdown "you should put `BTreeSet` between ticks in the documentation"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/ops/common_for_install_and_uninstall.rs:92:19 clippy::doc_markdown "you should put `InstallTracker` between ticks in the documentation"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/ops/fix.rs:200:1 clippy::missing_errors_doc "docs for function returning `Result` missing `# Errors` section"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/ops/fix.rs:200:1 clippy::module_name_repetitions "item name starts with its containing module's name"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/ops/fix.rs:424:20 clippy::map_unwrap_or "called `map(<f>).unwrap_or(<a>)` on an `Option` value. This can be done more directly by calling `map_or(<a>, <f>)` instead"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/ops/fix.rs:455:13 clippy::similar_names "binding's name is too similar to existing binding"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/ops/fix.rs:506:17 clippy::similar_names "binding's name is too similar to existing binding"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/ops/fix.rs:608:9 clippy::field_reassign_with_default "field assignment outside of initializer for an instance created with Default::default()"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/ops/fix.rs:612:42 clippy::redundant_closure_for_method_calls "redundant closure"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/ops/fix.rs:619:48 clippy::manual_strip "stripping a prefix manually"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/ops/fix.rs:66:1 clippy::module_name_repetitions "item name starts with its containing module's name"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/ops/fix.rs:66:1 clippy::struct_excessive_bools "more than 3 bools in a struct"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/ops/fix.rs:708:18 clippy::match_same_arms "this `match` has identical arm bodies"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/ops/fix.rs:77:1 clippy::missing_errors_doc "docs for function returning `Result` missing `# Errors` section"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/ops/lockfile.rs:154:13 clippy::single_char_add_str "calling `push_str()` using a single-character string literal"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/ops/lockfile.rs:217:9 clippy::single_char_add_str "calling `push_str()` using a single-character string literal"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/ops/lockfile.rs:30:1 clippy::missing_errors_doc "docs for function returning `Result` missing `# Errors` section"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/ops/lockfile.rs:35:1 clippy::missing_errors_doc "docs for function returning `Result` missing `# Errors` section"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/ops/lockfile.rs:35:1 clippy::module_name_repetitions "item name ends with its containing module's name"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/ops/lockfile.rs:87:1 clippy::unnecessary_wraps "this function's return value is unnecessarily wrapped by `Result`"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/ops/lockfile.rs:8:1 clippy::missing_errors_doc "docs for function returning `Result` missing `# Errors` section"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/ops/lockfile.rs:8:1 clippy::module_name_repetitions "item name ends with its containing module's name"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/ops/registry.rs:150:21 clippy::redundant_closure_for_method_calls "redundant closure"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/ops/registry.rs:188:1 clippy::too_many_lines "this function has too many lines (130/100)"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/ops/registry.rs:212:32 clippy::if_not_else "unnecessary `!=` operation"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/ops/registry.rs:222:53 clippy::redundant_closure_for_method_calls "redundant closure"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/ops/registry.rs:224:44 clippy::redundant_closure_for_method_calls "redundant closure"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/ops/registry.rs:31:1 clippy::module_name_repetitions "item name starts with its containing module's name"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/ops/registry.rs:346:1 clippy::missing_errors_doc "docs for function returning `Result` missing `# Errors` section"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/ops/registry.rs:346:1 clippy::module_name_repetitions "item name starts with its containing module's name"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/ops/registry.rs:351:26 clippy::single_match_else "you seem to be trying to use `match` for destructuring a single pattern. Consider using `if let`"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/ops/registry.rs:385:12 clippy::needless_pass_by_value "this argument is passed by value, but not consumed in the function body"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/ops/registry.rs:386:15 clippy::needless_pass_by_value "this argument is passed by value, but not consumed in the function body"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/ops/registry.rs:38:1 clippy::struct_excessive_bools "more than 3 bools in a struct"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/ops/registry.rs:477:1 clippy::missing_errors_doc "docs for function returning `Result` missing `# Errors` section"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/ops/registry.rs:483:1 clippy::missing_errors_doc "docs for function returning `Result` missing `# Errors` section"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/ops/registry.rs:503:1 clippy::missing_errors_doc "docs for function returning `Result` missing `# Errors` section"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/ops/registry.rs:505:38 clippy::default_trait_access "calling `util::config::CargoHttpConfig::default()` is more clear than this expression"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/ops/registry.rs:510:1 clippy::missing_errors_doc "docs for function returning `Result` missing `# Errors` section"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/ops/registry.rs:529:5 clippy::items_after_statements "adding items after statements is confusing, since items exist from the start of the scope"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/ops/registry.rs:53:1 clippy::missing_errors_doc "docs for function returning `Result` missing `# Errors` section"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/ops/registry.rs:53:1 clippy::missing_panics_doc "docs for function which may panic missing `# Panics` section"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/ops/registry.rs:573:17 clippy::match_wildcard_for_single_variants "wildcard matches only a single variant and will also match any future added variants"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/ops/registry.rs:573:22 clippy::match_same_arms "this `match` has identical arm bodies"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/ops/registry.rs:608:5 clippy::missing_errors_doc "docs for function returning `Result` missing `# Errors` section"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/ops/registry.rs:621:5 clippy::missing_errors_doc "docs for function returning `Result` missing `# Errors` section"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/ops/registry.rs:671:1 clippy::missing_errors_doc "docs for function returning `Result` missing `# Errors` section"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/ops/registry.rs:671:1 clippy::module_name_repetitions "item name starts with its containing module's name"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/ops/registry.rs:674:10 clippy::needless_pass_by_value "this argument is passed by value, but not consumed in the function body"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/ops/registry.rs:678:17 clippy::single_match_else "you seem to be trying to use `match` for destructuring a single pattern. Consider using `if let`"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/ops/registry.rs:730:1 clippy::missing_errors_doc "docs for function returning `Result` missing `# Errors` section"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/ops/registry.rs:731:16 clippy::single_match_else "you seem to be trying to use `match` for destructuring a single pattern. Consider using `if let`"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/ops/registry.rs:785:1 clippy::missing_errors_doc "docs for function returning `Result` missing `# Errors` section"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/ops/registry.rs:794:16 clippy::single_match_else "you seem to be trying to use `match` for destructuring a single pattern. Consider using `if let`"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/ops/registry.rs:828:14 clippy::doc_markdown "you should put `SourceId` between ticks in the documentation"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/ops/registry.rs:848:1 clippy::missing_errors_doc "docs for function returning `Result` missing `# Errors` section"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/ops/resolve.rs:199:1 clippy::missing_errors_doc "docs for function returning `Result` missing `# Errors` section"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/ops/resolve.rs:199:1 clippy::module_name_repetitions "item name starts with its containing module's name"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/ops/resolve.rs:199:1 clippy::too_many_lines "this function has too many lines (137/100)"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/ops/resolve.rs:241:28 clippy::single_match_else "you seem to be trying to use `match` for destructuring a single pattern. Consider using `if let`"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/ops/resolve.rs:28:1 clippy::module_name_repetitions "item name ends with its containing module's name"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/ops/resolve.rs:384:1 clippy::missing_errors_doc "docs for function returning `Result` missing `# Errors` section"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/ops/resolve.rs:417:1 clippy::missing_errors_doc "docs for function returning `Result` missing `# Errors` section"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/ops/resolve.rs:589:9 clippy::shadow_unrelated "`keep` is being shadowed"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/ops/resolve.rs:58:1 clippy::missing_errors_doc "docs for function returning `Result` missing `# Errors` section"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/ops/resolve.rs:58:1 clippy::module_name_repetitions "item name starts with its containing module's name"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/ops/resolve.rs:602:5 clippy::items_after_statements "adding items after statements is confusing, since items exist from the start of the scope"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/ops/resolve.rs:75:1 clippy::missing_errors_doc "docs for function returning `Result` missing `# Errors` section"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/ops/resolve.rs:75:1 clippy::module_name_repetitions "item name starts with its containing module's name"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/ops/tree/format/mod.rs:103:21 clippy::match_wildcard_for_single_variants "wildcard matches only a single variant and will also match any future added variants"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/ops/tree/graph.rs:129:26 clippy::doc_markdown "you should put `PackageIds` between ticks in the documentation"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/ops/tree/graph.rs:137:17 clippy::match_wildcard_for_single_variants "wildcard matches only a single variant and will also match any future added variants"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/ops/tree/graph.rs:152:15 clippy::match_on_vec_items "indexing into a vector may panic"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/ops/tree/graph.rs:173:9 clippy::items_after_statements "adding items after statements is confusing, since items exist from the start of the scope"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/ops/tree/graph.rs:234:46 clippy::filter_map "called `filter(..).flat_map(..)` on an `Iterator`"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/ops/tree/graph.rs:328:44 clippy::match_same_arms "this `match` has identical arm bodies"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/ops/tree/graph.rs:330:50 clippy::match_same_arms "this `match` has identical arm bodies"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/ops/tree/graph.rs:563:35 clippy::single_match_else "you seem to be trying to use `match` for destructuring a single pattern. Consider using `if let`"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/ops/tree/mod.rs:112:11 clippy::non_ascii_literal "literal non-ASCII character detected"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/ops/tree/mod.rs:113:10 clippy::non_ascii_literal "literal non-ASCII character detected"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/ops/tree/mod.rs:114:10 clippy::non_ascii_literal "literal non-ASCII character detected"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/ops/tree/mod.rs:115:12 clippy::non_ascii_literal "literal non-ASCII character detected"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/ops/tree/mod.rs:126:1 clippy::missing_errors_doc "docs for function returning `Result` missing `# Errors` section"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/ops/tree/mod.rs:21:1 clippy::module_name_repetitions "item name starts with its containing module's name"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/ops/tree/mod.rs:21:1 clippy::struct_excessive_bools "more than 3 bools in a struct"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/ops/tree/mod.rs:360:30 clippy::match_same_arms "this `match` has identical arm bodies"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/ops/tree/mod.rs:58:5 clippy::must_use_candidate "this method could have a `#[must_use]` attribute"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/ops/vendor.rs:14:1 clippy::module_name_repetitions "item name starts with its containing module's name"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/ops/vendor.rs:215:9 clippy::let_underscore_drop "non-binding `let` on a type that implements `Drop`"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/ops/vendor.rs:21:1 clippy::missing_errors_doc "docs for function returning `Result` missing `# Errors` section"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/ops/vendor.rs:21:1 clippy::missing_panics_doc "docs for function which may panic missing `# Panics` section"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/ops/vendor.rs:311:13 clippy::unnested_or_patterns "unnested or-patterns"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/ops/vendor.rs:314:34 clippy::match_same_arms "this `match` has identical arm bodies"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/ops/vendor.rs:320:29 clippy::case_sensitive_file_extension_comparisons "case-sensitive file extension comparison"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/ops/vendor.rs:320:60 clippy::case_sensitive_file_extension_comparisons "case-sensitive file extension comparison"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/ops/vendor.rs:70:1 clippy::too_many_lines "this function has too many lines (175/100)"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/sources/config.rs:102:5 clippy::missing_errors_doc "docs for function returning `Result` missing `# Errors` section"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/sources/config.rs:111:28 clippy::needless_question_mark "question mark operator is useless here"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/sources/config.rs:133:48 clippy::needless_question_mark "question mark operator is useless here"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/sources/config.rs:135:67 clippy::redundant_closure_for_method_calls "redundant closure"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/sources/config.rs:206:36 clippy::needless_pass_by_value "this argument is passed by value, but not consumed in the function body"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/sources/config.rs:282:9 clippy::items_after_statements "adding items after statements is confusing, since items exist from the start of the scope"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/sources/config.rs:70:5 clippy::missing_errors_doc "docs for function returning `Result` missing `# Errors` section"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/sources/config.rs:81:5 clippy::missing_errors_doc "docs for function returning `Result` missing `# Errors` section"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/sources/config.rs:97:5 clippy::must_use_candidate "this method could have a `#[must_use]` attribute"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/sources/directory.rs:14:1 clippy::module_name_repetitions "item name starts with its containing module's name"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/sources/directory.rs:90:56 clippy::redundant_closure_for_method_calls "redundant closure"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/sources/git/source.rs:14:1 clippy::module_name_repetitions "item name ends with its containing module's name"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/sources/git/source.rs:25:5 clippy::missing_errors_doc "docs for function returning `Result` missing `# Errors` section"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/sources/git/source.rs:49:5 clippy::must_use_candidate "this method could have a `#[must_use]` attribute"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/sources/git/source.rs:53:5 clippy::missing_errors_doc "docs for function returning `Result` missing `# Errors` section"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/sources/git/source.rs:53:5 clippy::missing_panics_doc "docs for function which may panic missing `# Panics` section"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/sources/git/source.rs:69:20 clippy::comparison_to_empty "comparison to empty slice"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/sources/git/utils.rs:1025:19 clippy::single_match_else "you seem to be trying to use `match` for destructuring a single pattern. Consider using `if let`"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/sources/git/utils.rs:1157:36 clippy::case_sensitive_file_extension_comparisons "case-sensitive file extension comparison"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/sources/git/utils.rs:1158:9 clippy::manual_strip "stripping a suffix manually"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/sources/git/utils.rs:176:5 clippy::must_use_candidate "this method could have a `#[must_use]` attribute"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/sources/git/utils.rs:180:5 clippy::must_use_candidate "this method could have a `#[must_use]` attribute"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/sources/git/utils.rs:184:5 clippy::missing_errors_doc "docs for function returning `Result` missing `# Errors` section"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/sources/git/utils.rs:188:5 clippy::missing_errors_doc "docs for function returning `Result` missing `# Errors` section"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/sources/git/utils.rs:242:5 clippy::missing_errors_doc "docs for function returning `Result` missing `# Errors` section"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/sources/git/utils.rs:253:5 clippy::missing_errors_doc "docs for function returning `Result` missing `# Errors` section"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/sources/git/utils.rs:262:13 clippy::if_not_else "unnecessary boolean `not` operation"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/sources/git/utils.rs:289:5 clippy::missing_errors_doc "docs for function returning `Result` missing `# Errors` section"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/sources/git/utils.rs:294:5 clippy::must_use_candidate "this method could have a `#[must_use]` attribute"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/sources/git/utils.rs:298:5 clippy::missing_errors_doc "docs for function returning `Result` missing `# Errors` section"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/sources/git/utils.rs:308:5 clippy::missing_errors_doc "docs for function returning `Result` missing `# Errors` section"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/sources/git/utils.rs:472:9 clippy::let_underscore_drop "non-binding `let` on a type that implements `Drop`"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/sources/git/utils.rs:489:9 clippy::items_after_statements "adding items after statements is confusing, since items exist from the start of the scope"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/sources/git/utils.rs:503:9 clippy::items_after_statements "adding items after statements is confusing, since items exist from the start of the scope"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/sources/git/utils.rs:528:28 clippy::single_match_else "you seem to be trying to use `match` for destructuring a single pattern. Consider using `if let`"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/sources/git/utils.rs:537:21 clippy::let_underscore_drop "non-binding `let` on a type that implements `Drop`"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/sources/git/utils.rs:588:1 clippy::too_many_lines "this function has too many lines (135/100)"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/sources/git/utils.rs:692:9 clippy::vec_init_then_push "calls to `push` immediately after creation"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/sources/git/utils.rs:758:9 clippy::single_char_add_str "calling `push_str()` using a single-character string literal"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/sources/git/utils.rs:858:1 clippy::missing_errors_doc "docs for function returning `Result` missing `# Errors` section"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/sources/path.rs:129:44 clippy::match_same_arms "this `match` has identical arm bodies"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/sources/path.rs:143:44 clippy::match_same_arms "this `match` has identical arm bodies"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/sources/path.rs:15:1 clippy::module_name_repetitions "item name starts with its containing module's name"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/sources/path.rs:282:50 clippy::redundant_closure_for_method_calls "redundant closure"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/sources/path.rs:313:21 clippy::similar_names "binding's name is too similar to existing binding"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/sources/path.rs:314:21 clippy::similar_names "binding's name is too similar to existing binding"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/sources/path.rs:319:21 clippy::similar_names "binding's name is too similar to existing binding"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/sources/path.rs:339:9 clippy::items_after_statements "adding items after statements is confusing, since items exist from the start of the scope"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/sources/path.rs:339:9 clippy::unnecessary_wraps "this function's return value is unnecessarily wrapped by `Result`"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/sources/path.rs:380:9 clippy::unused_self "unused `self` argument"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/sources/path.rs:419:50 clippy::redundant_closure_for_method_calls "redundant closure"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/sources/path.rs:429:5 clippy::missing_errors_doc "docs for function returning `Result` missing `# Errors` section"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/sources/path.rs:460:5 clippy::must_use_candidate "this method could have a `#[must_use]` attribute"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/sources/path.rs:63:5 clippy::missing_errors_doc "docs for function returning `Result` missing `# Errors` section"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/sources/path.rs:77:5 clippy::missing_errors_doc "docs for function returning `Result` missing `# Errors` section"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/sources/path.rs:98:5 clippy::missing_errors_doc "docs for function returning `Result` missing `# Errors` section"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/sources/registry/index.rs:117:23 clippy::unseparated_literal_suffix "integer type suffix should be separated by an underscore"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/sources/registry/index.rs:121:70 clippy::unseparated_literal_suffix "integer type suffix should be separated by an underscore"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/sources/registry/index.rs:167:1 clippy::module_name_repetitions "item name ends with its containing module's name"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/sources/registry/index.rs:215:1 clippy::module_name_repetitions "item name starts with its containing module's name"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/sources/registry/index.rs:324:23 clippy::redundant_closure_for_method_calls "redundant closure"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/sources/registry/index.rs:468:40 clippy::doc_markdown "you should put `SourceId` between ticks in the documentation"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/sources/registry/index.rs:590:9 clippy::items_after_statements "adding items after statements is confusing, since items exist from the start of the scope"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/sources/registry/index.rs:648:17 clippy::similar_names "binding's name is too similar to existing binding"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/sources/registry/index.rs:736:1 clippy::needless_lifetimes "explicit lifetimes given in parameter types where they could be elided (or replaced with `'_` if needed by type declaration)"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/sources/registry/index.rs:95:37 clippy::cast_possible_truncation "casting `usize` to `u32` may truncate the value on targets with 64-bit wide pointers"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/sources/registry/local.rs:12:1 clippy::module_name_repetitions "item name starts with its containing module's name"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/sources/registry/mod.rs:192:1 clippy::module_name_repetitions "item name starts with its containing module's name"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/sources/registry/mod.rs:203:1 clippy::module_name_repetitions "item name starts with its containing module's name"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/sources/registry/mod.rs:229:1 clippy::module_name_repetitions "item name starts with its containing module's name"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/sources/registry/mod.rs:372:1 clippy::module_name_repetitions "item name starts with its containing module's name"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/sources/registry/mod.rs:373:5 clippy::missing_errors_doc "docs for function returning `Result` missing `# Errors` section"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/sources/registry/mod.rs:375:5 clippy::missing_errors_doc "docs for function returning `Result` missing `# Errors` section"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/sources/registry/mod.rs:381:5 clippy::missing_errors_doc "docs for function returning `Result` missing `# Errors` section"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/sources/registry/mod.rs:382:5 clippy::missing_errors_doc "docs for function returning `Result` missing `# Errors` section"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/sources/registry/mod.rs:383:5 clippy::missing_errors_doc "docs for function returning `Result` missing `# Errors` section"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/sources/registry/mod.rs:384:5 clippy::missing_errors_doc "docs for function returning `Result` missing `# Errors` section"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/sources/registry/mod.rs:452:5 clippy::missing_errors_doc "docs for function returning `Result` missing `# Errors` section"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/sources/registry/mod.rs:582:20 clippy::redundant_else "redundant else block"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/sources/registry/mod.rs:621:9 clippy::if_not_else "unnecessary `!=` operation"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/sources/registry/remote.rs:139:17 clippy::unused_self "unused `self` argument"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/sources/registry/remote.rs:32:1 clippy::module_name_repetitions "item name starts with its containing module's name"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/sources/registry/remote.rs:72:13 clippy::single_match_else "you seem to be trying to use `match` for destructuring a single pattern. Consider using `if let`"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/sources/replaced.rs:12:5 clippy::must_use_candidate "this method could have a `#[must_use]` attribute"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/sources/replaced.rs:5:1 clippy::module_name_repetitions "item name starts with its containing module's name"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/util/canonical_url.rs:19:5 clippy::missing_errors_doc "docs for function returning `Result` missing `# Errors` section"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/util/canonical_url.rs:19:5 clippy::missing_panics_doc "docs for function which may panic missing `# Panics` section"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/util/canonical_url.rs:50:41 clippy::case_sensitive_file_extension_comparisons "case-sensitive file extension comparison"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/util/canonical_url.rs:65:5 clippy::must_use_candidate "this method could have a `#[must_use]` attribute"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/util/command_prelude.rs:218:1 clippy::must_use_candidate "this function could have a `#[must_use]` attribute"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/util/command_prelude.rs:222:1 clippy::must_use_candidate "this function could have a `#[must_use]` attribute"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/util/command_prelude.rs:234:1 clippy::must_use_candidate "this function could have a `#[must_use]` attribute"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/util/command_prelude.rs:249:1 clippy::must_use_candidate "this function could have a `#[must_use]` attribute"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/util/command_prelude.rs:264:5 clippy::missing_errors_doc "docs for function returning `Result` missing `# Errors` section"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/util/command_prelude.rs:279:5 clippy::missing_errors_doc "docs for function returning `Result` missing `# Errors` section"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/util/command_prelude.rs:298:5 clippy::missing_errors_doc "docs for function returning `Result` missing `# Errors` section"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/util/command_prelude.rs:320:5 clippy::missing_errors_doc "docs for function returning `Result` missing `# Errors` section"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/util/command_prelude.rs:328:5 clippy::missing_errors_doc "docs for function returning `Result` missing `# Errors` section"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/util/command_prelude.rs:352:13 clippy::if_not_else "unnecessary boolean `not` operation"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/util/command_prelude.rs:363:13 clippy::if_not_else "unnecessary boolean `not` operation"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/util/command_prelude.rs:378:5 clippy::missing_errors_doc "docs for function returning `Result` missing `# Errors` section"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/util/command_prelude.rs:387:5 clippy::missing_errors_doc "docs for function returning `Result` missing `# Errors` section"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/util/command_prelude.rs:387:5 clippy::too_many_lines "this function has too many lines (104/100)"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/util/command_prelude.rs:39:20 clippy::doc_markdown "you should put `arg_package_spec` between ticks in the documentation"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/util/command_prelude.rs:504:5 clippy::missing_errors_doc "docs for function returning `Result` missing `# Errors` section"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/util/command_prelude.rs:516:5 clippy::missing_errors_doc "docs for function returning `Result` missing `# Errors` section"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/util/command_prelude.rs:530:40 clippy::redundant_closure_for_method_calls "redundant closure"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/util/command_prelude.rs:531:43 clippy::redundant_closure_for_method_calls "redundant closure"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/util/command_prelude.rs:536:5 clippy::missing_errors_doc "docs for function returning `Result` missing `# Errors` section"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/util/command_prelude.rs:556:5 clippy::missing_errors_doc "docs for function returning `Result` missing `# Errors` section"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/util/command_prelude.rs:575:49 clippy::redundant_closure_for_method_calls "redundant closure"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/util/command_prelude.rs:580:5 clippy::missing_errors_doc "docs for function returning `Result` missing `# Errors` section"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/util/command_prelude.rs:631:18 clippy::redundant_closure_for_method_calls "redundant closure"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/util/command_prelude.rs:638:18 clippy::redundant_closure_for_method_calls "redundant closure"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/util/command_prelude.rs:647:1 clippy::must_use_candidate "this function could have a `#[must_use]` attribute"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/util/command_prelude.rs:651:1 clippy::must_use_candidate "this function could have a `#[must_use]` attribute"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/util/command_prelude.rs:662:5 clippy::must_use_candidate "this method could have a `#[must_use]` attribute"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/util/command_prelude.rs:665:51 clippy::match_same_arms "this `match` has identical arm bodies"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/util/config/de.rs:420:16 clippy::needless_pass_by_value "this argument is passed by value, but not consumed in the function body"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/util/config/de.rs:46:25 clippy::doc_markdown "you should put `CV::List` between ticks in the documentation"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/util/config/de.rs:47:24 clippy::doc_markdown "you should put `ConfigSeqAccess` between ticks in the documentation"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/util/config/de.rs:527:53 clippy::unseparated_literal_suffix "integer type suffix should be separated by an underscore"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/util/config/de.rs:530:53 clippy::unseparated_literal_suffix "integer type suffix should be separated by an underscore"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/util/config/de.rs:532:68 clippy::unseparated_literal_suffix "integer type suffix should be separated by an underscore"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/util/config/key.rs:11:1 clippy::module_name_repetitions "item name ends with its containing module's name"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/util/config/key.rs:69:9 clippy::single_char_add_str "calling `push_str()` using a single-character string literal"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/util/config/mod.rs:100:71 clippy::doc_markdown "you should put `OptValue` between ticks in the documentation"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/util/config/mod.rs:100:71 clippy::doc_markdown "you should put `OptValue` between ticks in the documentation"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/util/config/mod.rs:100:71 clippy::doc_markdown "you should put `OptValue` between ticks in the documentation"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/util/config/mod.rs:1049:5 clippy::missing_errors_doc "docs for function returning `Result` missing `# Errors` section"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/util/config/mod.rs:1064:5 clippy::missing_errors_doc "docs for function returning `Result` missing `# Errors` section"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/util/config/mod.rs:1090:5 clippy::missing_errors_doc "docs for function returning `Result` missing `# Errors` section"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/util/config/mod.rs:1166:5 clippy::missing_errors_doc "docs for function returning `Result` missing `# Errors` section"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/util/config/mod.rs:1179:5 clippy::missing_errors_doc "docs for function returning `Result` missing `# Errors` section"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/util/config/mod.rs:1181:33 clippy::needless_question_mark "question mark operator is useless here"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/util/config/mod.rs:1184:5 clippy::missing_errors_doc "docs for function returning `Result` missing `# Errors` section"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/util/config/mod.rs:1186:33 clippy::needless_question_mark "question mark operator is useless here"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/util/config/mod.rs:1189:5 clippy::missing_errors_doc "docs for function returning `Result` missing `# Errors` section"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/util/config/mod.rs:1191:33 clippy::needless_question_mark "question mark operator is useless here"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/util/config/mod.rs:1203:5 clippy::missing_errors_doc "docs for function returning `Result` missing `# Errors` section"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/util/config/mod.rs:1211:5 clippy::missing_errors_doc "docs for function returning `Result` missing `# Errors` section"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/util/config/mod.rs:1216:5 clippy::missing_errors_doc "docs for function returning `Result` missing `# Errors` section"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/util/config/mod.rs:1225:5 clippy::missing_errors_doc "docs for function returning `Result` missing `# Errors` section"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/util/config/mod.rs:1229:5 clippy::missing_errors_doc "docs for function returning `Result` missing `# Errors` section"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/util/config/mod.rs:124:1 clippy::struct_excessive_bools "more than 3 bools in a struct"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/util/config/mod.rs:1254:5 clippy::missing_errors_doc "docs for function returning `Result` missing `# Errors` section"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/util/config/mod.rs:1279:5 clippy::missing_errors_doc "docs for function returning `Result` missing `# Errors` section"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/util/config/mod.rs:1281:9 clippy::single_match_else "you seem to be trying to use `match` for destructuring a single pattern. Consider using `if let`"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/util/config/mod.rs:1323:9 clippy::items_after_statements "adding items after statements is confusing, since items exist from the start of the scope"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/util/config/mod.rs:1339:39 clippy::unused_self "unused `self` argument"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/util/config/mod.rs:1344:1 clippy::module_name_repetitions "item name starts with its containing module's name"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/util/config/mod.rs:1420:1 clippy::module_name_repetitions "item name starts with its containing module's name"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/util/config/mod.rs:1531:13 clippy::unnested_or_patterns "unnested or-patterns"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/util/config/mod.rs:1553:5 clippy::missing_errors_doc "docs for function returning `Result` missing `# Errors` section"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/util/config/mod.rs:1560:5 clippy::missing_errors_doc "docs for function returning `Result` missing `# Errors` section"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/util/config/mod.rs:1567:5 clippy::missing_errors_doc "docs for function returning `Result` missing `# Errors` section"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/util/config/mod.rs:1574:5 clippy::missing_errors_doc "docs for function returning `Result` missing `# Errors` section"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/util/config/mod.rs:1581:5 clippy::missing_errors_doc "docs for function returning `Result` missing `# Errors` section"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/util/config/mod.rs:1588:5 clippy::must_use_candidate "this method could have a `#[must_use]` attribute"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/util/config/mod.rs:1598:5 clippy::must_use_candidate "this method could have a `#[must_use]` attribute"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/util/config/mod.rs:1619:1 clippy::must_use_candidate "this function could have a `#[must_use]` attribute"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/util/config/mod.rs:1623:1 clippy::missing_errors_doc "docs for function returning `Result` missing `# Errors` section"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/util/config/mod.rs:1623:1 clippy::missing_panics_doc "docs for function which may panic missing `# Panics` section"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/util/config/mod.rs:1623:64 clippy::needless_pass_by_value "this argument is passed by value, but not consumed in the function body"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/util/config/mod.rs:1649:9 clippy::option_if_let_else "use Option::map_or_else instead of an if let/else"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/util/config/mod.rs:1699:5 clippy::items_after_statements "adding items after statements is confusing, since items exist from the start of the scope"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/util/config/mod.rs:1730:1 clippy::module_name_repetitions "item name ends with its containing module's name"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/util/config/mod.rs:1757:1 clippy::module_name_repetitions "item name ends with its containing module's name"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/util/config/mod.rs:1770:1 clippy::module_name_repetitions "item name ends with its containing module's name"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/util/config/mod.rs:1778:1 clippy::module_name_repetitions "item name ends with its containing module's name"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/util/config/mod.rs:1804:1 clippy::module_name_repetitions "item name ends with its containing module's name"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/util/config/mod.rs:1896:5 clippy::must_use_candidate "this method could have a `#[must_use]` attribute"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/util/config/mod.rs:1901:5 clippy::doc_markdown "you should put `StringList` between ticks in the documentation"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/util/config/mod.rs:259:5 clippy::missing_errors_doc "docs for function returning `Result` missing `# Errors` section"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/util/config/mod.rs:298:5 clippy::missing_errors_doc "docs for function returning `Result` missing `# Errors` section"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/util/config/mod.rs:311:5 clippy::missing_errors_doc "docs for function returning `Result` missing `# Errors` section"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/util/config/mod.rs:318:5 clippy::missing_errors_doc "docs for function returning `Result` missing `# Errors` section"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/util/config/mod.rs:353:5 clippy::missing_errors_doc "docs for function returning `Result` missing `# Errors` section"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/util/config/mod.rs:401:5 clippy::missing_errors_doc "docs for function returning `Result` missing `# Errors` section"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/util/config/mod.rs:411:5 clippy::missing_errors_doc "docs for function returning `Result` missing `# Errors` section"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/util/config/mod.rs:419:5 clippy::missing_errors_doc "docs for function returning `Result` missing `# Errors` section"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/util/config/mod.rs:431:5 clippy::missing_errors_doc "docs for function returning `Result` missing `# Errors` section"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/util/config/mod.rs:449:5 clippy::missing_errors_doc "docs for function returning `Result` missing `# Errors` section"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/util/config/mod.rs:454:16 clippy::option_if_let_else "use Option::map_or instead of an if let/else"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/util/config/mod.rs:547:5 clippy::missing_errors_doc "docs for function returning `Result` missing `# Errors` section"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/util/config/mod.rs:556:5 clippy::missing_errors_doc "docs for function returning `Result` missing `# Errors` section"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/util/config/mod.rs:582:5 clippy::missing_errors_doc "docs for function returning `Result` missing `# Errors` section"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/util/config/mod.rs:595:20 clippy::doc_markdown "you should put `StringList` between ticks in the documentation"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/util/config/mod.rs:689:20 clippy::unused_self "unused `self` argument"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/util/config/mod.rs:699:5 clippy::fn_params_excessive_bools "more than 3 bools in function parameters"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/util/config/mod.rs:699:5 clippy::missing_errors_doc "docs for function returning `Result` missing `# Errors` section"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/util/config/mod.rs:719:58 clippy::redundant_closure_for_method_calls "redundant closure"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/util/config/mod.rs:748:30 clippy::manual_map "manual implementation of `Option::map`"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/util/config/mod.rs:816:5 clippy::missing_errors_doc "docs for function returning `Result` missing `# Errors` section"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/util/config/path.rs:10:1 clippy::module_name_repetitions "item name ends with its containing module's name"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/util/config/path.rs:14:5 clippy::must_use_candidate "this method could have a `#[must_use]` attribute"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/util/config/path.rs:48:1 clippy::module_name_repetitions "item name starts with its containing module's name"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/util/config/target.rs:12:1 clippy::module_name_repetitions "item name starts with its containing module's name"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/util/config/target.rs:24:1 clippy::module_name_repetitions "item name starts with its containing module's name"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/util/config/value.rs:29:1 clippy::module_name_repetitions "item name ends with its containing module's name"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/util/config/value.rs:70:5 clippy::missing_panics_doc "docs for function which may panic missing `# Panics` section"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/util/config/value.rs:80:5 clippy::must_use_candidate "this method could have a `#[must_use]` attribute"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/util/config/value.rs:81:9 clippy::match_like_matches_macro "match expression looks like `matches!` macro"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/util/cpu.rs:11:5 clippy::missing_errors_doc "docs for function returning `Result` missing `# Errors` section"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/util/cpu.rs:22:5 clippy::must_use_candidate "this method could have a `#[must_use]` attribute"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/util/cpu.rs:82:25 clippy::cast_precision_loss "casting `u64` to `f64` causes a loss of precision (`u64` is 64 bits wide, but `f64`'s mantissa is only 52 bits wide)"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/util/cpu.rs:82:9 clippy::cast_precision_loss "casting `u64` to `f64` causes a loss of precision (`u64` is 64 bits wide, but `f64`'s mantissa is only 52 bits wide)"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/util/dependency_queue.rs:109:27 clippy::redundant_closure_for_method_calls "redundant closure"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/util/dependency_queue.rs:125:5 clippy::missing_panics_doc "docs for function which may panic missing `# Panics` section"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/util/dependency_queue.rs:151:5 clippy::must_use_candidate "this method could have a `#[must_use]` attribute"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/util/dependency_queue.rs:156:5 clippy::must_use_candidate "this method could have a `#[must_use]` attribute"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/util/dependency_queue.rs:168:5 clippy::missing_panics_doc "docs for function which may panic missing `# Panics` section"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/util/dependency_queue.rs:46:5 clippy::must_use_candidate "this method could have a `#[must_use]` attribute"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/util/dependency_queue.rs:91:9 clippy::items_after_statements "adding items after statements is confusing, since items exist from the start of the scope"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/util/diagnostic_server.rs:218:1 clippy::module_name_repetitions "item name ends with its containing module's name"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/util/diagnostic_server.rs:230:5 clippy::missing_errors_doc "docs for function returning `Result` missing `# Errors` section"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/util/diagnostic_server.rs:242:5 clippy::missing_errors_doc "docs for function returning `Result` missing `# Errors` section"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/util/diagnostic_server.rs:58:5 clippy::missing_errors_doc "docs for function returning `Result` missing `# Errors` section"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/util/diagnostic_server.rs:96:5 clippy::missing_errors_doc "docs for function returning `Result` missing `# Errors` section"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/util/diagnostic_server.rs:96:5 clippy::too_many_lines "this function has too many lines (110/100)"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/util/diagnostic_server.rs:99:21 clippy::shadow_unrelated "`msg` is being shadowed"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/util/errors.rs:101:5 clippy::must_use_candidate "this method could have a `#[must_use]` attribute"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/util/errors.rs:143:5 clippy::must_use_candidate "this method could have a `#[must_use]` attribute"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/util/errors.rs:150:5 clippy::must_use_candidate "this method could have a `#[must_use]` attribute"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/util/errors.rs:15:5 clippy::missing_errors_doc "docs for function returning `Result` missing `# Errors` section"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/util/errors.rs:237:5 clippy::pub_enum_variant_names "variant name ends with the enum's name"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/util/errors.rs:245:5 clippy::must_use_candidate "this method could have a `#[must_use]` attribute"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/util/errors.rs:289:21 clippy::match_wildcard_for_single_variants "wildcard matches only a single variant and will also match any future added variants"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/util/errors.rs:293:13 clippy::match_wildcard_for_single_variants "wildcard matches only a single variant and will also match any future added variants"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/util/errors.rs:321:5 clippy::must_use_candidate "this method could have a `#[must_use]` attribute"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/util/errors.rs:328:5 clippy::must_use_candidate "this method could have a `#[must_use]` attribute"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/util/errors.rs:356:1 clippy::must_use_candidate "this function could have a `#[must_use]` attribute"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/util/errors.rs:391:5 clippy::items_after_statements "adding items after statements is confusing, since items exist from the start of the scope"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/util/errors.rs:392:13 clippy::wildcard_imports "usage of wildcard import"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/util/errors.rs:465:1 clippy::must_use_candidate "this function could have a `#[must_use]` attribute"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/util/errors.rs:473:5 clippy::manual_range_contains "manual `RangeInclusive::contains` implementation"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/util/errors.rs:66:5 clippy::must_use_candidate "this method could have a `#[must_use]` attribute"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/util/flock.rs:115:5 clippy::must_use_candidate "this method could have a `#[must_use]` attribute"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/util/flock.rs:11:5 clippy::wildcard_imports "usage of wildcard import"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/util/flock.rs:134:5 clippy::must_use_candidate "this method could have a `#[must_use]` attribute"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/util/flock.rs:142:5 clippy::must_use_candidate "this method could have a `#[must_use]` attribute"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/util/flock.rs:150:5 clippy::missing_errors_doc "docs for function returning `Result` missing `# Errors` section"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/util/flock.rs:156:5 clippy::must_use_candidate "this method could have a `#[must_use]` attribute"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/util/flock.rs:170:5 clippy::missing_errors_doc "docs for function returning `Result` missing `# Errors` section"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/util/flock.rs:192:5 clippy::missing_errors_doc "docs for function returning `Result` missing `# Errors` section"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/util/flock.rs:29:5 clippy::missing_panics_doc "docs for function which may panic missing `# Panics` section"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/util/flock.rs:29:5 clippy::must_use_candidate "this method could have a `#[must_use]` attribute"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/util/flock.rs:321:5 clippy::items_after_statements "adding items after statements is confusing, since items exist from the start of the scope"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/util/flock.rs:335:23 clippy::cast_possible_truncation "casting `i64` to `u32` may truncate the value"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/util/flock.rs:335:23 clippy::cast_sign_loss "casting `i64` to `u32` may lose the sign of the value"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/util/flock.rs:335:44 clippy::cast_possible_truncation "casting `i64` to `u32` may truncate the value"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/util/flock.rs:379:35 clippy::match_same_arms "this `match` has identical arm bodies"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/util/flock.rs:37:5 clippy::must_use_candidate "this method could have a `#[must_use]` attribute"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/util/flock.rs:43:5 clippy::missing_panics_doc "docs for function which may panic missing `# Panics` section"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/util/flock.rs:43:5 clippy::must_use_candidate "this method could have a `#[must_use]` attribute"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/util/flock.rs:52:5 clippy::missing_errors_doc "docs for function returning `Result` missing `# Errors` section"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/util/flock.rs:52:5 clippy::missing_panics_doc "docs for function which may panic missing `# Panics` section"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/util/flock.rs:96:17 clippy::let_underscore_drop "non-binding `let` on a type that implements `Drop`"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/util/graph.rs:10:5 clippy::must_use_candidate "this method could have a `#[must_use]` attribute"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/util/graph.rs:41:51 clippy::redundant_closure_for_method_calls "redundant closure"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/util/graph.rs:45:5 clippy::must_use_candidate "this method could have a `#[must_use]` attribute"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/util/hasher.rs:12:5 clippy::must_use_candidate "this method could have a `#[must_use]` attribute"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/util/hasher.rs:9:1 clippy::module_name_repetitions "item name ends with its containing module's name"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/util/hex.rs:10:9 clippy::cast_possible_truncation "casting `u64` to `u8` may truncate the value"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/util/hex.rs:11:9 clippy::cast_possible_truncation "casting `u64` to `u8` may truncate the value"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/util/hex.rs:12:9 clippy::cast_possible_truncation "casting `u64` to `u8` may truncate the value"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/util/hex.rs:13:9 clippy::cast_possible_truncation "casting `u64` to `u8` may truncate the value"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/util/hex.rs:14:9 clippy::cast_possible_truncation "casting `u64` to `u8` may truncate the value"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/util/hex.rs:15:9 clippy::cast_possible_truncation "casting `u64` to `u8` may truncate the value"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/util/hex.rs:25:1 clippy::missing_errors_doc "docs for function returning `Result` missing `# Errors` section"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/util/hex.rs:6:1 clippy::module_name_repetitions "item name ends with its containing module's name"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/util/hex.rs:6:1 clippy::must_use_candidate "this function could have a `#[must_use]` attribute"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/util/hex.rs:8:9 clippy::cast_possible_truncation "casting `u64` to `u8` may truncate the value"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/util/hex.rs:9:9 clippy::cast_possible_truncation "casting `u64` to `u8` may truncate the value"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/util/important_paths.rs:23:1 clippy::missing_errors_doc "docs for function returning `Result` missing `# Errors` section"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/util/important_paths.rs:6:1 clippy::missing_errors_doc "docs for function returning `Result` missing `# Errors` section"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/util/interning.rs:66:5 clippy::missing_panics_doc "docs for function which may panic missing `# Panics` section"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/util/interning.rs:66:5 clippy::must_use_candidate "this method could have a `#[must_use]` attribute"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/util/interning.rs:77:5 clippy::must_use_candidate "this method could have a `#[must_use]` attribute"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/util/into_url.rs:10:5 clippy::missing_errors_doc "docs for function returning `Result` missing `# Errors` section"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/util/into_url_with_base.rs:9:5 clippy::missing_errors_doc "docs for function returning `Result` missing `# Errors` section"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/util/job.rs:20:1 clippy::must_use_candidate "this function could have a `#[must_use]` attribute"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/util/lev_distance.rs:3:1 clippy::must_use_candidate "this function could have a `#[must_use]` attribute"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/util/lockserver.rs:111:32 clippy::redundant_else "redundant else block"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/util/lockserver.rs:158:5 clippy::missing_errors_doc "docs for function returning `Result` missing `# Errors` section"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/util/lockserver.rs:46:5 clippy::missing_errors_doc "docs for function returning `Result` missing `# Errors` section"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/util/lockserver.rs:58:5 clippy::must_use_candidate "this method could have a `#[must_use]` attribute"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/util/lockserver.rs:62:5 clippy::missing_errors_doc "docs for function returning `Result` missing `# Errors` section"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/util/mod.rs:68:1 clippy::must_use_candidate "this function could have a `#[must_use]` attribute"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/util/mod.rs:79:1 clippy::must_use_candidate "this function could have a `#[must_use]` attribute"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/util/network.rs:12:5 clippy::missing_errors_doc "docs for function returning `Result` missing `# Errors` section"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/util/network.rs:19:5 clippy::missing_errors_doc "docs for function returning `Result` missing `# Errors` section"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/util/network.rs:84:1 clippy::missing_errors_doc "docs for function returning `Result` missing `# Errors` section"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/util/paths.rs:109:12 clippy::redundant_else "redundant else block"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/util/paths.rs:114:1 clippy::missing_errors_doc "docs for function returning `Result` missing `# Errors` section"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/util/paths.rs:121:1 clippy::missing_errors_doc "docs for function returning `Result` missing `# Errors` section"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/util/paths.rs:125:1 clippy::missing_errors_doc "docs for function returning `Result` missing `# Errors` section"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/util/paths.rs:130:1 clippy::missing_errors_doc "docs for function returning `Result` missing `# Errors` section"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/util/paths.rs:14:1 clippy::missing_errors_doc "docs for function returning `Result` missing `# Errors` section"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/util/paths.rs:14:1 clippy::module_name_repetitions "item name ends with its containing module's name"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/util/paths.rs:151:1 clippy::missing_errors_doc "docs for function returning `Result` missing `# Errors` section"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/util/paths.rs:167:1 clippy::missing_errors_doc "docs for function returning `Result` missing `# Errors` section"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/util/paths.rs:173:1 clippy::missing_errors_doc "docs for function returning `Result` missing `# Errors` section"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/util/paths.rs:178:1 clippy::missing_errors_doc "docs for function returning `Result` missing `# Errors` section"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/util/paths.rs:185:1 clippy::missing_errors_doc "docs for function returning `Result` missing `# Errors` section"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/util/paths.rs:199:1 clippy::missing_errors_doc "docs for function returning `Result` missing `# Errors` section"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/util/paths.rs:215:1 clippy::missing_errors_doc "docs for function returning `Result` missing `# Errors` section"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/util/paths.rs:228:1 clippy::must_use_candidate "this function could have a `#[must_use]` attribute"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/util/paths.rs:251:9 clippy::option_if_let_else "use Option::map_or instead of an if let/else"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/util/paths.rs:267:1 clippy::missing_errors_doc "docs for function returning `Result` missing `# Errors` section"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/util/paths.rs:276:1 clippy::missing_errors_doc "docs for function returning `Result` missing `# Errors` section"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/util/paths.rs:29:1 clippy::must_use_candidate "this function could have a `#[must_use]` attribute"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/util/paths.rs:303:1 clippy::missing_errors_doc "docs for function returning `Result` missing `# Errors` section"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/util/paths.rs:312:1 clippy::missing_errors_doc "docs for function returning `Result` missing `# Errors` section"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/util/paths.rs:346:1 clippy::missing_errors_doc "docs for function returning `Result` missing `# Errors` section"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/util/paths.rs:415:1 clippy::missing_errors_doc "docs for function returning `Result` missing `# Errors` section"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/util/paths.rs:445:1 clippy::missing_errors_doc "docs for function returning `Result` missing `# Errors` section"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/util/paths.rs:459:45 clippy::redundant_closure_for_method_calls "redundant closure"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/util/paths.rs:469:1 clippy::missing_errors_doc "docs for function returning `Result` missing `# Errors` section"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/util/paths.rs:469:1 clippy::missing_panics_doc "docs for function which may panic missing `# Panics` section"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/util/paths.rs:514:5 clippy::let_underscore_drop "non-binding `let` on a type that implements `Drop`"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/util/paths.rs:54:1 clippy::must_use_candidate "this function could have a `#[must_use]` attribute"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/util/paths.rs:61:1 clippy::must_use_candidate "this function could have a `#[must_use]` attribute"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/util/paths.rs:63:19 clippy::option_if_let_else "use Option::map_or_else instead of an if let/else"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/util/paths.rs:88:1 clippy::missing_errors_doc "docs for function returning `Result` missing `# Errors` section"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/util/paths.rs:93:31 clippy::comparison_to_empty "comparison to empty slice"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/util/process_builder.rs:106:5 clippy::must_use_candidate "this method could have a `#[must_use]` attribute"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/util/process_builder.rs:111:5 clippy::must_use_candidate "this method could have a `#[must_use]` attribute"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/util/process_builder.rs:122:5 clippy::must_use_candidate "this method could have a `#[must_use]` attribute"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/util/process_builder.rs:132:5 clippy::must_use_candidate "this method could have a `#[must_use]` attribute"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/util/process_builder.rs:152:5 clippy::missing_errors_doc "docs for function returning `Result` missing `# Errors` section"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/util/process_builder.rs:185:5 clippy::missing_errors_doc "docs for function returning `Result` missing `# Errors` section"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/util/process_builder.rs:190:5 clippy::missing_errors_doc "docs for function returning `Result` missing `# Errors` section"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/util/process_builder.rs:218:5 clippy::missing_errors_doc "docs for function returning `Result` missing `# Errors` section"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/util/process_builder.rs:218:5 clippy::missing_panics_doc "docs for function which may panic missing `# Panics` section"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/util/process_builder.rs:278:22 clippy::inconsistent_struct_constructor "struct constructor field order is inconsistent with struct definition field order"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/util/process_builder.rs:307:5 clippy::must_use_candidate "this method could have a `#[must_use]` attribute"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/util/process_builder.rs:343:39 clippy::needless_pass_by_value "this argument is passed by value, but not consumed in the function body"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/util/progress.rs:122:5 clippy::missing_errors_doc "docs for function returning `Result` missing `# Errors` section"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/util/progress.rs:136:5 clippy::missing_errors_doc "docs for function returning `Result` missing `# Errors` section"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/util/progress.rs:15:1 clippy::module_name_repetitions "item name starts with its containing module's name"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/util/progress.rs:249:19 clippy::cast_precision_loss "casting `usize` to `f64` causes a loss of precision on targets with 64-bit wide pointers (`usize` is 64 bits wide, but `f64`'s mantissa is only 52 bits wide)"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/util/progress.rs:249:34 clippy::cast_precision_loss "casting `usize` to `f64` causes a loss of precision on targets with 64-bit wide pointers (`usize` is 64 bits wide, but `f64`'s mantissa is only 52 bits wide)"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/util/progress.rs:250:19 clippy::if_not_else "unnecessary boolean `not` operation"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/util/progress.rs:263:22 clippy::cast_precision_loss "casting `usize` to `f64` causes a loss of precision on targets with 64-bit wide pointers (`usize` is 64 bits wide, but `f64`'s mantissa is only 52 bits wide)"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/util/progress.rs:264:22 clippy::cast_possible_truncation "casting `f64` to `usize` may truncate the value"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/util/progress.rs:264:22 clippy::cast_sign_loss "casting `f64` to `usize` may lose the sign of the value"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/util/progress.rs:269:17 clippy::single_char_add_str "calling `push_str()` using a single-character string literal"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/util/progress.rs:272:17 clippy::single_char_add_str "calling `push_str()` using a single-character string literal"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/util/progress.rs:274:17 clippy::single_char_add_str "calling `push_str()` using a single-character string literal"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/util/progress.rs:280:13 clippy::single_char_add_str "calling `push_str()` using a single-character string literal"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/util/progress.rs:282:9 clippy::single_char_add_str "calling `push_str()` using a single-character string literal"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/util/progress.rs:89:5 clippy::must_use_candidate "this method could have a `#[must_use]` attribute"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/util/progress.rs:97:5 clippy::missing_errors_doc "docs for function returning `Result` missing `# Errors` section"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/util/queue.rs:25:5 clippy::must_use_candidate "this method could have a `#[must_use]` attribute"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/util/queue.rs:36:5 clippy::missing_panics_doc "docs for function which may panic missing `# Panics` section"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/util/queue.rs:42:5 clippy::missing_panics_doc "docs for function which may panic missing `# Panics` section"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/util/queue.rs:52:5 clippy::missing_panics_doc "docs for function which may panic missing `# Panics` section"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/util/queue.rs:69:5 clippy::missing_panics_doc "docs for function which may panic missing `# Panics` section"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/util/read2.rs:11:5 clippy::missing_errors_doc "docs for function returning `Result` missing `# Errors` section"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/util/read2.rs:31:17 clippy::similar_names "binding's name is too similar to existing binding"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/util/restricted_names.rs:13:1 clippy::must_use_candidate "this function could have a `#[must_use]` attribute"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/util/restricted_names.rs:26:1 clippy::must_use_candidate "this function could have a `#[must_use]` attribute"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/util/restricted_names.rs:35:1 clippy::must_use_candidate "this function could have a `#[must_use]` attribute"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/util/restricted_names.rs:45:1 clippy::missing_errors_doc "docs for function returning `Result` missing `# Errors` section"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/util/restricted_names.rs:87:1 clippy::missing_panics_doc "docs for function which may panic missing `# Panics` section"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/util/restricted_names.rs:87:1 clippy::must_use_candidate "this function could have a `#[must_use]` attribute"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/util/restricted_names.rs:89:21 clippy::redundant_closure_for_method_calls "redundant closure"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/util/restricted_names.rs:8:1 clippy::must_use_candidate "this function could have a `#[must_use]` attribute"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/util/rustc.rs:103:5 clippy::missing_errors_doc "docs for function returning `Result` missing `# Errors` section"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/util/rustc.rs:103:5 clippy::missing_panics_doc "docs for function which may panic missing `# Panics` section"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/util/rustc.rs:114:5 clippy::doc_markdown "you should put bare URLs between `<`/`>` or make a proper Markdown link"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/util/rustc.rs:115:5 clippy::doc_markdown "you should put bare URLs between `<`/`>` or make a proper Markdown link"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/util/rustc.rs:162:17 clippy::items_after_statements "adding items after statements is confusing, since items exist from the start of the scope"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/util/rustc.rs:39:5 clippy::missing_errors_doc "docs for function returning `Result` missing `# Errors` section"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/util/sha256.rs:10:5 clippy::must_use_candidate "this method could have a `#[must_use]` attribute"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/util/sha256.rs:16:9 clippy::let_underscore_drop "non-binding `let` on a type that implements `Drop`"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/util/sha256.rs:20:5 clippy::missing_errors_doc "docs for function returning `Result` missing `# Errors` section"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/util/sha256.rs:31:5 clippy::missing_errors_doc "docs for function returning `Result` missing `# Errors` section"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/util/sha256.rs:40:24 clippy::unseparated_literal_suffix "integer type suffix should be separated by an underscore"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/util/to_semver.rs:5:5 clippy::missing_errors_doc "docs for function returning `Result` missing `# Errors` section"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/util/toml/mod.rs:1005:5 clippy::missing_errors_doc "docs for function returning `Result` missing `# Errors` section"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/util/toml/mod.rs:1005:5 clippy::too_many_lines "this function has too many lines (282/100)"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/util/toml/mod.rs:1094:36 clippy::redundant_closure_for_method_calls "redundant closure"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/util/toml/mod.rs:1121:13 clippy::items_after_statements "adding items after statements is confusing, since items exist from the start of the scope"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/util/toml/mod.rs:1197:32 clippy::map_unwrap_or "called `map(<f>).unwrap_or_else(<g>)` on an `Option` value. This can be done more directly by calling `map_or_else(<g>, <f>)` instead"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/util/toml/mod.rs:124:1 clippy::missing_errors_doc "docs for function returning `Result` missing `# Errors` section"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/util/toml/mod.rs:1504:9 clippy::unused_self "unused `self` argument"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/util/toml/mod.rs:1526:5 clippy::must_use_candidate "this method could have a `#[must_use]` attribute"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/util/toml/mod.rs:1582:19 clippy::default_trait_access "calling `util::toml::DetailedTomlDependency::default()` is more clear than this expression"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/util/toml/mod.rs:1598:5 clippy::too_many_lines "this function has too many lines (153/100)"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/util/toml/mod.rs:1687:33 clippy::unnecessary_lazy_evaluations "unnecessary closure used to substitute value for `Option::None`"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/util/toml/mod.rs:178:1 clippy::module_name_repetitions "item name starts with its containing module's name"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/util/toml/mod.rs:248:1 clippy::module_name_repetitions "item name starts with its containing module's name"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/util/toml/mod.rs:274:1 clippy::module_name_repetitions "item name starts with its containing module's name"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/util/toml/mod.rs:277:5 clippy::must_use_candidate "this method could have a `#[must_use]` attribute"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/util/toml/mod.rs:281:5 clippy::must_use_candidate "this method could have a `#[must_use]` attribute"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/util/toml/mod.rs:285:5 clippy::missing_errors_doc "docs for function returning `Result` missing `# Errors` section"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/util/toml/mod.rs:294:1 clippy::module_name_repetitions "item name starts with its containing module's name"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/util/toml/mod.rs:31:1 clippy::missing_errors_doc "docs for function returning `Result` missing `# Errors` section"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/util/toml/mod.rs:381:35 clippy::cast_possible_truncation "casting `i64` to `u32` may truncate the value"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/util/toml/mod.rs:381:35 clippy::cast_sign_loss "casting `i64` to `u32` may lose the sign of the value"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/util/toml/mod.rs:388:35 clippy::cast_possible_truncation "casting `u64` to `u32` may truncate the value"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/util/toml/mod.rs:398:1 clippy::module_name_repetitions "item name starts with its containing module's name"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/util/toml/mod.rs:450:5 clippy::missing_errors_doc "docs for function returning `Result` missing `# Errors` section"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/util/toml/mod.rs:536:5 clippy::missing_errors_doc "docs for function returning `Result` missing `# Errors` section"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/util/toml/mod.rs:783:1 clippy::module_name_repetitions "item name starts with its containing module's name"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/util/toml/mod.rs:824:1 clippy::module_name_repetitions "item name starts with its containing module's name"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/util/toml/mod.rs:834:5 clippy::missing_errors_doc "docs for function returning `Result` missing `# Errors` section"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/util/toml/mod.rs:83:42 clippy::redundant_closure_for_method_calls "redundant closure"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/util/toml/mod.rs:852:5 clippy::missing_errors_doc "docs for function returning `Result` missing `# Errors` section"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/util/toml/mod.rs:852:5 clippy::missing_panics_doc "docs for function which may panic missing `# Panics` section"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/util/toml/mod.rs:852:5 clippy::too_many_lines "this function has too many lines (138/100)"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/util/toml/mod.rs:962:9 clippy::items_after_statements "adding items after statements is confusing, since items exist from the start of the scope"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/util/toml/mod.rs:979:9 clippy::items_after_statements "adding items after statements is confusing, since items exist from the start of the scope"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/util/toml/mod.rs:98:5 clippy::items_after_statements "adding items after statements is confusing, since items exist from the start of the scope"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/util/toml/mod.rs:999:23 clippy::default_trait_access "calling `util::toml::DetailedTomlDependency::default()` is more clear than this expression"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/util/toml/targets.rs:112:27 clippy::redundant_closure_for_method_calls "redundant closure"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/util/toml/targets.rs:325:5 clippy::items_after_statements "adding items after statements is confusing, since items exist from the start of the scope"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/util/toml/targets.rs:586:21 clippy::redundant_closure_for_method_calls "redundant closure"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/util/toml/targets.rs:593:42 clippy::redundant_closure_for_method_calls "redundant closure"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/util/toml/targets.rs:605:19 clippy::redundant_closure_for_method_calls "redundant closure"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/util/toml/targets.rs:612:42 clippy::redundant_closure_for_method_calls "redundant closure"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/util/vcs.rs:10:1 clippy::must_use_candidate "this function could have a `#[must_use]` attribute"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/util/vcs.rs:33:5 clippy::missing_errors_doc "docs for function returning `Result` missing `# Errors` section"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/util/vcs.rs:37:5 clippy::missing_errors_doc "docs for function returning `Result` missing `# Errors` section"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/util/vcs.rs:43:5 clippy::missing_errors_doc "docs for function returning `Result` missing `# Errors` section"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/util/vcs.rs:47:5 clippy::missing_errors_doc "docs for function returning `Result` missing `# Errors` section"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/util/vcs.rs:59:5 clippy::missing_errors_doc "docs for function returning `Result` missing `# Errors` section"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/util/vcs.rs:66:5 clippy::missing_errors_doc "docs for function returning `Result` missing `# Errors` section"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/util/workspace.rs:52:1 clippy::missing_errors_doc "docs for function returning `Result` missing `# Errors` section"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/util/workspace.rs:56:1 clippy::missing_errors_doc "docs for function returning `Result` missing `# Errors` section"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/util/workspace.rs:60:1 clippy::missing_errors_doc "docs for function returning `Result` missing `# Errors` section"
-target/lintcheck/sources/cargo-0.49.0/src/cargo/util/workspace.rs:64:1 clippy::missing_errors_doc "docs for function returning `Result` missing `# Errors` section"
-target/lintcheck/sources/cfg-expr-0.7.1/src/error.rs:107:13 clippy::enum_glob_use "usage of wildcard import for enum variants"
-target/lintcheck/sources/cfg-expr-0.7.1/src/error.rs:55:13 clippy::unnested_or_patterns "unnested or-patterns"
-target/lintcheck/sources/cfg-expr-0.7.1/src/error.rs:58:13 clippy::unnested_or_patterns "unnested or-patterns"
-target/lintcheck/sources/cfg-expr-0.7.1/src/error.rs:5:1 clippy::module_name_repetitions "item name ends with its containing module's name"
-target/lintcheck/sources/cfg-expr-0.7.1/src/error.rs:74:13 clippy::enum_glob_use "usage of wildcard import for enum variants"
-target/lintcheck/sources/cfg-expr-0.7.1/src/error.rs:91:24 clippy::if_not_else "unnecessary boolean `not` operation"
-target/lintcheck/sources/cfg-expr-0.7.1/src/expr/lexer.rs:102:9 clippy::items_after_statements "adding items after statements is confusing, since items exist from the start of the scope"
-target/lintcheck/sources/cfg-expr-0.7.1/src/expr/lexer.rs:125:33 clippy::redundant_slicing "redundant slicing of the whole range"
-target/lintcheck/sources/cfg-expr-0.7.1/src/expr/lexer.rs:4:5 clippy::doc_markdown "you should put bare URLs between `<`/`>` or make a proper Markdown link"
-target/lintcheck/sources/cfg-expr-0.7.1/src/expr/lexer.rs:58:5 clippy::must_use_candidate "this method could have a `#[must_use]` attribute"
-target/lintcheck/sources/cfg-expr-0.7.1/src/expr/lexer.rs:76:1 clippy::module_name_repetitions "item name starts with its containing module's name"
-target/lintcheck/sources/cfg-expr-0.7.1/src/expr/lexer.rs:97:9 clippy::items_after_statements "adding items after statements is confusing, since items exist from the start of the scope"
-target/lintcheck/sources/cfg-expr-0.7.1/src/expr/mod.rs:351:13 clippy::enum_glob_use "usage of wildcard import for enum variants"
-target/lintcheck/sources/cfg-expr-0.7.1/src/expr/mod.rs:408:13 clippy::match_wildcard_for_single_variants "wildcard matches only a single variant and will also match any future added variants"
-target/lintcheck/sources/cfg-expr-0.7.1/src/expr/mod.rs:464:5 clippy::missing_panics_doc "docs for function which may panic missing `# Panics` section"
-target/lintcheck/sources/cfg-expr-0.7.1/src/expr/mod.rs:57:13 clippy::enum_glob_use "usage of wildcard import for enum variants"
-target/lintcheck/sources/cfg-expr-0.7.1/src/expr/mod.rs:586:33 clippy::match_same_arms "this `match` has identical arm bodies"
-target/lintcheck/sources/cfg-expr-0.7.1/src/expr/mod.rs:599:32 clippy::match_same_arms "this `match` has identical arm bodies"
-target/lintcheck/sources/cfg-expr-0.7.1/src/expr/mod.rs:609:9 clippy::manual_map "manual implementation of `Option::map`"
-target/lintcheck/sources/cfg-expr-0.7.1/src/expr/parser.rs:116:31 clippy::similar_names "binding's name is too similar to existing binding"
-target/lintcheck/sources/cfg-expr-0.7.1/src/expr/parser.rs:124:36 clippy::similar_names "binding's name is too similar to existing binding"
-target/lintcheck/sources/cfg-expr-0.7.1/src/expr/parser.rs:17:5 clippy::missing_errors_doc "docs for function returning `Result` missing `# Errors` section"
-target/lintcheck/sources/cfg-expr-0.7.1/src/expr/parser.rs:17:5 clippy::too_many_lines "this function has too many lines (345/100)"
-target/lintcheck/sources/cfg-expr-0.7.1/src/expr/parser.rs:211:21 clippy::unnested_or_patterns "unnested or-patterns"
-target/lintcheck/sources/cfg-expr-0.7.1/src/expr/parser.rs:211:21 clippy::unnested_or_patterns "unnested or-patterns"
-target/lintcheck/sources/cfg-expr-0.7.1/src/expr/parser.rs:211:21 clippy::unnested_or_patterns "unnested or-patterns"
-target/lintcheck/sources/cfg-expr-0.7.1/src/expr/parser.rs:211:21 clippy::unnested_or_patterns "unnested or-patterns"
-target/lintcheck/sources/cfg-expr-0.7.1/src/expr/parser.rs:211:21 clippy::unnested_or_patterns "unnested or-patterns"
-target/lintcheck/sources/cfg-expr-0.7.1/src/expr/parser.rs:211:21 clippy::unnested_or_patterns "unnested or-patterns"
-target/lintcheck/sources/cfg-expr-0.7.1/src/expr/parser.rs:211:21 clippy::unnested_or_patterns "unnested or-patterns"
-target/lintcheck/sources/cfg-expr-0.7.1/src/expr/parser.rs:22:13 clippy::shadow_unrelated "`original` is being shadowed"
-target/lintcheck/sources/cfg-expr-0.7.1/src/expr/parser.rs:238:21 clippy::unnested_or_patterns "unnested or-patterns"
-target/lintcheck/sources/cfg-expr-0.7.1/src/expr/parser.rs:243:36 clippy::single_match_else "you seem to be trying to use `match` for destructuring a single pattern. Consider using `if let`"
-target/lintcheck/sources/cfg-expr-0.7.1/src/expr/parser.rs:254:34 clippy::single_match_else "you seem to be trying to use `match` for destructuring a single pattern. Consider using `if let`"
-target/lintcheck/sources/cfg-expr-0.7.1/src/expr/parser.rs:259:21 clippy::unnested_or_patterns "unnested or-patterns"
-target/lintcheck/sources/cfg-expr-0.7.1/src/expr/parser.rs:25:9 clippy::items_after_statements "adding items after statements is confusing, since items exist from the start of the scope"
-target/lintcheck/sources/cfg-expr-0.7.1/src/expr/parser.rs:284:21 clippy::unnested_or_patterns "unnested or-patterns"
-target/lintcheck/sources/cfg-expr-0.7.1/src/expr/parser.rs:292:21 clippy::unnested_or_patterns "unnested or-patterns"
-target/lintcheck/sources/cfg-expr-0.7.1/src/expr/parser.rs:347:21 clippy::unnested_or_patterns "unnested or-patterns"
-target/lintcheck/sources/cfg-expr-0.7.1/src/expr/parser.rs:390:9 clippy::single_match_else "you seem to be trying to use `match` for destructuring a single pattern. Consider using `if let`"
-target/lintcheck/sources/cfg-expr-0.7.1/src/expr/parser.rs:392:17 clippy::if_not_else "unnecessary `!=` operation"
-target/lintcheck/sources/cfg-expr-0.7.1/src/expr/parser.rs:39:31 clippy::too_many_lines "this function has too many lines (136/100)"
-target/lintcheck/sources/cfg-expr-0.7.1/src/expr/parser.rs:67:13 clippy::items_after_statements "adding items after statements is confusing, since items exist from the start of the scope"
-target/lintcheck/sources/cfg-expr-0.7.1/src/lib.rs:1:null clippy::cargo_common_metadata "package `cfg-expr` is missing `package.categories` metadata"
-target/lintcheck/sources/cfg-expr-0.7.1/src/targets/builtins.rs:11:5 clippy::wildcard_imports "usage of wildcard import"
-target/lintcheck/sources/cfg-expr-0.7.1/src/targets/mod.rs:139:1 clippy::must_use_candidate "this function could have a `#[must_use]` attribute"
-target/lintcheck/sources/cfg-expr-0.7.1/src/targets/mod.rs:153:1 clippy::must_use_candidate "this function could have a `#[must_use]` attribute"
-target/lintcheck/sources/cxx-1.0.32/src/rust_string.rs:15:20 clippy::ptr_as_ptr "`as` casting between raw pointers without changing its mutability"
-target/lintcheck/sources/cxx-1.0.32/src/rust_string.rs:19:24 clippy::ptr_as_ptr "`as` casting between raw pointers without changing its mutability"
-target/lintcheck/sources/cxx-1.0.32/src/rust_vec.rs:21:20 clippy::ptr_as_ptr "`as` casting between raw pointers without changing its mutability"
-target/lintcheck/sources/cxx-1.0.32/src/rust_vec.rs:25:24 clippy::ptr_as_ptr "`as` casting between raw pointers without changing its mutability"
-target/lintcheck/sources/cxx-1.0.32/src/rust_vec.rs:74:35 clippy::ptr_as_ptr "`as` casting between raw pointers without changing its mutability"
-target/lintcheck/sources/cxx-1.0.32/src/rust_vec.rs:78:39 clippy::ptr_as_ptr "`as` casting between raw pointers without changing its mutability"
-target/lintcheck/sources/cxx-1.0.32/src/rust_vec.rs:90:20 clippy::ptr_as_ptr "`as` casting between raw pointers without changing its mutability"
-target/lintcheck/sources/cxx-1.0.32/src/rust_vec.rs:94:24 clippy::ptr_as_ptr "`as` casting between raw pointers without changing its mutability"
-target/lintcheck/sources/cxx-1.0.32/src/shared_ptr.rs:108:20 clippy::ptr_as_ptr "`as` casting between raw pointers without changing its mutability"
-target/lintcheck/sources/cxx-1.0.32/src/shared_ptr.rs:165:9 clippy::let_underscore_drop "non-binding `let` on a type that implements `Drop`"
-target/lintcheck/sources/cxx-1.0.32/src/shared_ptr.rs:54:20 clippy::ptr_as_ptr "`as` casting between raw pointers without changing its mutability"
-target/lintcheck/sources/cxx-1.0.32/src/shared_ptr.rs:62:20 clippy::ptr_as_ptr "`as` casting between raw pointers without changing its mutability"
-target/lintcheck/sources/cxx-1.0.32/src/shared_ptr.rs:75:20 clippy::ptr_as_ptr "`as` casting between raw pointers without changing its mutability"
-target/lintcheck/sources/cxx-1.0.32/src/unique_ptr.rs:185:9 clippy::let_underscore_drop "non-binding `let` on a type that implements `Drop`"
-target/lintcheck/sources/cxx-1.0.32/src/unwind.rs:22:5 clippy::let_underscore_drop "non-binding `let` on a type that implements `Drop`"
-target/lintcheck/sources/cxx-1.0.32/src/weak_ptr.rs:47:20 clippy::ptr_as_ptr "`as` casting between raw pointers without changing its mutability"
-target/lintcheck/sources/cxx-1.0.32/src/weak_ptr.rs:80:20 clippy::ptr_as_ptr "`as` casting between raw pointers without changing its mutability"
-target/lintcheck/sources/iron-0.6.1/src/error.rs:24:1 clippy::module_name_repetitions "item name ends with its containing module's name"
-target/lintcheck/sources/iron-0.6.1/src/iron.rs:105:13 clippy::redundant_field_names "redundant field names in struct initialization"
-target/lintcheck/sources/iron-0.6.1/src/iron.rs:119:5 clippy::missing_errors_doc "docs for function returning `Result` missing `# Errors` section"
-target/lintcheck/sources/iron-0.6.1/src/iron.rs:133:5 clippy::missing_errors_doc "docs for function returning `Result` missing `# Errors` section"
-target/lintcheck/sources/iron-0.6.1/src/iron.rs:143:5 clippy::missing_errors_doc "docs for function returning `Result` missing `# Errors` section"
-target/lintcheck/sources/iron-0.6.1/src/iron.rs:149:13 clippy::redundant_field_names "redundant field names in struct initialization"
-target/lintcheck/sources/iron-0.6.1/src/iron.rs:167:49 clippy::similar_names "binding's name is too similar to existing binding"
-target/lintcheck/sources/iron-0.6.1/src/iron.rs:196:9 clippy::let_underscore_drop "non-binding `let` on a type that implements `Drop`"
-target/lintcheck/sources/iron-0.6.1/src/iron.rs:80:5 clippy::must_use_candidate "this method could have a `#[must_use]` attribute"
-target/lintcheck/sources/iron-0.6.1/src/iron.rs:85:5 clippy::must_use_candidate "this method could have a `#[must_use]` attribute"
-target/lintcheck/sources/iron-0.6.1/src/iron.rs:90:5 clippy::must_use_candidate "this method could have a `#[must_use]` attribute"
-target/lintcheck/sources/iron-0.6.1/src/lib.rs:1:null clippy::cargo_common_metadata "package `iron` is missing `package.categories` metadata"
-target/lintcheck/sources/iron-0.6.1/src/lib.rs:1:null clippy::cargo_common_metadata "package `iron` is missing `package.keywords` metadata"
-target/lintcheck/sources/iron-0.6.1/src/lib.rs:1:null clippy::multiple_crate_versions "multiple versions for dependency `log`: 0.3.9, 0.4.8"
-target/lintcheck/sources/iron-0.6.1/src/middleware/mod.rs:137:5 clippy::missing_errors_doc "docs for function returning `Result` missing `# Errors` section"
-target/lintcheck/sources/iron-0.6.1/src/middleware/mod.rs:150:1 clippy::module_name_repetitions "item name ends with its containing module's name"
-target/lintcheck/sources/iron-0.6.1/src/middleware/mod.rs:152:5 clippy::missing_errors_doc "docs for function returning `Result` missing `# Errors` section"
-target/lintcheck/sources/iron-0.6.1/src/middleware/mod.rs:159:5 clippy::missing_errors_doc "docs for function returning `Result` missing `# Errors` section"
-target/lintcheck/sources/iron-0.6.1/src/middleware/mod.rs:171:1 clippy::module_name_repetitions "item name ends with its containing module's name"
-target/lintcheck/sources/iron-0.6.1/src/middleware/mod.rs:173:5 clippy::missing_errors_doc "docs for function returning `Result` missing `# Errors` section"
-target/lintcheck/sources/iron-0.6.1/src/middleware/mod.rs:182:5 clippy::missing_errors_doc "docs for function returning `Result` missing `# Errors` section"
-target/lintcheck/sources/iron-0.6.1/src/middleware/mod.rs:192:1 clippy::module_name_repetitions "item name ends with its containing module's name"
-target/lintcheck/sources/iron-0.6.1/src/middleware/mod.rs:217:25 clippy::doc_markdown "you should put `ChainBuilder` between ticks in the documentation"
-target/lintcheck/sources/iron-0.6.1/src/middleware/mod.rs:264:5 clippy::missing_panics_doc "docs for function which may panic missing `# Panics` section"
-target/lintcheck/sources/iron-0.6.1/src/middleware/mod.rs:328:20 clippy::similar_names "binding's name is too similar to existing binding"
-target/lintcheck/sources/iron-0.6.1/src/middleware/mod.rs:360:16 clippy::similar_names "binding's name is too similar to existing binding"
-target/lintcheck/sources/iron-0.6.1/src/middleware/mod.rs:368:33 clippy::similar_names "binding's name is too similar to existing binding"
-target/lintcheck/sources/iron-0.6.1/src/middleware/mod.rs:428:40 clippy::similar_names "binding's name is too similar to existing binding"
-target/lintcheck/sources/iron-0.6.1/src/middleware/mod.rs:434:40 clippy::similar_names "binding's name is too similar to existing binding"
-target/lintcheck/sources/iron-0.6.1/src/middleware/mod.rs:444:40 clippy::similar_names "binding's name is too similar to existing binding"
-target/lintcheck/sources/iron-0.6.1/src/modifiers.rs:132:14 clippy::expect_fun_call "use of `expect` followed by a function call"
-target/lintcheck/sources/iron-0.6.1/src/request/mod.rs:113:24 clippy::similar_names "binding's name is too similar to existing binding"
-target/lintcheck/sources/iron-0.6.1/src/request/mod.rs:121:13 clippy::redundant_field_names "redundant field names in struct initialization"
-target/lintcheck/sources/iron-0.6.1/src/request/mod.rs:123:13 clippy::redundant_field_names "redundant field names in struct initialization"
-target/lintcheck/sources/iron-0.6.1/src/request/mod.rs:124:13 clippy::redundant_field_names "redundant field names in struct initialization"
-target/lintcheck/sources/iron-0.6.1/src/request/mod.rs:126:13 clippy::redundant_field_names "redundant field names in struct initialization"
-target/lintcheck/sources/iron-0.6.1/src/request/mod.rs:128:13 clippy::redundant_field_names "redundant field names in struct initialization"
-target/lintcheck/sources/iron-0.6.1/src/request/mod.rs:153:69 clippy::doc_markdown "you should put `HttpReader` between ticks in the documentation"
-target/lintcheck/sources/iron-0.6.1/src/request/mod.rs:154:5 clippy::must_use_candidate "this method could have a `#[must_use]` attribute"
-target/lintcheck/sources/iron-0.6.1/src/request/mod.rs:32:1 clippy::manual_non_exhaustive "this seems like a manual implementation of the non-exhaustive pattern"
-target/lintcheck/sources/iron-0.6.1/src/request/mod.rs:75:34 clippy::doc_markdown "you should put `HttpRequest` between ticks in the documentation"
-target/lintcheck/sources/iron-0.6.1/src/request/mod.rs:77:39 clippy::doc_markdown "you should put `HttpRequest` between ticks in the documentation"
-target/lintcheck/sources/iron-0.6.1/src/request/mod.rs:78:5 clippy::missing_errors_doc "docs for function returning `Result` missing `# Errors` section"
-target/lintcheck/sources/iron-0.6.1/src/request/mod.rs:82:13 clippy::similar_names "binding's name is too similar to existing binding"
-target/lintcheck/sources/iron-0.6.1/src/request/mod.rs:83:29 clippy::similar_names "binding's name is too similar to existing binding"
-target/lintcheck/sources/iron-0.6.1/src/request/mod.rs:85:24 clippy::similar_names "binding's name is too similar to existing binding"
-target/lintcheck/sources/iron-0.6.1/src/request/url.rs:109:5 clippy::must_use_candidate "this method could have a `#[must_use]` attribute"
-target/lintcheck/sources/iron-0.6.1/src/request/url.rs:117:5 clippy::must_use_candidate "this method could have a `#[must_use]` attribute"
-target/lintcheck/sources/iron-0.6.1/src/request/url.rs:129:1 clippy::from_over_into "an implementation of `From` is preferred since it gives you `Into<_>` for free where the reverse isn't true"
-target/lintcheck/sources/iron-0.6.1/src/request/url.rs:21:14 clippy::doc_markdown "you should put bare URLs between `<`/`>` or make a proper Markdown link"
-target/lintcheck/sources/iron-0.6.1/src/request/url.rs:22:5 clippy::missing_errors_doc "docs for function returning `Result` missing `# Errors` section"
-target/lintcheck/sources/iron-0.6.1/src/request/url.rs:31:5 clippy::missing_errors_doc "docs for function returning `Result` missing `# Errors` section"
-target/lintcheck/sources/iron-0.6.1/src/request/url.rs:47:5 clippy::must_use_candidate "this method could have a `#[must_use]` attribute"
-target/lintcheck/sources/iron-0.6.1/src/request/url.rs:52:5 clippy::must_use_candidate "this method could have a `#[must_use]` attribute"
-target/lintcheck/sources/iron-0.6.1/src/request/url.rs:57:5 clippy::missing_panics_doc "docs for function which may panic missing `# Panics` section"
-target/lintcheck/sources/iron-0.6.1/src/request/url.rs:57:5 clippy::must_use_candidate "this method could have a `#[must_use]` attribute"
-target/lintcheck/sources/iron-0.6.1/src/request/url.rs:63:5 clippy::missing_panics_doc "docs for function which may panic missing `# Panics` section"
-target/lintcheck/sources/iron-0.6.1/src/request/url.rs:63:5 clippy::must_use_candidate "this method could have a `#[must_use]` attribute"
-target/lintcheck/sources/iron-0.6.1/src/request/url.rs:73:5 clippy::missing_panics_doc "docs for function which may panic missing `# Panics` section"
-target/lintcheck/sources/iron-0.6.1/src/request/url.rs:73:5 clippy::must_use_candidate "this method could have a `#[must_use]` attribute"
-target/lintcheck/sources/iron-0.6.1/src/request/url.rs:83:5 clippy::must_use_candidate "this method could have a `#[must_use]` attribute"
-target/lintcheck/sources/iron-0.6.1/src/request/url.rs:96:5 clippy::must_use_candidate "this method could have a `#[must_use]` attribute"
-target/lintcheck/sources/iron-0.6.1/src/response.rs:121:19 clippy::single_match_else "you seem to be trying to use `match` for destructuring a single pattern. Consider using `if let`"
-target/lintcheck/sources/iron-0.6.1/src/response.rs:125:43 clippy::redundant_closure_for_method_calls "redundant closure"
-target/lintcheck/sources/iron-0.6.1/src/response.rs:139:41 clippy::redundant_closure_for_method_calls "redundant closure"
-target/lintcheck/sources/iron-0.6.1/src/response.rs:24:5 clippy::missing_errors_doc "docs for function returning `Result` missing `# Errors` section"
-target/lintcheck/sources/iron-0.6.1/src/response.rs:95:5 clippy::must_use_candidate "this method could have a `#[must_use]` attribute"
-target/lintcheck/sources/iron-0.6.1/src/response.rs:95:5 clippy::new_without_default "you should consider adding a `Default` implementation for `response::Response`"
-target/lintcheck/sources/libc-0.2.81/build.rs:114:19 clippy::map_unwrap_or "called `map(<f>).unwrap_or(<a>)` on an `Option` value. This can be done more directly by calling `map_or(<a>, <f>)` instead"
-target/lintcheck/sources/libc-0.2.81/build.rs:124:5 clippy::question_mark "this block may be rewritten with the `?` operator"
-target/lintcheck/sources/libc-0.2.81/build.rs:133:5 clippy::question_mark "this block may be rewritten with the `?` operator"
-target/lintcheck/sources/libc-0.2.81/src/macros.rs:120:9 clippy::expl_impl_clone_on_copy "you are implementing `Clone` explicitly on a `Copy` type"
-target/lintcheck/sources/libc-0.2.81/src/macros.rs:120:9 clippy::expl_impl_clone_on_copy "you are implementing `Clone` explicitly on a `Copy` type"
-target/lintcheck/sources/libc-0.2.81/src/macros.rs:120:9 clippy::expl_impl_clone_on_copy "you are implementing `Clone` explicitly on a `Copy` type"
-target/lintcheck/sources/libc-0.2.81/src/macros.rs:120:9 clippy::expl_impl_clone_on_copy "you are implementing `Clone` explicitly on a `Copy` type"
-target/lintcheck/sources/libc-0.2.81/src/macros.rs:120:9 clippy::expl_impl_clone_on_copy "you are implementing `Clone` explicitly on a `Copy` type"
-target/lintcheck/sources/libc-0.2.81/src/macros.rs:120:9 clippy::expl_impl_clone_on_copy "you are implementing `Clone` explicitly on a `Copy` type"
-target/lintcheck/sources/libc-0.2.81/src/macros.rs:120:9 clippy::expl_impl_clone_on_copy "you are implementing `Clone` explicitly on a `Copy` type"
-target/lintcheck/sources/libc-0.2.81/src/macros.rs:120:9 clippy::expl_impl_clone_on_copy "you are implementing `Clone` explicitly on a `Copy` type"
-target/lintcheck/sources/libc-0.2.81/src/macros.rs:120:9 clippy::expl_impl_clone_on_copy "you are implementing `Clone` explicitly on a `Copy` type"
-target/lintcheck/sources/libc-0.2.81/src/macros.rs:120:9 clippy::expl_impl_clone_on_copy "you are implementing `Clone` explicitly on a `Copy` type"
-target/lintcheck/sources/libc-0.2.81/src/macros.rs:120:9 clippy::expl_impl_clone_on_copy "you are implementing `Clone` explicitly on a `Copy` type"
-target/lintcheck/sources/libc-0.2.81/src/macros.rs:120:9 clippy::expl_impl_clone_on_copy "you are implementing `Clone` explicitly on a `Copy` type"
-target/lintcheck/sources/libc-0.2.81/src/macros.rs:120:9 clippy::expl_impl_clone_on_copy "you are implementing `Clone` explicitly on a `Copy` type"
-target/lintcheck/sources/libc-0.2.81/src/macros.rs:120:9 clippy::expl_impl_clone_on_copy "you are implementing `Clone` explicitly on a `Copy` type"
-target/lintcheck/sources/libc-0.2.81/src/macros.rs:120:9 clippy::expl_impl_clone_on_copy "you are implementing `Clone` explicitly on a `Copy` type"
-target/lintcheck/sources/libc-0.2.81/src/macros.rs:120:9 clippy::expl_impl_clone_on_copy "you are implementing `Clone` explicitly on a `Copy` type"
-target/lintcheck/sources/libc-0.2.81/src/macros.rs:120:9 clippy::expl_impl_clone_on_copy "you are implementing `Clone` explicitly on a `Copy` type"
-target/lintcheck/sources/libc-0.2.81/src/macros.rs:120:9 clippy::expl_impl_clone_on_copy "you are implementing `Clone` explicitly on a `Copy` type"
-target/lintcheck/sources/libc-0.2.81/src/macros.rs:243:17 clippy::missing_safety_doc "unsafe function's docs miss `# Safety` section"
-target/lintcheck/sources/libc-0.2.81/src/macros.rs:243:17 clippy::missing_safety_doc "unsafe function's docs miss `# Safety` section"
-target/lintcheck/sources/libc-0.2.81/src/macros.rs:243:17 clippy::missing_safety_doc "unsafe function's docs miss `# Safety` section"
-target/lintcheck/sources/libc-0.2.81/src/macros.rs:243:null clippy::must_use_candidate "this function could have a `#[must_use]` attribute"
-target/lintcheck/sources/libc-0.2.81/src/macros.rs:243:null clippy::must_use_candidate "this function could have a `#[must_use]` attribute"
-target/lintcheck/sources/libc-0.2.81/src/macros.rs:243:null clippy::must_use_candidate "this function could have a `#[must_use]` attribute"
-target/lintcheck/sources/libc-0.2.81/src/macros.rs:243:null clippy::must_use_candidate "this function could have a `#[must_use]` attribute"
-target/lintcheck/sources/libc-0.2.81/src/macros.rs:243:null clippy::must_use_candidate "this function could have a `#[must_use]` attribute"
-target/lintcheck/sources/libc-0.2.81/src/macros.rs:243:null clippy::must_use_candidate "this function could have a `#[must_use]` attribute"
-target/lintcheck/sources/libc-0.2.81/src/macros.rs:243:null clippy::must_use_candidate "this function could have a `#[must_use]` attribute"
-target/lintcheck/sources/libc-0.2.81/src/macros.rs:243:null clippy::must_use_candidate "this function could have a `#[must_use]` attribute"
-target/lintcheck/sources/libc-0.2.81/src/macros.rs:243:null clippy::must_use_candidate "this function could have a `#[must_use]` attribute"
-target/lintcheck/sources/libc-0.2.81/src/macros.rs:243:null clippy::must_use_candidate "this function could have a `#[must_use]` attribute"
-target/lintcheck/sources/libc-0.2.81/src/macros.rs:243:null clippy::must_use_candidate "this function could have a `#[must_use]` attribute"
-target/lintcheck/sources/libc-0.2.81/src/macros.rs:243:null clippy::must_use_candidate "this function could have a `#[must_use]` attribute"
-target/lintcheck/sources/libc-0.2.81/src/macros.rs:243:null clippy::must_use_candidate "this function could have a `#[must_use]` attribute"
-target/lintcheck/sources/libc-0.2.81/src/macros.rs:243:null clippy::must_use_candidate "this function could have a `#[must_use]` attribute"
-target/lintcheck/sources/libc-0.2.81/src/macros.rs:243:null clippy::must_use_candidate "this function could have a `#[must_use]` attribute"
-target/lintcheck/sources/libc-0.2.81/src/macros.rs:243:null clippy::must_use_candidate "this function could have a `#[must_use]` attribute"
-target/lintcheck/sources/libc-0.2.81/src/macros.rs:243:null clippy::must_use_candidate "this function could have a `#[must_use]` attribute"
-target/lintcheck/sources/libc-0.2.81/src/macros.rs:243:null clippy::must_use_candidate "this function could have a `#[must_use]` attribute"
-target/lintcheck/sources/libc-0.2.81/src/macros.rs:243:null clippy::must_use_candidate "this function could have a `#[must_use]` attribute"
-target/lintcheck/sources/libc-0.2.81/src/macros.rs:243:null clippy::must_use_candidate "this function could have a `#[must_use]` attribute"
-target/lintcheck/sources/libc-0.2.81/src/macros.rs:259:null clippy::must_use_candidate "this function could have a `#[must_use]` attribute"
-target/lintcheck/sources/libc-0.2.81/src/macros.rs:259:null clippy::must_use_candidate "this function could have a `#[must_use]` attribute"
-target/lintcheck/sources/libc-0.2.81/src/macros.rs:259:null clippy::must_use_candidate "this function could have a `#[must_use]` attribute"
-target/lintcheck/sources/libc-0.2.81/src/macros.rs:259:null clippy::must_use_candidate "this function could have a `#[must_use]` attribute"
-target/lintcheck/sources/libc-0.2.81/src/macros.rs:259:null clippy::must_use_candidate "this function could have a `#[must_use]` attribute"
-target/lintcheck/sources/libc-0.2.81/src/macros.rs:259:null clippy::must_use_candidate "this function could have a `#[must_use]` attribute"
-target/lintcheck/sources/libc-0.2.81/src/macros.rs:259:null clippy::must_use_candidate "this function could have a `#[must_use]` attribute"
-target/lintcheck/sources/libc-0.2.81/src/macros.rs:259:null clippy::must_use_candidate "this function could have a `#[must_use]` attribute"
-target/lintcheck/sources/libc-0.2.81/src/macros.rs:259:null clippy::must_use_candidate "this function could have a `#[must_use]` attribute"
-target/lintcheck/sources/libc-0.2.81/src/macros.rs:259:null clippy::must_use_candidate "this function could have a `#[must_use]` attribute"
-target/lintcheck/sources/libc-0.2.81/src/macros.rs:259:null clippy::must_use_candidate "this function could have a `#[must_use]` attribute"
-target/lintcheck/sources/libc-0.2.81/src/macros.rs:259:null clippy::must_use_candidate "this function could have a `#[must_use]` attribute"
-target/lintcheck/sources/libc-0.2.81/src/macros.rs:259:null clippy::must_use_candidate "this function could have a `#[must_use]` attribute"
-target/lintcheck/sources/libc-0.2.81/src/macros.rs:259:null clippy::must_use_candidate "this function could have a `#[must_use]` attribute"
-target/lintcheck/sources/libc-0.2.81/src/macros.rs:259:null clippy::must_use_candidate "this function could have a `#[must_use]` attribute"
-target/lintcheck/sources/libc-0.2.81/src/macros.rs:84:9 clippy::expl_impl_clone_on_copy "you are implementing `Clone` explicitly on a `Copy` type"
-target/lintcheck/sources/libc-0.2.81/src/macros.rs:84:9 clippy::expl_impl_clone_on_copy "you are implementing `Clone` explicitly on a `Copy` type"
-target/lintcheck/sources/libc-0.2.81/src/macros.rs:84:9 clippy::expl_impl_clone_on_copy "you are implementing `Clone` explicitly on a `Copy` type"
-target/lintcheck/sources/libc-0.2.81/src/macros.rs:84:9 clippy::expl_impl_clone_on_copy "you are implementing `Clone` explicitly on a `Copy` type"
-target/lintcheck/sources/libc-0.2.81/src/macros.rs:84:9 clippy::expl_impl_clone_on_copy "you are implementing `Clone` explicitly on a `Copy` type"
-target/lintcheck/sources/libc-0.2.81/src/macros.rs:84:9 clippy::expl_impl_clone_on_copy "you are implementing `Clone` explicitly on a `Copy` type"
-target/lintcheck/sources/libc-0.2.81/src/macros.rs:84:9 clippy::expl_impl_clone_on_copy "you are implementing `Clone` explicitly on a `Copy` type"
-target/lintcheck/sources/libc-0.2.81/src/macros.rs:84:9 clippy::expl_impl_clone_on_copy "you are implementing `Clone` explicitly on a `Copy` type"
-target/lintcheck/sources/libc-0.2.81/src/macros.rs:84:9 clippy::expl_impl_clone_on_copy "you are implementing `Clone` explicitly on a `Copy` type"
-target/lintcheck/sources/libc-0.2.81/src/macros.rs:84:9 clippy::expl_impl_clone_on_copy "you are implementing `Clone` explicitly on a `Copy` type"
-target/lintcheck/sources/libc-0.2.81/src/macros.rs:84:9 clippy::expl_impl_clone_on_copy "you are implementing `Clone` explicitly on a `Copy` type"
-target/lintcheck/sources/libc-0.2.81/src/macros.rs:84:9 clippy::expl_impl_clone_on_copy "you are implementing `Clone` explicitly on a `Copy` type"
-target/lintcheck/sources/libc-0.2.81/src/macros.rs:84:9 clippy::expl_impl_clone_on_copy "you are implementing `Clone` explicitly on a `Copy` type"
-target/lintcheck/sources/libc-0.2.81/src/macros.rs:84:9 clippy::expl_impl_clone_on_copy "you are implementing `Clone` explicitly on a `Copy` type"
-target/lintcheck/sources/libc-0.2.81/src/macros.rs:84:9 clippy::expl_impl_clone_on_copy "you are implementing `Clone` explicitly on a `Copy` type"
-target/lintcheck/sources/libc-0.2.81/src/macros.rs:84:9 clippy::expl_impl_clone_on_copy "you are implementing `Clone` explicitly on a `Copy` type"
-target/lintcheck/sources/libc-0.2.81/src/macros.rs:84:9 clippy::expl_impl_clone_on_copy "you are implementing `Clone` explicitly on a `Copy` type"
-target/lintcheck/sources/libc-0.2.81/src/macros.rs:84:9 clippy::expl_impl_clone_on_copy "you are implementing `Clone` explicitly on a `Copy` type"
-target/lintcheck/sources/libc-0.2.81/src/macros.rs:84:9 clippy::expl_impl_clone_on_copy "you are implementing `Clone` explicitly on a `Copy` type"
-target/lintcheck/sources/libc-0.2.81/src/macros.rs:84:9 clippy::expl_impl_clone_on_copy "you are implementing `Clone` explicitly on a `Copy` type"
-target/lintcheck/sources/libc-0.2.81/src/macros.rs:84:9 clippy::expl_impl_clone_on_copy "you are implementing `Clone` explicitly on a `Copy` type"
-target/lintcheck/sources/libc-0.2.81/src/macros.rs:84:9 clippy::expl_impl_clone_on_copy "you are implementing `Clone` explicitly on a `Copy` type"
-target/lintcheck/sources/libc-0.2.81/src/macros.rs:84:9 clippy::expl_impl_clone_on_copy "you are implementing `Clone` explicitly on a `Copy` type"
-target/lintcheck/sources/libc-0.2.81/src/macros.rs:84:9 clippy::expl_impl_clone_on_copy "you are implementing `Clone` explicitly on a `Copy` type"
-target/lintcheck/sources/libc-0.2.81/src/macros.rs:84:9 clippy::expl_impl_clone_on_copy "you are implementing `Clone` explicitly on a `Copy` type"
-target/lintcheck/sources/libc-0.2.81/src/macros.rs:84:9 clippy::expl_impl_clone_on_copy "you are implementing `Clone` explicitly on a `Copy` type"
-target/lintcheck/sources/libc-0.2.81/src/macros.rs:84:9 clippy::expl_impl_clone_on_copy "you are implementing `Clone` explicitly on a `Copy` type"
-target/lintcheck/sources/libc-0.2.81/src/macros.rs:84:9 clippy::expl_impl_clone_on_copy "you are implementing `Clone` explicitly on a `Copy` type"
-target/lintcheck/sources/libc-0.2.81/src/macros.rs:84:9 clippy::expl_impl_clone_on_copy "you are implementing `Clone` explicitly on a `Copy` type"
-target/lintcheck/sources/libc-0.2.81/src/macros.rs:84:9 clippy::expl_impl_clone_on_copy "you are implementing `Clone` explicitly on a `Copy` type"
-target/lintcheck/sources/libc-0.2.81/src/macros.rs:84:9 clippy::expl_impl_clone_on_copy "you are implementing `Clone` explicitly on a `Copy` type"
-target/lintcheck/sources/libc-0.2.81/src/macros.rs:84:9 clippy::expl_impl_clone_on_copy "you are implementing `Clone` explicitly on a `Copy` type"
-target/lintcheck/sources/libc-0.2.81/src/macros.rs:84:9 clippy::expl_impl_clone_on_copy "you are implementing `Clone` explicitly on a `Copy` type"
-target/lintcheck/sources/libc-0.2.81/src/macros.rs:84:9 clippy::expl_impl_clone_on_copy "you are implementing `Clone` explicitly on a `Copy` type"
-target/lintcheck/sources/libc-0.2.81/src/macros.rs:84:9 clippy::expl_impl_clone_on_copy "you are implementing `Clone` explicitly on a `Copy` type"
-target/lintcheck/sources/libc-0.2.81/src/macros.rs:84:9 clippy::expl_impl_clone_on_copy "you are implementing `Clone` explicitly on a `Copy` type"
-target/lintcheck/sources/libc-0.2.81/src/macros.rs:84:9 clippy::expl_impl_clone_on_copy "you are implementing `Clone` explicitly on a `Copy` type"
-target/lintcheck/sources/libc-0.2.81/src/macros.rs:84:9 clippy::expl_impl_clone_on_copy "you are implementing `Clone` explicitly on a `Copy` type"
-target/lintcheck/sources/libc-0.2.81/src/macros.rs:84:9 clippy::expl_impl_clone_on_copy "you are implementing `Clone` explicitly on a `Copy` type"
-target/lintcheck/sources/libc-0.2.81/src/macros.rs:84:9 clippy::expl_impl_clone_on_copy "you are implementing `Clone` explicitly on a `Copy` type"
-target/lintcheck/sources/libc-0.2.81/src/macros.rs:84:9 clippy::expl_impl_clone_on_copy "you are implementing `Clone` explicitly on a `Copy` type"
-target/lintcheck/sources/libc-0.2.81/src/macros.rs:84:9 clippy::expl_impl_clone_on_copy "you are implementing `Clone` explicitly on a `Copy` type"
-target/lintcheck/sources/libc-0.2.81/src/macros.rs:84:9 clippy::expl_impl_clone_on_copy "you are implementing `Clone` explicitly on a `Copy` type"
-target/lintcheck/sources/libc-0.2.81/src/macros.rs:84:9 clippy::expl_impl_clone_on_copy "you are implementing `Clone` explicitly on a `Copy` type"
-target/lintcheck/sources/libc-0.2.81/src/macros.rs:84:9 clippy::expl_impl_clone_on_copy "you are implementing `Clone` explicitly on a `Copy` type"
-target/lintcheck/sources/libc-0.2.81/src/macros.rs:84:9 clippy::expl_impl_clone_on_copy "you are implementing `Clone` explicitly on a `Copy` type"
-target/lintcheck/sources/libc-0.2.81/src/macros.rs:84:9 clippy::expl_impl_clone_on_copy "you are implementing `Clone` explicitly on a `Copy` type"
-target/lintcheck/sources/libc-0.2.81/src/macros.rs:84:9 clippy::expl_impl_clone_on_copy "you are implementing `Clone` explicitly on a `Copy` type"
-target/lintcheck/sources/libc-0.2.81/src/macros.rs:84:9 clippy::expl_impl_clone_on_copy "you are implementing `Clone` explicitly on a `Copy` type"
-target/lintcheck/sources/libc-0.2.81/src/macros.rs:84:9 clippy::expl_impl_clone_on_copy "you are implementing `Clone` explicitly on a `Copy` type"
-target/lintcheck/sources/libc-0.2.81/src/macros.rs:84:9 clippy::expl_impl_clone_on_copy "you are implementing `Clone` explicitly on a `Copy` type"
-target/lintcheck/sources/libc-0.2.81/src/macros.rs:84:9 clippy::expl_impl_clone_on_copy "you are implementing `Clone` explicitly on a `Copy` type"
-target/lintcheck/sources/libc-0.2.81/src/macros.rs:84:9 clippy::expl_impl_clone_on_copy "you are implementing `Clone` explicitly on a `Copy` type"
-target/lintcheck/sources/libc-0.2.81/src/macros.rs:84:9 clippy::expl_impl_clone_on_copy "you are implementing `Clone` explicitly on a `Copy` type"
-target/lintcheck/sources/libc-0.2.81/src/macros.rs:84:9 clippy::expl_impl_clone_on_copy "you are implementing `Clone` explicitly on a `Copy` type"
-target/lintcheck/sources/libc-0.2.81/src/macros.rs:84:9 clippy::expl_impl_clone_on_copy "you are implementing `Clone` explicitly on a `Copy` type"
-target/lintcheck/sources/libc-0.2.81/src/macros.rs:84:9 clippy::expl_impl_clone_on_copy "you are implementing `Clone` explicitly on a `Copy` type"
-target/lintcheck/sources/libc-0.2.81/src/macros.rs:84:9 clippy::expl_impl_clone_on_copy "you are implementing `Clone` explicitly on a `Copy` type"
-target/lintcheck/sources/libc-0.2.81/src/macros.rs:84:9 clippy::expl_impl_clone_on_copy "you are implementing `Clone` explicitly on a `Copy` type"
-target/lintcheck/sources/libc-0.2.81/src/macros.rs:84:9 clippy::expl_impl_clone_on_copy "you are implementing `Clone` explicitly on a `Copy` type"
-target/lintcheck/sources/libc-0.2.81/src/macros.rs:84:9 clippy::expl_impl_clone_on_copy "you are implementing `Clone` explicitly on a `Copy` type"
-target/lintcheck/sources/libc-0.2.81/src/macros.rs:84:9 clippy::expl_impl_clone_on_copy "you are implementing `Clone` explicitly on a `Copy` type"
-target/lintcheck/sources/libc-0.2.81/src/macros.rs:84:9 clippy::expl_impl_clone_on_copy "you are implementing `Clone` explicitly on a `Copy` type"
-target/lintcheck/sources/libc-0.2.81/src/macros.rs:84:9 clippy::expl_impl_clone_on_copy "you are implementing `Clone` explicitly on a `Copy` type"
-target/lintcheck/sources/libc-0.2.81/src/macros.rs:84:9 clippy::expl_impl_clone_on_copy "you are implementing `Clone` explicitly on a `Copy` type"
-target/lintcheck/sources/libc-0.2.81/src/macros.rs:84:9 clippy::expl_impl_clone_on_copy "you are implementing `Clone` explicitly on a `Copy` type"
-target/lintcheck/sources/libc-0.2.81/src/macros.rs:84:9 clippy::expl_impl_clone_on_copy "you are implementing `Clone` explicitly on a `Copy` type"
-target/lintcheck/sources/libc-0.2.81/src/macros.rs:84:9 clippy::expl_impl_clone_on_copy "you are implementing `Clone` explicitly on a `Copy` type"
-target/lintcheck/sources/libc-0.2.81/src/macros.rs:84:9 clippy::expl_impl_clone_on_copy "you are implementing `Clone` explicitly on a `Copy` type"
-target/lintcheck/sources/libc-0.2.81/src/macros.rs:84:9 clippy::expl_impl_clone_on_copy "you are implementing `Clone` explicitly on a `Copy` type"
-target/lintcheck/sources/libc-0.2.81/src/macros.rs:84:9 clippy::expl_impl_clone_on_copy "you are implementing `Clone` explicitly on a `Copy` type"
-target/lintcheck/sources/libc-0.2.81/src/macros.rs:84:9 clippy::expl_impl_clone_on_copy "you are implementing `Clone` explicitly on a `Copy` type"
-target/lintcheck/sources/libc-0.2.81/src/macros.rs:84:9 clippy::expl_impl_clone_on_copy "you are implementing `Clone` explicitly on a `Copy` type"
-target/lintcheck/sources/libc-0.2.81/src/macros.rs:84:9 clippy::expl_impl_clone_on_copy "you are implementing `Clone` explicitly on a `Copy` type"
-target/lintcheck/sources/libc-0.2.81/src/macros.rs:84:9 clippy::expl_impl_clone_on_copy "you are implementing `Clone` explicitly on a `Copy` type"
-target/lintcheck/sources/libc-0.2.81/src/macros.rs:84:9 clippy::expl_impl_clone_on_copy "you are implementing `Clone` explicitly on a `Copy` type"
-target/lintcheck/sources/libc-0.2.81/src/macros.rs:84:9 clippy::expl_impl_clone_on_copy "you are implementing `Clone` explicitly on a `Copy` type"
-target/lintcheck/sources/libc-0.2.81/src/macros.rs:84:9 clippy::expl_impl_clone_on_copy "you are implementing `Clone` explicitly on a `Copy` type"
-target/lintcheck/sources/libc-0.2.81/src/macros.rs:84:9 clippy::expl_impl_clone_on_copy "you are implementing `Clone` explicitly on a `Copy` type"
-target/lintcheck/sources/libc-0.2.81/src/macros.rs:84:9 clippy::expl_impl_clone_on_copy "you are implementing `Clone` explicitly on a `Copy` type"
-target/lintcheck/sources/libc-0.2.81/src/macros.rs:84:9 clippy::expl_impl_clone_on_copy "you are implementing `Clone` explicitly on a `Copy` type"
-target/lintcheck/sources/libc-0.2.81/src/macros.rs:84:9 clippy::expl_impl_clone_on_copy "you are implementing `Clone` explicitly on a `Copy` type"
-target/lintcheck/sources/libc-0.2.81/src/macros.rs:84:9 clippy::expl_impl_clone_on_copy "you are implementing `Clone` explicitly on a `Copy` type"
-target/lintcheck/sources/libc-0.2.81/src/macros.rs:84:9 clippy::expl_impl_clone_on_copy "you are implementing `Clone` explicitly on a `Copy` type"
-target/lintcheck/sources/libc-0.2.81/src/macros.rs:84:9 clippy::expl_impl_clone_on_copy "you are implementing `Clone` explicitly on a `Copy` type"
-target/lintcheck/sources/libc-0.2.81/src/macros.rs:84:9 clippy::expl_impl_clone_on_copy "you are implementing `Clone` explicitly on a `Copy` type"
-target/lintcheck/sources/libc-0.2.81/src/macros.rs:84:9 clippy::expl_impl_clone_on_copy "you are implementing `Clone` explicitly on a `Copy` type"
-target/lintcheck/sources/libc-0.2.81/src/macros.rs:84:9 clippy::expl_impl_clone_on_copy "you are implementing `Clone` explicitly on a `Copy` type"
-target/lintcheck/sources/libc-0.2.81/src/macros.rs:84:9 clippy::expl_impl_clone_on_copy "you are implementing `Clone` explicitly on a `Copy` type"
-target/lintcheck/sources/libc-0.2.81/src/macros.rs:84:9 clippy::expl_impl_clone_on_copy "you are implementing `Clone` explicitly on a `Copy` type"
-target/lintcheck/sources/libc-0.2.81/src/macros.rs:84:9 clippy::expl_impl_clone_on_copy "you are implementing `Clone` explicitly on a `Copy` type"
-target/lintcheck/sources/libc-0.2.81/src/macros.rs:84:9 clippy::expl_impl_clone_on_copy "you are implementing `Clone` explicitly on a `Copy` type"
-target/lintcheck/sources/libc-0.2.81/src/macros.rs:84:9 clippy::expl_impl_clone_on_copy "you are implementing `Clone` explicitly on a `Copy` type"
-target/lintcheck/sources/libc-0.2.81/src/macros.rs:84:9 clippy::expl_impl_clone_on_copy "you are implementing `Clone` explicitly on a `Copy` type"
-target/lintcheck/sources/libc-0.2.81/src/macros.rs:84:9 clippy::expl_impl_clone_on_copy "you are implementing `Clone` explicitly on a `Copy` type"
-target/lintcheck/sources/libc-0.2.81/src/macros.rs:84:9 clippy::expl_impl_clone_on_copy "you are implementing `Clone` explicitly on a `Copy` type"
-target/lintcheck/sources/libc-0.2.81/src/macros.rs:84:9 clippy::expl_impl_clone_on_copy "you are implementing `Clone` explicitly on a `Copy` type"
-target/lintcheck/sources/libc-0.2.81/src/macros.rs:84:9 clippy::expl_impl_clone_on_copy "you are implementing `Clone` explicitly on a `Copy` type"
-target/lintcheck/sources/libc-0.2.81/src/macros.rs:84:9 clippy::expl_impl_clone_on_copy "you are implementing `Clone` explicitly on a `Copy` type"
-target/lintcheck/sources/libc-0.2.81/src/macros.rs:84:9 clippy::expl_impl_clone_on_copy "you are implementing `Clone` explicitly on a `Copy` type"
-target/lintcheck/sources/libc-0.2.81/src/macros.rs:84:9 clippy::expl_impl_clone_on_copy "you are implementing `Clone` explicitly on a `Copy` type"
-target/lintcheck/sources/libc-0.2.81/src/macros.rs:84:9 clippy::expl_impl_clone_on_copy "you are implementing `Clone` explicitly on a `Copy` type"
-target/lintcheck/sources/libc-0.2.81/src/macros.rs:84:9 clippy::expl_impl_clone_on_copy "you are implementing `Clone` explicitly on a `Copy` type"
-target/lintcheck/sources/libc-0.2.81/src/macros.rs:84:9 clippy::expl_impl_clone_on_copy "you are implementing `Clone` explicitly on a `Copy` type"
-target/lintcheck/sources/libc-0.2.81/src/macros.rs:84:9 clippy::expl_impl_clone_on_copy "you are implementing `Clone` explicitly on a `Copy` type"
-target/lintcheck/sources/libc-0.2.81/src/macros.rs:84:9 clippy::expl_impl_clone_on_copy "you are implementing `Clone` explicitly on a `Copy` type"
-target/lintcheck/sources/libc-0.2.81/src/macros.rs:84:9 clippy::expl_impl_clone_on_copy "you are implementing `Clone` explicitly on a `Copy` type"
-target/lintcheck/sources/libc-0.2.81/src/macros.rs:84:9 clippy::expl_impl_clone_on_copy "you are implementing `Clone` explicitly on a `Copy` type"
-target/lintcheck/sources/libc-0.2.81/src/macros.rs:84:9 clippy::expl_impl_clone_on_copy "you are implementing `Clone` explicitly on a `Copy` type"
-target/lintcheck/sources/libc-0.2.81/src/macros.rs:84:9 clippy::expl_impl_clone_on_copy "you are implementing `Clone` explicitly on a `Copy` type"
-target/lintcheck/sources/libc-0.2.81/src/macros.rs:84:9 clippy::expl_impl_clone_on_copy "you are implementing `Clone` explicitly on a `Copy` type"
-target/lintcheck/sources/libc-0.2.81/src/macros.rs:84:9 clippy::expl_impl_clone_on_copy "you are implementing `Clone` explicitly on a `Copy` type"
-target/lintcheck/sources/libc-0.2.81/src/macros.rs:84:9 clippy::expl_impl_clone_on_copy "you are implementing `Clone` explicitly on a `Copy` type"
-target/lintcheck/sources/libc-0.2.81/src/macros.rs:84:9 clippy::expl_impl_clone_on_copy "you are implementing `Clone` explicitly on a `Copy` type"
-target/lintcheck/sources/libc-0.2.81/src/macros.rs:84:9 clippy::expl_impl_clone_on_copy "you are implementing `Clone` explicitly on a `Copy` type"
-target/lintcheck/sources/libc-0.2.81/src/macros.rs:84:9 clippy::expl_impl_clone_on_copy "you are implementing `Clone` explicitly on a `Copy` type"
-target/lintcheck/sources/libc-0.2.81/src/macros.rs:84:9 clippy::expl_impl_clone_on_copy "you are implementing `Clone` explicitly on a `Copy` type"
-target/lintcheck/sources/libc-0.2.81/src/macros.rs:84:9 clippy::expl_impl_clone_on_copy "you are implementing `Clone` explicitly on a `Copy` type"
-target/lintcheck/sources/libc-0.2.81/src/macros.rs:84:9 clippy::expl_impl_clone_on_copy "you are implementing `Clone` explicitly on a `Copy` type"
-target/lintcheck/sources/libc-0.2.81/src/macros.rs:84:9 clippy::expl_impl_clone_on_copy "you are implementing `Clone` explicitly on a `Copy` type"
-target/lintcheck/sources/libc-0.2.81/src/macros.rs:84:9 clippy::expl_impl_clone_on_copy "you are implementing `Clone` explicitly on a `Copy` type"
-target/lintcheck/sources/libc-0.2.81/src/macros.rs:84:9 clippy::expl_impl_clone_on_copy "you are implementing `Clone` explicitly on a `Copy` type"
-target/lintcheck/sources/libc-0.2.81/src/macros.rs:84:9 clippy::expl_impl_clone_on_copy "you are implementing `Clone` explicitly on a `Copy` type"
-target/lintcheck/sources/libc-0.2.81/src/macros.rs:84:9 clippy::expl_impl_clone_on_copy "you are implementing `Clone` explicitly on a `Copy` type"
-target/lintcheck/sources/libc-0.2.81/src/macros.rs:84:9 clippy::expl_impl_clone_on_copy "you are implementing `Clone` explicitly on a `Copy` type"
-target/lintcheck/sources/libc-0.2.81/src/macros.rs:84:9 clippy::expl_impl_clone_on_copy "you are implementing `Clone` explicitly on a `Copy` type"
-target/lintcheck/sources/libc-0.2.81/src/macros.rs:84:9 clippy::expl_impl_clone_on_copy "you are implementing `Clone` explicitly on a `Copy` type"
-target/lintcheck/sources/libc-0.2.81/src/macros.rs:84:9 clippy::expl_impl_clone_on_copy "you are implementing `Clone` explicitly on a `Copy` type"
-target/lintcheck/sources/libc-0.2.81/src/macros.rs:84:9 clippy::expl_impl_clone_on_copy "you are implementing `Clone` explicitly on a `Copy` type"
-target/lintcheck/sources/libc-0.2.81/src/macros.rs:84:9 clippy::expl_impl_clone_on_copy "you are implementing `Clone` explicitly on a `Copy` type"
-target/lintcheck/sources/libc-0.2.81/src/macros.rs:84:9 clippy::expl_impl_clone_on_copy "you are implementing `Clone` explicitly on a `Copy` type"
-target/lintcheck/sources/libc-0.2.81/src/macros.rs:84:9 clippy::expl_impl_clone_on_copy "you are implementing `Clone` explicitly on a `Copy` type"
-target/lintcheck/sources/libc-0.2.81/src/macros.rs:84:9 clippy::expl_impl_clone_on_copy "you are implementing `Clone` explicitly on a `Copy` type"
-target/lintcheck/sources/libc-0.2.81/src/macros.rs:84:9 clippy::expl_impl_clone_on_copy "you are implementing `Clone` explicitly on a `Copy` type"
-target/lintcheck/sources/libc-0.2.81/src/macros.rs:84:9 clippy::expl_impl_clone_on_copy "you are implementing `Clone` explicitly on a `Copy` type"
-target/lintcheck/sources/libc-0.2.81/src/macros.rs:84:9 clippy::expl_impl_clone_on_copy "you are implementing `Clone` explicitly on a `Copy` type"
-target/lintcheck/sources/libc-0.2.81/src/macros.rs:84:9 clippy::expl_impl_clone_on_copy "you are implementing `Clone` explicitly on a `Copy` type"
-target/lintcheck/sources/libc-0.2.81/src/macros.rs:84:9 clippy::expl_impl_clone_on_copy "you are implementing `Clone` explicitly on a `Copy` type"
-target/lintcheck/sources/libc-0.2.81/src/unix/linux_like/linux/gnu/b64/x86_64/mod.rs:428:29 clippy::unreadable_literal "long literal lacking separators"
-target/lintcheck/sources/libc-0.2.81/src/unix/linux_like/linux/gnu/b64/x86_64/mod.rs:429:30 clippy::unreadable_literal "long literal lacking separators"
-target/lintcheck/sources/libc-0.2.81/src/unix/linux_like/linux/gnu/b64/x86_64/mod.rs:431:30 clippy::unreadable_literal "long literal lacking separators"
-target/lintcheck/sources/libc-0.2.81/src/unix/linux_like/linux/gnu/b64/x86_64/mod.rs:432:32 clippy::unreadable_literal "long literal lacking separators"
-target/lintcheck/sources/libc-0.2.81/src/unix/linux_like/linux/gnu/b64/x86_64/mod.rs:433:29 clippy::unreadable_literal "long literal lacking separators"
-target/lintcheck/sources/libc-0.2.81/src/unix/linux_like/linux/gnu/b64/x86_64/mod.rs:434:32 clippy::unreadable_literal "long literal lacking separators"
-target/lintcheck/sources/libc-0.2.81/src/unix/linux_like/linux/gnu/b64/x86_64/mod.rs:595:33 clippy::unreadable_literal "long literal lacking separators"
-target/lintcheck/sources/libc-0.2.81/src/unix/linux_like/linux/gnu/b64/x86_64/mod.rs:596:33 clippy::unreadable_literal "long literal lacking separators"
-target/lintcheck/sources/libc-0.2.81/src/unix/linux_like/linux/gnu/b64/x86_64/mod.rs:597:35 clippy::unreadable_literal "long literal lacking separators"
-target/lintcheck/sources/libc-0.2.81/src/unix/linux_like/linux/gnu/b64/x86_64/mod.rs:622:32 clippy::unreadable_literal "long literal lacking separators"
-target/lintcheck/sources/libc-0.2.81/src/unix/linux_like/linux/gnu/b64/x86_64/mod.rs:673:34 clippy::unreadable_literal "long literal lacking separators"
-target/lintcheck/sources/libc-0.2.81/src/unix/linux_like/linux/gnu/b64/x86_64/mod.rs:696:33 clippy::unreadable_literal "long literal lacking separators"
-target/lintcheck/sources/libc-0.2.81/src/unix/linux_like/linux/gnu/b64/x86_64/mod.rs:697:35 clippy::unreadable_literal "long literal lacking separators"
-target/lintcheck/sources/libc-0.2.81/src/unix/linux_like/linux/gnu/b64/x86_64/mod.rs:698:33 clippy::unreadable_literal "long literal lacking separators"
-target/lintcheck/sources/libc-0.2.81/src/unix/linux_like/linux/gnu/b64/x86_64/mod.rs:699:35 clippy::unreadable_literal "long literal lacking separators"
-target/lintcheck/sources/libc-0.2.81/src/unix/linux_like/linux/gnu/b64/x86_64/mod.rs:712:34 clippy::unreadable_literal "long literal lacking separators"
-target/lintcheck/sources/libc-0.2.81/src/unix/linux_like/linux/gnu/b64/x86_64/mod.rs:721:35 clippy::unreadable_literal "long literal lacking separators"
-target/lintcheck/sources/libc-0.2.81/src/unix/linux_like/linux/gnu/b64/x86_64/mod.rs:722:32 clippy::unreadable_literal "long literal lacking separators"
-target/lintcheck/sources/libc-0.2.81/src/unix/linux_like/linux/gnu/b64/x86_64/mod.rs:723:32 clippy::unreadable_literal "long literal lacking separators"
-target/lintcheck/sources/libc-0.2.81/src/unix/linux_like/linux/gnu/b64/x86_64/mod.rs:751:31 clippy::unreadable_literal "long literal lacking separators"
-target/lintcheck/sources/libc-0.2.81/src/unix/linux_like/linux/gnu/b64/x86_64/mod.rs:752:30 clippy::unreadable_literal "long literal lacking separators"
-target/lintcheck/sources/libc-0.2.81/src/unix/linux_like/linux/gnu/b64/x86_64/mod.rs:753:30 clippy::unreadable_literal "long literal lacking separators"
-target/lintcheck/sources/libc-0.2.81/src/unix/linux_like/linux/gnu/b64/x86_64/mod.rs:754:30 clippy::unreadable_literal "long literal lacking separators"
-target/lintcheck/sources/libc-0.2.81/src/unix/linux_like/linux/gnu/b64/x86_64/mod.rs:755:29 clippy::unreadable_literal "long literal lacking separators"
-target/lintcheck/sources/libc-0.2.81/src/unix/linux_like/linux/gnu/b64/x86_64/mod.rs:756:29 clippy::unreadable_literal "long literal lacking separators"
-target/lintcheck/sources/libc-0.2.81/src/unix/linux_like/linux/gnu/b64/x86_64/mod.rs:757:29 clippy::unreadable_literal "long literal lacking separators"
-target/lintcheck/sources/libc-0.2.81/src/unix/linux_like/linux/gnu/b64/x86_64/mod.rs:758:29 clippy::unreadable_literal "long literal lacking separators"
-target/lintcheck/sources/libc-0.2.81/src/unix/linux_like/linux/gnu/b64/x86_64/mod.rs:759:29 clippy::unreadable_literal "long literal lacking separators"
-target/lintcheck/sources/libc-0.2.81/src/unix/linux_like/linux/gnu/b64/x86_64/mod.rs:760:29 clippy::unreadable_literal "long literal lacking separators"
-target/lintcheck/sources/libc-0.2.81/src/unix/linux_like/linux/gnu/b64/x86_64/mod.rs:768:30 clippy::unreadable_literal "long literal lacking separators"
-target/lintcheck/sources/libc-0.2.81/src/unix/linux_like/linux/gnu/b64/x86_64/mod.rs:769:31 clippy::unreadable_literal "long literal lacking separators"
-target/lintcheck/sources/libc-0.2.81/src/unix/linux_like/linux/gnu/b64/x86_64/mod.rs:771:31 clippy::unreadable_literal "long literal lacking separators"
-target/lintcheck/sources/libc-0.2.81/src/unix/linux_like/linux/gnu/b64/x86_64/mod.rs:772:29 clippy::unreadable_literal "long literal lacking separators"
-target/lintcheck/sources/libc-0.2.81/src/unix/linux_like/linux/gnu/b64/x86_64/mod.rs:773:29 clippy::unreadable_literal "long literal lacking separators"
-target/lintcheck/sources/libc-0.2.81/src/unix/linux_like/linux/gnu/b64/x86_64/mod.rs:774:29 clippy::unreadable_literal "long literal lacking separators"
-target/lintcheck/sources/libc-0.2.81/src/unix/linux_like/linux/gnu/b64/x86_64/mod.rs:775:32 clippy::unreadable_literal "long literal lacking separators"
-target/lintcheck/sources/libc-0.2.81/src/unix/linux_like/linux/gnu/b64/x86_64/mod.rs:776:31 clippy::unreadable_literal "long literal lacking separators"
-target/lintcheck/sources/libc-0.2.81/src/unix/linux_like/linux/gnu/b64/x86_64/mod.rs:777:32 clippy::unreadable_literal "long literal lacking separators"
-target/lintcheck/sources/libc-0.2.81/src/unix/linux_like/linux/gnu/b64/x86_64/mod.rs:778:32 clippy::unreadable_literal "long literal lacking separators"
-target/lintcheck/sources/libc-0.2.81/src/unix/linux_like/linux/gnu/b64/x86_64/mod.rs:779:31 clippy::unreadable_literal "long literal lacking separators"
-target/lintcheck/sources/libc-0.2.81/src/unix/linux_like/linux/gnu/b64/x86_64/mod.rs:780:32 clippy::unreadable_literal "long literal lacking separators"
-target/lintcheck/sources/libc-0.2.81/src/unix/linux_like/linux/gnu/b64/x86_64/mod.rs:781:32 clippy::unreadable_literal "long literal lacking separators"
-target/lintcheck/sources/libc-0.2.81/src/unix/linux_like/linux/gnu/b64/x86_64/mod.rs:782:31 clippy::unreadable_literal "long literal lacking separators"
-target/lintcheck/sources/libc-0.2.81/src/unix/linux_like/linux/gnu/b64/x86_64/mod.rs:783:31 clippy::unreadable_literal "long literal lacking separators"
-target/lintcheck/sources/libc-0.2.81/src/unix/linux_like/linux/gnu/b64/x86_64/mod.rs:784:32 clippy::unreadable_literal "long literal lacking separators"
-target/lintcheck/sources/libc-0.2.81/src/unix/linux_like/linux/gnu/b64/x86_64/mod.rs:785:33 clippy::unreadable_literal "long literal lacking separators"
-target/lintcheck/sources/libc-0.2.81/src/unix/linux_like/linux/gnu/b64/x86_64/mod.rs:786:33 clippy::unreadable_literal "long literal lacking separators"
-target/lintcheck/sources/libc-0.2.81/src/unix/linux_like/linux/gnu/b64/x86_64/mod.rs:787:30 clippy::unreadable_literal "long literal lacking separators"
-target/lintcheck/sources/libc-0.2.81/src/unix/linux_like/linux/gnu/b64/x86_64/mod.rs:788:32 clippy::unreadable_literal "long literal lacking separators"
-target/lintcheck/sources/libc-0.2.81/src/unix/linux_like/linux/gnu/b64/x86_64/mod.rs:789:32 clippy::unreadable_literal "long literal lacking separators"
-target/lintcheck/sources/libc-0.2.81/src/unix/linux_like/linux/gnu/b64/x86_64/mod.rs:790:32 clippy::unreadable_literal "long literal lacking separators"
-target/lintcheck/sources/libc-0.2.81/src/unix/linux_like/linux/gnu/b64/x86_64/mod.rs:791:32 clippy::unreadable_literal "long literal lacking separators"
-target/lintcheck/sources/libc-0.2.81/src/unix/linux_like/linux/gnu/b64/x86_64/mod.rs:792:33 clippy::unreadable_literal "long literal lacking separators"
-target/lintcheck/sources/libc-0.2.81/src/unix/linux_like/linux/gnu/b64/x86_64/mod.rs:794:31 clippy::unreadable_literal "long literal lacking separators"
-target/lintcheck/sources/libc-0.2.81/src/unix/linux_like/linux/gnu/b64/x86_64/mod.rs:795:31 clippy::unreadable_literal "long literal lacking separators"
-target/lintcheck/sources/libc-0.2.81/src/unix/linux_like/linux/gnu/b64/x86_64/mod.rs:796:31 clippy::unreadable_literal "long literal lacking separators"
-target/lintcheck/sources/libc-0.2.81/src/unix/linux_like/linux/gnu/b64/x86_64/mod.rs:797:32 clippy::unreadable_literal "long literal lacking separators"
-target/lintcheck/sources/libc-0.2.81/src/unix/linux_like/linux/gnu/b64/x86_64/mod.rs:798:31 clippy::unreadable_literal "long literal lacking separators"
-target/lintcheck/sources/libc-0.2.81/src/unix/linux_like/linux/gnu/b64/x86_64/mod.rs:799:31 clippy::unreadable_literal "long literal lacking separators"
-target/lintcheck/sources/libc-0.2.81/src/unix/linux_like/linux/gnu/b64/x86_64/mod.rs:800:31 clippy::unreadable_literal "long literal lacking separators"
-target/lintcheck/sources/libc-0.2.81/src/unix/linux_like/linux/gnu/b64/x86_64/mod.rs:801:31 clippy::unreadable_literal "long literal lacking separators"
-target/lintcheck/sources/libc-0.2.81/src/unix/linux_like/linux/gnu/b64/x86_64/mod.rs:803:27 clippy::unreadable_literal "long literal lacking separators"
-target/lintcheck/sources/libc-0.2.81/src/unix/linux_like/linux/gnu/b64/x86_64/mod.rs:804:28 clippy::unreadable_literal "long literal lacking separators"
-target/lintcheck/sources/libc-0.2.81/src/unix/linux_like/linux/gnu/b64/x86_64/mod.rs:805:28 clippy::unreadable_literal "long literal lacking separators"
-target/lintcheck/sources/libc-0.2.81/src/unix/linux_like/linux/gnu/b64/x86_64/mod.rs:806:29 clippy::unreadable_literal "long literal lacking separators"
-target/lintcheck/sources/libc-0.2.81/src/unix/linux_like/linux/gnu/b64/x86_64/mod.rs:807:29 clippy::unreadable_literal "long literal lacking separators"
-target/lintcheck/sources/libc-0.2.81/src/unix/linux_like/linux/gnu/b64/x86_64/mod.rs:808:29 clippy::unreadable_literal "long literal lacking separators"
-target/lintcheck/sources/libc-0.2.81/src/unix/linux_like/linux/gnu/b64/x86_64/mod.rs:809:29 clippy::unreadable_literal "long literal lacking separators"
-target/lintcheck/sources/libc-0.2.81/src/unix/linux_like/linux/gnu/b64/x86_64/mod.rs:810:29 clippy::unreadable_literal "long literal lacking separators"
-target/lintcheck/sources/libc-0.2.81/src/unix/linux_like/linux/gnu/b64/x86_64/mod.rs:811:29 clippy::unreadable_literal "long literal lacking separators"
-target/lintcheck/sources/libc-0.2.81/src/unix/linux_like/linux/gnu/b64/x86_64/mod.rs:812:30 clippy::unreadable_literal "long literal lacking separators"
-target/lintcheck/sources/libc-0.2.81/src/unix/linux_like/linux/gnu/b64/x86_64/mod.rs:813:30 clippy::unreadable_literal "long literal lacking separators"
-target/lintcheck/sources/libc-0.2.81/src/unix/linux_like/linux/gnu/b64/x86_64/mod.rs:814:30 clippy::unreadable_literal "long literal lacking separators"
-target/lintcheck/sources/libc-0.2.81/src/unix/linux_like/linux/gnu/b64/x86_64/mod.rs:815:30 clippy::unreadable_literal "long literal lacking separators"
-target/lintcheck/sources/libc-0.2.81/src/unix/linux_like/linux/gnu/b64/x86_64/mod.rs:816:30 clippy::unreadable_literal "long literal lacking separators"
-target/lintcheck/sources/libc-0.2.81/src/unix/linux_like/linux/gnu/b64/x86_64/mod.rs:817:31 clippy::unreadable_literal "long literal lacking separators"
-target/lintcheck/sources/libc-0.2.81/src/unix/linux_like/linux/gnu/b64/x86_64/mod.rs:818:31 clippy::unreadable_literal "long literal lacking separators"
-target/lintcheck/sources/libc-0.2.81/src/unix/linux_like/linux/gnu/b64/x86_64/mod.rs:821:31 clippy::unreadable_literal "long literal lacking separators"
-target/lintcheck/sources/libc-0.2.81/src/unix/linux_like/linux/gnu/b64/x86_64/mod.rs:822:31 clippy::unreadable_literal "long literal lacking separators"
-target/lintcheck/sources/libc-0.2.81/src/unix/linux_like/linux/gnu/b64/x86_64/mod.rs:823:32 clippy::unreadable_literal "long literal lacking separators"
-target/lintcheck/sources/libc-0.2.81/src/unix/linux_like/linux/gnu/b64/x86_64/mod.rs:824:32 clippy::unreadable_literal "long literal lacking separators"
-target/lintcheck/sources/libc-0.2.81/src/unix/linux_like/linux/gnu/b64/x86_64/mod.rs:825:32 clippy::unreadable_literal "long literal lacking separators"
-target/lintcheck/sources/libc-0.2.81/src/unix/linux_like/linux/gnu/b64/x86_64/mod.rs:826:32 clippy::unreadable_literal "long literal lacking separators"
-target/lintcheck/sources/libc-0.2.81/src/unix/linux_like/linux/gnu/b64/x86_64/mod.rs:827:32 clippy::unreadable_literal "long literal lacking separators"
-target/lintcheck/sources/libc-0.2.81/src/unix/linux_like/linux/gnu/b64/x86_64/mod.rs:828:32 clippy::unreadable_literal "long literal lacking separators"
-target/lintcheck/sources/libc-0.2.81/src/unix/linux_like/linux/gnu/b64/x86_64/mod.rs:829:33 clippy::unreadable_literal "long literal lacking separators"
-target/lintcheck/sources/libc-0.2.81/src/unix/linux_like/linux/gnu/b64/x86_64/mod.rs:830:33 clippy::unreadable_literal "long literal lacking separators"
-target/lintcheck/sources/libc-0.2.81/src/unix/linux_like/linux/gnu/b64/x86_64/mod.rs:831:33 clippy::unreadable_literal "long literal lacking separators"
-target/lintcheck/sources/libc-0.2.81/src/unix/linux_like/linux/gnu/b64/x86_64/mod.rs:832:33 clippy::unreadable_literal "long literal lacking separators"
-target/lintcheck/sources/libc-0.2.81/src/unix/linux_like/linux/gnu/b64/x86_64/mod.rs:833:33 clippy::unreadable_literal "long literal lacking separators"
-target/lintcheck/sources/libc-0.2.81/src/unix/linux_like/linux/gnu/b64/x86_64/mod.rs:834:33 clippy::unreadable_literal "long literal lacking separators"
-target/lintcheck/sources/libc-0.2.81/src/unix/linux_like/linux/gnu/b64/x86_64/mod.rs:835:33 clippy::unreadable_literal "long literal lacking separators"
-target/lintcheck/sources/libc-0.2.81/src/unix/linux_like/linux/gnu/b64/x86_64/mod.rs:836:33 clippy::unreadable_literal "long literal lacking separators"
-target/lintcheck/sources/libc-0.2.81/src/unix/linux_like/linux/gnu/b64/x86_64/mod.rs:841:32 clippy::unreadable_literal "long literal lacking separators"
-target/lintcheck/sources/libc-0.2.81/src/unix/linux_like/linux/gnu/b64/x86_64/mod.rs:842:32 clippy::unreadable_literal "long literal lacking separators"
-target/lintcheck/sources/libc-0.2.81/src/unix/linux_like/linux/gnu/b64/x86_64/mod.rs:843:32 clippy::unreadable_literal "long literal lacking separators"
-target/lintcheck/sources/libc-0.2.81/src/unix/linux_like/linux/gnu/b64/x86_64/mod.rs:844:33 clippy::unreadable_literal "long literal lacking separators"
-target/lintcheck/sources/libc-0.2.81/src/unix/linux_like/linux/gnu/mod.rs:1120:38 clippy::unreadable_literal "long literal lacking separators"
-target/lintcheck/sources/libc-0.2.81/src/unix/linux_like/linux/gnu/mod.rs:178:34 clippy::unseparated_literal_suffix "integer type suffix should be separated by an underscore"
-target/lintcheck/sources/libc-0.2.81/src/unix/linux_like/linux/gnu/mod.rs:291:5 clippy::missing_safety_doc "unsafe function's docs miss `# Safety` section"
-target/lintcheck/sources/libc-0.2.81/src/unix/linux_like/linux/gnu/mod.rs:291:5 clippy::must_use_candidate "this method could have a `#[must_use]` attribute"
-target/lintcheck/sources/libc-0.2.81/src/unix/linux_like/linux/gnu/mod.rs:299:11 clippy::ptr_as_ptr "`as` casting between raw pointers without changing its mutability"
-target/lintcheck/sources/libc-0.2.81/src/unix/linux_like/linux/gnu/mod.rs:302:5 clippy::missing_safety_doc "unsafe function's docs miss `# Safety` section"
-target/lintcheck/sources/libc-0.2.81/src/unix/linux_like/linux/gnu/mod.rs:302:5 clippy::must_use_candidate "this method could have a `#[must_use]` attribute"
-target/lintcheck/sources/libc-0.2.81/src/unix/linux_like/linux/gnu/mod.rs:312:11 clippy::ptr_as_ptr "`as` casting between raw pointers without changing its mutability"
-target/lintcheck/sources/libc-0.2.81/src/unix/linux_like/linux/gnu/mod.rs:328:9 clippy::expl_impl_clone_on_copy "you are implementing `Clone` explicitly on a `Copy` type"
-target/lintcheck/sources/libc-0.2.81/src/unix/linux_like/linux/gnu/mod.rs:352:20 clippy::ptr_as_ptr "`as` casting between raw pointers without changing its mutability"
-target/lintcheck/sources/libc-0.2.81/src/unix/linux_like/linux/gnu/mod.rs:355:13 clippy::missing_safety_doc "unsafe function's docs miss `# Safety` section"
-target/lintcheck/sources/libc-0.2.81/src/unix/linux_like/linux/gnu/mod.rs:355:13 clippy::must_use_candidate "this method could have a `#[must_use]` attribute"
-target/lintcheck/sources/libc-0.2.81/src/unix/linux_like/linux/gnu/mod.rs:359:13 clippy::missing_safety_doc "unsafe function's docs miss `# Safety` section"
-target/lintcheck/sources/libc-0.2.81/src/unix/linux_like/linux/gnu/mod.rs:359:13 clippy::must_use_candidate "this method could have a `#[must_use]` attribute"
-target/lintcheck/sources/libc-0.2.81/src/unix/linux_like/linux/gnu/mod.rs:363:13 clippy::missing_safety_doc "unsafe function's docs miss `# Safety` section"
-target/lintcheck/sources/libc-0.2.81/src/unix/linux_like/linux/gnu/mod.rs:363:13 clippy::must_use_candidate "this method could have a `#[must_use]` attribute"
-target/lintcheck/sources/libc-0.2.81/src/unix/linux_like/linux/gnu/mod.rs:367:13 clippy::missing_safety_doc "unsafe function's docs miss `# Safety` section"
-target/lintcheck/sources/libc-0.2.81/src/unix/linux_like/linux/gnu/mod.rs:367:13 clippy::must_use_candidate "this method could have a `#[must_use]` attribute"
-target/lintcheck/sources/libc-0.2.81/src/unix/linux_like/linux/gnu/mod.rs:371:13 clippy::missing_safety_doc "unsafe function's docs miss `# Safety` section"
-target/lintcheck/sources/libc-0.2.81/src/unix/linux_like/linux/gnu/mod.rs:371:13 clippy::must_use_candidate "this method could have a `#[must_use]` attribute"
-target/lintcheck/sources/libc-0.2.81/src/unix/linux_like/linux/gnu/mod.rs:534:36 clippy::unreadable_literal "long literal lacking separators"
-target/lintcheck/sources/libc-0.2.81/src/unix/linux_like/linux/gnu/mod.rs:645:31 clippy::unreadable_literal "long literal lacking separators"
-target/lintcheck/sources/libc-0.2.81/src/unix/linux_like/linux/gnu/mod.rs:727:40 clippy::unreadable_literal "long literal lacking separators"
-target/lintcheck/sources/libc-0.2.81/src/unix/linux_like/linux/gnu/mod.rs:728:40 clippy::unreadable_literal "long literal lacking separators"
-target/lintcheck/sources/libc-0.2.81/src/unix/linux_like/linux/gnu/mod.rs:729:39 clippy::unreadable_literal "long literal lacking separators"
-target/lintcheck/sources/libc-0.2.81/src/unix/linux_like/linux/gnu/mod.rs:731:44 clippy::unreadable_literal "long literal lacking separators"
-target/lintcheck/sources/libc-0.2.81/src/unix/linux_like/linux/gnu/mod.rs:732:36 clippy::unreadable_literal "long literal lacking separators"
-target/lintcheck/sources/libc-0.2.81/src/unix/linux_like/linux/gnu/mod.rs:733:41 clippy::unreadable_literal "long literal lacking separators"
-target/lintcheck/sources/libc-0.2.81/src/unix/linux_like/linux/gnu/mod.rs:734:43 clippy::unreadable_literal "long literal lacking separators"
-target/lintcheck/sources/libc-0.2.81/src/unix/linux_like/linux/gnu/mod.rs:735:42 clippy::unreadable_literal "long literal lacking separators"
-target/lintcheck/sources/libc-0.2.81/src/unix/linux_like/linux/gnu/mod.rs:736:40 clippy::unreadable_literal "long literal lacking separators"
-target/lintcheck/sources/libc-0.2.81/src/unix/linux_like/linux/gnu/mod.rs:737:36 clippy::unreadable_literal "long literal lacking separators"
-target/lintcheck/sources/libc-0.2.81/src/unix/linux_like/linux/gnu/mod.rs:738:37 clippy::unreadable_literal "long literal lacking separators"
-target/lintcheck/sources/libc-0.2.81/src/unix/linux_like/linux/gnu/mod.rs:741:39 clippy::unreadable_literal "long literal lacking separators"
-target/lintcheck/sources/libc-0.2.81/src/unix/linux_like/linux/gnu/mod.rs:742:40 clippy::unreadable_literal "long literal lacking separators"
-target/lintcheck/sources/libc-0.2.81/src/unix/linux_like/linux/gnu/mod.rs:743:40 clippy::unreadable_literal "long literal lacking separators"
-target/lintcheck/sources/libc-0.2.81/src/unix/linux_like/linux/gnu/mod.rs:744:40 clippy::unreadable_literal "long literal lacking separators"
-target/lintcheck/sources/libc-0.2.81/src/unix/linux_like/linux/gnu/mod.rs:745:40 clippy::unreadable_literal "long literal lacking separators"
-target/lintcheck/sources/libc-0.2.81/src/unix/linux_like/linux/gnu/mod.rs:746:43 clippy::unreadable_literal "long literal lacking separators"
-target/lintcheck/sources/libc-0.2.81/src/unix/linux_like/linux/gnu/mod.rs:747:42 clippy::unreadable_literal "long literal lacking separators"
-target/lintcheck/sources/libc-0.2.81/src/unix/linux_like/linux/gnu/mod.rs:748:40 clippy::unreadable_literal "long literal lacking separators"
-target/lintcheck/sources/libc-0.2.81/src/unix/linux_like/linux/gnu/mod.rs:749:39 clippy::unreadable_literal "long literal lacking separators"
-target/lintcheck/sources/libc-0.2.81/src/unix/linux_like/linux/gnu/mod.rs:750:41 clippy::unreadable_literal "long literal lacking separators"
-target/lintcheck/sources/libc-0.2.81/src/unix/linux_like/linux/gnu/mod.rs:751:41 clippy::unreadable_literal "long literal lacking separators"
-target/lintcheck/sources/libc-0.2.81/src/unix/linux_like/linux/gnu/mod.rs:752:43 clippy::unreadable_literal "long literal lacking separators"
-target/lintcheck/sources/libc-0.2.81/src/unix/linux_like/linux/gnu/mod.rs:753:42 clippy::unreadable_literal "long literal lacking separators"
-target/lintcheck/sources/libc-0.2.81/src/unix/linux_like/linux/gnu/mod.rs:755:42 clippy::unreadable_literal "long literal lacking separators"
-target/lintcheck/sources/libc-0.2.81/src/unix/linux_like/linux/gnu/mod.rs:756:41 clippy::unreadable_literal "long literal lacking separators"
-target/lintcheck/sources/libc-0.2.81/src/unix/linux_like/linux/gnu/mod.rs:757:41 clippy::unreadable_literal "long literal lacking separators"
-target/lintcheck/sources/libc-0.2.81/src/unix/linux_like/linux/gnu/mod.rs:758:39 clippy::unreadable_literal "long literal lacking separators"
-target/lintcheck/sources/libc-0.2.81/src/unix/linux_like/linux/gnu/mod.rs:759:39 clippy::unreadable_literal "long literal lacking separators"
-target/lintcheck/sources/libc-0.2.81/src/unix/linux_like/linux/gnu/mod.rs:761:41 clippy::unreadable_literal "long literal lacking separators"
-target/lintcheck/sources/libc-0.2.81/src/unix/linux_like/linux/gnu/mod.rs:762:44 clippy::unreadable_literal "long literal lacking separators"
-target/lintcheck/sources/libc-0.2.81/src/unix/linux_like/linux/gnu/mod.rs:763:45 clippy::unreadable_literal "long literal lacking separators"
-target/lintcheck/sources/libc-0.2.81/src/unix/linux_like/linux/gnu/mod.rs:764:40 clippy::unreadable_literal "long literal lacking separators"
-target/lintcheck/sources/libc-0.2.81/src/unix/linux_like/linux/gnu/mod.rs:765:40 clippy::unreadable_literal "long literal lacking separators"
-target/lintcheck/sources/libc-0.2.81/src/unix/linux_like/linux/gnu/mod.rs:766:40 clippy::unreadable_literal "long literal lacking separators"
-target/lintcheck/sources/libc-0.2.81/src/unix/linux_like/linux/gnu/mod.rs:767:44 clippy::unreadable_literal "long literal lacking separators"
-target/lintcheck/sources/libc-0.2.81/src/unix/linux_like/linux/gnu/mod.rs:768:44 clippy::unreadable_literal "long literal lacking separators"
-target/lintcheck/sources/libc-0.2.81/src/unix/linux_like/linux/gnu/mod.rs:769:39 clippy::unreadable_literal "long literal lacking separators"
-target/lintcheck/sources/libc-0.2.81/src/unix/linux_like/linux/gnu/mod.rs:770:35 clippy::unreadable_literal "long literal lacking separators"
-target/lintcheck/sources/libc-0.2.81/src/unix/linux_like/linux/gnu/mod.rs:771:35 clippy::unreadable_literal "long literal lacking separators"
-target/lintcheck/sources/libc-0.2.81/src/unix/linux_like/linux/gnu/mod.rs:772:37 clippy::unreadable_literal "long literal lacking separators"
-target/lintcheck/sources/libc-0.2.81/src/unix/linux_like/linux/gnu/mod.rs:773:39 clippy::unreadable_literal "long literal lacking separators"
-target/lintcheck/sources/libc-0.2.81/src/unix/linux_like/linux/gnu/mod.rs:774:45 clippy::unreadable_literal "long literal lacking separators"
-target/lintcheck/sources/libc-0.2.81/src/unix/linux_like/linux/gnu/mod.rs:775:41 clippy::unreadable_literal "long literal lacking separators"
-target/lintcheck/sources/libc-0.2.81/src/unix/linux_like/linux/gnu/mod.rs:776:39 clippy::unreadable_literal "long literal lacking separators"
-target/lintcheck/sources/libc-0.2.81/src/unix/linux_like/linux/gnu/mod.rs:803:34 clippy::unreadable_literal "long literal lacking separators"
-target/lintcheck/sources/libc-0.2.81/src/unix/linux_like/linux/gnu/mod.rs:841:30 clippy::unreadable_literal "long literal lacking separators"
-target/lintcheck/sources/libc-0.2.81/src/unix/linux_like/linux/gnu/mod.rs:842:37 clippy::unreadable_literal "long literal lacking separators"
-target/lintcheck/sources/libc-0.2.81/src/unix/linux_like/linux/gnu/mod.rs:982:40 clippy::unreadable_literal "long literal lacking separators"
-target/lintcheck/sources/libc-0.2.81/src/unix/linux_like/linux/gnu/mod.rs:984:46 clippy::unreadable_literal "long literal lacking separators"
-target/lintcheck/sources/libc-0.2.81/src/unix/linux_like/linux/mod.rs:1209:36 clippy::cast_possible_truncation "casting `i32` to `i16` may truncate the value"
-target/lintcheck/sources/libc-0.2.81/src/unix/linux_like/linux/mod.rs:1210:36 clippy::cast_possible_truncation "casting `i32` to `i16` may truncate the value"
-target/lintcheck/sources/libc-0.2.81/src/unix/linux_like/linux/mod.rs:1235:39 clippy::unseparated_literal_suffix "integer type suffix should be separated by an underscore"
-target/lintcheck/sources/libc-0.2.81/src/unix/linux_like/linux/mod.rs:1236:41 clippy::unseparated_literal_suffix "integer type suffix should be separated by an underscore"
-target/lintcheck/sources/libc-0.2.81/src/unix/linux_like/linux/mod.rs:1274:42 clippy::unreadable_literal "long literal lacking separators"
-target/lintcheck/sources/libc-0.2.81/src/unix/linux_like/linux/mod.rs:1324:31 clippy::unreadable_literal "long literal lacking separators"
-target/lintcheck/sources/libc-0.2.81/src/unix/linux_like/linux/mod.rs:1333:37 clippy::unreadable_literal "long literal lacking separators"
-target/lintcheck/sources/libc-0.2.81/src/unix/linux_like/linux/mod.rs:1334:35 clippy::unreadable_literal "long literal lacking separators"
-target/lintcheck/sources/libc-0.2.81/src/unix/linux_like/linux/mod.rs:1346:34 clippy::cast_possible_wrap "casting `u32` to `i32` may wrap around the value"
-target/lintcheck/sources/libc-0.2.81/src/unix/linux_like/linux/mod.rs:1346:34 clippy::unreadable_literal "long literal lacking separators"
-target/lintcheck/sources/libc-0.2.81/src/unix/linux_like/linux/mod.rs:1346:34 clippy::unseparated_literal_suffix "integer type suffix should be separated by an underscore"
-target/lintcheck/sources/libc-0.2.81/src/unix/linux_like/linux/mod.rs:1347:37 clippy::cast_possible_wrap "casting `u32` to `i32` may wrap around the value"
-target/lintcheck/sources/libc-0.2.81/src/unix/linux_like/linux/mod.rs:1347:37 clippy::unreadable_literal "long literal lacking separators"
-target/lintcheck/sources/libc-0.2.81/src/unix/linux_like/linux/mod.rs:1347:37 clippy::unseparated_literal_suffix "integer type suffix should be separated by an underscore"
-target/lintcheck/sources/libc-0.2.81/src/unix/linux_like/linux/mod.rs:1348:36 clippy::cast_possible_wrap "casting `u32` to `i32` may wrap around the value"
-target/lintcheck/sources/libc-0.2.81/src/unix/linux_like/linux/mod.rs:1348:36 clippy::unreadable_literal "long literal lacking separators"
-target/lintcheck/sources/libc-0.2.81/src/unix/linux_like/linux/mod.rs:1348:36 clippy::unseparated_literal_suffix "integer type suffix should be separated by an underscore"
-target/lintcheck/sources/libc-0.2.81/src/unix/linux_like/linux/mod.rs:1349:37 clippy::cast_possible_wrap "casting `u32` to `i32` may wrap around the value"
-target/lintcheck/sources/libc-0.2.81/src/unix/linux_like/linux/mod.rs:1349:37 clippy::unreadable_literal "long literal lacking separators"
-target/lintcheck/sources/libc-0.2.81/src/unix/linux_like/linux/mod.rs:1349:37 clippy::unseparated_literal_suffix "integer type suffix should be separated by an underscore"
-target/lintcheck/sources/libc-0.2.81/src/unix/linux_like/linux/mod.rs:1350:35 clippy::cast_possible_wrap "casting `u32` to `i32` may wrap around the value"
-target/lintcheck/sources/libc-0.2.81/src/unix/linux_like/linux/mod.rs:1350:35 clippy::unreadable_literal "long literal lacking separators"
-target/lintcheck/sources/libc-0.2.81/src/unix/linux_like/linux/mod.rs:1350:35 clippy::unseparated_literal_suffix "integer type suffix should be separated by an underscore"
-target/lintcheck/sources/libc-0.2.81/src/unix/linux_like/linux/mod.rs:1351:36 clippy::cast_possible_wrap "casting `u32` to `i32` may wrap around the value"
-target/lintcheck/sources/libc-0.2.81/src/unix/linux_like/linux/mod.rs:1351:36 clippy::unreadable_literal "long literal lacking separators"
-target/lintcheck/sources/libc-0.2.81/src/unix/linux_like/linux/mod.rs:1351:36 clippy::unseparated_literal_suffix "integer type suffix should be separated by an underscore"
-target/lintcheck/sources/libc-0.2.81/src/unix/linux_like/linux/mod.rs:1352:31 clippy::cast_possible_wrap "casting `u32` to `i32` may wrap around the value"
-target/lintcheck/sources/libc-0.2.81/src/unix/linux_like/linux/mod.rs:1352:31 clippy::unreadable_literal "long literal lacking separators"
-target/lintcheck/sources/libc-0.2.81/src/unix/linux_like/linux/mod.rs:1352:31 clippy::unseparated_literal_suffix "integer type suffix should be separated by an underscore"
-target/lintcheck/sources/libc-0.2.81/src/unix/linux_like/linux/mod.rs:1419:36 clippy::unreadable_literal "long literal lacking separators"
-target/lintcheck/sources/libc-0.2.81/src/unix/linux_like/linux/mod.rs:1420:36 clippy::unreadable_literal "long literal lacking separators"
-target/lintcheck/sources/libc-0.2.81/src/unix/linux_like/linux/mod.rs:1421:36 clippy::unreadable_literal "long literal lacking separators"
-target/lintcheck/sources/libc-0.2.81/src/unix/linux_like/linux/mod.rs:1422:36 clippy::unreadable_literal "long literal lacking separators"
-target/lintcheck/sources/libc-0.2.81/src/unix/linux_like/linux/mod.rs:1423:36 clippy::unreadable_literal "long literal lacking separators"
-target/lintcheck/sources/libc-0.2.81/src/unix/linux_like/linux/mod.rs:1490:37 clippy::unreadable_literal "long literal lacking separators"
-target/lintcheck/sources/libc-0.2.81/src/unix/linux_like/linux/mod.rs:1561:46 clippy::unreadable_literal "long literal lacking separators"
-target/lintcheck/sources/libc-0.2.81/src/unix/linux_like/linux/mod.rs:1562:45 clippy::unreadable_literal "long literal lacking separators"
-target/lintcheck/sources/libc-0.2.81/src/unix/linux_like/linux/mod.rs:1567:31 clippy::unreadable_literal "long literal lacking separators"
-target/lintcheck/sources/libc-0.2.81/src/unix/linux_like/linux/mod.rs:1568:32 clippy::unreadable_literal "long literal lacking separators"
-target/lintcheck/sources/libc-0.2.81/src/unix/linux_like/linux/mod.rs:1586:26 clippy::unreadable_literal "long literal lacking separators"
-target/lintcheck/sources/libc-0.2.81/src/unix/linux_like/linux/mod.rs:1587:34 clippy::unreadable_literal "long literal lacking separators"
-target/lintcheck/sources/libc-0.2.81/src/unix/linux_like/linux/mod.rs:1588:31 clippy::unreadable_literal "long literal lacking separators"
-target/lintcheck/sources/libc-0.2.81/src/unix/linux_like/linux/mod.rs:1589:31 clippy::unreadable_literal "long literal lacking separators"
-target/lintcheck/sources/libc-0.2.81/src/unix/linux_like/linux/mod.rs:1897:38 clippy::unreadable_literal "long literal lacking separators"
-target/lintcheck/sources/libc-0.2.81/src/unix/linux_like/linux/mod.rs:1898:51 clippy::unreadable_literal "long literal lacking separators"
-target/lintcheck/sources/libc-0.2.81/src/unix/linux_like/linux/mod.rs:1900:39 clippy::unreadable_literal "long literal lacking separators"
-target/lintcheck/sources/libc-0.2.81/src/unix/linux_like/linux/mod.rs:1969:34 clippy::unreadable_literal "long literal lacking separators"
-target/lintcheck/sources/libc-0.2.81/src/unix/linux_like/linux/mod.rs:1970:34 clippy::unreadable_literal "long literal lacking separators"
-target/lintcheck/sources/libc-0.2.81/src/unix/linux_like/linux/mod.rs:1971:36 clippy::unreadable_literal "long literal lacking separators"
-target/lintcheck/sources/libc-0.2.81/src/unix/linux_like/linux/mod.rs:1972:36 clippy::unreadable_literal "long literal lacking separators"
-target/lintcheck/sources/libc-0.2.81/src/unix/linux_like/linux/mod.rs:1973:36 clippy::unreadable_literal "long literal lacking separators"
-target/lintcheck/sources/libc-0.2.81/src/unix/linux_like/linux/mod.rs:1974:37 clippy::unreadable_literal "long literal lacking separators"
-target/lintcheck/sources/libc-0.2.81/src/unix/linux_like/linux/mod.rs:1975:37 clippy::unreadable_literal "long literal lacking separators"
-target/lintcheck/sources/libc-0.2.81/src/unix/linux_like/linux/mod.rs:1976:36 clippy::unreadable_literal "long literal lacking separators"
-target/lintcheck/sources/libc-0.2.81/src/unix/linux_like/linux/mod.rs:1977:36 clippy::unreadable_literal "long literal lacking separators"
-target/lintcheck/sources/libc-0.2.81/src/unix/linux_like/linux/mod.rs:1978:39 clippy::unreadable_literal "long literal lacking separators"
-target/lintcheck/sources/libc-0.2.81/src/unix/linux_like/linux/mod.rs:1979:39 clippy::unreadable_literal "long literal lacking separators"
-target/lintcheck/sources/libc-0.2.81/src/unix/linux_like/linux/mod.rs:1980:39 clippy::unreadable_literal "long literal lacking separators"
-target/lintcheck/sources/libc-0.2.81/src/unix/linux_like/linux/mod.rs:1981:39 clippy::unreadable_literal "long literal lacking separators"
-target/lintcheck/sources/libc-0.2.81/src/unix/linux_like/linux/mod.rs:1982:39 clippy::unreadable_literal "long literal lacking separators"
-target/lintcheck/sources/libc-0.2.81/src/unix/linux_like/linux/mod.rs:1983:39 clippy::unreadable_literal "long literal lacking separators"
-target/lintcheck/sources/libc-0.2.81/src/unix/linux_like/linux/mod.rs:1984:38 clippy::unreadable_literal "long literal lacking separators"
-target/lintcheck/sources/libc-0.2.81/src/unix/linux_like/linux/mod.rs:1985:38 clippy::unreadable_literal "long literal lacking separators"
-target/lintcheck/sources/libc-0.2.81/src/unix/linux_like/linux/mod.rs:1986:35 clippy::unreadable_literal "long literal lacking separators"
-target/lintcheck/sources/libc-0.2.81/src/unix/linux_like/linux/mod.rs:1987:35 clippy::unreadable_literal "long literal lacking separators"
-target/lintcheck/sources/libc-0.2.81/src/unix/linux_like/linux/mod.rs:1988:35 clippy::unreadable_literal "long literal lacking separators"
-target/lintcheck/sources/libc-0.2.81/src/unix/linux_like/linux/mod.rs:1989:35 clippy::unreadable_literal "long literal lacking separators"
-target/lintcheck/sources/libc-0.2.81/src/unix/linux_like/linux/mod.rs:1990:38 clippy::unreadable_literal "long literal lacking separators"
-target/lintcheck/sources/libc-0.2.81/src/unix/linux_like/linux/mod.rs:1991:37 clippy::unreadable_literal "long literal lacking separators"
-target/lintcheck/sources/libc-0.2.81/src/unix/linux_like/linux/mod.rs:1992:37 clippy::unreadable_literal "long literal lacking separators"
-target/lintcheck/sources/libc-0.2.81/src/unix/linux_like/linux/mod.rs:1993:38 clippy::unreadable_literal "long literal lacking separators"
-target/lintcheck/sources/libc-0.2.81/src/unix/linux_like/linux/mod.rs:1994:37 clippy::unreadable_literal "long literal lacking separators"
-target/lintcheck/sources/libc-0.2.81/src/unix/linux_like/linux/mod.rs:1995:37 clippy::unreadable_literal "long literal lacking separators"
-target/lintcheck/sources/libc-0.2.81/src/unix/linux_like/linux/mod.rs:1996:37 clippy::unreadable_literal "long literal lacking separators"
-target/lintcheck/sources/libc-0.2.81/src/unix/linux_like/linux/mod.rs:1997:37 clippy::unreadable_literal "long literal lacking separators"
-target/lintcheck/sources/libc-0.2.81/src/unix/linux_like/linux/mod.rs:1998:33 clippy::unreadable_literal "long literal lacking separators"
-target/lintcheck/sources/libc-0.2.81/src/unix/linux_like/linux/mod.rs:1999:33 clippy::unreadable_literal "long literal lacking separators"
-target/lintcheck/sources/libc-0.2.81/src/unix/linux_like/linux/mod.rs:2000:33 clippy::unreadable_literal "long literal lacking separators"
-target/lintcheck/sources/libc-0.2.81/src/unix/linux_like/linux/mod.rs:2001:34 clippy::unreadable_literal "long literal lacking separators"
-target/lintcheck/sources/libc-0.2.81/src/unix/linux_like/linux/mod.rs:2002:34 clippy::unreadable_literal "long literal lacking separators"
-target/lintcheck/sources/libc-0.2.81/src/unix/linux_like/linux/mod.rs:2003:34 clippy::unreadable_literal "long literal lacking separators"
-target/lintcheck/sources/libc-0.2.81/src/unix/linux_like/linux/mod.rs:2004:35 clippy::unreadable_literal "long literal lacking separators"
-target/lintcheck/sources/libc-0.2.81/src/unix/linux_like/linux/mod.rs:2005:35 clippy::unreadable_literal "long literal lacking separators"
-target/lintcheck/sources/libc-0.2.81/src/unix/linux_like/linux/mod.rs:2032:30 clippy::unreadable_literal "long literal lacking separators"
-target/lintcheck/sources/libc-0.2.81/src/unix/linux_like/linux/mod.rs:2033:32 clippy::unreadable_literal "long literal lacking separators"
-target/lintcheck/sources/libc-0.2.81/src/unix/linux_like/linux/mod.rs:2034:31 clippy::unreadable_literal "long literal lacking separators"
-target/lintcheck/sources/libc-0.2.81/src/unix/linux_like/linux/mod.rs:2035:29 clippy::unreadable_literal "long literal lacking separators"
-target/lintcheck/sources/libc-0.2.81/src/unix/linux_like/linux/mod.rs:2036:32 clippy::unreadable_literal "long literal lacking separators"
-target/lintcheck/sources/libc-0.2.81/src/unix/linux_like/linux/mod.rs:2037:28 clippy::unreadable_literal "long literal lacking separators"
-target/lintcheck/sources/libc-0.2.81/src/unix/linux_like/linux/mod.rs:2038:27 clippy::unreadable_literal "long literal lacking separators"
-target/lintcheck/sources/libc-0.2.81/src/unix/linux_like/linux/mod.rs:2039:29 clippy::unreadable_literal "long literal lacking separators"
-target/lintcheck/sources/libc-0.2.81/src/unix/linux_like/linux/mod.rs:2041:29 clippy::unreadable_literal "long literal lacking separators"
-target/lintcheck/sources/libc-0.2.81/src/unix/linux_like/linux/mod.rs:2042:28 clippy::unreadable_literal "long literal lacking separators"
-target/lintcheck/sources/libc-0.2.81/src/unix/linux_like/linux/mod.rs:2043:27 clippy::unreadable_literal "long literal lacking separators"
-target/lintcheck/sources/libc-0.2.81/src/unix/linux_like/linux/mod.rs:2044:34 clippy::unreadable_literal "long literal lacking separators"
-target/lintcheck/sources/libc-0.2.81/src/unix/linux_like/linux/mod.rs:2045:27 clippy::unreadable_literal "long literal lacking separators"
-target/lintcheck/sources/libc-0.2.81/src/unix/linux_like/linux/mod.rs:2046:33 clippy::unreadable_literal "long literal lacking separators"
-target/lintcheck/sources/libc-0.2.81/src/unix/linux_like/linux/mod.rs:2048:28 clippy::unreadable_literal "long literal lacking separators"
-target/lintcheck/sources/libc-0.2.81/src/unix/linux_like/linux/mod.rs:2049:32 clippy::unreadable_literal "long literal lacking separators"
-target/lintcheck/sources/libc-0.2.81/src/unix/linux_like/linux/mod.rs:2050:32 clippy::unreadable_literal "long literal lacking separators"
-target/lintcheck/sources/libc-0.2.81/src/unix/linux_like/linux/mod.rs:2051:32 clippy::unreadable_literal "long literal lacking separators"
-target/lintcheck/sources/libc-0.2.81/src/unix/linux_like/linux/mod.rs:2052:26 clippy::unreadable_literal "long literal lacking separators"
-target/lintcheck/sources/libc-0.2.81/src/unix/linux_like/linux/mod.rs:2053:36 clippy::unreadable_literal "long literal lacking separators"
-target/lintcheck/sources/libc-0.2.81/src/unix/linux_like/linux/mod.rs:2318:42 clippy::unreadable_literal "long literal lacking separators"
-target/lintcheck/sources/libc-0.2.81/src/unix/linux_like/linux/mod.rs:2321:38 clippy::unreadable_literal "long literal lacking separators"
-target/lintcheck/sources/libc-0.2.81/src/unix/linux_like/linux/mod.rs:2331:39 clippy::unreadable_literal "long literal lacking separators"
-target/lintcheck/sources/libc-0.2.81/src/unix/linux_like/linux/mod.rs:2487:42 clippy::unreadable_literal "long literal lacking separators"
-target/lintcheck/sources/libc-0.2.81/src/unix/linux_like/linux/mod.rs:2488:42 clippy::unreadable_literal "long literal lacking separators"
-target/lintcheck/sources/libc-0.2.81/src/unix/linux_like/linux/mod.rs:2489:43 clippy::unreadable_literal "long literal lacking separators"
-target/lintcheck/sources/libc-0.2.81/src/unix/linux_like/linux/mod.rs:2490:43 clippy::unreadable_literal "long literal lacking separators"
-target/lintcheck/sources/libc-0.2.81/src/unix/linux_like/linux/mod.rs:2491:43 clippy::unreadable_literal "long literal lacking separators"
-target/lintcheck/sources/libc-0.2.81/src/unix/linux_like/linux/mod.rs:2493:47 clippy::unreadable_literal "long literal lacking separators"
-target/lintcheck/sources/libc-0.2.81/src/unix/linux_like/linux/mod.rs:2494:44 clippy::unreadable_literal "long literal lacking separators"
-target/lintcheck/sources/libc-0.2.81/src/unix/linux_like/linux/mod.rs:2495:46 clippy::unreadable_literal "long literal lacking separators"
-target/lintcheck/sources/libc-0.2.81/src/unix/linux_like/linux/mod.rs:2496:47 clippy::unreadable_literal "long literal lacking separators"
-target/lintcheck/sources/libc-0.2.81/src/unix/linux_like/linux/mod.rs:2497:49 clippy::unreadable_literal "long literal lacking separators"
-target/lintcheck/sources/libc-0.2.81/src/unix/linux_like/linux/mod.rs:2498:48 clippy::unreadable_literal "long literal lacking separators"
-target/lintcheck/sources/libc-0.2.81/src/unix/linux_like/linux/mod.rs:2499:50 clippy::unreadable_literal "long literal lacking separators"
-target/lintcheck/sources/libc-0.2.81/src/unix/linux_like/linux/mod.rs:2500:45 clippy::unreadable_literal "long literal lacking separators"
-target/lintcheck/sources/libc-0.2.81/src/unix/linux_like/linux/mod.rs:2572:9 clippy::needless_return "unneeded `return` statement"
-target/lintcheck/sources/libc-0.2.81/src/unix/linux_like/linux/mod.rs:2578:20 clippy::zero_ptr "`0 as *mut _` detected"
-target/lintcheck/sources/libc-0.2.81/src/unix/linux_like/linux/mod.rs:2588:13 clippy::zero_ptr "`0 as *mut _` detected"
-target/lintcheck/sources/libc-0.2.81/src/unix/linux_like/linux/mod.rs:2590:13 clippy::ptr_as_ptr "`as` casting between raw pointers without changing its mutability"
-target/lintcheck/sources/libc-0.2.81/src/unix/linux_like/linux/mod.rs:2596:52 clippy::used_underscore_binding "used binding `_dummy` which is prefixed with an underscore. A leading underscore signals that a binding will not be used"
-target/lintcheck/sources/libc-0.2.81/src/unix/linux_like/linux/mod.rs:2597:11 clippy::cast_sign_loss "casting `i32` to `usize` may lose the sign of the value"
-target/lintcheck/sources/libc-0.2.81/src/unix/linux_like/linux/mod.rs:2601:21 clippy::explicit_iter_loop "it is more concise to loop over references to containers instead of using explicit iteration methods"
-target/lintcheck/sources/libc-0.2.81/src/unix/linux_like/linux/mod.rs:2611:9 clippy::unused_unit "unneeded unit expression"
-target/lintcheck/sources/libc-0.2.81/src/unix/linux_like/linux/mod.rs:2619:9 clippy::unused_unit "unneeded unit expression"
-target/lintcheck/sources/libc-0.2.81/src/unix/linux_like/linux/mod.rs:2634:9 clippy::cast_possible_wrap "casting `u32` to `i32` may wrap around the value"
-target/lintcheck/sources/libc-0.2.81/src/unix/linux_like/linux/mod.rs:2647:25 clippy::unreadable_literal "long literal lacking separators"
-target/lintcheck/sources/libc-0.2.81/src/unix/linux_like/linux/mod.rs:2648:25 clippy::unreadable_literal "long literal lacking separators"
-target/lintcheck/sources/libc-0.2.81/src/unix/linux_like/linux/mod.rs:2649:9 clippy::cast_possible_truncation "casting `u64` to `u32` may truncate the value"
-target/lintcheck/sources/libc-0.2.81/src/unix/linux_like/linux/mod.rs:2654:18 clippy::identity_op "the operation is ineffective. Consider reducing it to `(dev & 0x00000000000000ff)`"
-target/lintcheck/sources/libc-0.2.81/src/unix/linux_like/linux/mod.rs:2654:25 clippy::unreadable_literal "long literal lacking separators"
-target/lintcheck/sources/libc-0.2.81/src/unix/linux_like/linux/mod.rs:2655:25 clippy::unreadable_literal "long literal lacking separators"
-target/lintcheck/sources/libc-0.2.81/src/unix/linux_like/linux/mod.rs:2656:9 clippy::cast_possible_truncation "casting `u64` to `u32` may truncate the value"
-target/lintcheck/sources/libc-0.2.81/src/unix/linux_like/linux/mod.rs:2660:21 clippy::cast_lossless "casting `u32` to `u64` may become silently lossy if you later change the type"
-target/lintcheck/sources/libc-0.2.81/src/unix/linux_like/linux/mod.rs:2661:21 clippy::cast_lossless "casting `u32` to `u64` may become silently lossy if you later change the type"
-target/lintcheck/sources/libc-0.2.81/src/unix/linux_like/linux/mod.rs:2663:25 clippy::unreadable_literal "long literal lacking separators"
-target/lintcheck/sources/libc-0.2.81/src/unix/linux_like/linux/mod.rs:2664:25 clippy::unreadable_literal "long literal lacking separators"
-target/lintcheck/sources/libc-0.2.81/src/unix/linux_like/linux/mod.rs:2665:16 clippy::identity_op "the operation is ineffective. Consider reducing it to `(minor & 0x000000ff)`"
-target/lintcheck/sources/libc-0.2.81/src/unix/linux_like/linux/mod.rs:2665:25 clippy::unreadable_literal "long literal lacking separators"
-target/lintcheck/sources/libc-0.2.81/src/unix/linux_like/linux/mod.rs:2666:25 clippy::unreadable_literal "long literal lacking separators"
-target/lintcheck/sources/libc-0.2.81/src/unix/linux_like/linux/mod.rs:42:1 clippy::expl_impl_clone_on_copy "you are implementing `Clone` explicitly on a `Copy` type"
-target/lintcheck/sources/libc-0.2.81/src/unix/linux_like/linux/mod.rs:954:34 clippy::unreadable_literal "long literal lacking separators"
-target/lintcheck/sources/libc-0.2.81/src/unix/linux_like/mod.rs:1000:31 clippy::unreadable_literal "long literal lacking separators"
-target/lintcheck/sources/libc-0.2.81/src/unix/linux_like/mod.rs:1001:32 clippy::unreadable_literal "long literal lacking separators"
-target/lintcheck/sources/libc-0.2.81/src/unix/linux_like/mod.rs:1002:32 clippy::unreadable_literal "long literal lacking separators"
-target/lintcheck/sources/libc-0.2.81/src/unix/linux_like/mod.rs:1016:29 clippy::unreadable_literal "long literal lacking separators"
-target/lintcheck/sources/libc-0.2.81/src/unix/linux_like/mod.rs:1017:32 clippy::unreadable_literal "long literal lacking separators"
-target/lintcheck/sources/libc-0.2.81/src/unix/linux_like/mod.rs:1018:33 clippy::unreadable_literal "long literal lacking separators"
-target/lintcheck/sources/libc-0.2.81/src/unix/linux_like/mod.rs:1019:33 clippy::unreadable_literal "long literal lacking separators"
-target/lintcheck/sources/libc-0.2.81/src/unix/linux_like/mod.rs:1020:33 clippy::unreadable_literal "long literal lacking separators"
-target/lintcheck/sources/libc-0.2.81/src/unix/linux_like/mod.rs:1029:29 clippy::unreadable_literal "long literal lacking separators"
-target/lintcheck/sources/libc-0.2.81/src/unix/linux_like/mod.rs:1030:29 clippy::unreadable_literal "long literal lacking separators"
-target/lintcheck/sources/libc-0.2.81/src/unix/linux_like/mod.rs:1031:30 clippy::unreadable_literal "long literal lacking separators"
-target/lintcheck/sources/libc-0.2.81/src/unix/linux_like/mod.rs:1032:29 clippy::unreadable_literal "long literal lacking separators"
-target/lintcheck/sources/libc-0.2.81/src/unix/linux_like/mod.rs:1033:29 clippy::unreadable_literal "long literal lacking separators"
-target/lintcheck/sources/libc-0.2.81/src/unix/linux_like/mod.rs:1034:29 clippy::unreadable_literal "long literal lacking separators"
-target/lintcheck/sources/libc-0.2.81/src/unix/linux_like/mod.rs:1035:29 clippy::unreadable_literal "long literal lacking separators"
-target/lintcheck/sources/libc-0.2.81/src/unix/linux_like/mod.rs:1041:32 clippy::unreadable_literal "long literal lacking separators"
-target/lintcheck/sources/libc-0.2.81/src/unix/linux_like/mod.rs:1042:32 clippy::unreadable_literal "long literal lacking separators"
-target/lintcheck/sources/libc-0.2.81/src/unix/linux_like/mod.rs:1043:32 clippy::unreadable_literal "long literal lacking separators"
-target/lintcheck/sources/libc-0.2.81/src/unix/linux_like/mod.rs:1044:32 clippy::unreadable_literal "long literal lacking separators"
-target/lintcheck/sources/libc-0.2.81/src/unix/linux_like/mod.rs:1045:31 clippy::unreadable_literal "long literal lacking separators"
-target/lintcheck/sources/libc-0.2.81/src/unix/linux_like/mod.rs:1046:32 clippy::unreadable_literal "long literal lacking separators"
-target/lintcheck/sources/libc-0.2.81/src/unix/linux_like/mod.rs:1047:31 clippy::unreadable_literal "long literal lacking separators"
-target/lintcheck/sources/libc-0.2.81/src/unix/linux_like/mod.rs:1048:31 clippy::unreadable_literal "long literal lacking separators"
-target/lintcheck/sources/libc-0.2.81/src/unix/linux_like/mod.rs:1049:31 clippy::unreadable_literal "long literal lacking separators"
-target/lintcheck/sources/libc-0.2.81/src/unix/linux_like/mod.rs:1050:31 clippy::unreadable_literal "long literal lacking separators"
-target/lintcheck/sources/libc-0.2.81/src/unix/linux_like/mod.rs:1051:33 clippy::unreadable_literal "long literal lacking separators"
-target/lintcheck/sources/libc-0.2.81/src/unix/linux_like/mod.rs:1053:29 clippy::unreadable_literal "long literal lacking separators"
-target/lintcheck/sources/libc-0.2.81/src/unix/linux_like/mod.rs:1054:33 clippy::unreadable_literal "long literal lacking separators"
-target/lintcheck/sources/libc-0.2.81/src/unix/linux_like/mod.rs:1055:30 clippy::unreadable_literal "long literal lacking separators"
-target/lintcheck/sources/libc-0.2.81/src/unix/linux_like/mod.rs:1056:31 clippy::unreadable_literal "long literal lacking separators"
-target/lintcheck/sources/libc-0.2.81/src/unix/linux_like/mod.rs:1057:31 clippy::unreadable_literal "long literal lacking separators"
-target/lintcheck/sources/libc-0.2.81/src/unix/linux_like/mod.rs:1058:32 clippy::unreadable_literal "long literal lacking separators"
-target/lintcheck/sources/libc-0.2.81/src/unix/linux_like/mod.rs:1059:31 clippy::unreadable_literal "long literal lacking separators"
-target/lintcheck/sources/libc-0.2.81/src/unix/linux_like/mod.rs:1060:31 clippy::unreadable_literal "long literal lacking separators"
-target/lintcheck/sources/libc-0.2.81/src/unix/linux_like/mod.rs:1073:42 clippy::unreadable_literal "long literal lacking separators"
-target/lintcheck/sources/libc-0.2.81/src/unix/linux_like/mod.rs:1074:43 clippy::unreadable_literal "long literal lacking separators"
-target/lintcheck/sources/libc-0.2.81/src/unix/linux_like/mod.rs:1075:37 clippy::unreadable_literal "long literal lacking separators"
-target/lintcheck/sources/libc-0.2.81/src/unix/linux_like/mod.rs:1076:37 clippy::unreadable_literal "long literal lacking separators"
-target/lintcheck/sources/libc-0.2.81/src/unix/linux_like/mod.rs:1077:41 clippy::unreadable_literal "long literal lacking separators"
-target/lintcheck/sources/libc-0.2.81/src/unix/linux_like/mod.rs:1078:35 clippy::unreadable_literal "long literal lacking separators"
-target/lintcheck/sources/libc-0.2.81/src/unix/linux_like/mod.rs:1079:35 clippy::unreadable_literal "long literal lacking separators"
-target/lintcheck/sources/libc-0.2.81/src/unix/linux_like/mod.rs:1080:36 clippy::unreadable_literal "long literal lacking separators"
-target/lintcheck/sources/libc-0.2.81/src/unix/linux_like/mod.rs:1081:35 clippy::unreadable_literal "long literal lacking separators"
-target/lintcheck/sources/libc-0.2.81/src/unix/linux_like/mod.rs:1082:35 clippy::unreadable_literal "long literal lacking separators"
-target/lintcheck/sources/libc-0.2.81/src/unix/linux_like/mod.rs:1083:31 clippy::unreadable_literal "long literal lacking separators"
-target/lintcheck/sources/libc-0.2.81/src/unix/linux_like/mod.rs:1084:38 clippy::unreadable_literal "long literal lacking separators"
-target/lintcheck/sources/libc-0.2.81/src/unix/linux_like/mod.rs:1086:30 clippy::unreadable_literal "long literal lacking separators"
-target/lintcheck/sources/libc-0.2.81/src/unix/linux_like/mod.rs:1087:32 clippy::unreadable_literal "long literal lacking separators"
-target/lintcheck/sources/libc-0.2.81/src/unix/linux_like/mod.rs:1089:30 clippy::unreadable_literal "long literal lacking separators"
-target/lintcheck/sources/libc-0.2.81/src/unix/linux_like/mod.rs:1090:33 clippy::unreadable_literal "long literal lacking separators"
-target/lintcheck/sources/libc-0.2.81/src/unix/linux_like/mod.rs:1091:30 clippy::unreadable_literal "long literal lacking separators"
-target/lintcheck/sources/libc-0.2.81/src/unix/linux_like/mod.rs:1094:40 clippy::unreadable_literal "long literal lacking separators"
-target/lintcheck/sources/libc-0.2.81/src/unix/linux_like/mod.rs:1095:37 clippy::unreadable_literal "long literal lacking separators"
-target/lintcheck/sources/libc-0.2.81/src/unix/linux_like/mod.rs:1096:41 clippy::unreadable_literal "long literal lacking separators"
-target/lintcheck/sources/libc-0.2.81/src/unix/linux_like/mod.rs:1097:40 clippy::unreadable_literal "long literal lacking separators"
-target/lintcheck/sources/libc-0.2.81/src/unix/linux_like/mod.rs:1098:39 clippy::unreadable_literal "long literal lacking separators"
-target/lintcheck/sources/libc-0.2.81/src/unix/linux_like/mod.rs:1099:34 clippy::unreadable_literal "long literal lacking separators"
-target/lintcheck/sources/libc-0.2.81/src/unix/linux_like/mod.rs:1100:36 clippy::unreadable_literal "long literal lacking separators"
-target/lintcheck/sources/libc-0.2.81/src/unix/linux_like/mod.rs:1101:38 clippy::unreadable_literal "long literal lacking separators"
-target/lintcheck/sources/libc-0.2.81/src/unix/linux_like/mod.rs:1102:37 clippy::unreadable_literal "long literal lacking separators"
-target/lintcheck/sources/libc-0.2.81/src/unix/linux_like/mod.rs:1105:44 clippy::unreadable_literal "long literal lacking separators"
-target/lintcheck/sources/libc-0.2.81/src/unix/linux_like/mod.rs:1106:41 clippy::unreadable_literal "long literal lacking separators"
-target/lintcheck/sources/libc-0.2.81/src/unix/linux_like/mod.rs:1107:42 clippy::unreadable_literal "long literal lacking separators"
-target/lintcheck/sources/libc-0.2.81/src/unix/linux_like/mod.rs:1108:42 clippy::unreadable_literal "long literal lacking separators"
-target/lintcheck/sources/libc-0.2.81/src/unix/linux_like/mod.rs:1109:41 clippy::unreadable_literal "long literal lacking separators"
-target/lintcheck/sources/libc-0.2.81/src/unix/linux_like/mod.rs:1110:46 clippy::unreadable_literal "long literal lacking separators"
-target/lintcheck/sources/libc-0.2.81/src/unix/linux_like/mod.rs:1111:41 clippy::unreadable_literal "long literal lacking separators"
-target/lintcheck/sources/libc-0.2.81/src/unix/linux_like/mod.rs:1112:44 clippy::unreadable_literal "long literal lacking separators"
-target/lintcheck/sources/libc-0.2.81/src/unix/linux_like/mod.rs:1113:40 clippy::unreadable_literal "long literal lacking separators"
-target/lintcheck/sources/libc-0.2.81/src/unix/linux_like/mod.rs:1114:47 clippy::unreadable_literal "long literal lacking separators"
-target/lintcheck/sources/libc-0.2.81/src/unix/linux_like/mod.rs:1115:36 clippy::unreadable_literal "long literal lacking separators"
-target/lintcheck/sources/libc-0.2.81/src/unix/linux_like/mod.rs:1126:34 clippy::unreadable_literal "long literal lacking separators"
-target/lintcheck/sources/libc-0.2.81/src/unix/linux_like/mod.rs:1127:29 clippy::unreadable_literal "long literal lacking separators"
-target/lintcheck/sources/libc-0.2.81/src/unix/linux_like/mod.rs:1128:31 clippy::unreadable_literal "long literal lacking separators"
-target/lintcheck/sources/libc-0.2.81/src/unix/linux_like/mod.rs:1179:32 clippy::unreadable_literal "long literal lacking separators"
-target/lintcheck/sources/libc-0.2.81/src/unix/linux_like/mod.rs:1180:31 clippy::unreadable_literal "long literal lacking separators"
-target/lintcheck/sources/libc-0.2.81/src/unix/linux_like/mod.rs:11:1 clippy::expl_impl_clone_on_copy "you are implementing `Clone` explicitly on a `Copy` type"
-target/lintcheck/sources/libc-0.2.81/src/unix/linux_like/mod.rs:1218:27 clippy::identity_op "the operation is ineffective. Consider reducing it to `IPOPT_CONTROL`"
-target/lintcheck/sources/libc-0.2.81/src/unix/linux_like/mod.rs:1314:9 clippy::precedence "operator precedence can trip the unwary"
-target/lintcheck/sources/libc-0.2.81/src/unix/linux_like/mod.rs:1321:13 clippy::ptr_as_ptr "`as` casting between raw pointers without changing its mutability"
-target/lintcheck/sources/libc-0.2.81/src/unix/linux_like/mod.rs:1323:13 clippy::zero_ptr "`0 as *mut _` detected"
-target/lintcheck/sources/libc-0.2.81/src/unix/linux_like/mod.rs:1332:9 clippy::cast_possible_truncation "casting `usize` to `u32` may truncate the value on targets with 64-bit wide pointers"
-target/lintcheck/sources/libc-0.2.81/src/unix/linux_like/mod.rs:1337:9 clippy::cast_possible_truncation "casting `usize` to `u32` may truncate the value on targets with 64-bit wide pointers"
-target/lintcheck/sources/libc-0.2.81/src/unix/linux_like/mod.rs:1341:18 clippy::cast_sign_loss "casting `i32` to `usize` may lose the sign of the value"
-target/lintcheck/sources/libc-0.2.81/src/unix/linux_like/mod.rs:1344:9 clippy::needless_return "unneeded `return` statement"
-target/lintcheck/sources/libc-0.2.81/src/unix/linux_like/mod.rs:1348:18 clippy::cast_sign_loss "casting `i32` to `usize` may lose the sign of the value"
-target/lintcheck/sources/libc-0.2.81/src/unix/linux_like/mod.rs:1350:9 clippy::needless_return "unneeded `return` statement"
-target/lintcheck/sources/libc-0.2.81/src/unix/linux_like/mod.rs:1354:18 clippy::cast_sign_loss "casting `i32` to `usize` may lose the sign of the value"
-target/lintcheck/sources/libc-0.2.81/src/unix/linux_like/mod.rs:1357:9 clippy::needless_return "unneeded `return` statement"
-target/lintcheck/sources/libc-0.2.81/src/unix/linux_like/mod.rs:1361:21 clippy::explicit_iter_loop "it is more concise to loop over references to containers instead of using explicit iteration methods"
-target/lintcheck/sources/libc-0.2.81/src/unix/linux_like/mod.rs:1381:9 clippy::cast_possible_truncation "casting `i32` to `i8` may truncate the value"
-target/lintcheck/sources/libc-0.2.81/src/unix/linux_like/mod.rs:1389:9 clippy::verbose_bit_mask "bit mask could be simplified with a call to `trailing_zeros`"
-target/lintcheck/sources/libc-0.2.81/src/unix/linux_like/mod.rs:446:31 clippy::unreadable_literal "long literal lacking separators"
-target/lintcheck/sources/libc-0.2.81/src/unix/linux_like/mod.rs:591:36 clippy::unreadable_literal "long literal lacking separators"
-target/lintcheck/sources/libc-0.2.81/src/unix/linux_like/mod.rs:592:38 clippy::unreadable_literal "long literal lacking separators"
-target/lintcheck/sources/libc-0.2.81/src/unix/linux_like/mod.rs:593:35 clippy::unreadable_literal "long literal lacking separators"
-target/lintcheck/sources/libc-0.2.81/src/unix/linux_like/mod.rs:594:33 clippy::unreadable_literal "long literal lacking separators"
-target/lintcheck/sources/libc-0.2.81/src/unix/linux_like/mod.rs:595:34 clippy::unreadable_literal "long literal lacking separators"
-target/lintcheck/sources/libc-0.2.81/src/unix/linux_like/mod.rs:596:36 clippy::unreadable_literal "long literal lacking separators"
-target/lintcheck/sources/libc-0.2.81/src/unix/linux_like/mod.rs:597:37 clippy::unreadable_literal "long literal lacking separators"
-target/lintcheck/sources/libc-0.2.81/src/unix/linux_like/mod.rs:598:37 clippy::unreadable_literal "long literal lacking separators"
-target/lintcheck/sources/libc-0.2.81/src/unix/linux_like/mod.rs:599:39 clippy::unreadable_literal "long literal lacking separators"
-target/lintcheck/sources/libc-0.2.81/src/unix/linux_like/mod.rs:600:34 clippy::unreadable_literal "long literal lacking separators"
-target/lintcheck/sources/libc-0.2.81/src/unix/linux_like/mod.rs:601:35 clippy::unreadable_literal "long literal lacking separators"
-target/lintcheck/sources/libc-0.2.81/src/unix/linux_like/mod.rs:602:35 clippy::unreadable_literal "long literal lacking separators"
-target/lintcheck/sources/libc-0.2.81/src/unix/linux_like/mod.rs:607:37 clippy::unreadable_literal "long literal lacking separators"
-target/lintcheck/sources/libc-0.2.81/src/unix/linux_like/mod.rs:608:35 clippy::unreadable_literal "long literal lacking separators"
-target/lintcheck/sources/libc-0.2.81/src/unix/linux_like/mod.rs:764:35 clippy::unreadable_literal "long literal lacking separators"
-target/lintcheck/sources/libc-0.2.81/src/unix/linux_like/mod.rs:765:39 clippy::unreadable_literal "long literal lacking separators"
-target/lintcheck/sources/libc-0.2.81/src/unix/linux_like/mod.rs:991:30 clippy::unreadable_literal "long literal lacking separators"
-target/lintcheck/sources/libc-0.2.81/src/unix/mod.rs:198:29 clippy::unreadable_literal "long literal lacking separators"
-target/lintcheck/sources/libc-0.2.81/src/unix/mod.rs:199:28 clippy::unreadable_literal "long literal lacking separators"
-target/lintcheck/sources/libc-0.2.81/src/unix/mod.rs:201:35 clippy::unnecessary_cast "casting integer literal to `usize` is unnecessary"
-target/lintcheck/sources/libc-0.2.81/src/unix/mod.rs:202:35 clippy::unnecessary_cast "casting integer literal to `usize` is unnecessary"
-target/lintcheck/sources/libc-0.2.81/src/unix/mod.rs:282:40 clippy::unreadable_literal "long literal lacking separators"
-target/lintcheck/sources/libc-0.2.81/src/unix/mod.rs:284:41 clippy::unreadable_literal "long literal lacking separators"
-target/lintcheck/sources/libc-0.2.81/src/unix/mod.rs:285:36 clippy::unreadable_literal "long literal lacking separators"
-target/lintcheck/sources/libc-0.2.81/src/unix/mod.rs:36:1 clippy::expl_impl_clone_on_copy "you are implementing `Clone` explicitly on a `Copy` type"
-target/lintcheck/sources/libc-0.2.81/src/unix/mod.rs:388:1 clippy::expl_impl_clone_on_copy "you are implementing `Clone` explicitly on a `Copy` type"
-target/lintcheck/sources/libc-0.2.81/src/unix/mod.rs:396:1 clippy::expl_impl_clone_on_copy "you are implementing `Clone` explicitly on a `Copy` type"
-target/lintcheck/sources/log-0.4.11/src/lib.rs:1047:5 clippy::must_use_candidate "this method could have a `#[must_use]` attribute"
-target/lintcheck/sources/log-0.4.11/src/lib.rs:1053:5 clippy::must_use_candidate "this method could have a `#[must_use]` attribute"
-target/lintcheck/sources/log-0.4.11/src/lib.rs:1059:5 clippy::must_use_candidate "this method could have a `#[must_use]` attribute"
-target/lintcheck/sources/log-0.4.11/src/lib.rs:1093:5 clippy::must_use_candidate "this method could have a `#[must_use]` attribute"
-target/lintcheck/sources/log-0.4.11/src/lib.rs:1093:5 clippy::new_without_default "you should consider adding a `Default` implementation for `MetadataBuilder<'a>`"
-target/lintcheck/sources/log-0.4.11/src/lib.rs:1118:5 clippy::must_use_candidate "this method could have a `#[must_use]` attribute"
-target/lintcheck/sources/log-0.4.11/src/lib.rs:1177:1 clippy::inline_always "you have declared `#[inline(always)]` on `max_level`. This is usually a bad idea"
-target/lintcheck/sources/log-0.4.11/src/lib.rs:1178:1 clippy::must_use_candidate "this function could have a `#[must_use]` attribute"
-target/lintcheck/sources/log-0.4.11/src/lib.rs:1306:1 clippy::missing_errors_doc "docs for function returning `Result` missing `# Errors` section"
-target/lintcheck/sources/log-0.4.11/src/lib.rs:1358:1 clippy::must_use_candidate "this function could have a `#[must_use]` attribute"
-target/lintcheck/sources/log-0.4.11/src/lib.rs:1359:5 clippy::if_not_else "unnecessary `!=` operation"
-target/lintcheck/sources/log-0.4.11/src/lib.rs:1407:1 clippy::must_use_candidate "this function could have a `#[must_use]` attribute"
-target/lintcheck/sources/log-0.4.11/src/lib.rs:356:1 clippy::expl_impl_clone_on_copy "you are implementing `Clone` explicitly on a `Copy` type"
-target/lintcheck/sources/log-0.4.11/src/lib.rs:448:12 clippy::manual_range_contains "manual `RangeInclusive::contains` implementation"
-target/lintcheck/sources/log-0.4.11/src/lib.rs:500:5 clippy::must_use_candidate "this method could have a `#[must_use]` attribute"
-target/lintcheck/sources/log-0.4.11/src/lib.rs:506:28 clippy::trivially_copy_pass_by_ref "this argument (8 byte) is passed by reference, but would be more efficient if passed by value (limit: 8 byte)"
-target/lintcheck/sources/log-0.4.11/src/lib.rs:506:28 clippy::wrong_self_convention "methods with the following characteristics: (`to_*` and `self` type is `Copy`) usually take `self` by value"
-target/lintcheck/sources/log-0.4.11/src/lib.rs:506:5 clippy::missing_panics_doc "docs for function which may panic missing `# Panics` section"
-target/lintcheck/sources/log-0.4.11/src/lib.rs:506:5 clippy::must_use_candidate "this method could have a `#[must_use]` attribute"
-target/lintcheck/sources/log-0.4.11/src/lib.rs:538:1 clippy::expl_impl_clone_on_copy "you are implementing `Clone` explicitly on a `Copy` type"
-target/lintcheck/sources/log-0.4.11/src/lib.rs:653:5 clippy::must_use_candidate "this method could have a `#[must_use]` attribute"
-target/lintcheck/sources/log-0.4.11/src/lib.rs:661:21 clippy::trivially_copy_pass_by_ref "this argument (8 byte) is passed by reference, but would be more efficient if passed by value (limit: 8 byte)"
-target/lintcheck/sources/log-0.4.11/src/lib.rs:661:21 clippy::wrong_self_convention "methods with the following characteristics: (`to_*` and `self` type is `Copy`) usually take `self` by value"
-target/lintcheck/sources/log-0.4.11/src/lib.rs:661:5 clippy::must_use_candidate "this method could have a `#[must_use]` attribute"
-target/lintcheck/sources/log-0.4.11/src/lib.rs:677:44 clippy::match_same_arms "this `match` has identical arm bodies"
-target/lintcheck/sources/log-0.4.11/src/lib.rs:758:5 clippy::must_use_candidate "this method could have a `#[must_use]` attribute"
-target/lintcheck/sources/log-0.4.11/src/lib.rs:764:5 clippy::must_use_candidate "this method could have a `#[must_use]` attribute"
-target/lintcheck/sources/log-0.4.11/src/lib.rs:770:5 clippy::must_use_candidate "this method could have a `#[must_use]` attribute"
-target/lintcheck/sources/log-0.4.11/src/lib.rs:776:5 clippy::must_use_candidate "this method could have a `#[must_use]` attribute"
-target/lintcheck/sources/log-0.4.11/src/lib.rs:782:5 clippy::must_use_candidate "this method could have a `#[must_use]` attribute"
-target/lintcheck/sources/log-0.4.11/src/lib.rs:788:5 clippy::must_use_candidate "this method could have a `#[must_use]` attribute"
-target/lintcheck/sources/log-0.4.11/src/lib.rs:794:5 clippy::must_use_candidate "this method could have a `#[must_use]` attribute"
-target/lintcheck/sources/log-0.4.11/src/lib.rs:803:5 clippy::must_use_candidate "this method could have a `#[must_use]` attribute"
-target/lintcheck/sources/log-0.4.11/src/lib.rs:809:5 clippy::must_use_candidate "this method could have a `#[must_use]` attribute"
-target/lintcheck/sources/log-0.4.11/src/lib.rs:818:5 clippy::must_use_candidate "this method could have a `#[must_use]` attribute"
-target/lintcheck/sources/log-0.4.11/src/lib.rs:908:5 clippy::must_use_candidate "this method could have a `#[must_use]` attribute"
-target/lintcheck/sources/log-0.4.11/src/lib.rs:908:5 clippy::new_without_default "you should consider adding a `Default` implementation for `RecordBuilder<'a>`"
-target/lintcheck/sources/log-0.4.11/src/lib.rs:995:5 clippy::must_use_candidate "this method could have a `#[must_use]` attribute"
-target/lintcheck/sources/proc-macro2-1.0.24/src/detection.rs:2:5 clippy::wildcard_imports "usage of wildcard import"
-target/lintcheck/sources/proc-macro2-1.0.24/src/fallback.rs:108:17 clippy::match_wildcard_for_single_variants "wildcard matches only a single variant and will also match any future added variants"
-target/lintcheck/sources/proc-macro2-1.0.24/src/fallback.rs:269:20 clippy::unused_self "unused `self` argument"
-target/lintcheck/sources/proc-macro2-1.0.24/src/fallback.rs:430:24 clippy::trivially_copy_pass_by_ref "this argument (0 byte) is passed by reference, but would be more efficient if passed by value (limit: 8 byte)"
-target/lintcheck/sources/proc-macro2-1.0.24/src/fallback.rs:437:23 clippy::trivially_copy_pass_by_ref "this argument (0 byte) is passed by reference, but would be more efficient if passed by value (limit: 8 byte)"
-target/lintcheck/sources/proc-macro2-1.0.24/src/fallback.rs:437:23 clippy::unused_self "unused `self` argument"
-target/lintcheck/sources/proc-macro2-1.0.24/src/fallback.rs:471:17 clippy::trivially_copy_pass_by_ref "this argument (0 byte) is passed by reference, but would be more efficient if passed by value (limit: 8 byte)"
-target/lintcheck/sources/proc-macro2-1.0.24/src/fallback.rs:471:17 clippy::unused_self "unused `self` argument"
-target/lintcheck/sources/proc-macro2-1.0.24/src/fallback.rs:50:9 clippy::mem_replace_with_default "replacing a value of type `T` with `T::default()` is better expressed using `std::mem::take`"
-target/lintcheck/sources/proc-macro2-1.0.24/src/fallback.rs:654:5 clippy::manual_range_contains "manual `RangeInclusive::contains` implementation"
-target/lintcheck/sources/proc-macro2-1.0.24/src/fallback.rs:655:12 clippy::manual_range_contains "manual `RangeInclusive::contains` implementation"
-target/lintcheck/sources/proc-macro2-1.0.24/src/fallback.rs:661:5 clippy::manual_range_contains "manual `RangeInclusive::contains` implementation"
-target/lintcheck/sources/proc-macro2-1.0.24/src/fallback.rs:662:12 clippy::manual_range_contains "manual `RangeInclusive::contains` implementation"
-target/lintcheck/sources/proc-macro2-1.0.24/src/fallback.rs:664:12 clippy::manual_range_contains "manual `RangeInclusive::contains` implementation"
-target/lintcheck/sources/proc-macro2-1.0.24/src/fallback.rs:674:37 clippy::manual_range_contains "manual `RangeInclusive::contains` implementation"
-target/lintcheck/sources/proc-macro2-1.0.24/src/fallback.rs:678:5 clippy::items_after_statements "adding items after statements is confusing, since items exist from the start of the scope"
-target/lintcheck/sources/proc-macro2-1.0.24/src/fallback.rs:85:9 clippy::items_after_statements "adding items after statements is confusing, since items exist from the start of the scope"
-target/lintcheck/sources/proc-macro2-1.0.24/src/fallback.rs:882:43 clippy::unused_self "unused `self` argument"
-target/lintcheck/sources/proc-macro2-1.0.24/src/lib.rs:1017:9 clippy::must_use_candidate "this method could have a `#[must_use]` attribute"
-target/lintcheck/sources/proc-macro2-1.0.24/src/lib.rs:1081:5 clippy::must_use_candidate "this method could have a `#[must_use]` attribute"
-target/lintcheck/sources/proc-macro2-1.0.24/src/lib.rs:1099:5 clippy::must_use_candidate "this method could have a `#[must_use]` attribute"
-target/lintcheck/sources/proc-macro2-1.0.24/src/lib.rs:1117:5 clippy::must_use_candidate "this method could have a `#[must_use]` attribute"
-target/lintcheck/sources/proc-macro2-1.0.24/src/lib.rs:1135:5 clippy::must_use_candidate "this method could have a `#[must_use]` attribute"
-target/lintcheck/sources/proc-macro2-1.0.24/src/lib.rs:1141:5 clippy::must_use_candidate "this method could have a `#[must_use]` attribute"
-target/lintcheck/sources/proc-macro2-1.0.24/src/lib.rs:1146:5 clippy::must_use_candidate "this method could have a `#[must_use]` attribute"
-target/lintcheck/sources/proc-macro2-1.0.24/src/lib.rs:1151:5 clippy::must_use_candidate "this method could have a `#[must_use]` attribute"
-target/lintcheck/sources/proc-macro2-1.0.24/src/lib.rs:1156:5 clippy::must_use_candidate "this method could have a `#[must_use]` attribute"
-target/lintcheck/sources/proc-macro2-1.0.24/src/lib.rs:152:5 clippy::must_use_candidate "this method could have a `#[must_use]` attribute"
-target/lintcheck/sources/proc-macro2-1.0.24/src/lib.rs:157:5 clippy::must_use_candidate "this method could have a `#[must_use]` attribute"
-target/lintcheck/sources/proc-macro2-1.0.24/src/lib.rs:373:5 clippy::must_use_candidate "this method could have a `#[must_use]` attribute"
-target/lintcheck/sources/proc-macro2-1.0.24/src/lib.rs:383:5 clippy::must_use_candidate "this method could have a `#[must_use]` attribute"
-target/lintcheck/sources/proc-macro2-1.0.24/src/lib.rs:397:24 clippy::trivially_copy_pass_by_ref "this argument (4 byte) is passed by reference, but would be more efficient if passed by value (limit: 8 byte)"
-target/lintcheck/sources/proc-macro2-1.0.24/src/lib.rs:397:5 clippy::must_use_candidate "this method could have a `#[must_use]` attribute"
-target/lintcheck/sources/proc-macro2-1.0.24/src/lib.rs:403:23 clippy::trivially_copy_pass_by_ref "this argument (4 byte) is passed by reference, but would be more efficient if passed by value (limit: 8 byte)"
-target/lintcheck/sources/proc-macro2-1.0.24/src/lib.rs:403:5 clippy::must_use_candidate "this method could have a `#[must_use]` attribute"
-target/lintcheck/sources/proc-macro2-1.0.24/src/lib.rs:418:5 clippy::must_use_candidate "this method could have a `#[must_use]` attribute"
-target/lintcheck/sources/proc-macro2-1.0.24/src/lib.rs:425:5 clippy::must_use_candidate "this method could have a `#[must_use]` attribute"
-target/lintcheck/sources/proc-macro2-1.0.24/src/lib.rs:464:17 clippy::trivially_copy_pass_by_ref "this argument (4 byte) is passed by reference, but would be more efficient if passed by value (limit: 8 byte)"
-target/lintcheck/sources/proc-macro2-1.0.24/src/lib.rs:500:5 clippy::must_use_candidate "this method could have a `#[must_use]` attribute"
-target/lintcheck/sources/proc-macro2-1.0.24/src/lib.rs:626:5 clippy::must_use_candidate "this method could have a `#[must_use]` attribute"
-target/lintcheck/sources/proc-macro2-1.0.24/src/lib.rs:633:5 clippy::must_use_candidate "this method could have a `#[must_use]` attribute"
-target/lintcheck/sources/proc-macro2-1.0.24/src/lib.rs:641:5 clippy::must_use_candidate "this method could have a `#[must_use]` attribute"
-target/lintcheck/sources/proc-macro2-1.0.24/src/lib.rs:652:5 clippy::must_use_candidate "this method could have a `#[must_use]` attribute"
-target/lintcheck/sources/proc-macro2-1.0.24/src/lib.rs:662:5 clippy::must_use_candidate "this method could have a `#[must_use]` attribute"
-target/lintcheck/sources/proc-macro2-1.0.24/src/lib.rs:672:5 clippy::must_use_candidate "this method could have a `#[must_use]` attribute"
-target/lintcheck/sources/proc-macro2-1.0.24/src/lib.rs:734:5 clippy::must_use_candidate "this method could have a `#[must_use]` attribute"
-target/lintcheck/sources/proc-macro2-1.0.24/src/lib.rs:743:5 clippy::must_use_candidate "this method could have a `#[must_use]` attribute"
-target/lintcheck/sources/proc-macro2-1.0.24/src/lib.rs:752:5 clippy::must_use_candidate "this method could have a `#[must_use]` attribute"
-target/lintcheck/sources/proc-macro2-1.0.24/src/lib.rs:757:5 clippy::must_use_candidate "this method could have a `#[must_use]` attribute"
-target/lintcheck/sources/proc-macro2-1.0.24/src/lib.rs:788:19 clippy::doc_markdown "you should put `XID_Start` between ticks in the documentation"
-target/lintcheck/sources/proc-macro2-1.0.24/src/lib.rs:788:69 clippy::doc_markdown "you should put `XID_Continue` between ticks in the documentation"
-target/lintcheck/sources/proc-macro2-1.0.24/src/lib.rs:891:36 clippy::doc_markdown "you should put `syn::parse_str` between ticks in the documentation"
-target/lintcheck/sources/proc-macro2-1.0.24/src/lib.rs:894:5 clippy::must_use_candidate "this method could have a `#[must_use]` attribute"
-target/lintcheck/sources/proc-macro2-1.0.24/src/lib.rs:911:5 clippy::must_use_candidate "this method could have a `#[must_use]` attribute"
-target/lintcheck/sources/proc-macro2-1.0.24/src/lib.rs:996:9 clippy::must_use_candidate "this method could have a `#[must_use]` attribute"
-target/lintcheck/sources/proc-macro2-1.0.24/src/parse.rs:353:17 clippy::unnested_or_patterns "unnested or-patterns"
-target/lintcheck/sources/proc-macro2-1.0.24/src/parse.rs:360:17 clippy::unnested_or_patterns "unnested or-patterns"
-target/lintcheck/sources/proc-macro2-1.0.24/src/parse.rs:411:17 clippy::unnested_or_patterns "unnested or-patterns"
-target/lintcheck/sources/proc-macro2-1.0.24/src/parse.rs:413:17 clippy::unnested_or_patterns "unnested or-patterns"
-target/lintcheck/sources/proc-macro2-1.0.24/src/parse.rs:476:13 clippy::unnested_or_patterns "unnested or-patterns"
-target/lintcheck/sources/proc-macro2-1.0.24/src/parse.rs:500:13 clippy::unnested_or_patterns "unnested or-patterns"
-target/lintcheck/sources/proc-macro2-1.0.24/src/parse.rs:552:5 clippy::while_let_on_iterator "this loop could be written as a `for` loop"
-target/lintcheck/sources/proc-macro2-1.0.24/src/parse.rs:584:21 clippy::manual_range_contains "manual `RangeInclusive::contains` implementation"
-target/lintcheck/sources/proc-macro2-1.0.24/src/parse.rs:602:20 clippy::map_unwrap_or "called `map(<f>).unwrap_or(<a>)` on an `Option` value. This can be done more directly by calling `map_or(<a>, <f>)` instead"
-target/lintcheck/sources/proc-macro2-1.0.24/src/parse.rs:696:29 clippy::cast_lossless "casting `u8` to `u64` may become silently lossy if you later change the type"
-target/lintcheck/sources/proc-macro2-1.0.24/src/parse.rs:702:34 clippy::cast_lossless "casting `u8` to `u64` may become silently lossy if you later change the type"
-target/lintcheck/sources/proc-macro2-1.0.24/src/parse.rs:708:34 clippy::cast_lossless "casting `u8` to `u64` may become silently lossy if you later change the type"
-target/lintcheck/sources/proc-macro2-1.0.24/src/parse.rs:793:5 clippy::vec_init_then_push "calls to `push` immediately after creation"
-target/lintcheck/sources/proc-macro2-1.0.24/src/parse.rs:803:15 clippy::explicit_iter_loop "it is more concise to loop over references to containers instead of using explicit iteration methods"
-target/lintcheck/sources/proc-macro2-1.0.24/src/parse.rs:808:15 clippy::explicit_iter_loop "it is more concise to loop over references to containers instead of using explicit iteration methods"
-target/lintcheck/sources/proc-macro2-1.0.24/src/wrapper.rs:415:24 clippy::trivially_copy_pass_by_ref "this argument (4 byte) is passed by reference, but would be more efficient if passed by value (limit: 8 byte)"
-target/lintcheck/sources/proc-macro2-1.0.24/src/wrapper.rs:429:23 clippy::trivially_copy_pass_by_ref "this argument (4 byte) is passed by reference, but would be more efficient if passed by value (limit: 8 byte)"
-target/lintcheck/sources/proc-macro2-1.0.24/src/wrapper.rs:492:17 clippy::trivially_copy_pass_by_ref "this argument (4 byte) is passed by reference, but would be more efficient if passed by value (limit: 8 byte)"
-target/lintcheck/sources/puffin-02dd4a3/puffin-imgui/src/ui.rs:158:15 clippy::cast_precision_loss "casting `i64` to `f32` causes a loss of precision (`i64` is 64 bits wide, but `f32`'s mantissa is only 23 bits wide)"
-target/lintcheck/sources/puffin-02dd4a3/puffin-imgui/src/ui.rs:175:5 clippy::must_use_candidate "this method could have a `#[must_use]` attribute"
-target/lintcheck/sources/puffin-02dd4a3/puffin-imgui/src/ui.rs:183:5 clippy::too_many_lines "this function has too many lines (115/100)"
-target/lintcheck/sources/puffin-02dd4a3/puffin-imgui/src/ui.rs:1:5 clippy::wildcard_imports "usage of wildcard import"
-target/lintcheck/sources/puffin-02dd4a3/puffin-imgui/src/ui.rs:207:16 clippy::collapsible_else_if "this `else { if .. }` block can be collapsed"
-target/lintcheck/sources/puffin-02dd4a3/puffin-imgui/src/ui.rs:271:67 clippy::cast_precision_loss "casting `i64` to `f32` causes a loss of precision (`i64` is 64 bits wide, but `f32`'s mantissa is only 23 bits wide)"
-target/lintcheck/sources/puffin-02dd4a3/puffin-imgui/src/ui.rs:2:5 clippy::wildcard_imports "usage of wildcard import"
-target/lintcheck/sources/puffin-02dd4a3/puffin-imgui/src/ui.rs:376:29 clippy::cast_precision_loss "casting `i64` to `f32` causes a loss of precision (`i64` is 64 bits wide, but `f32`'s mantissa is only 23 bits wide)"
-target/lintcheck/sources/puffin-02dd4a3/puffin-imgui/src/ui.rs:381:44 clippy::cast_precision_loss "casting `i64` to `f32` causes a loss of precision (`i64` is 64 bits wide, but `f32`'s mantissa is only 23 bits wide)"
-target/lintcheck/sources/puffin-02dd4a3/puffin-imgui/src/ui.rs:453:9 clippy::similar_names "binding's name is too similar to existing binding"
-target/lintcheck/sources/puffin-02dd4a3/puffin-imgui/src/ui.rs:540:14 clippy::cast_possible_truncation "casting `f64` to `f32` may truncate the value"
-target/lintcheck/sources/puffin-02dd4a3/puffin-imgui/src/ui.rs:551:5 clippy::cast_precision_loss "casting `i64` to `f64` causes a loss of precision (`i64` is 64 bits wide, but `f64`'s mantissa is only 52 bits wide)"
-target/lintcheck/sources/puffin-02dd4a3/puffin-imgui/src/ui.rs:584:39 clippy::cast_precision_loss "casting `usize` to `f32` causes a loss of precision (`usize` is 32 or 64 bits wide, but `f32`'s mantissa is only 23 bits wide)"
-target/lintcheck/sources/puffin-02dd4a3/puffin-imgui/src/ui.rs:59:26 clippy::unsafe_derive_deserialize "you are deriving `serde::Deserialize` on a type that has methods using `unsafe`"
-target/lintcheck/sources/puffin-02dd4a3/puffin-imgui/src/ui.rs:61:1 clippy::module_name_repetitions "item name ends with its containing module's name"
-target/lintcheck/sources/puffin-02dd4a3/puffin-imgui/src/ui.rs:627:39 clippy::cast_precision_loss "casting `usize` to `f32` causes a loss of precision (`usize` is 32 or 64 bits wide, but `f32`'s mantissa is only 23 bits wide)"
-target/lintcheck/sources/puffin-02dd4a3/puffin-imgui/src/ui.rs:674:47 clippy::cast_precision_loss "casting `usize` to `f64` causes a loss of precision on targets with 64-bit wide pointers (`usize` is 64 bits wide, but `f64`'s mantissa is only 52 bits wide)"
-target/lintcheck/sources/puffin-02dd4a3/puffin-imgui/src/ui.rs:690:9 clippy::cast_precision_loss "casting `usize` to `f32` causes a loss of precision (`usize` is 32 or 64 bits wide, but `f32`'s mantissa is only 23 bits wide)"
-target/lintcheck/sources/puffin-02dd4a3/puffin/src/data.rs:102:25 clippy::cast_possible_truncation "casting `usize` to `u8` may truncate the value"
-target/lintcheck/sources/puffin-02dd4a3/puffin/src/data.rs:112:5 clippy::must_use_candidate "this method could have a `#[must_use]` attribute"
-target/lintcheck/sources/puffin-02dd4a3/puffin/src/data.rs:116:5 clippy::missing_errors_doc "docs for function returning `Result` missing `# Errors` section"
-target/lintcheck/sources/puffin-02dd4a3/puffin/src/data.rs:137:24 clippy::match_same_arms "this `match` has identical arm bodies"
-target/lintcheck/sources/puffin-02dd4a3/puffin/src/data.rs:177:5 clippy::missing_errors_doc "docs for function returning `Result` missing `# Errors` section"
-target/lintcheck/sources/puffin-02dd4a3/puffin/src/data.rs:211:21 clippy::cast_possible_truncation "casting `u64` to `usize` may truncate the value on targets with 32-bit wide pointers"
-target/lintcheck/sources/puffin-02dd4a3/puffin/src/data.rs:24:5 clippy::wildcard_imports "usage of wildcard import"
-target/lintcheck/sources/puffin-02dd4a3/puffin/src/lib.rs:113:5 clippy::must_use_candidate "this method could have a `#[must_use]` attribute"
-target/lintcheck/sources/puffin-02dd4a3/puffin/src/lib.rs:147:5 clippy::missing_errors_doc "docs for function returning `Result` missing `# Errors` section"
-target/lintcheck/sources/puffin-02dd4a3/puffin/src/lib.rs:147:5 clippy::missing_panics_doc "docs for function which may panic missing `# Panics` section"
-target/lintcheck/sources/puffin-02dd4a3/puffin/src/lib.rs:165:5 clippy::missing_errors_doc "docs for function returning `Result` missing `# Errors` section"
-target/lintcheck/sources/puffin-02dd4a3/puffin/src/lib.rs:200:21 clippy::default_trait_access "calling `Stream::default()` is more clear than this expression"
-target/lintcheck/sources/puffin-02dd4a3/puffin/src/lib.rs:257:78 clippy::default_trait_access "calling `std::cell::RefCell::default()` is more clear than this expression"
-target/lintcheck/sources/puffin-02dd4a3/puffin/src/lib.rs:297:5 clippy::must_use_candidate "this method could have a `#[must_use]` attribute"
-target/lintcheck/sources/puffin-02dd4a3/puffin/src/lib.rs:302:5 clippy::must_use_candidate "this method could have a `#[must_use]` attribute"
-target/lintcheck/sources/puffin-02dd4a3/puffin/src/lib.rs:308:28 clippy::default_trait_access "calling `FullProfileData::default()` is more clear than this expression"
-target/lintcheck/sources/puffin-02dd4a3/puffin/src/lib.rs:316:1 clippy::must_use_candidate "this function could have a `#[must_use]` attribute"
-target/lintcheck/sources/puffin-02dd4a3/puffin/src/lib.rs:321:5 clippy::cast_possible_truncation "casting `u128` to `i64` may truncate the value"
-target/lintcheck/sources/puffin-02dd4a3/puffin/src/lib.rs:348:28 clippy::default_trait_access "calling `std::marker::PhantomData::default()` is more clear than this expression"
-target/lintcheck/sources/puffin-02dd4a3/puffin/src/lib.rs:359:1 clippy::must_use_candidate "this function could have a `#[must_use]` attribute"
-target/lintcheck/sources/puffin-02dd4a3/puffin/src/lib.rs:375:1 clippy::must_use_candidate "this function could have a `#[must_use]` attribute"
-target/lintcheck/sources/puffin-02dd4a3/puffin/src/lib.rs:376:5 clippy::option_if_let_else "use Option::map_or instead of an if let/else"
-target/lintcheck/sources/puffin-02dd4a3/puffin/src/lib.rs:377:9 clippy::option_if_let_else "use Option::map_or instead of an if let/else"
-target/lintcheck/sources/puffin-02dd4a3/puffin/src/lib.rs:406:1 clippy::must_use_candidate "this function could have a `#[must_use]` attribute"
-target/lintcheck/sources/puffin-02dd4a3/puffin/src/lib.rs:408:5 clippy::option_if_let_else "use Option::map_or instead of an if let/else"
-target/lintcheck/sources/puffin-02dd4a3/puffin/src/lib.rs:69:5 clippy::must_use_candidate "this method could have a `#[must_use]` attribute"
-target/lintcheck/sources/puffin-02dd4a3/puffin/src/lib.rs:73:5 clippy::must_use_candidate "this method could have a `#[must_use]` attribute"
-target/lintcheck/sources/puffin-02dd4a3/puffin/src/lib.rs:77:5 clippy::must_use_candidate "this method could have a `#[must_use]` attribute"
-target/lintcheck/sources/puffin-02dd4a3/puffin/src/merge.rs:21:1 clippy::module_name_repetitions "item name starts with its containing module's name"
-target/lintcheck/sources/puffin-02dd4a3/puffin/src/merge.rs:28:1 clippy::module_name_repetitions "item name starts with its containing module's name"
-target/lintcheck/sources/puffin-02dd4a3/puffin/src/merge.rs:28:1 clippy::must_use_candidate "this function could have a `#[must_use]` attribute"
-target/lintcheck/sources/puffin-02dd4a3/puffin/src/merge.rs:35:1 clippy::missing_errors_doc "docs for function returning `Result` missing `# Errors` section"
-target/lintcheck/sources/puffin-02dd4a3/puffin/src/merge.rs:35:1 clippy::module_name_repetitions "item name starts with its containing module's name"
-target/lintcheck/sources/puffin-02dd4a3/puffin/src/merge.rs:64:43 clippy::default_trait_access "calling `std::vec::Vec::default()` is more clear than this expression"
-target/lintcheck/sources/puffin-02dd4a3/puffin/src/merge.rs:65:54 clippy::default_trait_access "calling `std::collections::HashMap::default()` is more clear than this expression"
-target/lintcheck/sources/puffin-02dd4a3/puffin/src/merge.rs:9:1 clippy::module_name_repetitions "item name starts with its containing module's name"
-target/lintcheck/sources/quote-1.0.7/src/ext.rs:10:1 clippy::module_name_repetitions "item name ends with its containing module's name"
-target/lintcheck/sources/quote-1.0.7/src/ext.rs:7:5 clippy::doc_markdown "you should put `TokenStream` between ticks in the documentation"
-target/lintcheck/sources/quote-1.0.7/src/ident_fragment.rs:13:5 clippy::missing_errors_doc "docs for function returning `Result` missing `# Errors` section"
-target/lintcheck/sources/quote-1.0.7/src/ident_fragment.rs:51:31 clippy::manual_strip "stripping a prefix manually"
-target/lintcheck/sources/quote-1.0.7/src/runtime.rs:52:5 clippy::module_name_repetitions "item name ends with its containing module's name"
-target/lintcheck/sources/quote-1.0.7/src/runtime.rs:63:5 clippy::module_name_repetitions "item name ends with its containing module's name"
-target/lintcheck/sources/quote-1.0.7/src/runtime.rs:66:33 clippy::doc_markdown "you should put `DoesNotHaveIter` between ticks in the documentation"
-target/lintcheck/sources/quote-1.0.7/src/runtime.rs:80:5 clippy::module_name_repetitions "item name ends with its containing module's name"
-target/lintcheck/sources/quote-1.0.7/src/to_tokens.rs:132:26 clippy::wrong_self_convention "methods with the following characteristics: (`to_*` and `self` type is `Copy`) usually take `self` by value"
-target/lintcheck/sources/quote-1.0.7/src/to_tokens.rs:159:18 clippy::wrong_self_convention "methods with the following characteristics: (`to_*` and `self` type is `Copy`) usually take `self` by value"
-target/lintcheck/sources/quote-1.0.7/src/to_tokens.rs:165:18 clippy::wrong_self_convention "methods with the following characteristics: (`to_*` and `self` type is `Copy`) usually take `self` by value"
-target/lintcheck/sources/quote-1.0.7/src/to_tokens.rs:80:18 clippy::wrong_self_convention "methods with the following characteristics: (`to_*` and `self` type is `Copy`) usually take `self` by value"
-target/lintcheck/sources/rand-0.7.3/src/distributions/bernoulli.rs:103:20 clippy::cast_possible_truncation "casting `f64` to `u64` may truncate the value"
-target/lintcheck/sources/rand-0.7.3/src/distributions/bernoulli.rs:103:20 clippy::cast_sign_loss "casting `f64` to `u64` may lose the sign of the value"
-target/lintcheck/sources/rand-0.7.3/src/distributions/bernoulli.rs:116:5 clippy::missing_errors_doc "docs for function returning `Result` missing `# Errors` section"
-target/lintcheck/sources/rand-0.7.3/src/distributions/bernoulli.rs:123:21 clippy::cast_possible_truncation "casting `f64` to `u64` may truncate the value"
-target/lintcheck/sources/rand-0.7.3/src/distributions/bernoulli.rs:123:21 clippy::cast_sign_loss "casting `f64` to `u64` may lose the sign of the value"
-target/lintcheck/sources/rand-0.7.3/src/distributions/bernoulli.rs:63:26 clippy::cast_precision_loss "casting `u64` to `f64` causes a loss of precision (`u64` is 64 bits wide, but `f64`'s mantissa is only 52 bits wide)"
-target/lintcheck/sources/rand-0.7.3/src/distributions/bernoulli.rs:63:27 clippy::unseparated_literal_suffix "integer type suffix should be separated by an underscore"
-target/lintcheck/sources/rand-0.7.3/src/distributions/bernoulli.rs:67:1 clippy::module_name_repetitions "item name starts with its containing module's name"
-target/lintcheck/sources/rand-0.7.3/src/distributions/bernoulli.rs:95:5 clippy::missing_errors_doc "docs for function returning `Result` missing `# Errors` section"
-target/lintcheck/sources/rand-0.7.3/src/distributions/bernoulli.rs:96:13 clippy::manual_range_contains "manual `Range::contains` implementation"
-target/lintcheck/sources/rand-0.7.3/src/distributions/binomial.rs:107:23 clippy::cast_precision_loss "casting `i64` to `f64` causes a loss of precision (`i64` is 64 bits wide, but `f64`'s mantissa is only 52 bits wide)"
-target/lintcheck/sources/rand-0.7.3/src/distributions/binomial.rs:112:44 clippy::cast_precision_loss "casting `i64` to `f64` causes a loss of precision (`i64` is 64 bits wide, but `f64`'s mantissa is only 52 bits wide)"
-target/lintcheck/sources/rand-0.7.3/src/distributions/binomial.rs:116:13 clippy::items_after_statements "adding items after statements is confusing, since items exist from the start of the scope"
-target/lintcheck/sources/rand-0.7.3/src/distributions/binomial.rs:150:28 clippy::redundant_else "redundant else block"
-target/lintcheck/sources/rand-0.7.3/src/distributions/binomial.rs:153:24 clippy::if_not_else "unnecessary boolean `not` operation"
-target/lintcheck/sources/rand-0.7.3/src/distributions/binomial.rs:158:28 clippy::redundant_else "redundant else block"
-target/lintcheck/sources/rand-0.7.3/src/distributions/binomial.rs:164:33 clippy::cast_sign_loss "casting `i64` to `u64` may lose the sign of the value"
-target/lintcheck/sources/rand-0.7.3/src/distributions/binomial.rs:166:28 clippy::redundant_else "redundant else block"
-target/lintcheck/sources/rand-0.7.3/src/distributions/binomial.rs:175:47 clippy::cast_precision_loss "casting `i64` to `f64` causes a loss of precision (`i64` is 64 bits wide, but `f64`'s mantissa is only 52 bits wide)"
-target/lintcheck/sources/rand-0.7.3/src/distributions/binomial.rs:185:38 clippy::cast_precision_loss "casting `i64` to `f64` causes a loss of precision (`i64` is 64 bits wide, but `f64`'s mantissa is only 52 bits wide)"
-target/lintcheck/sources/rand-0.7.3/src/distributions/binomial.rs:194:38 clippy::cast_precision_loss "casting `i64` to `f64` causes a loss of precision (`i64` is 64 bits wide, but `f64`'s mantissa is only 52 bits wide)"
-target/lintcheck/sources/rand-0.7.3/src/distributions/binomial.rs:202:28 clippy::redundant_else "redundant else block"
-target/lintcheck/sources/rand-0.7.3/src/distributions/binomial.rs:209:25 clippy::cast_precision_loss "casting `i64` to `f64` causes a loss of precision (`i64` is 64 bits wide, but `f64`'s mantissa is only 52 bits wide)"
-target/lintcheck/sources/rand-0.7.3/src/distributions/binomial.rs:221:26 clippy::cast_precision_loss "casting `i64` to `f64` causes a loss of precision (`i64` is 64 bits wide, but `f64`'s mantissa is only 52 bits wide)"
-target/lintcheck/sources/rand-0.7.3/src/distributions/binomial.rs:222:26 clippy::cast_precision_loss "casting `i64` to `f64` causes a loss of precision (`i64` is 64 bits wide, but `f64`'s mantissa is only 52 bits wide)"
-target/lintcheck/sources/rand-0.7.3/src/distributions/binomial.rs:223:25 clippy::cast_precision_loss "casting `i64` to `f64` causes a loss of precision (`i64` is 64 bits wide, but `f64`'s mantissa is only 52 bits wide)"
-target/lintcheck/sources/rand-0.7.3/src/distributions/binomial.rs:224:25 clippy::cast_precision_loss "casting `i64` to `f64` causes a loss of precision (`i64` is 64 bits wide, but `f64`'s mantissa is only 52 bits wide)"
-target/lintcheck/sources/rand-0.7.3/src/distributions/binomial.rs:226:17 clippy::items_after_statements "adding items after statements is confusing, since items exist from the start of the scope"
-target/lintcheck/sources/rand-0.7.3/src/distributions/binomial.rs:233:32 clippy::cast_precision_loss "casting `i64` to `f64` causes a loss of precision (`i64` is 64 bits wide, but `f64`'s mantissa is only 52 bits wide)"
-target/lintcheck/sources/rand-0.7.3/src/distributions/binomial.rs:234:27 clippy::cast_precision_loss "casting `i64` to `f64` causes a loss of precision (`i64` is 64 bits wide, but `f64`'s mantissa is only 52 bits wide)"
-target/lintcheck/sources/rand-0.7.3/src/distributions/binomial.rs:251:22 clippy::cast_sign_loss "casting `i64` to `u64` may lose the sign of the value"
-target/lintcheck/sources/rand-0.7.3/src/distributions/binomial.rs:255:9 clippy::if_not_else "unnecessary `!=` operation"
-target/lintcheck/sources/rand-0.7.3/src/distributions/binomial.rs:35:5 clippy::must_use_candidate "this method could have a `#[must_use]` attribute"
-target/lintcheck/sources/rand-0.7.3/src/distributions/binomial.rs:45:17 clippy::cast_precision_loss "casting `i64` to `f64` causes a loss of precision (`i64` is 64 bits wide, but `f64`'s mantissa is only 52 bits wide)"
-target/lintcheck/sources/rand-0.7.3/src/distributions/binomial.rs:46:5 clippy::cast_possible_truncation "casting `f64` to `i64` may truncate the value"
-target/lintcheck/sources/rand-0.7.3/src/distributions/binomial.rs:50:5 clippy::too_many_lines "this function has too many lines (143/100)"
-target/lintcheck/sources/rand-0.7.3/src/distributions/binomial.rs:76:9 clippy::items_after_statements "adding items after statements is confusing, since items exist from the start of the scope"
-target/lintcheck/sources/rand-0.7.3/src/distributions/binomial.rs:78:12 clippy::cast_precision_loss "casting `u64` to `f64` causes a loss of precision (`u64` is 64 bits wide, but `f64`'s mantissa is only 52 bits wide)"
-target/lintcheck/sources/rand-0.7.3/src/distributions/binomial.rs:81:21 clippy::cast_precision_loss "casting `u64` to `f64` causes a loss of precision (`u64` is 64 bits wide, but `f64`'s mantissa is only 52 bits wide)"
-target/lintcheck/sources/rand-0.7.3/src/distributions/binomial.rs:82:32 clippy::cast_possible_truncation "casting `u64` to `i32` may truncate the value"
-target/lintcheck/sources/rand-0.7.3/src/distributions/binomial.rs:88:26 clippy::cast_precision_loss "casting `u64` to `f64` causes a loss of precision (`u64` is 64 bits wide, but `f64`'s mantissa is only 52 bits wide)"
-target/lintcheck/sources/rand-0.7.3/src/distributions/binomial.rs:99:21 clippy::cast_precision_loss "casting `u64` to `f64` causes a loss of precision (`u64` is 64 bits wide, but `f64`'s mantissa is only 52 bits wide)"
-target/lintcheck/sources/rand-0.7.3/src/distributions/cauchy.rs:33:5 clippy::must_use_candidate "this method could have a `#[must_use]` attribute"
-target/lintcheck/sources/rand-0.7.3/src/distributions/dirichlet.rs:52:5 clippy::must_use_candidate "this method could have a `#[must_use]` attribute"
-target/lintcheck/sources/rand-0.7.3/src/distributions/dirichlet.rs:64:32 clippy::unseparated_literal_suffix "float type suffix should be separated by an underscore"
-target/lintcheck/sources/rand-0.7.3/src/distributions/dirichlet.rs:65:23 clippy::unseparated_literal_suffix "float type suffix should be separated by an underscore"
-target/lintcheck/sources/rand-0.7.3/src/distributions/exponential.rs:76:5 clippy::must_use_candidate "this method could have a `#[must_use]` attribute"
-target/lintcheck/sources/rand-0.7.3/src/distributions/float.rs:73:1 clippy::module_name_repetitions "item name ends with its containing module's name"
-target/lintcheck/sources/rand-0.7.3/src/distributions/gamma.rs:13:5 clippy::enum_glob_use "usage of wildcard import for enum variants"
-target/lintcheck/sources/rand-0.7.3/src/distributions/gamma.rs:14:5 clippy::enum_glob_use "usage of wildcard import for enum variants"
-target/lintcheck/sources/rand-0.7.3/src/distributions/gamma.rs:189:5 clippy::must_use_candidate "this method could have a `#[must_use]` attribute"
-target/lintcheck/sources/rand-0.7.3/src/distributions/gamma.rs:230:5 clippy::must_use_candidate "this method could have a `#[must_use]` attribute"
-target/lintcheck/sources/rand-0.7.3/src/distributions/gamma.rs:259:5 clippy::must_use_candidate "this method could have a `#[must_use]` attribute"
-target/lintcheck/sources/rand-0.7.3/src/distributions/gamma.rs:287:5 clippy::must_use_candidate "this method could have a `#[must_use]` attribute"
-target/lintcheck/sources/rand-0.7.3/src/distributions/gamma.rs:90:5 clippy::must_use_candidate "this method could have a `#[must_use]` attribute"
-target/lintcheck/sources/rand-0.7.3/src/distributions/integer.rs:23:9 clippy::cast_possible_truncation "casting `u32` to `u8` may truncate the value"
-target/lintcheck/sources/rand-0.7.3/src/distributions/integer.rs:30:9 clippy::cast_possible_truncation "casting `u32` to `u16` may truncate the value"
-target/lintcheck/sources/rand-0.7.3/src/distributions/integer.rs:69:9 clippy::cast_possible_truncation "casting `u64` to `usize` may truncate the value on targets with 32-bit wide pointers"
-target/lintcheck/sources/rand-0.7.3/src/distributions/mod.rs:263:5 clippy::inline_always "you have declared `#[inline(always)]` on `next`. This is usually a bad idea"
-target/lintcheck/sources/rand-0.7.3/src/distributions/normal.rs:100:5 clippy::must_use_candidate "this method could have a `#[must_use]` attribute"
-target/lintcheck/sources/rand-0.7.3/src/distributions/normal.rs:119:1 clippy::module_name_repetitions "item name ends with its containing module's name"
-target/lintcheck/sources/rand-0.7.3/src/distributions/normal.rs:131:5 clippy::must_use_candidate "this method could have a `#[must_use]` attribute"
-target/lintcheck/sources/rand-0.7.3/src/distributions/normal.rs:31:1 clippy::module_name_repetitions "item name ends with its containing module's name"
-target/lintcheck/sources/rand-0.7.3/src/distributions/normal.rs:47:25 clippy::unseparated_literal_suffix "float type suffix should be separated by an underscore"
-target/lintcheck/sources/rand-0.7.3/src/distributions/normal.rs:48:25 clippy::unseparated_literal_suffix "float type suffix should be separated by an underscore"
-target/lintcheck/sources/rand-0.7.3/src/distributions/other.rs:89:9 clippy::cast_possible_wrap "casting `u32` to `i32` may wrap around the value"
-target/lintcheck/sources/rand-0.7.3/src/distributions/pareto.rs:32:5 clippy::must_use_candidate "this method could have a `#[must_use]` attribute"
-target/lintcheck/sources/rand-0.7.3/src/distributions/poisson.rs:35:5 clippy::must_use_candidate "this method could have a `#[must_use]` attribute"
-target/lintcheck/sources/rand-0.7.3/src/distributions/poisson.rs:87:30 clippy::cast_possible_truncation "casting `f64` to `u64` may truncate the value"
-target/lintcheck/sources/rand-0.7.3/src/distributions/poisson.rs:87:30 clippy::cast_sign_loss "casting `f64` to `u64` may lose the sign of the value"
-target/lintcheck/sources/rand-0.7.3/src/distributions/triangular.rs:32:5 clippy::must_use_candidate "this method could have a `#[must_use]` attribute"
-target/lintcheck/sources/rand-0.7.3/src/distributions/uniform.rs:146:4 clippy::needless_doctest_main "needless `fn main` in doctest"
-target/lintcheck/sources/rand-0.7.3/src/distributions/uniform.rs:199:1 clippy::module_name_repetitions "item name ends with its containing module's name"
-target/lintcheck/sources/rand-0.7.3/src/distributions/uniform.rs:214:1 clippy::module_name_repetitions "item name starts with its containing module's name"
-target/lintcheck/sources/rand-0.7.3/src/distributions/uniform.rs:283:14 clippy::doc_markdown "you should put `SampleUniform` between ticks in the documentation"
-target/lintcheck/sources/rand-0.7.3/src/distributions/uniform.rs:283:46 clippy::doc_markdown "you should put `SampleUniform` between ticks in the documentation"
-target/lintcheck/sources/rand-0.7.3/src/distributions/uniform.rs:296:5 clippy::inline_always "you have declared `#[inline(always)]` on `borrow`. This is usually a bad idea"
-target/lintcheck/sources/rand-0.7.3/src/distributions/uniform.rs:304:5 clippy::inline_always "you have declared `#[inline(always)]` on `borrow`. This is usually a bad idea"
-target/lintcheck/sources/rand-0.7.3/src/distributions/uniform.rs:350:1 clippy::module_name_repetitions "item name starts with its containing module's name"
-target/lintcheck/sources/rand-0.7.3/src/distributions/uniform.rs:407:21 clippy::redundant_field_names "redundant field names in struct initialization"
-target/lintcheck/sources/rand-0.7.3/src/distributions/uniform.rs:407:21 clippy::redundant_field_names "redundant field names in struct initialization"
-target/lintcheck/sources/rand-0.7.3/src/distributions/uniform.rs:407:21 clippy::redundant_field_names "redundant field names in struct initialization"
-target/lintcheck/sources/rand-0.7.3/src/distributions/uniform.rs:407:21 clippy::redundant_field_names "redundant field names in struct initialization"
-target/lintcheck/sources/rand-0.7.3/src/distributions/uniform.rs:407:21 clippy::redundant_field_names "redundant field names in struct initialization"
-target/lintcheck/sources/rand-0.7.3/src/distributions/uniform.rs:407:21 clippy::redundant_field_names "redundant field names in struct initialization"
-target/lintcheck/sources/rand-0.7.3/src/distributions/uniform.rs:407:21 clippy::redundant_field_names "redundant field names in struct initialization"
-target/lintcheck/sources/rand-0.7.3/src/distributions/uniform.rs:407:21 clippy::redundant_field_names "redundant field names in struct initialization"
-target/lintcheck/sources/rand-0.7.3/src/distributions/uniform.rs:407:21 clippy::redundant_field_names "redundant field names in struct initialization"
-target/lintcheck/sources/rand-0.7.3/src/distributions/uniform.rs:407:21 clippy::redundant_field_names "redundant field names in struct initialization"
-target/lintcheck/sources/rand-0.7.3/src/distributions/uniform.rs:407:21 clippy::redundant_field_names "redundant field names in struct initialization"
-target/lintcheck/sources/rand-0.7.3/src/distributions/uniform.rs:407:21 clippy::redundant_field_names "redundant field names in struct initialization"
-target/lintcheck/sources/rand-0.7.3/src/distributions/uniform.rs:441:31 clippy::invalid_upcast_comparisons "because of the numeric bounds on `::core::u16::MAX` prior to casting, this expression is always false"
-target/lintcheck/sources/rand-0.7.3/src/distributions/uniform.rs:441:31 clippy::invalid_upcast_comparisons "because of the numeric bounds on `::core::u16::MAX` prior to casting, this expression is always false"
-target/lintcheck/sources/rand-0.7.3/src/distributions/uniform.rs:441:31 clippy::invalid_upcast_comparisons "because of the numeric bounds on `::core::u16::MAX` prior to casting, this expression is always false"
-target/lintcheck/sources/rand-0.7.3/src/distributions/uniform.rs:441:31 clippy::invalid_upcast_comparisons "because of the numeric bounds on `::core::u16::MAX` prior to casting, this expression is always false"
-target/lintcheck/sources/rand-0.7.3/src/distributions/uniform.rs:441:31 clippy::invalid_upcast_comparisons "because of the numeric bounds on `::core::u16::MAX` prior to casting, this expression is always false"
-target/lintcheck/sources/rand-0.7.3/src/distributions/uniform.rs:441:31 clippy::invalid_upcast_comparisons "because of the numeric bounds on `::core::u16::MAX` prior to casting, this expression is always false"
-target/lintcheck/sources/rand-0.7.3/src/distributions/uniform.rs:441:31 clippy::invalid_upcast_comparisons "because of the numeric bounds on `::core::u16::MAX` prior to casting, this expression is always false"
-target/lintcheck/sources/rand-0.7.3/src/distributions/uniform.rs:441:31 clippy::invalid_upcast_comparisons "because of the numeric bounds on `::core::u16::MAX` prior to casting, this expression is always false"
-target/lintcheck/sources/rand-0.7.3/src/distributions/uniform.rs:56:10 clippy::doc_markdown "you should put `SampleBorrow` between ticks in the documentation"
-target/lintcheck/sources/rand-0.7.3/src/distributions/uniform.rs:647:1 clippy::module_name_repetitions "item name starts with its containing module's name"
-target/lintcheck/sources/rand-0.7.3/src/distributions/uniform.rs:840:1 clippy::module_name_repetitions "item name starts with its containing module's name"
-target/lintcheck/sources/rand-0.7.3/src/distributions/uniform.rs:913:13 clippy::option_if_let_else "use Option::map_or_else instead of an if let/else"
-target/lintcheck/sources/rand-0.7.3/src/distributions/uniform.rs:943:54 clippy::cast_possible_truncation "casting `u64` to `u32` may truncate the value"
-target/lintcheck/sources/rand-0.7.3/src/distributions/unit_circle.rs:30:5 clippy::must_use_candidate "this method could have a `#[must_use]` attribute"
-target/lintcheck/sources/rand-0.7.3/src/distributions/unit_sphere.rs:24:1 clippy::module_name_repetitions "item name starts with its containing module's name"
-target/lintcheck/sources/rand-0.7.3/src/distributions/unit_sphere.rs:29:5 clippy::must_use_candidate "this method could have a `#[must_use]` attribute"
-target/lintcheck/sources/rand-0.7.3/src/distributions/utils.rs:247:15 clippy::wrong_self_convention "methods called `is_*` usually take `self` by reference or no `self`"
-target/lintcheck/sources/rand-0.7.3/src/distributions/utils.rs:248:20 clippy::wrong_self_convention "methods called `is_*` usually take `self` by reference or no `self`"
-target/lintcheck/sources/rand-0.7.3/src/distributions/utils.rs:249:18 clippy::wrong_self_convention "methods called `is_*` usually take `self` by reference or no `self`"
-target/lintcheck/sources/rand-0.7.3/src/distributions/utils.rs:254:5 clippy::inline_always "you have declared `#[inline(always)]` on `lanes`. This is usually a bad idea"
-target/lintcheck/sources/rand-0.7.3/src/distributions/utils.rs:258:5 clippy::inline_always "you have declared `#[inline(always)]` on `splat`. This is usually a bad idea"
-target/lintcheck/sources/rand-0.7.3/src/distributions/utils.rs:262:5 clippy::inline_always "you have declared `#[inline(always)]` on `extract`. This is usually a bad idea"
-target/lintcheck/sources/rand-0.7.3/src/distributions/utils.rs:267:5 clippy::inline_always "you have declared `#[inline(always)]` on `replace`. This is usually a bad idea"
-target/lintcheck/sources/rand-0.7.3/src/distributions/utils.rs:281:5 clippy::inline_always "you have declared `#[inline(always)]` on `any`. This is usually a bad idea"
-target/lintcheck/sources/rand-0.7.3/src/distributions/utils.rs:286:5 clippy::inline_always "you have declared `#[inline(always)]` on `all`. This is usually a bad idea"
-target/lintcheck/sources/rand-0.7.3/src/distributions/utils.rs:291:5 clippy::inline_always "you have declared `#[inline(always)]` on `none`. This is usually a bad idea"
-target/lintcheck/sources/rand-0.7.3/src/distributions/utils.rs:488:17 clippy::doc_markdown "you should put `x_i` between ticks in the documentation"
-target/lintcheck/sources/rand-0.7.3/src/distributions/utils.rs:489:50 clippy::doc_markdown "you should put `x_i` between ticks in the documentation"
-target/lintcheck/sources/rand-0.7.3/src/distributions/utils.rs:489:63 clippy::doc_markdown "you should put `f(x_i` between ticks in the documentation"
-target/lintcheck/sources/rand-0.7.3/src/distributions/utils.rs:490:40 clippy::doc_markdown "you should put `f(x_i` between ticks in the documentation"
-target/lintcheck/sources/rand-0.7.3/src/distributions/utils.rs:490:49 clippy::doc_markdown "you should put `f(x_{i+1` between ticks in the documentation"
-target/lintcheck/sources/rand-0.7.3/src/distributions/utils.rs:518:17 clippy::cast_possible_truncation "casting `u64` to `usize` may truncate the value on targets with 32-bit wide pointers"
-target/lintcheck/sources/rand-0.7.3/src/distributions/weibull.rs:29:5 clippy::must_use_candidate "this method could have a `#[must_use]` attribute"
-target/lintcheck/sources/rand-0.7.3/src/distributions/weighted/alias_method.rs:113:21 clippy::explicit_iter_loop "it is more concise to loop over references to containers instead of using explicit iteration methods"
-target/lintcheck/sources/rand-0.7.3/src/distributions/weighted/alias_method.rs:125:9 clippy::items_after_statements "adding items after statements is confusing, since items exist from the start of the scope"
-target/lintcheck/sources/rand-0.7.3/src/distributions/weighted/alias_method.rs:131:9 clippy::items_after_statements "adding items after statements is confusing, since items exist from the start of the scope"
-target/lintcheck/sources/rand-0.7.3/src/distributions/weighted/alias_method.rs:180:36 clippy::cast_possible_truncation "casting `usize` to `u32` may truncate the value on targets with 64-bit wide pointers"
-target/lintcheck/sources/rand-0.7.3/src/distributions/weighted/alias_method.rs:182:34 clippy::cast_possible_truncation "casting `usize` to `u32` may truncate the value on targets with 64-bit wide pointers"
-target/lintcheck/sources/rand-0.7.3/src/distributions/weighted/alias_method.rs:259:28 clippy::clone_on_copy "using `clone` on type `distributions::uniform::Uniform<u32>` which implements the `Copy` trait"
-target/lintcheck/sources/rand-0.7.3/src/distributions/weighted/alias_method.rs:296:9 clippy::map_clone "you are using an explicit closure for copying elements"
-target/lintcheck/sources/rand-0.7.3/src/distributions/weighted/alias_method.rs:321:9 clippy::map_clone "you are using an explicit closure for copying elements"
-target/lintcheck/sources/rand-0.7.3/src/distributions/weighted/alias_method.rs:78:5 clippy::missing_errors_doc "docs for function returning `Result` missing `# Errors` section"
-target/lintcheck/sources/rand-0.7.3/src/distributions/weighted/alias_method.rs:78:5 clippy::missing_panics_doc "docs for function which may panic missing `# Panics` section"
-target/lintcheck/sources/rand-0.7.3/src/distributions/weighted/alias_method.rs:78:5 clippy::too_many_lines "this function has too many lines (106/100)"
-target/lintcheck/sources/rand-0.7.3/src/distributions/weighted/alias_method.rs:85:17 clippy::cast_possible_truncation "casting `usize` to `u32` may truncate the value on targets with 64-bit wide pointers"
-target/lintcheck/sources/rand-0.7.3/src/distributions/weighted/alias_method.rs:87:31 clippy::map_unwrap_or "called `map(<f>).unwrap_or(<a>)` on an `Option` value. This can be done more directly by calling `map_or(<a>, <f>)` instead"
-target/lintcheck/sources/rand-0.7.3/src/distributions/weighted/mod.rs:100:5 clippy::missing_errors_doc "docs for function returning `Result` missing `# Errors` section"
-target/lintcheck/sources/rand-0.7.3/src/distributions/weighted/mod.rs:144:5 clippy::missing_errors_doc "docs for function returning `Result` missing `# Errors` section"
-target/lintcheck/sources/rand-0.7.3/src/distributions/weighted/mod.rs:144:5 clippy::missing_panics_doc "docs for function which may panic missing `# Panics` section"
-target/lintcheck/sources/rand-0.7.3/src/distributions/weighted/mod.rs:169:16 clippy::int_plus_one "unnecessary `>= y + 1` or `x - 1 >=`"
-target/lintcheck/sources/rand-0.7.3/src/distributions/weighted/mod.rs:386:1 clippy::module_name_repetitions "item name starts with its containing module's name"
-target/lintcheck/sources/rand-0.7.3/src/distributions/weighted/mod.rs:85:1 clippy::module_name_repetitions "item name starts with its containing module's name"
-target/lintcheck/sources/rand-0.7.3/src/lib.rs:333:5 clippy::missing_errors_doc "docs for function returning `Result` missing `# Errors` section"
-target/lintcheck/sources/rand-0.7.3/src/lib.rs:412:14 clippy::wrong_self_convention "methods with the following characteristics: (`to_*` and `self` type is not `Copy`) usually take `self` by reference"
-target/lintcheck/sources/rand-0.7.3/src/lib.rs:435:22 clippy::wrong_self_convention "methods with the following characteristics: (`to_*` and `self` type is not `Copy`) usually take `self` by reference"
-target/lintcheck/sources/rand-0.7.3/src/lib.rs:435:22 clippy::wrong_self_convention "methods with the following characteristics: (`to_*` and `self` type is not `Copy`) usually take `self` by reference"
-target/lintcheck/sources/rand-0.7.3/src/lib.rs:435:22 clippy::wrong_self_convention "methods with the following characteristics: (`to_*` and `self` type is not `Copy`) usually take `self` by reference"
-target/lintcheck/sources/rand-0.7.3/src/lib.rs:435:22 clippy::wrong_self_convention "methods with the following characteristics: (`to_*` and `self` type is not `Copy`) usually take `self` by reference"
-target/lintcheck/sources/rand-0.7.3/src/lib.rs:435:22 clippy::wrong_self_convention "methods with the following characteristics: (`to_*` and `self` type is not `Copy`) usually take `self` by reference"
-target/lintcheck/sources/rand-0.7.3/src/lib.rs:435:22 clippy::wrong_self_convention "methods with the following characteristics: (`to_*` and `self` type is not `Copy`) usually take `self` by reference"
-target/lintcheck/sources/rand-0.7.3/src/lib.rs:435:22 clippy::wrong_self_convention "methods with the following characteristics: (`to_*` and `self` type is not `Copy`) usually take `self` by reference"
-target/lintcheck/sources/rand-0.7.3/src/lib.rs:435:22 clippy::wrong_self_convention "methods with the following characteristics: (`to_*` and `self` type is not `Copy`) usually take `self` by reference"
-target/lintcheck/sources/rand-0.7.3/src/lib.rs:435:22 clippy::wrong_self_convention "methods with the following characteristics: (`to_*` and `self` type is not `Copy`) usually take `self` by reference"
-target/lintcheck/sources/rand-0.7.3/src/lib.rs:435:22 clippy::wrong_self_convention "methods with the following characteristics: (`to_*` and `self` type is not `Copy`) usually take `self` by reference"
-target/lintcheck/sources/rand-0.7.3/src/lib.rs:435:22 clippy::wrong_self_convention "methods with the following characteristics: (`to_*` and `self` type is not `Copy`) usually take `self` by reference"
-target/lintcheck/sources/rand-0.7.3/src/lib.rs:459:22 clippy::wrong_self_convention "methods with the following characteristics: (`to_*` and `self` type is not `Copy`) usually take `self` by reference"
-target/lintcheck/sources/rand-0.7.3/src/lib.rs:459:22 clippy::wrong_self_convention "methods with the following characteristics: (`to_*` and `self` type is not `Copy`) usually take `self` by reference"
-target/lintcheck/sources/rand-0.7.3/src/lib.rs:459:22 clippy::wrong_self_convention "methods with the following characteristics: (`to_*` and `self` type is not `Copy`) usually take `self` by reference"
-target/lintcheck/sources/rand-0.7.3/src/lib.rs:459:22 clippy::wrong_self_convention "methods with the following characteristics: (`to_*` and `self` type is not `Copy`) usually take `self` by reference"
-target/lintcheck/sources/rand-0.7.3/src/lib.rs:459:22 clippy::wrong_self_convention "methods with the following characteristics: (`to_*` and `self` type is not `Copy`) usually take `self` by reference"
-target/lintcheck/sources/rand-0.7.3/src/lib.rs:459:22 clippy::wrong_self_convention "methods with the following characteristics: (`to_*` and `self` type is not `Copy`) usually take `self` by reference"
-target/lintcheck/sources/rand-0.7.3/src/lib.rs:459:22 clippy::wrong_self_convention "methods with the following characteristics: (`to_*` and `self` type is not `Copy`) usually take `self` by reference"
-target/lintcheck/sources/rand-0.7.3/src/lib.rs:459:22 clippy::wrong_self_convention "methods with the following characteristics: (`to_*` and `self` type is not `Copy`) usually take `self` by reference"
-target/lintcheck/sources/rand-0.7.3/src/lib.rs:459:22 clippy::wrong_self_convention "methods with the following characteristics: (`to_*` and `self` type is not `Copy`) usually take `self` by reference"
-target/lintcheck/sources/rand-0.7.3/src/lib.rs:459:22 clippy::wrong_self_convention "methods with the following characteristics: (`to_*` and `self` type is not `Copy`) usually take `self` by reference"
-target/lintcheck/sources/rand-0.7.3/src/lib.rs:459:22 clippy::wrong_self_convention "methods with the following characteristics: (`to_*` and `self` type is not `Copy`) usually take `self` by reference"
-target/lintcheck/sources/rand-0.7.3/src/lib.rs:489:22 clippy::wrong_self_convention "methods with the following characteristics: (`to_*` and `self` type is not `Copy`) usually take `self` by reference"
-target/lintcheck/sources/rand-0.7.3/src/lib.rs:489:22 clippy::wrong_self_convention "methods with the following characteristics: (`to_*` and `self` type is not `Copy`) usually take `self` by reference"
-target/lintcheck/sources/rand-0.7.3/src/lib.rs:489:22 clippy::wrong_self_convention "methods with the following characteristics: (`to_*` and `self` type is not `Copy`) usually take `self` by reference"
-target/lintcheck/sources/rand-0.7.3/src/lib.rs:489:22 clippy::wrong_self_convention "methods with the following characteristics: (`to_*` and `self` type is not `Copy`) usually take `self` by reference"
-target/lintcheck/sources/rand-0.7.3/src/lib.rs:489:22 clippy::wrong_self_convention "methods with the following characteristics: (`to_*` and `self` type is not `Copy`) usually take `self` by reference"
-target/lintcheck/sources/rand-0.7.3/src/lib.rs:489:22 clippy::wrong_self_convention "methods with the following characteristics: (`to_*` and `self` type is not `Copy`) usually take `self` by reference"
-target/lintcheck/sources/rand-0.7.3/src/lib.rs:489:22 clippy::wrong_self_convention "methods with the following characteristics: (`to_*` and `self` type is not `Copy`) usually take `self` by reference"
-target/lintcheck/sources/rand-0.7.3/src/lib.rs:489:22 clippy::wrong_self_convention "methods with the following characteristics: (`to_*` and `self` type is not `Copy`) usually take `self` by reference"
-target/lintcheck/sources/rand-0.7.3/src/lib.rs:489:22 clippy::wrong_self_convention "methods with the following characteristics: (`to_*` and `self` type is not `Copy`) usually take `self` by reference"
-target/lintcheck/sources/rand-0.7.3/src/lib.rs:489:22 clippy::wrong_self_convention "methods with the following characteristics: (`to_*` and `self` type is not `Copy`) usually take `self` by reference"
-target/lintcheck/sources/rand-0.7.3/src/lib.rs:489:22 clippy::wrong_self_convention "methods with the following characteristics: (`to_*` and `self` type is not `Copy`) usually take `self` by reference"
-target/lintcheck/sources/rand-0.7.3/src/lib.rs:489:22 clippy::wrong_self_convention "methods with the following characteristics: (`to_*` and `self` type is not `Copy`) usually take `self` by reference"
-target/lintcheck/sources/rand-0.7.3/src/lib.rs:489:22 clippy::wrong_self_convention "methods with the following characteristics: (`to_*` and `self` type is not `Copy`) usually take `self` by reference"
-target/lintcheck/sources/rand-0.7.3/src/lib.rs:489:22 clippy::wrong_self_convention "methods with the following characteristics: (`to_*` and `self` type is not `Copy`) usually take `self` by reference"
-target/lintcheck/sources/rand-0.7.3/src/lib.rs:489:22 clippy::wrong_self_convention "methods with the following characteristics: (`to_*` and `self` type is not `Copy`) usually take `self` by reference"
-target/lintcheck/sources/rand-0.7.3/src/lib.rs:489:22 clippy::wrong_self_convention "methods with the following characteristics: (`to_*` and `self` type is not `Copy`) usually take `self` by reference"
-target/lintcheck/sources/rand-0.7.3/src/lib.rs:489:22 clippy::wrong_self_convention "methods with the following characteristics: (`to_*` and `self` type is not `Copy`) usually take `self` by reference"
-target/lintcheck/sources/rand-0.7.3/src/lib.rs:489:22 clippy::wrong_self_convention "methods with the following characteristics: (`to_*` and `self` type is not `Copy`) usually take `self` by reference"
-target/lintcheck/sources/rand-0.7.3/src/lib.rs:489:22 clippy::wrong_self_convention "methods with the following characteristics: (`to_*` and `self` type is not `Copy`) usually take `self` by reference"
-target/lintcheck/sources/rand-0.7.3/src/lib.rs:489:22 clippy::wrong_self_convention "methods with the following characteristics: (`to_*` and `self` type is not `Copy`) usually take `self` by reference"
-target/lintcheck/sources/rand-0.7.3/src/lib.rs:489:22 clippy::wrong_self_convention "methods with the following characteristics: (`to_*` and `self` type is not `Copy`) usually take `self` by reference"
-target/lintcheck/sources/rand-0.7.3/src/lib.rs:489:22 clippy::wrong_self_convention "methods with the following characteristics: (`to_*` and `self` type is not `Copy`) usually take `self` by reference"
-target/lintcheck/sources/rand-0.7.3/src/lib.rs:489:22 clippy::wrong_self_convention "methods with the following characteristics: (`to_*` and `self` type is not `Copy`) usually take `self` by reference"
-target/lintcheck/sources/rand-0.7.3/src/lib.rs:489:22 clippy::wrong_self_convention "methods with the following characteristics: (`to_*` and `self` type is not `Copy`) usually take `self` by reference"
-target/lintcheck/sources/rand-0.7.3/src/lib.rs:489:22 clippy::wrong_self_convention "methods with the following characteristics: (`to_*` and `self` type is not `Copy`) usually take `self` by reference"
-target/lintcheck/sources/rand-0.7.3/src/lib.rs:489:22 clippy::wrong_self_convention "methods with the following characteristics: (`to_*` and `self` type is not `Copy`) usually take `self` by reference"
-target/lintcheck/sources/rand-0.7.3/src/lib.rs:489:22 clippy::wrong_self_convention "methods with the following characteristics: (`to_*` and `self` type is not `Copy`) usually take `self` by reference"
-target/lintcheck/sources/rand-0.7.3/src/lib.rs:489:22 clippy::wrong_self_convention "methods with the following characteristics: (`to_*` and `self` type is not `Copy`) usually take `self` by reference"
-target/lintcheck/sources/rand-0.7.3/src/lib.rs:489:22 clippy::wrong_self_convention "methods with the following characteristics: (`to_*` and `self` type is not `Copy`) usually take `self` by reference"
-target/lintcheck/sources/rand-0.7.3/src/lib.rs:489:22 clippy::wrong_self_convention "methods with the following characteristics: (`to_*` and `self` type is not `Copy`) usually take `self` by reference"
-target/lintcheck/sources/rand-0.7.3/src/lib.rs:489:22 clippy::wrong_self_convention "methods with the following characteristics: (`to_*` and `self` type is not `Copy`) usually take `self` by reference"
-target/lintcheck/sources/rand-0.7.3/src/lib.rs:489:22 clippy::wrong_self_convention "methods with the following characteristics: (`to_*` and `self` type is not `Copy`) usually take `self` by reference"
-target/lintcheck/sources/rand-0.7.3/src/lib.rs:489:22 clippy::wrong_self_convention "methods with the following characteristics: (`to_*` and `self` type is not `Copy`) usually take `self` by reference"
-target/lintcheck/sources/rand-0.7.3/src/lib.rs:489:22 clippy::wrong_self_convention "methods with the following characteristics: (`to_*` and `self` type is not `Copy`) usually take `self` by reference"
-target/lintcheck/sources/rand-0.7.3/src/lib.rs:489:22 clippy::wrong_self_convention "methods with the following characteristics: (`to_*` and `self` type is not `Copy`) usually take `self` by reference"
-target/lintcheck/sources/rand-0.7.3/src/lib.rs:489:22 clippy::wrong_self_convention "methods with the following characteristics: (`to_*` and `self` type is not `Copy`) usually take `self` by reference"
-target/lintcheck/sources/rand-0.7.3/src/lib.rs:489:22 clippy::wrong_self_convention "methods with the following characteristics: (`to_*` and `self` type is not `Copy`) usually take `self` by reference"
-target/lintcheck/sources/rand-0.7.3/src/lib.rs:489:22 clippy::wrong_self_convention "methods with the following characteristics: (`to_*` and `self` type is not `Copy`) usually take `self` by reference"
-target/lintcheck/sources/rand-0.7.3/src/lib.rs:489:22 clippy::wrong_self_convention "methods with the following characteristics: (`to_*` and `self` type is not `Copy`) usually take `self` by reference"
-target/lintcheck/sources/rand-0.7.3/src/lib.rs:489:22 clippy::wrong_self_convention "methods with the following characteristics: (`to_*` and `self` type is not `Copy`) usually take `self` by reference"
-target/lintcheck/sources/rand-0.7.3/src/lib.rs:552:1 clippy::must_use_candidate "this function could have a `#[must_use]` attribute"
-target/lintcheck/sources/rand-0.7.3/src/rngs/adapter/read.rs:47:1 clippy::module_name_repetitions "item name starts with its containing module's name"
-target/lintcheck/sources/rand-0.7.3/src/rngs/adapter/read.rs:89:1 clippy::module_name_repetitions "item name starts with its containing module's name"
-target/lintcheck/sources/rand-0.7.3/src/rngs/adapter/reseeding.rs:100:5 clippy::missing_errors_doc "docs for function returning `Result` missing `# Errors` section"
-target/lintcheck/sources/rand-0.7.3/src/rngs/adapter/reseeding.rs:112:5 clippy::inline_always "you have declared `#[inline(always)]` on `next_u32`. This is usually a bad idea"
-target/lintcheck/sources/rand-0.7.3/src/rngs/adapter/reseeding.rs:117:5 clippy::inline_always "you have declared `#[inline(always)]` on `next_u64`. This is usually a bad idea"
-target/lintcheck/sources/rand-0.7.3/src/rngs/adapter/reseeding.rs:198:13 clippy::cast_possible_wrap "casting `u64` to `i64` may wrap around the value"
-target/lintcheck/sources/rand-0.7.3/src/rngs/adapter/reseeding.rs:231:9 clippy::cast_possible_wrap "casting `usize` to `isize` may wrap around the value"
-target/lintcheck/sources/rand-0.7.3/src/rngs/adapter/reseeding.rs:249:13 clippy::let_underscore_drop "non-binding `let` on a type that implements `Drop`"
-target/lintcheck/sources/rand-0.7.3/src/rngs/adapter/reseeding.rs:27:28 clippy::doc_markdown "you should put `ChaCha` between ticks in the documentation"
-target/lintcheck/sources/rand-0.7.3/src/rngs/adapter/reseeding.rs:79:1 clippy::module_name_repetitions "item name starts with its containing module's name"
-target/lintcheck/sources/rand-0.7.3/src/rngs/entropy.rs:24:1 clippy::module_name_repetitions "item name starts with its containing module's name"
-target/lintcheck/sources/rand-0.7.3/src/rngs/entropy.rs:34:5 clippy::must_use_candidate "this method could have a `#[must_use]` attribute"
-target/lintcheck/sources/rand-0.7.3/src/rngs/mock.rs:36:5 clippy::must_use_candidate "this method could have a `#[must_use]` attribute"
-target/lintcheck/sources/rand-0.7.3/src/rngs/mock.rs:47:9 clippy::cast_possible_truncation "casting `u64` to `u32` may truncate the value"
-target/lintcheck/sources/rand-0.7.3/src/rngs/mod.rs:61:74 clippy::doc_markdown "you should put `ChaCha20` between ticks in the documentation"
-target/lintcheck/sources/rand-0.7.3/src/rngs/std.rs:25:39 clippy::doc_markdown "you should put `ChaCha` between ticks in the documentation"
-target/lintcheck/sources/rand-0.7.3/src/rngs/std.rs:32:10 clippy::doc_markdown "you should put `rand_chacha` between ticks in the documentation"
-target/lintcheck/sources/rand-0.7.3/src/rngs/std.rs:36:1 clippy::module_name_repetitions "item name starts with its containing module's name"
-target/lintcheck/sources/rand-0.7.3/src/rngs/std.rs:39:5 clippy::inline_always "you have declared `#[inline(always)]` on `next_u32`. This is usually a bad idea"
-target/lintcheck/sources/rand-0.7.3/src/rngs/std.rs:44:5 clippy::inline_always "you have declared `#[inline(always)]` on `next_u64`. This is usually a bad idea"
-target/lintcheck/sources/rand-0.7.3/src/rngs/std.rs:49:5 clippy::inline_always "you have declared `#[inline(always)]` on `fill_bytes`. This is usually a bad idea"
-target/lintcheck/sources/rand-0.7.3/src/rngs/std.rs:54:5 clippy::inline_always "you have declared `#[inline(always)]` on `try_fill_bytes`. This is usually a bad idea"
-target/lintcheck/sources/rand-0.7.3/src/rngs/std.rs:63:5 clippy::inline_always "you have declared `#[inline(always)]` on `from_seed`. This is usually a bad idea"
-target/lintcheck/sources/rand-0.7.3/src/rngs/std.rs:68:5 clippy::inline_always "you have declared `#[inline(always)]` on `from_rng`. This is usually a bad idea"
-target/lintcheck/sources/rand-0.7.3/src/rngs/thread.rs:57:1 clippy::module_name_repetitions "item name starts with its containing module's name"
-target/lintcheck/sources/rand-0.7.3/src/rngs/thread.rs:80:1 clippy::missing_panics_doc "docs for function which may panic missing `# Panics` section"
-target/lintcheck/sources/rand-0.7.3/src/rngs/thread.rs:80:1 clippy::module_name_repetitions "item name starts with its containing module's name"
-target/lintcheck/sources/rand-0.7.3/src/rngs/thread.rs:80:1 clippy::must_use_candidate "this function could have a `#[must_use]` attribute"
-target/lintcheck/sources/rand-0.7.3/src/rngs/thread.rs:81:35 clippy::redundant_closure_for_method_calls "redundant closure"
-target/lintcheck/sources/rand-0.7.3/src/rngs/thread.rs:93:5 clippy::inline_always "you have declared `#[inline(always)]` on `next_u32`. This is usually a bad idea"
-target/lintcheck/sources/rand-0.7.3/src/rngs/thread.rs:98:5 clippy::inline_always "you have declared `#[inline(always)]` on `next_u64`. This is usually a bad idea"
-target/lintcheck/sources/rand-0.7.3/src/seq/index.rs:127:1 clippy::module_name_repetitions "item name starts with its containing module's name"
-target/lintcheck/sources/rand-0.7.3/src/seq/index.rs:139:13 clippy::enum_glob_use "usage of wildcard import for enum variants"
-target/lintcheck/sources/rand-0.7.3/src/seq/index.rs:159:1 clippy::module_name_repetitions "item name starts with its containing module's name"
-target/lintcheck/sources/rand-0.7.3/src/seq/index.rs:171:13 clippy::enum_glob_use "usage of wildcard import for enum variants"
-target/lintcheck/sources/rand-0.7.3/src/seq/index.rs:180:13 clippy::enum_glob_use "usage of wildcard import for enum variants"
-target/lintcheck/sources/rand-0.7.3/src/seq/index.rs:223:18 clippy::cast_possible_truncation "casting `usize` to `u32` may truncate the value on targets with 64-bit wide pointers"
-target/lintcheck/sources/rand-0.7.3/src/seq/index.rs:224:18 clippy::cast_possible_truncation "casting `usize` to `u32` may truncate the value on targets with 64-bit wide pointers"
-target/lintcheck/sources/rand-0.7.3/src/seq/index.rs:233:25 clippy::cast_precision_loss "casting `u32` to `f32` causes a loss of precision (`u32` is 32 bits wide, but `f32`'s mantissa is only 23 bits wide)"
-target/lintcheck/sources/rand-0.7.3/src/seq/index.rs:236:27 clippy::cast_precision_loss "casting `u32` to `f32` causes a loss of precision (`u32` is 32 bits wide, but `f32`'s mantissa is only 23 bits wide)"
-target/lintcheck/sources/rand-0.7.3/src/seq/index.rs:244:12 clippy::cast_precision_loss "casting `u32` to `f32` causes a loss of precision (`u32` is 32 bits wide, but `f32`'s mantissa is only 23 bits wide)"
-target/lintcheck/sources/rand-0.7.3/src/seq/index.rs:244:37 clippy::cast_precision_loss "casting `u32` to `f32` causes a loss of precision (`u32` is 32 bits wide, but `f32`'s mantissa is only 23 bits wide)"
-target/lintcheck/sources/rand-0.7.3/src/seq/index.rs:29:1 clippy::module_name_repetitions "item name starts with its containing module's name"
-target/lintcheck/sources/rand-0.7.3/src/seq/index.rs:39:5 clippy::must_use_candidate "this method could have a `#[must_use]` attribute"
-target/lintcheck/sources/rand-0.7.3/src/seq/index.rs:48:5 clippy::must_use_candidate "this method could have a `#[must_use]` attribute"
-target/lintcheck/sources/rand-0.7.3/src/seq/index.rs:60:5 clippy::must_use_candidate "this method could have a `#[must_use]` attribute"
-target/lintcheck/sources/rand-0.7.3/src/seq/index.rs:69:5 clippy::must_use_candidate "this method could have a `#[must_use]` attribute"
-target/lintcheck/sources/rand-0.7.3/src/seq/index.rs:78:5 clippy::must_use_candidate "this method could have a `#[must_use]` attribute"
-target/lintcheck/sources/rand-0.7.3/src/seq/index.rs:87:5 clippy::must_use_candidate "this method could have a `#[must_use]` attribute"
-target/lintcheck/sources/rand-0.7.3/src/seq/index.rs:87:5 clippy::should_implement_trait "method `into_iter` can be confused for the standard trait method `std::iter::IntoIterator::into_iter`"
-target/lintcheck/sources/rand-0.7.3/src/seq/index.rs:97:13 clippy::enum_glob_use "usage of wildcard import for enum variants"
-target/lintcheck/sources/rand-0.7.3/src/seq/mod.rs:141:5 clippy::missing_errors_doc "docs for function returning `Result` missing `# Errors` section"
-target/lintcheck/sources/rand-0.7.3/src/seq/mod.rs:168:5 clippy::missing_errors_doc "docs for function returning `Result` missing `# Errors` section"
-target/lintcheck/sources/rand-0.7.3/src/seq/mod.rs:229:4 clippy::needless_doctest_main "needless `fn main` in doctest"
-target/lintcheck/sources/rand-0.7.3/src/seq/mod.rs:292:29 clippy::cast_precision_loss "casting `usize` to `f64` causes a loss of precision on targets with 64-bit wide pointers (`usize` is 64 bits wide, but `f64`'s mantissa is only 52 bits wide)"
-target/lintcheck/sources/rand-0.7.3/src/seq/mod.rs:410:23 clippy::default_trait_access "calling `std::marker::PhantomData::default()` is more clear than this expression"
-target/lintcheck/sources/rand-0.7.3/src/seq/mod.rs:45:4 clippy::needless_doctest_main "needless `fn main` in doctest"
-target/lintcheck/sources/rand-0.7.3/src/seq/mod.rs:527:26 clippy::cast_possible_truncation "casting `usize` to `u32` may truncate the value on targets with 64-bit wide pointers"
-target/lintcheck/sources/rand_core-0.6.0/src/block.rs:117:1 clippy::module_name_repetitions "item name starts with its containing module's name"
-target/lintcheck/sources/rand_core-0.6.0/src/block.rs:153:5 clippy::inline_always "you have declared `#[inline(always)]` on `index`. This is usually a bad idea"
-target/lintcheck/sources/rand_core-0.6.0/src/block.rs:230:5 clippy::inline_always "you have declared `#[inline(always)]` on `try_fill_bytes`. This is usually a bad idea"
-target/lintcheck/sources/rand_core-0.6.0/src/block.rs:240:5 clippy::inline_always "you have declared `#[inline(always)]` on `from_seed`. This is usually a bad idea"
-target/lintcheck/sources/rand_core-0.6.0/src/block.rs:245:5 clippy::inline_always "you have declared `#[inline(always)]` on `seed_from_u64`. This is usually a bad idea"
-target/lintcheck/sources/rand_core-0.6.0/src/block.rs:250:5 clippy::inline_always "you have declared `#[inline(always)]` on `from_rng`. This is usually a bad idea"
-target/lintcheck/sources/rand_core-0.6.0/src/block.rs:280:1 clippy::module_name_repetitions "item name starts with its containing module's name"
-target/lintcheck/sources/rand_core-0.6.0/src/block.rs:319:5 clippy::inline_always "you have declared `#[inline(always)]` on `index`. This is usually a bad idea"
-target/lintcheck/sources/rand_core-0.6.0/src/block.rs:405:5 clippy::inline_always "you have declared `#[inline(always)]` on `try_fill_bytes`. This is usually a bad idea"
-target/lintcheck/sources/rand_core-0.6.0/src/block.rs:415:5 clippy::inline_always "you have declared `#[inline(always)]` on `from_seed`. This is usually a bad idea"
-target/lintcheck/sources/rand_core-0.6.0/src/block.rs:420:5 clippy::inline_always "you have declared `#[inline(always)]` on `seed_from_u64`. This is usually a bad idea"
-target/lintcheck/sources/rand_core-0.6.0/src/block.rs:425:5 clippy::inline_always "you have declared `#[inline(always)]` on `from_rng`. This is usually a bad idea"
-target/lintcheck/sources/rand_core-0.6.0/src/block.rs:67:14 clippy::doc_markdown "you should put `module][crate::block` between ticks in the documentation"
-target/lintcheck/sources/rand_core-0.6.0/src/block.rs:68:1 clippy::module_name_repetitions "item name starts with its containing module's name"
-target/lintcheck/sources/rand_core-0.6.0/src/error.rs:106:5 clippy::must_use_candidate "this method could have a `#[must_use]` attribute"
-target/lintcheck/sources/rand_core-0.6.0/src/error.rs:87:5 clippy::must_use_candidate "this method could have a `#[must_use]` attribute"
-target/lintcheck/sources/rand_core-0.6.0/src/error.rs:95:74 clippy::cast_possible_wrap "casting `u32` to `i32` may wrap around the value"
-target/lintcheck/sources/rand_core-0.6.0/src/lib.rs:179:5 clippy::missing_errors_doc "docs for function returning `Result` missing `# Errors` section"
-target/lintcheck/sources/rand_core-0.6.0/src/lib.rs:301:5 clippy::must_use_candidate "this method could have a `#[must_use]` attribute"
-target/lintcheck/sources/rand_core-0.6.0/src/lib.rs:303:26 clippy::unreadable_literal "long literal lacking separators"
-target/lintcheck/sources/rand_core-0.6.0/src/lib.rs:304:26 clippy::unreadable_literal "long literal lacking separators"
-target/lintcheck/sources/rand_core-0.6.0/src/lib.rs:313:30 clippy::cast_possible_truncation "casting `u64` to `u32` may truncate the value"
-target/lintcheck/sources/rand_core-0.6.0/src/lib.rs:314:23 clippy::cast_possible_truncation "casting `u64` to `u32` may truncate the value"
-target/lintcheck/sources/rand_core-0.6.0/src/lib.rs:346:5 clippy::missing_errors_doc "docs for function returning `Result` missing `# Errors` section"
-target/lintcheck/sources/rand_core-0.6.0/src/lib.rs:381:5 clippy::inline_always "you have declared `#[inline(always)]` on `next_u32`. This is usually a bad idea"
-target/lintcheck/sources/rand_core-0.6.0/src/lib.rs:386:5 clippy::inline_always "you have declared `#[inline(always)]` on `next_u64`. This is usually a bad idea"
-target/lintcheck/sources/rand_core-0.6.0/src/lib.rs:391:5 clippy::inline_always "you have declared `#[inline(always)]` on `fill_bytes`. This is usually a bad idea"
-target/lintcheck/sources/rand_core-0.6.0/src/lib.rs:396:5 clippy::inline_always "you have declared `#[inline(always)]` on `try_fill_bytes`. This is usually a bad idea"
-target/lintcheck/sources/rayon-1.5.0/src/collections/binary_heap.rs:7:5 clippy::wildcard_imports "usage of wildcard import"
-target/lintcheck/sources/rayon-1.5.0/src/collections/binary_heap.rs:8:5 clippy::wildcard_imports "usage of wildcard import"
-target/lintcheck/sources/rayon-1.5.0/src/collections/btree_map.rs:7:5 clippy::wildcard_imports "usage of wildcard import"
-target/lintcheck/sources/rayon-1.5.0/src/collections/btree_map.rs:8:5 clippy::wildcard_imports "usage of wildcard import"
-target/lintcheck/sources/rayon-1.5.0/src/collections/btree_set.rs:7:5 clippy::wildcard_imports "usage of wildcard import"
-target/lintcheck/sources/rayon-1.5.0/src/collections/btree_set.rs:8:5 clippy::wildcard_imports "usage of wildcard import"
-target/lintcheck/sources/rayon-1.5.0/src/collections/hash_map.rs:10:5 clippy::wildcard_imports "usage of wildcard import"
-target/lintcheck/sources/rayon-1.5.0/src/collections/hash_map.rs:9:5 clippy::wildcard_imports "usage of wildcard import"
-target/lintcheck/sources/rayon-1.5.0/src/collections/hash_set.rs:10:5 clippy::wildcard_imports "usage of wildcard import"
-target/lintcheck/sources/rayon-1.5.0/src/collections/hash_set.rs:9:5 clippy::wildcard_imports "usage of wildcard import"
-target/lintcheck/sources/rayon-1.5.0/src/collections/linked_list.rs:7:5 clippy::wildcard_imports "usage of wildcard import"
-target/lintcheck/sources/rayon-1.5.0/src/collections/linked_list.rs:8:5 clippy::wildcard_imports "usage of wildcard import"
-target/lintcheck/sources/rayon-1.5.0/src/collections/mod.rs:59:32 clippy::mem_replace_with_default "replacing a value of type `T` with `T::default()` is better expressed using `std::mem::take`"
-target/lintcheck/sources/rayon-1.5.0/src/collections/mod.rs:68:40 clippy::mem_replace_with_default "replacing a value of type `T` with `T::default()` is better expressed using `std::mem::take`"
-target/lintcheck/sources/rayon-1.5.0/src/collections/vec_deque.rs:8:5 clippy::wildcard_imports "usage of wildcard import"
-target/lintcheck/sources/rayon-1.5.0/src/collections/vec_deque.rs:9:5 clippy::wildcard_imports "usage of wildcard import"
-target/lintcheck/sources/rayon-1.5.0/src/compile_fail/cannot_collect_filtermap_data.rs:2:1 clippy::needless_doctest_main "needless `fn main` in doctest"
-target/lintcheck/sources/rayon-1.5.0/src/compile_fail/cannot_zip_filtered_data.rs:2:1 clippy::needless_doctest_main "needless `fn main` in doctest"
-target/lintcheck/sources/rayon-1.5.0/src/compile_fail/cell_par_iter.rs:2:1 clippy::needless_doctest_main "needless `fn main` in doctest"
-target/lintcheck/sources/rayon-1.5.0/src/compile_fail/no_send_par_iter.rs:25:1 clippy::needless_doctest_main "needless `fn main` in doctest"
-target/lintcheck/sources/rayon-1.5.0/src/compile_fail/no_send_par_iter.rs:46:1 clippy::needless_doctest_main "needless `fn main` in doctest"
-target/lintcheck/sources/rayon-1.5.0/src/compile_fail/no_send_par_iter.rs:4:1 clippy::needless_doctest_main "needless `fn main` in doctest"
-target/lintcheck/sources/rayon-1.5.0/src/compile_fail/rc_par_iter.rs:2:1 clippy::needless_doctest_main "needless `fn main` in doctest"
-target/lintcheck/sources/rayon-1.5.0/src/iter/chain.rs:103:9 clippy::items_after_statements "adding items after statements is confusing, since items exist from the start of the scope"
-target/lintcheck/sources/rayon-1.5.0/src/iter/chain.rs:122:9 clippy::items_after_statements "adding items after statements is confusing, since items exist from the start of the scope"
-target/lintcheck/sources/rayon-1.5.0/src/iter/chain.rs:128:9 clippy::items_after_statements "adding items after statements is confusing, since items exist from the start of the scope"
-target/lintcheck/sources/rayon-1.5.0/src/iter/chain.rs:1:5 clippy::wildcard_imports "usage of wildcard import"
-target/lintcheck/sources/rayon-1.5.0/src/iter/chain.rs:221:36 clippy::doc_markdown "you should put `ExactSizeIterator` between ticks in the documentation"
-target/lintcheck/sources/rayon-1.5.0/src/iter/chain.rs:2:5 clippy::wildcard_imports "usage of wildcard import"
-target/lintcheck/sources/rayon-1.5.0/src/iter/chain.rs:51:38 clippy::option_if_let_else "use Option::map_or_else instead of an if let/else"
-target/lintcheck/sources/rayon-1.5.0/src/iter/chain.rs:58:14 clippy::shadow_unrelated "`a` is being shadowed"
-target/lintcheck/sources/rayon-1.5.0/src/iter/chain.rs:58:17 clippy::shadow_unrelated "`b` is being shadowed"
-target/lintcheck/sources/rayon-1.5.0/src/iter/chain.rs:78:14 clippy::shadow_unrelated "`a` is being shadowed"
-target/lintcheck/sources/rayon-1.5.0/src/iter/chain.rs:78:17 clippy::shadow_unrelated "`b` is being shadowed"
-target/lintcheck/sources/rayon-1.5.0/src/iter/chain.rs:97:9 clippy::items_after_statements "adding items after statements is confusing, since items exist from the start of the scope"
-target/lintcheck/sources/rayon-1.5.0/src/iter/chunks.rs:29:9 clippy::inconsistent_struct_constructor "struct constructor field order is inconsistent with struct definition field order"
-target/lintcheck/sources/rayon-1.5.0/src/iter/chunks.rs:3:5 clippy::wildcard_imports "usage of wildcard import"
-target/lintcheck/sources/rayon-1.5.0/src/iter/chunks.rs:4:5 clippy::wildcard_imports "usage of wildcard import"
-target/lintcheck/sources/rayon-1.5.0/src/iter/chunks.rs:77:9 clippy::items_after_statements "adding items after statements is confusing, since items exist from the start of the scope"
-target/lintcheck/sources/rayon-1.5.0/src/iter/chunks.rs:83:9 clippy::items_after_statements "adding items after statements is confusing, since items exist from the start of the scope"
-target/lintcheck/sources/rayon-1.5.0/src/iter/cloned.rs:1:5 clippy::wildcard_imports "usage of wildcard import"
-target/lintcheck/sources/rayon-1.5.0/src/iter/cloned.rs:2:5 clippy::wildcard_imports "usage of wildcard import"
-target/lintcheck/sources/rayon-1.5.0/src/iter/cloned.rs:71:9 clippy::items_after_statements "adding items after statements is confusing, since items exist from the start of the scope"
-target/lintcheck/sources/rayon-1.5.0/src/iter/cloned.rs:75:9 clippy::items_after_statements "adding items after statements is confusing, since items exist from the start of the scope"
-target/lintcheck/sources/rayon-1.5.0/src/iter/collect/consumer.rs:141:5 clippy::doc_markdown "you should put `CollectReducer` between ticks in the documentation"
-target/lintcheck/sources/rayon-1.5.0/src/iter/collect/consumer.rs:1:5 clippy::wildcard_imports "usage of wildcard import"
-target/lintcheck/sources/rayon-1.5.0/src/iter/collect/consumer.rs:28:5 clippy::doc_markdown "you should put `CollectResult` between ticks in the documentation"
-target/lintcheck/sources/rayon-1.5.0/src/iter/collect/consumer.rs:36:37 clippy::mut_mut "generally you want to avoid `&mut &mut _` if possible"
-target/lintcheck/sources/rayon-1.5.0/src/iter/collect/consumer.rs:36:37 clippy::mut_mut "generally you want to avoid `&mut &mut _` if possible"
-target/lintcheck/sources/rayon-1.5.0/src/iter/collect/mod.rs:154:9 clippy::single_match_else "you seem to be trying to use `match` for destructuring a single pattern. Consider using `if let`"
-target/lintcheck/sources/rayon-1.5.0/src/iter/copied.rs:1:5 clippy::wildcard_imports "usage of wildcard import"
-target/lintcheck/sources/rayon-1.5.0/src/iter/copied.rs:2:5 clippy::wildcard_imports "usage of wildcard import"
-target/lintcheck/sources/rayon-1.5.0/src/iter/copied.rs:71:9 clippy::items_after_statements "adding items after statements is confusing, since items exist from the start of the scope"
-target/lintcheck/sources/rayon-1.5.0/src/iter/copied.rs:75:9 clippy::items_after_statements "adding items after statements is confusing, since items exist from the start of the scope"
-target/lintcheck/sources/rayon-1.5.0/src/iter/empty.rs:1:5 clippy::wildcard_imports "usage of wildcard import"
-target/lintcheck/sources/rayon-1.5.0/src/iter/empty.rs:24:1 clippy::must_use_candidate "this function could have a `#[must_use]` attribute"
-target/lintcheck/sources/rayon-1.5.0/src/iter/empty.rs:2:5 clippy::wildcard_imports "usage of wildcard import"
-target/lintcheck/sources/rayon-1.5.0/src/iter/enumerate.rs:1:5 clippy::wildcard_imports "usage of wildcard import"
-target/lintcheck/sources/rayon-1.5.0/src/iter/enumerate.rs:2:5 clippy::wildcard_imports "usage of wildcard import"
-target/lintcheck/sources/rayon-1.5.0/src/iter/enumerate.rs:64:9 clippy::items_after_statements "adding items after statements is confusing, since items exist from the start of the scope"
-target/lintcheck/sources/rayon-1.5.0/src/iter/enumerate.rs:68:9 clippy::items_after_statements "adding items after statements is confusing, since items exist from the start of the scope"
-target/lintcheck/sources/rayon-1.5.0/src/iter/extend.rs:143:63 clippy::linkedlist "you seem to be using a `LinkedList`! Perhaps you meant some other data structure?"
-target/lintcheck/sources/rayon-1.5.0/src/iter/extend.rs:182:57 clippy::linkedlist "you seem to be using a `LinkedList`! Perhaps you meant some other data structure?"
-target/lintcheck/sources/rayon-1.5.0/src/iter/extend.rs:218:32 clippy::linkedlist "you seem to be using a `LinkedList`! Perhaps you meant some other data structure?"
-target/lintcheck/sources/rayon-1.5.0/src/iter/extend.rs:218:59 clippy::linkedlist "you seem to be using a `LinkedList`! Perhaps you meant some other data structure?"
-target/lintcheck/sources/rayon-1.5.0/src/iter/extend.rs:25:42 clippy::linkedlist "you seem to be using a `LinkedList`! Perhaps you meant some other data structure?"
-target/lintcheck/sources/rayon-1.5.0/src/iter/extend.rs:287:62 clippy::linkedlist "you seem to be using a `LinkedList`! Perhaps you meant some other data structure?"
-target/lintcheck/sources/rayon-1.5.0/src/iter/extend.rs:322:56 clippy::linkedlist "you seem to be using a `LinkedList`! Perhaps you meant some other data structure?"
-target/lintcheck/sources/rayon-1.5.0/src/iter/extend.rs:41:27 clippy::linkedlist "you seem to be using a `LinkedList`! Perhaps you meant some other data structure?"
-target/lintcheck/sources/rayon-1.5.0/src/iter/extend.rs:47:30 clippy::linkedlist "you seem to be using a `LinkedList`! Perhaps you meant some other data structure?"
-target/lintcheck/sources/rayon-1.5.0/src/iter/extend.rs:47:56 clippy::linkedlist "you seem to be using a `LinkedList`! Perhaps you meant some other data structure?"
-target/lintcheck/sources/rayon-1.5.0/src/iter/extend.rs:47:74 clippy::linkedlist "you seem to be using a `LinkedList`! Perhaps you meant some other data structure?"
-target/lintcheck/sources/rayon-1.5.0/src/iter/extend.rs:53:29 clippy::linkedlist "you seem to be using a `LinkedList`! Perhaps you meant some other data structure?"
-target/lintcheck/sources/rayon-1.5.0/src/iter/extend.rs:57:36 clippy::linkedlist "you seem to be using a `LinkedList`! Perhaps you meant some other data structure?"
-target/lintcheck/sources/rayon-1.5.0/src/iter/extend.rs:59:61 clippy::linkedlist "you seem to be using a `LinkedList`! Perhaps you meant some other data structure?"
-target/lintcheck/sources/rayon-1.5.0/src/iter/filter.rs:1:5 clippy::wildcard_imports "usage of wildcard import"
-target/lintcheck/sources/rayon-1.5.0/src/iter/filter.rs:2:5 clippy::wildcard_imports "usage of wildcard import"
-target/lintcheck/sources/rayon-1.5.0/src/iter/filter_map.rs:123:9 clippy::option_if_let_else "use Option::map_or instead of an if let/else"
-target/lintcheck/sources/rayon-1.5.0/src/iter/filter_map.rs:1:5 clippy::wildcard_imports "usage of wildcard import"
-target/lintcheck/sources/rayon-1.5.0/src/iter/filter_map.rs:2:5 clippy::wildcard_imports "usage of wildcard import"
-target/lintcheck/sources/rayon-1.5.0/src/iter/find.rs:1:5 clippy::wildcard_imports "usage of wildcard import"
-target/lintcheck/sources/rayon-1.5.0/src/iter/find.rs:2:5 clippy::wildcard_imports "usage of wildcard import"
-target/lintcheck/sources/rayon-1.5.0/src/iter/find_first_last/mod.rs:1:5 clippy::wildcard_imports "usage of wildcard import"
-target/lintcheck/sources/rayon-1.5.0/src/iter/find_first_last/mod.rs:2:5 clippy::wildcard_imports "usage of wildcard import"
-target/lintcheck/sources/rayon-1.5.0/src/iter/find_first_last/mod.rs:32:67 clippy::doc_markdown "you should put `MatchPosition` between ticks in the documentation"
-target/lintcheck/sources/rayon-1.5.0/src/iter/flat_map.rs:1:5 clippy::wildcard_imports "usage of wildcard import"
-target/lintcheck/sources/rayon-1.5.0/src/iter/flat_map.rs:2:5 clippy::wildcard_imports "usage of wildcard import"
-target/lintcheck/sources/rayon-1.5.0/src/iter/flat_map_iter.rs:1:5 clippy::wildcard_imports "usage of wildcard import"
-target/lintcheck/sources/rayon-1.5.0/src/iter/flat_map_iter.rs:2:5 clippy::wildcard_imports "usage of wildcard import"
-target/lintcheck/sources/rayon-1.5.0/src/iter/flatten.rs:1:5 clippy::wildcard_imports "usage of wildcard import"
-target/lintcheck/sources/rayon-1.5.0/src/iter/flatten.rs:2:5 clippy::wildcard_imports "usage of wildcard import"
-target/lintcheck/sources/rayon-1.5.0/src/iter/flatten_iter.rs:1:5 clippy::wildcard_imports "usage of wildcard import"
-target/lintcheck/sources/rayon-1.5.0/src/iter/flatten_iter.rs:2:5 clippy::wildcard_imports "usage of wildcard import"
-target/lintcheck/sources/rayon-1.5.0/src/iter/fold.rs:158:13 clippy::similar_names "binding's name is too similar to existing binding"
-target/lintcheck/sources/rayon-1.5.0/src/iter/fold.rs:1:5 clippy::wildcard_imports "usage of wildcard import"
-target/lintcheck/sources/rayon-1.5.0/src/iter/fold.rs:204:1 clippy::module_name_repetitions "item name starts with its containing module's name"
-target/lintcheck/sources/rayon-1.5.0/src/iter/fold.rs:2:5 clippy::wildcard_imports "usage of wildcard import"
-target/lintcheck/sources/rayon-1.5.0/src/iter/for_each.rs:1:5 clippy::wildcard_imports "usage of wildcard import"
-target/lintcheck/sources/rayon-1.5.0/src/iter/for_each.rs:2:5 clippy::wildcard_imports "usage of wildcard import"
-target/lintcheck/sources/rayon-1.5.0/src/iter/inspect.rs:1:5 clippy::wildcard_imports "usage of wildcard import"
-target/lintcheck/sources/rayon-1.5.0/src/iter/inspect.rs:2:5 clippy::wildcard_imports "usage of wildcard import"
-target/lintcheck/sources/rayon-1.5.0/src/iter/inspect.rs:83:9 clippy::items_after_statements "adding items after statements is confusing, since items exist from the start of the scope"
-target/lintcheck/sources/rayon-1.5.0/src/iter/inspect.rs:88:9 clippy::items_after_statements "adding items after statements is confusing, since items exist from the start of the scope"
-target/lintcheck/sources/rayon-1.5.0/src/iter/interleave.rs:111:9 clippy::items_after_statements "adding items after statements is confusing, since items exist from the start of the scope"
-target/lintcheck/sources/rayon-1.5.0/src/iter/interleave.rs:119:9 clippy::items_after_statements "adding items after statements is confusing, since items exist from the start of the scope"
-target/lintcheck/sources/rayon-1.5.0/src/iter/interleave.rs:195:30 clippy::doc_markdown "you should put `self.i_len` between ticks in the documentation"
-target/lintcheck/sources/rayon-1.5.0/src/iter/interleave.rs:195:43 clippy::doc_markdown "you should put `self.j_len` between ticks in the documentation"
-target/lintcheck/sources/rayon-1.5.0/src/iter/interleave.rs:199:23 clippy::doc_markdown "you should put `self.i_len` between ticks in the documentation"
-target/lintcheck/sources/rayon-1.5.0/src/iter/interleave.rs:1:5 clippy::wildcard_imports "usage of wildcard import"
-target/lintcheck/sources/rayon-1.5.0/src/iter/interleave.rs:200:23 clippy::doc_markdown "you should put `self.j_len` between ticks in the documentation"
-target/lintcheck/sources/rayon-1.5.0/src/iter/interleave.rs:249:41 clippy::doc_markdown "you should put `DoubleEndedIterator` between ticks in the documentation"
-target/lintcheck/sources/rayon-1.5.0/src/iter/interleave.rs:250:5 clippy::doc_markdown "you should put `ExactSizeIterator` between ticks in the documentation"
-target/lintcheck/sources/rayon-1.5.0/src/iter/interleave.rs:263:33 clippy::doc_markdown "you should put `InterleaveSeq` between ticks in the documentation"
-target/lintcheck/sources/rayon-1.5.0/src/iter/interleave.rs:2:5 clippy::wildcard_imports "usage of wildcard import"
-target/lintcheck/sources/rayon-1.5.0/src/iter/interleave.rs:313:9 clippy::comparison_chain "`if` chain can be rewritten with `match`"
-target/lintcheck/sources/rayon-1.5.0/src/iter/interleave.rs:82:9 clippy::items_after_statements "adding items after statements is confusing, since items exist from the start of the scope"
-target/lintcheck/sources/rayon-1.5.0/src/iter/interleave.rs:90:9 clippy::items_after_statements "adding items after statements is confusing, since items exist from the start of the scope"
-target/lintcheck/sources/rayon-1.5.0/src/iter/interleave_shortest.rs:1:5 clippy::wildcard_imports "usage of wildcard import"
-target/lintcheck/sources/rayon-1.5.0/src/iter/intersperse.rs:1:5 clippy::wildcard_imports "usage of wildcard import"
-target/lintcheck/sources/rayon-1.5.0/src/iter/intersperse.rs:2:5 clippy::wildcard_imports "usage of wildcard import"
-target/lintcheck/sources/rayon-1.5.0/src/iter/intersperse.rs:90:9 clippy::items_after_statements "adding items after statements is confusing, since items exist from the start of the scope"
-target/lintcheck/sources/rayon-1.5.0/src/iter/intersperse.rs:96:9 clippy::items_after_statements "adding items after statements is confusing, since items exist from the start of the scope"
-target/lintcheck/sources/rayon-1.5.0/src/iter/len.rs:12:1 clippy::module_name_repetitions "item name ends with its containing module's name"
-target/lintcheck/sources/rayon-1.5.0/src/iter/len.rs:146:1 clippy::module_name_repetitions "item name ends with its containing module's name"
-target/lintcheck/sources/rayon-1.5.0/src/iter/len.rs:1:5 clippy::wildcard_imports "usage of wildcard import"
-target/lintcheck/sources/rayon-1.5.0/src/iter/len.rs:200:9 clippy::items_after_statements "adding items after statements is confusing, since items exist from the start of the scope"
-target/lintcheck/sources/rayon-1.5.0/src/iter/len.rs:205:9 clippy::items_after_statements "adding items after statements is confusing, since items exist from the start of the scope"
-target/lintcheck/sources/rayon-1.5.0/src/iter/len.rs:2:5 clippy::wildcard_imports "usage of wildcard import"
-target/lintcheck/sources/rayon-1.5.0/src/iter/len.rs:66:9 clippy::items_after_statements "adding items after statements is confusing, since items exist from the start of the scope"
-target/lintcheck/sources/rayon-1.5.0/src/iter/len.rs:71:9 clippy::items_after_statements "adding items after statements is confusing, since items exist from the start of the scope"
-target/lintcheck/sources/rayon-1.5.0/src/iter/map.rs:1:5 clippy::wildcard_imports "usage of wildcard import"
-target/lintcheck/sources/rayon-1.5.0/src/iter/map.rs:2:5 clippy::wildcard_imports "usage of wildcard import"
-target/lintcheck/sources/rayon-1.5.0/src/iter/map.rs:84:9 clippy::items_after_statements "adding items after statements is confusing, since items exist from the start of the scope"
-target/lintcheck/sources/rayon-1.5.0/src/iter/map.rs:89:9 clippy::items_after_statements "adding items after statements is confusing, since items exist from the start of the scope"
-target/lintcheck/sources/rayon-1.5.0/src/iter/map_with.rs:1:5 clippy::wildcard_imports "usage of wildcard import"
-target/lintcheck/sources/rayon-1.5.0/src/iter/map_with.rs:2:5 clippy::wildcard_imports "usage of wildcard import"
-target/lintcheck/sources/rayon-1.5.0/src/iter/map_with.rs:419:9 clippy::items_after_statements "adding items after statements is confusing, since items exist from the start of the scope"
-target/lintcheck/sources/rayon-1.5.0/src/iter/map_with.rs:425:9 clippy::items_after_statements "adding items after statements is confusing, since items exist from the start of the scope"
-target/lintcheck/sources/rayon-1.5.0/src/iter/map_with.rs:90:9 clippy::items_after_statements "adding items after statements is confusing, since items exist from the start of the scope"
-target/lintcheck/sources/rayon-1.5.0/src/iter/map_with.rs:96:9 clippy::items_after_statements "adding items after statements is confusing, since items exist from the start of the scope"
-target/lintcheck/sources/rayon-1.5.0/src/iter/mod.rs:1874:24 clippy::trivially_copy_pass_by_ref "this argument (1 byte) is passed by reference, but would be more efficient if passed by value (limit: 8 byte)"
-target/lintcheck/sources/rayon-1.5.0/src/iter/mod.rs:2171:1 clippy::len_without_is_empty "trait `IndexedParallelIterator` has a `len` method but no (possibly inherited) `is_empty` method"
-target/lintcheck/sources/rayon-1.5.0/src/iter/mod.rs:2371:26 clippy::trivially_copy_pass_by_ref "this argument (1 byte) is passed by reference, but would be more efficient if passed by value (limit: 8 byte)"
-target/lintcheck/sources/rayon-1.5.0/src/iter/mod.rs:2411:26 clippy::trivially_copy_pass_by_ref "this argument (1 byte) is passed by reference, but would be more efficient if passed by value (limit: 8 byte)"
-target/lintcheck/sources/rayon-1.5.0/src/iter/mod.rs:82:5 clippy::wildcard_imports "usage of wildcard import"
-target/lintcheck/sources/rayon-1.5.0/src/iter/multizip.rs:1:5 clippy::wildcard_imports "usage of wildcard import"
-target/lintcheck/sources/rayon-1.5.0/src/iter/multizip.rs:2:5 clippy::wildcard_imports "usage of wildcard import"
-target/lintcheck/sources/rayon-1.5.0/src/iter/noop.rs:1:5 clippy::wildcard_imports "usage of wildcard import"
-target/lintcheck/sources/rayon-1.5.0/src/iter/once.rs:1:5 clippy::wildcard_imports "usage of wildcard import"
-target/lintcheck/sources/rayon-1.5.0/src/iter/once.rs:2:5 clippy::wildcard_imports "usage of wildcard import"
-target/lintcheck/sources/rayon-1.5.0/src/iter/panic_fuse.rs:102:9 clippy::items_after_statements "adding items after statements is confusing, since items exist from the start of the scope"
-target/lintcheck/sources/rayon-1.5.0/src/iter/panic_fuse.rs:1:5 clippy::wildcard_imports "usage of wildcard import"
-target/lintcheck/sources/rayon-1.5.0/src/iter/panic_fuse.rs:2:5 clippy::wildcard_imports "usage of wildcard import"
-target/lintcheck/sources/rayon-1.5.0/src/iter/panic_fuse.rs:98:9 clippy::items_after_statements "adding items after statements is confusing, since items exist from the start of the scope"
-target/lintcheck/sources/rayon-1.5.0/src/iter/par_bridge.rs:136:28 clippy::redundant_else "redundant else block"
-target/lintcheck/sources/rayon-1.5.0/src/iter/par_bridge.rs:163:28 clippy::redundant_else "redundant else block"
-target/lintcheck/sources/rayon-1.5.0/src/iter/plumbing/mod.rs:216:58 clippy::doc_markdown "you should put `find_first` between ticks in the documentation"
-target/lintcheck/sources/rayon-1.5.0/src/iter/plumbing/mod.rs:359:5 clippy::items_after_statements "adding items after statements is confusing, since items exist from the start of the scope"
-target/lintcheck/sources/rayon-1.5.0/src/iter/plumbing/mod.rs:364:5 clippy::items_after_statements "adding items after statements is confusing, since items exist from the start of the scope"
-target/lintcheck/sources/rayon-1.5.0/src/iter/plumbing/mod.rs:399:5 clippy::items_after_statements "adding items after statements is confusing, since items exist from the start of the scope"
-target/lintcheck/sources/rayon-1.5.0/src/iter/plumbing/mod.rs:53:19 clippy::doc_markdown "you should put `DoubleEndedIterator` between ticks in the documentation"
-target/lintcheck/sources/rayon-1.5.0/src/iter/plumbing/mod.rs:53:43 clippy::doc_markdown "you should put `ExactSizeIterator` between ticks in the documentation"
-target/lintcheck/sources/rayon-1.5.0/src/iter/plumbing/mod.rs:54:31 clippy::doc_markdown "you should put `IntoIterator` between ticks in the documentation"
-target/lintcheck/sources/rayon-1.5.0/src/iter/plumbing/mod.rs:55:5 clippy::doc_markdown "you should put `IntoIterator` between ticks in the documentation"
-target/lintcheck/sources/rayon-1.5.0/src/iter/positions.rs:1:5 clippy::wildcard_imports "usage of wildcard import"
-target/lintcheck/sources/rayon-1.5.0/src/iter/positions.rs:2:5 clippy::wildcard_imports "usage of wildcard import"
-target/lintcheck/sources/rayon-1.5.0/src/iter/product.rs:1:5 clippy::wildcard_imports "usage of wildcard import"
-target/lintcheck/sources/rayon-1.5.0/src/iter/reduce.rs:1:5 clippy::wildcard_imports "usage of wildcard import"
-target/lintcheck/sources/rayon-1.5.0/src/iter/reduce.rs:67:19 clippy::wrong_self_convention "methods with the following characteristics: (`to_*` and `self` type is `Copy`) usually take `self` by value"
-target/lintcheck/sources/rayon-1.5.0/src/iter/repeat.rs:103:1 clippy::module_name_repetitions "item name starts with its containing module's name"
-target/lintcheck/sources/rayon-1.5.0/src/iter/repeat.rs:1:5 clippy::wildcard_imports "usage of wildcard import"
-target/lintcheck/sources/rayon-1.5.0/src/iter/repeat.rs:2:5 clippy::wildcard_imports "usage of wildcard import"
-target/lintcheck/sources/rayon-1.5.0/src/iter/rev.rs:1:5 clippy::wildcard_imports "usage of wildcard import"
-target/lintcheck/sources/rayon-1.5.0/src/iter/rev.rs:2:5 clippy::wildcard_imports "usage of wildcard import"
-target/lintcheck/sources/rayon-1.5.0/src/iter/rev.rs:63:9 clippy::items_after_statements "adding items after statements is confusing, since items exist from the start of the scope"
-target/lintcheck/sources/rayon-1.5.0/src/iter/rev.rs:68:9 clippy::items_after_statements "adding items after statements is confusing, since items exist from the start of the scope"
-target/lintcheck/sources/rayon-1.5.0/src/iter/skip.rs:2:5 clippy::wildcard_imports "usage of wildcard import"
-target/lintcheck/sources/rayon-1.5.0/src/iter/skip.rs:3:5 clippy::wildcard_imports "usage of wildcard import"
-target/lintcheck/sources/rayon-1.5.0/src/iter/skip.rs:68:9 clippy::items_after_statements "adding items after statements is confusing, since items exist from the start of the scope"
-target/lintcheck/sources/rayon-1.5.0/src/iter/skip.rs:73:9 clippy::items_after_statements "adding items after statements is confusing, since items exist from the start of the scope"
-target/lintcheck/sources/rayon-1.5.0/src/iter/splitter.rs:1:5 clippy::wildcard_imports "usage of wildcard import"
-target/lintcheck/sources/rayon-1.5.0/src/iter/splitter.rs:2:5 clippy::wildcard_imports "usage of wildcard import"
-target/lintcheck/sources/rayon-1.5.0/src/iter/step_by.rs:4:5 clippy::wildcard_imports "usage of wildcard import"
-target/lintcheck/sources/rayon-1.5.0/src/iter/step_by.rs:5:5 clippy::wildcard_imports "usage of wildcard import"
-target/lintcheck/sources/rayon-1.5.0/src/iter/step_by.rs:73:9 clippy::items_after_statements "adding items after statements is confusing, since items exist from the start of the scope"
-target/lintcheck/sources/rayon-1.5.0/src/iter/step_by.rs:79:9 clippy::items_after_statements "adding items after statements is confusing, since items exist from the start of the scope"
-target/lintcheck/sources/rayon-1.5.0/src/iter/sum.rs:1:5 clippy::wildcard_imports "usage of wildcard import"
-target/lintcheck/sources/rayon-1.5.0/src/iter/take.rs:1:5 clippy::wildcard_imports "usage of wildcard import"
-target/lintcheck/sources/rayon-1.5.0/src/iter/take.rs:2:5 clippy::wildcard_imports "usage of wildcard import"
-target/lintcheck/sources/rayon-1.5.0/src/iter/take.rs:67:9 clippy::items_after_statements "adding items after statements is confusing, since items exist from the start of the scope"
-target/lintcheck/sources/rayon-1.5.0/src/iter/take.rs:72:9 clippy::items_after_statements "adding items after statements is confusing, since items exist from the start of the scope"
-target/lintcheck/sources/rayon-1.5.0/src/iter/try_fold.rs:190:1 clippy::module_name_repetitions "item name starts with its containing module's name"
-target/lintcheck/sources/rayon-1.5.0/src/iter/try_fold.rs:1:5 clippy::wildcard_imports "usage of wildcard import"
-target/lintcheck/sources/rayon-1.5.0/src/iter/try_fold.rs:2:5 clippy::wildcard_imports "usage of wildcard import"
-target/lintcheck/sources/rayon-1.5.0/src/iter/try_reduce.rs:1:5 clippy::wildcard_imports "usage of wildcard import"
-target/lintcheck/sources/rayon-1.5.0/src/iter/try_reduce.rs:74:19 clippy::wrong_self_convention "methods with the following characteristics: (`to_*` and `self` type is `Copy`) usually take `self` by value"
-target/lintcheck/sources/rayon-1.5.0/src/iter/try_reduce_with.rs:1:5 clippy::wildcard_imports "usage of wildcard import"
-target/lintcheck/sources/rayon-1.5.0/src/iter/try_reduce_with.rs:69:19 clippy::wrong_self_convention "methods with the following characteristics: (`to_*` and `self` type is `Copy`) usually take `self` by value"
-target/lintcheck/sources/rayon-1.5.0/src/iter/unzip.rs:1:5 clippy::wildcard_imports "usage of wildcard import"
-target/lintcheck/sources/rayon-1.5.0/src/iter/unzip.rs:2:5 clippy::wildcard_imports "usage of wildcard import"
-target/lintcheck/sources/rayon-1.5.0/src/iter/update.rs:1:5 clippy::wildcard_imports "usage of wildcard import"
-target/lintcheck/sources/rayon-1.5.0/src/iter/update.rs:2:5 clippy::wildcard_imports "usage of wildcard import"
-target/lintcheck/sources/rayon-1.5.0/src/iter/update.rs:82:9 clippy::items_after_statements "adding items after statements is confusing, since items exist from the start of the scope"
-target/lintcheck/sources/rayon-1.5.0/src/iter/update.rs:87:9 clippy::items_after_statements "adding items after statements is confusing, since items exist from the start of the scope"
-target/lintcheck/sources/rayon-1.5.0/src/iter/while_some.rs:130:22 clippy::single_match_else "you seem to be trying to use `match` for destructuring a single pattern. Consider using `if let`"
-target/lintcheck/sources/rayon-1.5.0/src/iter/while_some.rs:1:5 clippy::wildcard_imports "usage of wildcard import"
-target/lintcheck/sources/rayon-1.5.0/src/iter/while_some.rs:2:5 clippy::wildcard_imports "usage of wildcard import"
-target/lintcheck/sources/rayon-1.5.0/src/iter/zip.rs:102:9 clippy::items_after_statements "adding items after statements is confusing, since items exist from the start of the scope"
-target/lintcheck/sources/rayon-1.5.0/src/iter/zip.rs:1:5 clippy::wildcard_imports "usage of wildcard import"
-target/lintcheck/sources/rayon-1.5.0/src/iter/zip.rs:2:5 clippy::wildcard_imports "usage of wildcard import"
-target/lintcheck/sources/rayon-1.5.0/src/iter/zip.rs:74:9 clippy::items_after_statements "adding items after statements is confusing, since items exist from the start of the scope"
-target/lintcheck/sources/rayon-1.5.0/src/iter/zip.rs:79:9 clippy::items_after_statements "adding items after statements is confusing, since items exist from the start of the scope"
-target/lintcheck/sources/rayon-1.5.0/src/iter/zip.rs:97:9 clippy::items_after_statements "adding items after statements is confusing, since items exist from the start of the scope"
-target/lintcheck/sources/rayon-1.5.0/src/iter/zip_eq.rs:1:5 clippy::wildcard_imports "usage of wildcard import"
-target/lintcheck/sources/rayon-1.5.0/src/iter/zip_eq.rs:2:5 clippy::wildcard_imports "usage of wildcard import"
-target/lintcheck/sources/rayon-1.5.0/src/option.rs:8:5 clippy::wildcard_imports "usage of wildcard import"
-target/lintcheck/sources/rayon-1.5.0/src/option.rs:9:5 clippy::wildcard_imports "usage of wildcard import"
-target/lintcheck/sources/rayon-1.5.0/src/par_either.rs:1:5 clippy::wildcard_imports "usage of wildcard import"
-target/lintcheck/sources/rayon-1.5.0/src/par_either.rs:3:5 clippy::wildcard_imports "usage of wildcard import"
-target/lintcheck/sources/rayon-1.5.0/src/private.rs:9:1 clippy::module_name_repetitions "item name starts with its containing module's name"
-target/lintcheck/sources/rayon-1.5.0/src/range.rs:19:5 clippy::wildcard_imports "usage of wildcard import"
-target/lintcheck/sources/rayon-1.5.0/src/range.rs:20:5 clippy::wildcard_imports "usage of wildcard import"
-target/lintcheck/sources/rayon-1.5.0/src/range_inclusive.rs:194:9 clippy::range_plus_one "an inclusive range would be more readable"
-target/lintcheck/sources/rayon-1.5.0/src/range_inclusive.rs:194:9 clippy::range_plus_one "an inclusive range would be more readable"
-target/lintcheck/sources/rayon-1.5.0/src/range_inclusive.rs:19:5 clippy::wildcard_imports "usage of wildcard import"
-target/lintcheck/sources/rayon-1.5.0/src/range_inclusive.rs:209:9 clippy::range_plus_one "an inclusive range would be more readable"
-target/lintcheck/sources/rayon-1.5.0/src/range_inclusive.rs:209:9 clippy::range_plus_one "an inclusive range would be more readable"
-target/lintcheck/sources/rayon-1.5.0/src/range_inclusive.rs:20:5 clippy::wildcard_imports "usage of wildcard import"
-target/lintcheck/sources/rayon-1.5.0/src/range_inclusive.rs:231:9 clippy::range_plus_one "an inclusive range would be more readable"
-target/lintcheck/sources/rayon-1.5.0/src/range_inclusive.rs:231:9 clippy::range_plus_one "an inclusive range would be more readable"
-target/lintcheck/sources/rayon-1.5.0/src/result.rs:8:5 clippy::wildcard_imports "usage of wildcard import"
-target/lintcheck/sources/rayon-1.5.0/src/result.rs:9:5 clippy::wildcard_imports "usage of wildcard import"
-target/lintcheck/sources/rayon-1.5.0/src/slice/mergesort.rs:102:5 clippy::items_after_statements "adding items after statements is confusing, since items exist from the start of the scope"
-target/lintcheck/sources/rayon-1.5.0/src/slice/mergesort.rs:109:5 clippy::items_after_statements "adding items after statements is confusing, since items exist from the start of the scope"
-target/lintcheck/sources/rayon-1.5.0/src/slice/mergesort.rs:114:5 clippy::items_after_statements "adding items after statements is confusing, since items exist from the start of the scope"
-target/lintcheck/sources/rayon-1.5.0/src/slice/mergesort.rs:211:5 clippy::items_after_statements "adding items after statements is confusing, since items exist from the start of the scope"
-target/lintcheck/sources/rayon-1.5.0/src/slice/mergesort.rs:217:5 clippy::items_after_statements "adding items after statements is confusing, since items exist from the start of the scope"
-target/lintcheck/sources/rayon-1.5.0/src/slice/mergesort.rs:251:5 clippy::doc_markdown "you should put `TimSort` between ticks in the documentation"
-target/lintcheck/sources/rayon-1.5.0/src/slice/mergesort.rs:252:5 clippy::doc_markdown "you should put bare URLs between `<`/`>` or make a proper Markdown link"
-target/lintcheck/sources/rayon-1.5.0/src/slice/mergesort.rs:286:59 clippy::doc_markdown "you should put `TimSort` between ticks in the documentation"
-target/lintcheck/sources/rayon-1.5.0/src/slice/mergesort.rs:333:24 clippy::redundant_else "redundant else block"
-target/lintcheck/sources/rayon-1.5.0/src/slice/mergesort.rs:513:5 clippy::items_after_statements "adding items after statements is confusing, since items exist from the start of the scope"
-target/lintcheck/sources/rayon-1.5.0/src/slice/mergesort.rs:521:5 clippy::items_after_statements "adding items after statements is confusing, since items exist from the start of the scope"
-target/lintcheck/sources/rayon-1.5.0/src/slice/mergesort.rs:7:5 clippy::wildcard_imports "usage of wildcard import"
-target/lintcheck/sources/rayon-1.5.0/src/slice/mergesort.rs:98:5 clippy::items_after_statements "adding items after statements is confusing, since items exist from the start of the scope"
-target/lintcheck/sources/rayon-1.5.0/src/slice/mod.rs:15:5 clippy::wildcard_imports "usage of wildcard import"
-target/lintcheck/sources/rayon-1.5.0/src/slice/mod.rs:16:5 clippy::wildcard_imports "usage of wildcard import"
-target/lintcheck/sources/rayon-1.5.0/src/slice/mod.rs:17:5 clippy::wildcard_imports "usage of wildcard import"
-target/lintcheck/sources/rayon-1.5.0/src/slice/mod.rs:25:1 clippy::module_name_repetitions "item name ends with its containing module's name"
-target/lintcheck/sources/rayon-1.5.0/src/slice/mod.rs:657:5 clippy::must_use_candidate "this method could have a `#[must_use]` attribute"
-target/lintcheck/sources/rayon-1.5.0/src/slice/mod.rs:971:5 clippy::must_use_candidate "this method could have a `#[must_use]` attribute"
-target/lintcheck/sources/rayon-1.5.0/src/slice/quicksort.rs:230:36 clippy::doc_markdown "you should put `BlockQuicksort` between ticks in the documentation"
-target/lintcheck/sources/rayon-1.5.0/src/slice/quicksort.rs:233:1 clippy::too_many_lines "this function has too many lines (117/100)"
-target/lintcheck/sources/rayon-1.5.0/src/slice/quicksort.rs:258:26 clippy::unseparated_literal_suffix "integer type suffix should be separated by an underscore"
-target/lintcheck/sources/rayon-1.5.0/src/slice/quicksort.rs:265:26 clippy::unseparated_literal_suffix "integer type suffix should be separated by an underscore"
-target/lintcheck/sources/rayon-1.5.0/src/slice/quicksort.rs:268:5 clippy::items_after_statements "adding items after statements is confusing, since items exist from the start of the scope"
-target/lintcheck/sources/rayon-1.5.0/src/slice/quicksort.rs:308:30 clippy::cast_possible_truncation "casting `usize` to `u8` may truncate the value"
-target/lintcheck/sources/rayon-1.5.0/src/slice/quicksort.rs:325:30 clippy::cast_possible_truncation "casting `usize` to `u8` may truncate the value"
-target/lintcheck/sources/rayon-1.5.0/src/slice/quicksort.rs:393:36 clippy::cast_possible_wrap "casting `u8` to `isize` may wrap around the value on targets with 32-bit wide pointers"
-target/lintcheck/sources/rayon-1.5.0/src/slice/quicksort.rs:405:40 clippy::cast_possible_wrap "casting `u8` to `isize` may wrap around the value on targets with 32-bit wide pointers"
-target/lintcheck/sources/rayon-1.5.0/src/slice/quicksort.rs:430:14 clippy::shadow_unrelated "`pivot` is being shadowed"
-target/lintcheck/sources/rayon-1.5.0/src/slice/quicksort.rs:439:13 clippy::shadow_unrelated "`pivot` is being shadowed"
-target/lintcheck/sources/rayon-1.5.0/src/slice/quicksort.rs:482:10 clippy::shadow_unrelated "`pivot` is being shadowed"
-target/lintcheck/sources/rayon-1.5.0/src/slice/quicksort.rs:491:9 clippy::shadow_unrelated "`pivot` is being shadowed"
-target/lintcheck/sources/rayon-1.5.0/src/slice/quicksort.rs:534:26 clippy::cast_possible_truncation "casting `usize` to `u32` may truncate the value on targets with 64-bit wide pointers"
-target/lintcheck/sources/rayon-1.5.0/src/slice/quicksort.rs:545:17 clippy::cast_possible_truncation "casting `u64` to `usize` may truncate the value on targets with 32-bit wide pointers"
-target/lintcheck/sources/rayon-1.5.0/src/slice/quicksort.rs:588:17 clippy::identity_op "the operation is ineffective. Consider reducing it to `len / 4`"
-target/lintcheck/sources/rayon-1.5.0/src/slice/quicksort.rs:716:14 clippy::shadow_unrelated "`pivot` is being shadowed"
-target/lintcheck/sources/rayon-1.5.0/src/split_producer.rs:56:16 clippy::option_if_let_else "use Option::map_or_else instead of an if let/else"
-target/lintcheck/sources/rayon-1.5.0/src/split_producer.rs:92:9 clippy::option_if_let_else "use Option::map_or instead of an if let/else"
-target/lintcheck/sources/rayon-1.5.0/src/str.rs:16:5 clippy::wildcard_imports "usage of wildcard import"
-target/lintcheck/sources/rayon-1.5.0/src/str.rs:17:5 clippy::wildcard_imports "usage of wildcard import"
-target/lintcheck/sources/rayon-1.5.0/src/str.rs:18:5 clippy::wildcard_imports "usage of wildcard import"
-target/lintcheck/sources/rayon-1.5.0/src/str.rs:25:5 clippy::cast_possible_wrap "casting `u8` to `i8` may wrap around the value"
-target/lintcheck/sources/rayon-1.5.0/src/str.rs:715:9 clippy::manual_strip "stripping a suffix manually"
-target/lintcheck/sources/rayon-1.5.0/src/string.rs:5:5 clippy::wildcard_imports "usage of wildcard import"
-target/lintcheck/sources/rayon-1.5.0/src/vec.rs:137:12 clippy::len_zero "length comparison to zero"
-target/lintcheck/sources/rayon-1.5.0/src/vec.rs:8:5 clippy::wildcard_imports "usage of wildcard import"
-target/lintcheck/sources/rayon-1.5.0/src/vec.rs:9:5 clippy::wildcard_imports "usage of wildcard import"
-target/lintcheck/sources/regex-1.3.2/src/backtrack.rs:100:13 clippy::redundant_field_names "redundant field names in struct initialization"
-target/lintcheck/sources/regex-1.3.2/src/backtrack.rs:133:17 clippy::same_item_push "it looks like the same item is being pushed into this Vec"
-target/lintcheck/sources/regex-1.3.2/src/backtrack.rs:145:20 clippy::if_not_else "unnecessary boolean `not` operation"
-target/lintcheck/sources/regex-1.3.2/src/backtrack.rs:199:13 clippy::enum_glob_use "usage of wildcard import for enum variants"
-target/lintcheck/sources/regex-1.3.2/src/backtrack.rs:223:29 clippy::redundant_field_names "redundant field names in struct initialization"
-target/lintcheck/sources/regex-1.3.2/src/backtrack.rs:230:66 clippy::redundant_field_names "redundant field names in struct initialization"
-target/lintcheck/sources/regex-1.3.2/src/backtrack.rs:284:21 clippy::cast_lossless "casting `u32` to `u64` may become silently lossy if you later change the type"
-target/lintcheck/sources/regex-1.3.2/src/backtrack.rs:287:5 clippy::cast_possible_truncation "casting `usize` to `u32` may truncate the value on targets with 64-bit wide pointers"
-target/lintcheck/sources/regex-1.3.2/src/backtrack.rs:97:13 clippy::redundant_field_names "redundant field names in struct initialization"
-target/lintcheck/sources/regex-1.3.2/src/backtrack.rs:98:13 clippy::redundant_field_names "redundant field names in struct initialization"
-target/lintcheck/sources/regex-1.3.2/src/backtrack.rs:99:13 clippy::redundant_field_names "redundant field names in struct initialization"
-target/lintcheck/sources/regex-1.3.2/src/compile.rs:1005:32 clippy::unreadable_literal "long literal lacking separators"
-target/lintcheck/sources/regex-1.3.2/src/compile.rs:1006:21 clippy::unreadable_literal "long literal lacking separators"
-target/lintcheck/sources/regex-1.3.2/src/compile.rs:1008:18 clippy::cast_lossless "casting `u8` to `u64` may become silently lossy if you later change the type"
-target/lintcheck/sources/regex-1.3.2/src/compile.rs:1009:18 clippy::cast_lossless "casting `u8` to `u64` may become silently lossy if you later change the type"
-target/lintcheck/sources/regex-1.3.2/src/compile.rs:1010:9 clippy::cast_possible_truncation "casting `u64` to `usize` may truncate the value on targets with 32-bit wide pointers"
-target/lintcheck/sources/regex-1.3.2/src/compile.rs:102:5 clippy::must_use_candidate "this method could have a `#[must_use]` attribute"
-target/lintcheck/sources/regex-1.3.2/src/compile.rs:1037:37 clippy::cast_possible_truncation "casting `u16` to `u8` may truncate the value"
-target/lintcheck/sources/regex-1.3.2/src/compile.rs:1037:55 clippy::cast_possible_truncation "casting `u16` to `u8` may truncate the value"
-target/lintcheck/sources/regex-1.3.2/src/compile.rs:1040:28 clippy::cast_possible_truncation "casting `u16` to `u8` may truncate the value"
-target/lintcheck/sources/regex-1.3.2/src/compile.rs:1040:38 clippy::cast_possible_truncation "casting `u16` to `u8` may truncate the value"
-target/lintcheck/sources/regex-1.3.2/src/compile.rs:1051:25 clippy::unseparated_literal_suffix "integer type suffix should be separated by an underscore"
-target/lintcheck/sources/regex-1.3.2/src/compile.rs:1071:8 clippy::cast_lossless "casting `u32` to `u64` may become silently lossy if you later change the type"
-target/lintcheck/sources/regex-1.3.2/src/compile.rs:112:5 clippy::missing_errors_doc "docs for function returning `Result` missing `# Errors` section"
-target/lintcheck/sources/regex-1.3.2/src/compile.rs:154:30 clippy::redundant_closure_for_method_calls "redundant closure"
-target/lintcheck/sources/regex-1.3.2/src/compile.rs:156:30 clippy::redundant_closure_for_method_calls "redundant closure"
-target/lintcheck/sources/regex-1.3.2/src/compile.rs:185:5 clippy::unnecessary_wraps "this function's return value is unnecessarily wrapped by `Result`"
-target/lintcheck/sources/regex-1.3.2/src/compile.rs:187:40 clippy::redundant_closure_for_method_calls "redundant closure"
-target/lintcheck/sources/regex-1.3.2/src/compile.rs:201:53 clippy::doc_markdown "you should put `MaybeInsts` between ticks in the documentation"
-target/lintcheck/sources/regex-1.3.2/src/compile.rs:241:63 clippy::doc_markdown "you should put `c_concat` between ticks in the documentation"
-target/lintcheck/sources/regex-1.3.2/src/compile.rs:245:5 clippy::too_many_lines "this function has too many lines (111/100)"
-target/lintcheck/sources/regex-1.3.2/src/compile.rs:247:13 clippy::enum_glob_use "usage of wildcard import for enum variants"
-target/lintcheck/sources/regex-1.3.2/src/compile.rs:373:24 clippy::redundant_field_names "redundant field names in struct initialization"
-target/lintcheck/sources/regex-1.3.2/src/compile.rs:373:36 clippy::redundant_field_names "redundant field names in struct initialization"
-target/lintcheck/sources/regex-1.3.2/src/compile.rs:378:12 clippy::if_not_else "unnecessary boolean `not` operation"
-target/lintcheck/sources/regex-1.3.2/src/compile.rs:400:37 clippy::redundant_field_names "redundant field names in struct initialization"
-target/lintcheck/sources/regex-1.3.2/src/compile.rs:407:51 clippy::redundant_field_names "redundant field names in struct initialization"
-target/lintcheck/sources/regex-1.3.2/src/compile.rs:409:24 clippy::redundant_field_names "redundant field names in struct initialization"
-target/lintcheck/sources/regex-1.3.2/src/compile.rs:417:5 clippy::unnecessary_wraps "this function's return value is unnecessarily wrapped by `Result`"
-target/lintcheck/sources/regex-1.3.2/src/compile.rs:42:5 clippy::must_use_candidate "this method could have a `#[must_use]` attribute"
-target/lintcheck/sources/regex-1.3.2/src/compile.rs:42:5 clippy::new_without_default "you should consider adding a `Default` implementation for `compile::Compiler`"
-target/lintcheck/sources/regex-1.3.2/src/compile.rs:444:5 clippy::unnecessary_wraps "this function's return value is unnecessarily wrapped by `Result`"
-target/lintcheck/sources/regex-1.3.2/src/compile.rs:445:57 clippy::redundant_field_names "redundant field names in struct initialization"
-target/lintcheck/sources/regex-1.3.2/src/compile.rs:446:20 clippy::redundant_field_names "redundant field names in struct initialization"
-target/lintcheck/sources/regex-1.3.2/src/compile.rs:466:20 clippy::redundant_field_names "redundant field names in struct initialization"
-target/lintcheck/sources/regex-1.3.2/src/compile.rs:466:32 clippy::redundant_field_names "redundant field names in struct initialization"
-target/lintcheck/sources/regex-1.3.2/src/compile.rs:519:13 clippy::enum_glob_use "usage of wildcard import for enum variants"
-target/lintcheck/sources/regex-1.3.2/src/compile.rs:55:57 clippy::doc_markdown "you should put `size_limit` between ticks in the documentation"
-target/lintcheck/sources/regex-1.3.2/src/compile.rs:58:5 clippy::must_use_candidate "this method could have a `#[must_use]` attribute"
-target/lintcheck/sources/regex-1.3.2/src/compile.rs:748:41 clippy::redundant_field_names "redundant field names in struct initialization"
-target/lintcheck/sources/regex-1.3.2/src/compile.rs:74:5 clippy::must_use_candidate "this method could have a `#[must_use]` attribute"
-target/lintcheck/sources/regex-1.3.2/src/compile.rs:751:54 clippy::redundant_field_names "redundant field names in struct initialization"
-target/lintcheck/sources/regex-1.3.2/src/compile.rs:765:41 clippy::redundant_field_names "redundant field names in struct initialization"
-target/lintcheck/sources/regex-1.3.2/src/compile.rs:765:55 clippy::redundant_field_names "redundant field names in struct initialization"
-target/lintcheck/sources/regex-1.3.2/src/compile.rs:825:39 clippy::redundant_field_names "redundant field names in struct initialization"
-target/lintcheck/sources/regex-1.3.2/src/compile.rs:825:51 clippy::redundant_field_names "redundant field names in struct initialization"
-target/lintcheck/sources/regex-1.3.2/src/compile.rs:828:49 clippy::redundant_field_names "redundant field names in struct initialization"
-target/lintcheck/sources/regex-1.3.2/src/compile.rs:828:61 clippy::redundant_field_names "redundant field names in struct initialization"
-target/lintcheck/sources/regex-1.3.2/src/compile.rs:830:59 clippy::redundant_field_names "redundant field names in struct initialization"
-target/lintcheck/sources/regex-1.3.2/src/compile.rs:830:71 clippy::redundant_field_names "redundant field names in struct initialization"
-target/lintcheck/sources/regex-1.3.2/src/compile.rs:832:43 clippy::redundant_field_names "redundant field names in struct initialization"
-target/lintcheck/sources/regex-1.3.2/src/compile.rs:835:41 clippy::redundant_field_names "redundant field names in struct initialization"
-target/lintcheck/sources/regex-1.3.2/src/compile.rs:835:53 clippy::redundant_field_names "redundant field names in struct initialization"
-target/lintcheck/sources/regex-1.3.2/src/compile.rs:835:67 clippy::redundant_field_names "redundant field names in struct initialization"
-target/lintcheck/sources/regex-1.3.2/src/compile.rs:83:5 clippy::must_use_candidate "this method could have a `#[must_use]` attribute"
-target/lintcheck/sources/regex-1.3.2/src/compile.rs:896:5 clippy::unnecessary_wraps "this function's return value is unnecessarily wrapped by `Result`"
-target/lintcheck/sources/regex-1.3.2/src/compile.rs:905:17 clippy::redundant_field_names "redundant field names in struct initialization"
-target/lintcheck/sources/regex-1.3.2/src/compile.rs:953:17 clippy::doc_markdown "you should put `HashMap` between ticks in the documentation"
-target/lintcheck/sources/regex-1.3.2/src/compile.rs:95:5 clippy::must_use_candidate "this method could have a `#[must_use]` attribute"
-target/lintcheck/sources/regex-1.3.2/src/compile.rs:980:26 clippy::unseparated_literal_suffix "integer type suffix should be separated by an underscore"
-target/lintcheck/sources/regex-1.3.2/src/compile.rs:994:44 clippy::redundant_field_names "redundant field names in struct initialization"
-target/lintcheck/sources/regex-1.3.2/src/compile.rs:994:54 clippy::redundant_field_names "redundant field names in struct initialization"
-target/lintcheck/sources/regex-1.3.2/src/dfa.rs:1007:17 clippy::similar_names "binding's name is too similar to existing binding"
-target/lintcheck/sources/regex-1.3.2/src/dfa.rs:1010:22 clippy::similar_names "binding's name is too similar to existing binding"
-target/lintcheck/sources/regex-1.3.2/src/dfa.rs:1059:13 clippy::enum_glob_use "usage of wildcard import for enum variants"
-target/lintcheck/sources/regex-1.3.2/src/dfa.rs:1060:13 clippy::enum_glob_use "usage of wildcard import for enum variants"
-target/lintcheck/sources/regex-1.3.2/src/dfa.rs:1084:38 clippy::cast_possible_truncation "casting `usize` to `u32` may truncate the value on targets with 64-bit wide pointers"
-target/lintcheck/sources/regex-1.3.2/src/dfa.rs:1087:38 clippy::cast_possible_truncation "casting `usize` to `u32` may truncate the value on targets with 64-bit wide pointers"
-target/lintcheck/sources/regex-1.3.2/src/dfa.rs:1090:38 clippy::cast_possible_truncation "casting `usize` to `u32` may truncate the value on targets with 64-bit wide pointers"
-target/lintcheck/sources/regex-1.3.2/src/dfa.rs:1093:38 clippy::cast_possible_truncation "casting `usize` to `u32` may truncate the value on targets with 64-bit wide pointers"
-target/lintcheck/sources/regex-1.3.2/src/dfa.rs:1096:38 clippy::cast_possible_truncation "casting `usize` to `u32` may truncate the value on targets with 64-bit wide pointers"
-target/lintcheck/sources/regex-1.3.2/src/dfa.rs:1101:38 clippy::cast_possible_truncation "casting `usize` to `u32` may truncate the value on targets with 64-bit wide pointers"
-target/lintcheck/sources/regex-1.3.2/src/dfa.rs:1104:38 clippy::cast_possible_truncation "casting `usize` to `u32` may truncate the value on targets with 64-bit wide pointers"
-target/lintcheck/sources/regex-1.3.2/src/dfa.rs:1107:38 clippy::cast_possible_truncation "casting `usize` to `u32` may truncate the value on targets with 64-bit wide pointers"
-target/lintcheck/sources/regex-1.3.2/src/dfa.rs:1117:30 clippy::cast_possible_truncation "casting `usize` to `u32` may truncate the value on targets with 64-bit wide pointers"
-target/lintcheck/sources/regex-1.3.2/src/dfa.rs:1120:47 clippy::cast_possible_truncation "casting `usize` to `u32` may truncate the value on targets with 64-bit wide pointers"
-target/lintcheck/sources/regex-1.3.2/src/dfa.rs:1121:30 clippy::cast_possible_truncation "casting `usize` to `u32` may truncate the value on targets with 64-bit wide pointers"
-target/lintcheck/sources/regex-1.3.2/src/dfa.rs:1129:13 clippy::doc_markdown "you should put `is_match` between ticks in the documentation"
-target/lintcheck/sources/regex-1.3.2/src/dfa.rs:1134:13 clippy::doc_markdown "you should put `is_match` between ticks in the documentation"
-target/lintcheck/sources/regex-1.3.2/src/dfa.rs:1185:68 clippy::doc_markdown "you should put `is_match` between ticks in the documentation"
-target/lintcheck/sources/regex-1.3.2/src/dfa.rs:1193:13 clippy::enum_glob_use "usage of wildcard import for enum variants"
-target/lintcheck/sources/regex-1.3.2/src/dfa.rs:1205:13 clippy::mem_replace_with_default "replacing a value of type `T` with `T::default()` is better expressed using `std::mem::take`"
-target/lintcheck/sources/regex-1.3.2/src/dfa.rs:1244:50 clippy::doc_markdown "you should put `current_state` between ticks in the documentation"
-target/lintcheck/sources/regex-1.3.2/src/dfa.rs:1338:58 clippy::doc_markdown "you should put `STATE_DEAD` between ticks in the documentation"
-target/lintcheck/sources/regex-1.3.2/src/dfa.rs:1339:9 clippy::doc_markdown "you should put `STATE_UNKNOWN` between ticks in the documentation"
-target/lintcheck/sources/regex-1.3.2/src/dfa.rs:1366:25 clippy::doc_markdown "you should put `STATE_DEAD` between ticks in the documentation"
-target/lintcheck/sources/regex-1.3.2/src/dfa.rs:1366:46 clippy::doc_markdown "you should put `STATE_UNKNOWN` between ticks in the documentation"
-target/lintcheck/sources/regex-1.3.2/src/dfa.rs:1367:41 clippy::inline_always "you have declared `#[inline(always)]` on `start_state`. This is usually a bad idea"
-target/lintcheck/sources/regex-1.3.2/src/dfa.rs:1380:14 clippy::identity_op "the operation is ineffective. Consider reducing it to `(empty_flags.start as u8)`"
-target/lintcheck/sources/regex-1.3.2/src/dfa.rs:1388:15 clippy::match_on_vec_items "indexing into a vector may panic"
-target/lintcheck/sources/regex-1.3.2/src/dfa.rs:1412:20 clippy::unused_self "unused `self` argument"
-target/lintcheck/sources/regex-1.3.2/src/dfa.rs:1438:9 clippy::unused_self "unused `self` argument"
-target/lintcheck/sources/regex-1.3.2/src/dfa.rs:1472:9 clippy::doc_markdown "you should put `StatePtr` between ticks in the documentation"
-target/lintcheck/sources/regex-1.3.2/src/dfa.rs:1490:54 clippy::cast_possible_truncation "casting `i32` to `u8` may truncate the value"
-target/lintcheck/sources/regex-1.3.2/src/dfa.rs:1490:54 clippy::cast_sign_loss "casting `i32` to `u8` may lose the sign of the value"
-target/lintcheck/sources/regex-1.3.2/src/dfa.rs:1521:20 clippy::doc_markdown "you should put `num_byte_classes` between ticks in the documentation"
-target/lintcheck/sources/regex-1.3.2/src/dfa.rs:1529:41 clippy::inline_always "you have declared `#[inline(always)]` on `byte_class`. This is usually a bad idea"
-target/lintcheck/sources/regex-1.3.2/src/dfa.rs:1537:14 clippy::doc_markdown "you should put `byte_class` between ticks in the documentation"
-target/lintcheck/sources/regex-1.3.2/src/dfa.rs:1538:41 clippy::inline_always "you have declared `#[inline(always)]` on `u8_class`. This is usually a bad idea"
-target/lintcheck/sources/regex-1.3.2/src/dfa.rs:1562:18 clippy::doc_markdown "you should put `STATE_START` between ticks in the documentation"
-target/lintcheck/sources/regex-1.3.2/src/dfa.rs:1614:13 clippy::redundant_field_names "redundant field names in struct initialization"
-target/lintcheck/sources/regex-1.3.2/src/dfa.rs:1651:38 clippy::redundant_field_names "redundant field names in struct initialization"
-target/lintcheck/sources/regex-1.3.2/src/dfa.rs:1700:17 clippy::trivially_copy_pass_by_ref "this argument (1 byte) is passed by reference, but would be more efficient if passed by value (limit: 8 byte)"
-target/lintcheck/sources/regex-1.3.2/src/dfa.rs:1701:18 clippy::unusual_byte_groupings "digits of hex or binary literal not grouped by four"
-target/lintcheck/sources/regex-1.3.2/src/dfa.rs:1705:19 clippy::unusual_byte_groupings "digits of hex or binary literal not grouped by four"
-target/lintcheck/sources/regex-1.3.2/src/dfa.rs:1708:16 clippy::trivially_copy_pass_by_ref "this argument (1 byte) is passed by reference, but would be more efficient if passed by value (limit: 8 byte)"
-target/lintcheck/sources/regex-1.3.2/src/dfa.rs:1709:18 clippy::unusual_byte_groupings "digits of hex or binary literal not grouped by four"
-target/lintcheck/sources/regex-1.3.2/src/dfa.rs:1713:19 clippy::unusual_byte_groupings "digits of hex or binary literal not grouped by four"
-target/lintcheck/sources/regex-1.3.2/src/dfa.rs:1716:18 clippy::trivially_copy_pass_by_ref "this argument (1 byte) is passed by reference, but would be more efficient if passed by value (limit: 8 byte)"
-target/lintcheck/sources/regex-1.3.2/src/dfa.rs:1717:18 clippy::unusual_byte_groupings "digits of hex or binary literal not grouped by four"
-target/lintcheck/sources/regex-1.3.2/src/dfa.rs:1721:19 clippy::unusual_byte_groupings "digits of hex or binary literal not grouped by four"
-target/lintcheck/sources/regex-1.3.2/src/dfa.rs:1727:14 clippy::cast_lossless "casting `u8` to `u16` may become silently lossy if you later change the type"
-target/lintcheck/sources/regex-1.3.2/src/dfa.rs:1732:15 clippy::trivially_copy_pass_by_ref "this argument (2 byte) is passed by reference, but would be more efficient if passed by value (limit: 8 byte)"
-target/lintcheck/sources/regex-1.3.2/src/dfa.rs:1736:22 clippy::trivially_copy_pass_by_ref "this argument (2 byte) is passed by reference, but would be more efficient if passed by value (limit: 8 byte)"
-target/lintcheck/sources/regex-1.3.2/src/dfa.rs:1741:9 clippy::match_like_matches_macro "match expression looks like `matches!` macro"
-target/lintcheck/sources/regex-1.3.2/src/dfa.rs:1747:16 clippy::trivially_copy_pass_by_ref "this argument (2 byte) is passed by reference, but would be more efficient if passed by value (limit: 8 byte)"
-target/lintcheck/sources/regex-1.3.2/src/dfa.rs:1751:18 clippy::cast_possible_truncation "casting `u16` to `u8` may truncate the value"
-target/lintcheck/sources/regex-1.3.2/src/dfa.rs:1815:38 clippy::cast_possible_truncation "casting `usize` to `u8` may truncate the value"
-target/lintcheck/sources/regex-1.3.2/src/dfa.rs:1821:21 clippy::cast_lossless "casting `u32` to `u64` may become silently lossy if you later change the type"
-target/lintcheck/sources/regex-1.3.2/src/dfa.rs:1824:5 clippy::cast_possible_truncation "casting `usize` to `u32` may truncate the value on targets with 64-bit wide pointers"
-target/lintcheck/sources/regex-1.3.2/src/dfa.rs:1848:5 clippy::doc_markdown "you should put bare URLs between `<`/`>` or make a proper Markdown link"
-target/lintcheck/sources/regex-1.3.2/src/dfa.rs:1850:18 clippy::cast_sign_loss "casting `i32` to `u32` may lose the sign of the value"
-target/lintcheck/sources/regex-1.3.2/src/dfa.rs:1857:5 clippy::doc_markdown "you should put bare URLs between `<`/`>` or make a proper Markdown link"
-target/lintcheck/sources/regex-1.3.2/src/dfa.rs:1860:17 clippy::cast_possible_wrap "casting `u32` to `i32` may wrap around the value"
-target/lintcheck/sources/regex-1.3.2/src/dfa.rs:1867:5 clippy::doc_markdown "you should put bare URLs between `<`/`>` or make a proper Markdown link"
-target/lintcheck/sources/regex-1.3.2/src/dfa.rs:1870:19 clippy::cast_possible_truncation "casting `u32` to `u8` may truncate the value"
-target/lintcheck/sources/regex-1.3.2/src/dfa.rs:1873:15 clippy::cast_possible_truncation "casting `u32` to `u8` may truncate the value"
-target/lintcheck/sources/regex-1.3.2/src/dfa.rs:1876:5 clippy::doc_markdown "you should put bare URLs between `<`/`>` or make a proper Markdown link"
-target/lintcheck/sources/regex-1.3.2/src/dfa.rs:1882:26 clippy::cast_lossless "casting `u8` to `u32` may become silently lossy if you later change the type"
-target/lintcheck/sources/regex-1.3.2/src/dfa.rs:1884:15 clippy::cast_lossless "casting `u8` to `u32` may become silently lossy if you later change the type"
-target/lintcheck/sources/regex-1.3.2/src/dfa.rs:277:17 clippy::cast_possible_wrap "casting `u32` to `i32` may wrap around the value"
-target/lintcheck/sources/regex-1.3.2/src/dfa.rs:277:31 clippy::cast_possible_wrap "casting `u32` to `i32` may wrap around the value"
-target/lintcheck/sources/regex-1.3.2/src/dfa.rs:295:20 clippy::cast_possible_truncation "casting `usize` to `i32` may truncate the value on targets with 64-bit wide pointers"
-target/lintcheck/sources/regex-1.3.2/src/dfa.rs:295:20 clippy::cast_possible_wrap "casting `usize` to `i32` may wrap around the value on targets with 32-bit wide pointers"
-target/lintcheck/sources/regex-1.3.2/src/dfa.rs:299:21 clippy::cast_sign_loss "casting `i32` to `usize` may lose the sign of the value"
-target/lintcheck/sources/regex-1.3.2/src/dfa.rs:34:46 clippy::doc_markdown "you should put bare URLs between `<`/`>` or make a proper Markdown link"
-target/lintcheck/sources/regex-1.3.2/src/dfa.rs:398:1 clippy::struct_excessive_bools "more than 3 bools in a struct"
-target/lintcheck/sources/regex-1.3.2/src/dfa.rs:446:41 clippy::inline_always "you have declared `#[inline(always)]` on `forward`. This is usually a bad idea"
-target/lintcheck/sources/regex-1.3.2/src/dfa.rs:457:13 clippy::redundant_field_names "redundant field names in struct initialization"
-target/lintcheck/sources/regex-1.3.2/src/dfa.rs:459:13 clippy::redundant_field_names "redundant field names in struct initialization"
-target/lintcheck/sources/regex-1.3.2/src/dfa.rs:460:13 clippy::redundant_field_names "redundant field names in struct initialization"
-target/lintcheck/sources/regex-1.3.2/src/dfa.rs:476:41 clippy::inline_always "you have declared `#[inline(always)]` on `reverse`. This is usually a bad idea"
-target/lintcheck/sources/regex-1.3.2/src/dfa.rs:487:13 clippy::redundant_field_names "redundant field names in struct initialization"
-target/lintcheck/sources/regex-1.3.2/src/dfa.rs:489:13 clippy::redundant_field_names "redundant field names in struct initialization"
-target/lintcheck/sources/regex-1.3.2/src/dfa.rs:490:13 clippy::redundant_field_names "redundant field names in struct initialization"
-target/lintcheck/sources/regex-1.3.2/src/dfa.rs:506:41 clippy::inline_always "you have declared `#[inline(always)]` on `forward_many`. This is usually a bad idea"
-target/lintcheck/sources/regex-1.3.2/src/dfa.rs:518:13 clippy::redundant_field_names "redundant field names in struct initialization"
-target/lintcheck/sources/regex-1.3.2/src/dfa.rs:520:13 clippy::redundant_field_names "redundant field names in struct initialization"
-target/lintcheck/sources/regex-1.3.2/src/dfa.rs:554:41 clippy::inline_always "you have declared `#[inline(always)]` on `exec_at`. This is usually a bad idea"
-target/lintcheck/sources/regex-1.3.2/src/dfa.rs:555:5 clippy::too_many_lines "this function has too many lines (101/100)"
-target/lintcheck/sources/regex-1.3.2/src/dfa.rs:58:9 clippy::enum_glob_use "usage of wildcard import for enum variants"
-target/lintcheck/sources/regex-1.3.2/src/dfa.rs:667:21 clippy::similar_names "binding's name is too similar to existing binding"
-target/lintcheck/sources/regex-1.3.2/src/dfa.rs:747:41 clippy::inline_always "you have declared `#[inline(always)]` on `exec_at_reverse`. This is usually a bad idea"
-target/lintcheck/sources/regex-1.3.2/src/dfa.rs:795:21 clippy::similar_names "binding's name is too similar to existing binding"
-target/lintcheck/sources/regex-1.3.2/src/dfa.rs:848:9 clippy::doc_markdown "you should put `next_si` between ticks in the documentation"
-target/lintcheck/sources/regex-1.3.2/src/dfa.rs:852:41 clippy::inline_always "you have declared `#[inline(always)]` on `next_si`. This is usually a bad idea"
-target/lintcheck/sources/regex-1.3.2/src/dfa.rs:885:12 clippy::doc_markdown "you should put `STATE_DEAD` between ticks in the documentation"
-target/lintcheck/sources/regex-1.3.2/src/dfa.rs:889:9 clippy::doc_markdown "you should put `STATE_UNKNOWN` between ticks in the documentation"
-target/lintcheck/sources/regex-1.3.2/src/dfa.rs:897:13 clippy::enum_glob_use "usage of wildcard import for enum variants"
-target/lintcheck/sources/regex-1.3.2/src/dfa.rs:979:29 clippy::cast_possible_truncation "casting `usize` to `u32` may truncate the value on targets with 64-bit wide pointers"
-target/lintcheck/sources/regex-1.3.2/src/error.rs:6:1 clippy::manual_non_exhaustive "this seems like a manual implementation of the non-exhaustive pattern"
-target/lintcheck/sources/regex-1.3.2/src/exec.rs:1000:14 clippy::doc_markdown "you should put `captures_nfa` between ticks in the documentation"
-target/lintcheck/sources/regex-1.3.2/src/exec.rs:100:1 clippy::module_name_repetitions "item name starts with its containing module's name"
-target/lintcheck/sources/regex-1.3.2/src/exec.rs:1028:5 clippy::too_many_arguments "this function has too many arguments (9/7)"
-target/lintcheck/sources/regex-1.3.2/src/exec.rs:1039:13 clippy::enum_glob_use "usage of wildcard import for enum variants"
-target/lintcheck/sources/regex-1.3.2/src/exec.rs:1144:13 clippy::enum_glob_use "usage of wildcard import for enum variants"
-target/lintcheck/sources/regex-1.3.2/src/exec.rs:1179:26 clippy::match_same_arms "this `match` has identical arm bodies"
-target/lintcheck/sources/regex-1.3.2/src/exec.rs:122:5 clippy::must_use_candidate "this method could have a `#[must_use]` attribute"
-target/lintcheck/sources/regex-1.3.2/src/exec.rs:1250:41 clippy::inline_always "you have declared `#[inline(always)]` on `searcher`. This is usually a bad idea"
-target/lintcheck/sources/regex-1.3.2/src/exec.rs:1260:41 clippy::inline_always "you have declared `#[inline(always)]` on `searcher_str`. This is usually a bad idea"
-target/lintcheck/sources/regex-1.3.2/src/exec.rs:1270:17 clippy::doc_markdown "you should put `RegexSet` between ticks in the documentation"
-target/lintcheck/sources/regex-1.3.2/src/exec.rs:1280:17 clippy::doc_markdown "you should put `RegexSet` between ticks in the documentation"
-target/lintcheck/sources/regex-1.3.2/src/exec.rs:137:9 clippy::field_reassign_with_default "field assignment outside of initializer for an instance created with Default::default()"
-target/lintcheck/sources/regex-1.3.2/src/exec.rs:142:5 clippy::must_use_candidate "this method could have a `#[must_use]` attribute"
-target/lintcheck/sources/regex-1.3.2/src/exec.rs:158:5 clippy::must_use_candidate "this method could have a `#[must_use]` attribute"
-target/lintcheck/sources/regex-1.3.2/src/exec.rs:168:5 clippy::must_use_candidate "this method could have a `#[must_use]` attribute"
-target/lintcheck/sources/regex-1.3.2/src/exec.rs:181:5 clippy::must_use_candidate "this method could have a `#[must_use]` attribute"
-target/lintcheck/sources/regex-1.3.2/src/exec.rs:195:5 clippy::must_use_candidate "this method could have a `#[must_use]` attribute"
-target/lintcheck/sources/regex-1.3.2/src/exec.rs:204:5 clippy::must_use_candidate "this method could have a `#[must_use]` attribute"
-target/lintcheck/sources/regex-1.3.2/src/exec.rs:210:5 clippy::must_use_candidate "this method could have a `#[must_use]` attribute"
-target/lintcheck/sources/regex-1.3.2/src/exec.rs:245:62 clippy::if_same_then_else "this `if` has identical blocks"
-target/lintcheck/sources/regex-1.3.2/src/exec.rs:251:21 clippy::if_not_else "unnecessary boolean `not` operation"
-target/lintcheck/sources/regex-1.3.2/src/exec.rs:262:60 clippy::if_same_then_else "this `if` has identical blocks"
-target/lintcheck/sources/regex-1.3.2/src/exec.rs:268:21 clippy::if_not_else "unnecessary boolean `not` operation"
-target/lintcheck/sources/regex-1.3.2/src/exec.rs:278:13 clippy::redundant_field_names "redundant field names in struct initialization"
-target/lintcheck/sources/regex-1.3.2/src/exec.rs:281:13 clippy::redundant_field_names "redundant field names in struct initialization"
-target/lintcheck/sources/regex-1.3.2/src/exec.rs:286:5 clippy::missing_errors_doc "docs for function returning `Result` missing `# Errors` section"
-target/lintcheck/sources/regex-1.3.2/src/exec.rs:300:30 clippy::redundant_field_names "redundant field names in struct initialization"
-target/lintcheck/sources/regex-1.3.2/src/exec.rs:308:17 clippy::similar_names "binding's name is too similar to existing binding"
-target/lintcheck/sources/regex-1.3.2/src/exec.rs:329:13 clippy::redundant_field_names "redundant field names in struct initialization"
-target/lintcheck/sources/regex-1.3.2/src/exec.rs:330:13 clippy::redundant_field_names "redundant field names in struct initialization"
-target/lintcheck/sources/regex-1.3.2/src/exec.rs:331:13 clippy::redundant_field_names "redundant field names in struct initialization"
-target/lintcheck/sources/regex-1.3.2/src/exec.rs:334:13 clippy::redundant_field_names "redundant field names in struct initialization"
-target/lintcheck/sources/regex-1.3.2/src/exec.rs:340:19 clippy::redundant_field_names "redundant field names in struct initialization"
-target/lintcheck/sources/regex-1.3.2/src/exec.rs:344:27 clippy::unused_self "unused `self` argument"
-target/lintcheck/sources/regex-1.3.2/src/exec.rs:383:41 clippy::inline_always "you have declared `#[inline(always)]` on `shortest_match_at`. This is usually a bad idea"
-target/lintcheck/sources/regex-1.3.2/src/exec.rs:388:41 clippy::inline_always "you have declared `#[inline(always)]` on `is_match_at`. This is usually a bad idea"
-target/lintcheck/sources/regex-1.3.2/src/exec.rs:393:41 clippy::inline_always "you have declared `#[inline(always)]` on `find_at`. This is usually a bad idea"
-target/lintcheck/sources/regex-1.3.2/src/exec.rs:398:41 clippy::inline_always "you have declared `#[inline(always)]` on `captures_read_at`. This is usually a bad idea"
-target/lintcheck/sources/regex-1.3.2/src/exec.rs:425:41 clippy::inline_always "you have declared `#[inline(always)]` on `shortest_match_at`. This is usually a bad idea"
-target/lintcheck/sources/regex-1.3.2/src/exec.rs:44:1 clippy::module_name_repetitions "item name starts with its containing module's name"
-target/lintcheck/sources/regex-1.3.2/src/exec.rs:473:9 clippy::doc_markdown "you should put `shortest_match(...).is_some` between ticks in the documentation"
-target/lintcheck/sources/regex-1.3.2/src/exec.rs:474:41 clippy::inline_always "you have declared `#[inline(always)]` on `is_match_at`. This is usually a bad idea"
-target/lintcheck/sources/regex-1.3.2/src/exec.rs:524:41 clippy::inline_always "you have declared `#[inline(always)]` on `find_at`. This is usually a bad idea"
-target/lintcheck/sources/regex-1.3.2/src/exec.rs:52:1 clippy::module_name_repetitions "item name starts with its containing module's name"
-target/lintcheck/sources/regex-1.3.2/src/exec.rs:686:13 clippy::enum_glob_use "usage of wildcard import for enum variants"
-target/lintcheck/sources/regex-1.3.2/src/exec.rs:727:13 clippy::enum_glob_use "usage of wildcard import for enum variants"
-target/lintcheck/sources/regex-1.3.2/src/exec.rs:767:13 clippy::enum_glob_use "usage of wildcard import for enum variants"
-target/lintcheck/sources/regex-1.3.2/src/exec.rs:783:41 clippy::inline_always "you have declared `#[inline(always)]` on `shortest_dfa`. This is usually a bad idea"
-target/lintcheck/sources/regex-1.3.2/src/exec.rs:791:41 clippy::inline_always "you have declared `#[inline(always)]` on `shortest_dfa_reverse_suffix`. This is usually a bad idea"
-target/lintcheck/sources/regex-1.3.2/src/exec.rs:823:13 clippy::enum_glob_use "usage of wildcard import for enum variants"
-target/lintcheck/sources/regex-1.3.2/src/exec.rs:868:13 clippy::enum_glob_use "usage of wildcard import for enum variants"
-target/lintcheck/sources/regex-1.3.2/src/exec.rs:897:31 clippy::doc_markdown "you should put `shortest_nfa(...).is_some` between ticks in the documentation"
-target/lintcheck/sources/regex-1.3.2/src/exec.rs:899:9 clippy::doc_markdown "you should put `shortest_nfa` between ticks in the documentation"
-target/lintcheck/sources/regex-1.3.2/src/exec.rs:905:14 clippy::doc_markdown "you should put `match_nfa` between ticks in the documentation"
-target/lintcheck/sources/regex-1.3.2/src/exec.rs:930:14 clippy::doc_markdown "you should put `shortest_nfa` between ticks in the documentation"
-target/lintcheck/sources/regex-1.3.2/src/exec.rs:981:14 clippy::doc_markdown "you should put `find_nfa` between ticks in the documentation"
-target/lintcheck/sources/regex-1.3.2/src/expand.rs:170:27 clippy::trivially_copy_pass_by_ref "this argument (1 byte) is passed by reference, but would be more efficient if passed by value (limit: 8 byte)"
-target/lintcheck/sources/regex-1.3.2/src/expand.rs:171:5 clippy::match_like_matches_macro "match expression looks like `matches!` macro"
-target/lintcheck/sources/regex-1.3.2/src/expand.rs:22:13 clippy::single_char_add_str "calling `push_str()` using a single-character string literal"
-target/lintcheck/sources/regex-1.3.2/src/expand.rs:27:23 clippy::single_match_else "you seem to be trying to use `match` for destructuring a single pattern. Consider using `if let`"
-target/lintcheck/sources/regex-1.3.2/src/expand.rs:30:17 clippy::single_char_add_str "calling `push_str()` using a single-character string literal"
-target/lintcheck/sources/regex-1.3.2/src/expand.rs:38:30 clippy::map_unwrap_or "called `map(<f>).unwrap_or(<a>)` on an `Option` value. This can be done more directly by calling `map_or(<a>, <f>)` instead"
-target/lintcheck/sources/regex-1.3.2/src/expand.rs:42:21 clippy::map_unwrap_or "called `map(<f>).unwrap_or(<a>)` on an `Option` value. This can be done more directly by calling `map_or(<a>, <f>)` instead"
-target/lintcheck/sources/regex-1.3.2/src/expand.rs:50:1 clippy::module_name_repetitions "item name starts with its containing module's name"
-target/lintcheck/sources/regex-1.3.2/src/expand.rs:69:23 clippy::single_match_else "you seem to be trying to use `match` for destructuring a single pattern. Consider using `if let`"
-target/lintcheck/sources/regex-1.3.2/src/expand.rs:80:28 clippy::map_unwrap_or "called `map(<f>).unwrap_or(<a>)` on an `Option` value. This can be done more directly by calling `map_or(<a>, <f>)` instead"
-target/lintcheck/sources/regex-1.3.2/src/expand.rs:84:21 clippy::map_unwrap_or "called `map(<f>).unwrap_or(<a>)` on an `Option` value. This can be done more directly by calling `map_or(<a>, <f>)` instead"
-target/lintcheck/sources/regex-1.3.2/src/expand.rs:8:1 clippy::module_name_repetitions "item name starts with its containing module's name"
-target/lintcheck/sources/regex-1.3.2/src/input.rs:142:1 clippy::module_name_repetitions "item name ends with its containing module's name"
-target/lintcheck/sources/regex-1.3.2/src/input.rs:146:5 clippy::must_use_candidate "this method could have a `#[must_use]` attribute"
-target/lintcheck/sources/regex-1.3.2/src/input.rs:15:1 clippy::module_name_repetitions "item name starts with its containing module's name"
-target/lintcheck/sources/regex-1.3.2/src/input.rs:165:31 clippy::redundant_field_names "redundant field names in struct initialization"
-target/lintcheck/sources/regex-1.3.2/src/input.rs:178:13 clippy::enum_glob_use "usage of wildcard import for enum variants"
-target/lintcheck/sources/regex-1.3.2/src/input.rs:228:1 clippy::module_name_repetitions "item name ends with its containing module's name"
-target/lintcheck/sources/regex-1.3.2/src/input.rs:236:21 clippy::redundant_field_names "redundant field names in struct initialization"
-target/lintcheck/sources/regex-1.3.2/src/input.rs:236:33 clippy::redundant_field_names "redundant field names in struct initialization"
-target/lintcheck/sources/regex-1.3.2/src/input.rs:24:5 clippy::must_use_candidate "this method could have a `#[must_use]` attribute"
-target/lintcheck/sources/regex-1.3.2/src/input.rs:271:13 clippy::enum_glob_use "usage of wildcard import for enum variants"
-target/lintcheck/sources/regex-1.3.2/src/input.rs:29:5 clippy::must_use_candidate "this method could have a `#[must_use]` attribute"
-target/lintcheck/sources/regex-1.3.2/src/input.rs:362:5 clippy::must_use_candidate "this method could have a `#[must_use]` attribute"
-target/lintcheck/sources/regex-1.3.2/src/input.rs:370:5 clippy::must_use_candidate "this method could have a `#[must_use]` attribute"
-target/lintcheck/sources/regex-1.3.2/src/input.rs:371:42 clippy::redundant_closure_for_method_calls "redundant closure"
-target/lintcheck/sources/regex-1.3.2/src/input.rs:37:5 clippy::must_use_candidate "this method could have a `#[must_use]` attribute"
-target/lintcheck/sources/regex-1.3.2/src/input.rs:388:5 clippy::must_use_candidate "this method could have a `#[must_use]` attribute"
-target/lintcheck/sources/regex-1.3.2/src/input.rs:42:5 clippy::must_use_candidate "this method could have a `#[must_use]` attribute"
-target/lintcheck/sources/regex-1.3.2/src/input.rs:47:5 clippy::must_use_candidate "this method could have a `#[must_use]` attribute"
-target/lintcheck/sources/regex-1.3.2/src/input.rs:53:5 clippy::must_use_candidate "this method could have a `#[must_use]` attribute"
-target/lintcheck/sources/regex-1.3.2/src/input.rs:58:5 clippy::must_use_candidate "this method could have a `#[must_use]` attribute"
-target/lintcheck/sources/regex-1.3.2/src/input.rs:63:5 clippy::must_use_candidate "this method could have a `#[must_use]` attribute"
-target/lintcheck/sources/regex-1.3.2/src/lib.rs:1:null clippy::cargo_common_metadata "package `regex` is missing `package.keywords` metadata"
-target/lintcheck/sources/regex-1.3.2/src/literal/imp.rs:101:5 clippy::must_use_candidate "this method could have a `#[must_use]` attribute"
-target/lintcheck/sources/regex-1.3.2/src/literal/imp.rs:114:5 clippy::must_use_candidate "this method could have a `#[must_use]` attribute"
-target/lintcheck/sources/regex-1.3.2/src/literal/imp.rs:127:5 clippy::must_use_candidate "this method could have a `#[must_use]` attribute"
-target/lintcheck/sources/regex-1.3.2/src/literal/imp.rs:139:5 clippy::must_use_candidate "this method could have a `#[must_use]` attribute"
-target/lintcheck/sources/regex-1.3.2/src/literal/imp.rs:144:5 clippy::must_use_candidate "this method could have a `#[must_use]` attribute"
-target/lintcheck/sources/regex-1.3.2/src/literal/imp.rs:149:5 clippy::must_use_candidate "this method could have a `#[must_use]` attribute"
-target/lintcheck/sources/regex-1.3.2/src/literal/imp.rs:154:5 clippy::must_use_candidate "this method could have a `#[must_use]` attribute"
-target/lintcheck/sources/regex-1.3.2/src/literal/imp.rs:155:13 clippy::enum_glob_use "usage of wildcard import for enum variants"
-target/lintcheck/sources/regex-1.3.2/src/literal/imp.rs:160:30 clippy::match_same_arms "this `match` has identical arm bodies"
-target/lintcheck/sources/regex-1.3.2/src/literal/imp.rs:167:5 clippy::must_use_candidate "this method could have a `#[must_use]` attribute"
-target/lintcheck/sources/regex-1.3.2/src/literal/imp.rs:168:13 clippy::enum_glob_use "usage of wildcard import for enum variants"
-target/lintcheck/sources/regex-1.3.2/src/literal/imp.rs:211:20 clippy::redundant_else "redundant else block"
-target/lintcheck/sources/regex-1.3.2/src/literal/imp.rs:276:50 clippy::match_same_arms "this `match` has identical arm bodies"
-target/lintcheck/sources/regex-1.3.2/src/literal/imp.rs:342:41 clippy::inline_always "you have declared `#[inline(always)]` on `find`. This is usually a bad idea"
-target/lintcheck/sources/regex-1.3.2/src/literal/imp.rs:435:13 clippy::redundant_field_names "redundant field names in struct initialization"
-target/lintcheck/sources/regex-1.3.2/src/literal/imp.rs:436:13 clippy::redundant_field_names "redundant field names in struct initialization"
-target/lintcheck/sources/regex-1.3.2/src/literal/imp.rs:437:13 clippy::redundant_field_names "redundant field names in struct initialization"
-target/lintcheck/sources/regex-1.3.2/src/literal/imp.rs:438:13 clippy::redundant_field_names "redundant field names in struct initialization"
-target/lintcheck/sources/regex-1.3.2/src/literal/imp.rs:439:13 clippy::redundant_field_names "redundant field names in struct initialization"
-target/lintcheck/sources/regex-1.3.2/src/literal/imp.rs:440:13 clippy::redundant_field_names "redundant field names in struct initialization"
-target/lintcheck/sources/regex-1.3.2/src/literal/imp.rs:455:41 clippy::inline_always "you have declared `#[inline(always)]` on `find`. This is usually a bad idea"
-target/lintcheck/sources/regex-1.3.2/src/literal/imp.rs:46:5 clippy::must_use_candidate "this method could have a `#[must_use]` attribute"
-target/lintcheck/sources/regex-1.3.2/src/literal/imp.rs:481:41 clippy::inline_always "you have declared `#[inline(always)]` on `is_suffix`. This is usually a bad idea"
-target/lintcheck/sources/regex-1.3.2/src/literal/imp.rs:51:5 clippy::must_use_candidate "this method could have a `#[must_use]` attribute"
-target/lintcheck/sources/regex-1.3.2/src/literal/imp.rs:579:13 clippy::redundant_field_names "redundant field names in struct initialization"
-target/lintcheck/sources/regex-1.3.2/src/literal/imp.rs:57:5 clippy::must_use_candidate "this method could have a `#[must_use]` attribute"
-target/lintcheck/sources/regex-1.3.2/src/literal/imp.rs:580:13 clippy::redundant_field_names "redundant field names in struct initialization"
-target/lintcheck/sources/regex-1.3.2/src/literal/imp.rs:583:13 clippy::redundant_field_names "redundant field names in struct initialization"
-target/lintcheck/sources/regex-1.3.2/src/literal/imp.rs:602:9 clippy::items_after_statements "adding items after statements is confusing, since items exist from the start of the scope"
-target/lintcheck/sources/regex-1.3.2/src/literal/imp.rs:622:24 clippy::redundant_else "redundant else block"
-target/lintcheck/sources/regex-1.3.2/src/literal/imp.rs:62:18 clippy::needless_pass_by_value "this argument is passed by value, but not consumed in the function body"
-target/lintcheck/sources/regex-1.3.2/src/literal/imp.rs:637:24 clippy::redundant_else "redundant else block"
-target/lintcheck/sources/regex-1.3.2/src/literal/imp.rs:648:9 clippy::needless_return "unneeded `return` statement"
-target/lintcheck/sources/regex-1.3.2/src/literal/imp.rs:651:44 clippy::doc_markdown "you should put `BoyerMooreSearch` between ticks in the documentation"
-target/lintcheck/sources/regex-1.3.2/src/literal/imp.rs:65:13 clippy::redundant_field_names "redundant field names in struct initialization"
-target/lintcheck/sources/regex-1.3.2/src/literal/imp.rs:68:13 clippy::redundant_field_names "redundant field names in struct initialization"
-target/lintcheck/sources/regex-1.3.2/src/literal/imp.rs:783:32 clippy::redundant_else "redundant else block"
-target/lintcheck/sources/regex-1.3.2/src/literal/imp.rs:786:42 clippy::manual_saturating_arithmetic "manual saturating arithmetic"
-target/lintcheck/sources/regex-1.3.2/src/literal/imp.rs:78:5 clippy::must_use_candidate "this method could have a `#[must_use]` attribute"
-target/lintcheck/sources/regex-1.3.2/src/literal/imp.rs:84:5 clippy::must_use_candidate "this method could have a `#[must_use]` attribute"
-target/lintcheck/sources/regex-1.3.2/src/literal/imp.rs:850:20 clippy::unreadable_literal "long literal lacking separators"
-target/lintcheck/sources/regex-1.3.2/src/literal/imp.rs:85:13 clippy::enum_glob_use "usage of wildcard import for enum variants"
-target/lintcheck/sources/regex-1.3.2/src/pikevm.rs:103:15 clippy::redundant_field_names "redundant field names in struct initialization"
-target/lintcheck/sources/regex-1.3.2/src/pikevm.rs:103:52 clippy::redundant_field_names "redundant field names in struct initialization"
-target/lintcheck/sources/regex-1.3.2/src/pikevm.rs:114:5 clippy::too_many_arguments "this function has too many arguments (8/7)"
-target/lintcheck/sources/regex-1.3.2/src/pikevm.rs:117:13 clippy::similar_names "binding's name is too similar to existing binding"
-target/lintcheck/sources/regex-1.3.2/src/pikevm.rs:124:17 clippy::similar_names "binding's name is too similar to existing binding"
-target/lintcheck/sources/regex-1.3.2/src/pikevm.rs:220:9 clippy::doc_markdown "you should put `thread_caps` between ticks in the documentation"
-target/lintcheck/sources/regex-1.3.2/src/pikevm.rs:222:16 clippy::doc_markdown "you should put `at_next` between ticks in the documentation"
-target/lintcheck/sources/regex-1.3.2/src/pikevm.rs:223:9 clippy::doc_markdown "you should put `at_next` between ticks in the documentation"
-target/lintcheck/sources/regex-1.3.2/src/pikevm.rs:224:5 clippy::too_many_arguments "this function has too many arguments (8/7)"
-target/lintcheck/sources/regex-1.3.2/src/pikevm.rs:234:13 clippy::enum_glob_use "usage of wildcard import for enum variants"
-target/lintcheck/sources/regex-1.3.2/src/pikevm.rs:303:13 clippy::enum_glob_use "usage of wildcard import for enum variants"
-target/lintcheck/sources/regex-1.3.2/src/pikevm.rs:331:29 clippy::mut_mut "this expression mutably borrows a mutable reference. Consider reborrowing"
-target/lintcheck/sources/regex-1.3.2/src/pikevm.rs:88:5 clippy::too_many_arguments "this function has too many arguments (8/7)"
-target/lintcheck/sources/regex-1.3.2/src/prog.rs:102:5 clippy::must_use_candidate "this method could have a `#[must_use]` attribute"
-target/lintcheck/sources/regex-1.3.2/src/prog.rs:113:5 clippy::must_use_candidate "this method could have a `#[must_use]` attribute"
-target/lintcheck/sources/regex-1.3.2/src/prog.rs:120:9 clippy::match_like_matches_macro "match expression looks like `matches!` macro"
-target/lintcheck/sources/regex-1.3.2/src/prog.rs:128:5 clippy::must_use_candidate "this method could have a `#[must_use]` attribute"
-target/lintcheck/sources/regex-1.3.2/src/prog.rs:134:5 clippy::must_use_candidate "this method could have a `#[must_use]` attribute"
-target/lintcheck/sources/regex-1.3.2/src/prog.rs:141:5 clippy::must_use_candidate "this method could have a `#[must_use]` attribute"
-target/lintcheck/sources/regex-1.3.2/src/prog.rs:147:5 clippy::must_use_candidate "this method could have a `#[must_use]` attribute"
-target/lintcheck/sources/regex-1.3.2/src/prog.rs:164:41 clippy::inline_always "you have declared `#[inline(always)]` on `deref`. This is usually a bad idea"
-target/lintcheck/sources/regex-1.3.2/src/prog.rs:172:13 clippy::enum_glob_use "usage of wildcard import for enum variants"
-target/lintcheck/sources/regex-1.3.2/src/prog.rs:18:1 clippy::struct_excessive_bools "more than 3 bools in a struct"
-target/lintcheck/sources/regex-1.3.2/src/prog.rs:236:13 clippy::write_with_newline "using `write!()` with a format string that ends in a single newline"
-target/lintcheck/sources/regex-1.3.2/src/prog.rs:300:5 clippy::must_use_candidate "this method could have a `#[must_use]` attribute"
-target/lintcheck/sources/regex-1.3.2/src/prog.rs:301:9 clippy::match_like_matches_macro "match expression looks like `matches!` macro"
-target/lintcheck/sources/regex-1.3.2/src/prog.rs:382:5 clippy::must_use_candidate "this method could have a `#[must_use]` attribute"
-target/lintcheck/sources/regex-1.3.2/src/prog.rs:409:5 clippy::must_use_candidate "this method could have a `#[must_use]` attribute"
-target/lintcheck/sources/regex-1.3.2/src/prog.rs:80:5 clippy::must_use_candidate "this method could have a `#[must_use]` attribute"
-target/lintcheck/sources/regex-1.3.2/src/prog.rs:80:5 clippy::new_without_default "you should consider adding a `Default` implementation for `prog::Program`"
-target/lintcheck/sources/regex-1.3.2/src/re_builder.rs:267:17 clippy::missing_errors_doc "docs for function returning `Result` missing `# Errors` section"
-target/lintcheck/sources/regex-1.3.2/src/re_builder.rs:267:17 clippy::missing_errors_doc "docs for function returning `Result` missing `# Errors` section"
-target/lintcheck/sources/regex-1.3.2/src/re_builder.rs:4:1 clippy::struct_excessive_bools "more than 3 bools in a struct"
-target/lintcheck/sources/regex-1.3.2/src/re_builder.rs:57:17 clippy::must_use_candidate "this method could have a `#[must_use]` attribute"
-target/lintcheck/sources/regex-1.3.2/src/re_builder.rs:57:17 clippy::must_use_candidate "this method could have a `#[must_use]` attribute"
-target/lintcheck/sources/regex-1.3.2/src/re_builder.rs:68:17 clippy::missing_errors_doc "docs for function returning `Result` missing `# Errors` section"
-target/lintcheck/sources/regex-1.3.2/src/re_builder.rs:68:17 clippy::missing_errors_doc "docs for function returning `Result` missing `# Errors` section"
-target/lintcheck/sources/regex-1.3.2/src/re_bytes.rs:1017:9 clippy::map_unwrap_or "called `map(<f>).unwrap_or_else(<g>)` on an `Option` value. This can be done more directly by calling `map_or_else(<g>, <f>)` instead"
-target/lintcheck/sources/regex-1.3.2/src/re_bytes.rs:1039:9 clippy::map_unwrap_or "called `map(<f>).unwrap_or_else(<g>)` on an `Option` value. This can be done more directly by calling `map_or_else(<g>, <f>)` instead"
-target/lintcheck/sources/regex-1.3.2/src/re_bytes.rs:1093:5 clippy::needless_lifetimes "explicit lifetimes given in parameter types where they could be elided (or replaced with `'_` if needed by type declaration)"
-target/lintcheck/sources/regex-1.3.2/src/re_bytes.rs:1118:5 clippy::needless_lifetimes "explicit lifetimes given in parameter types where they could be elided (or replaced with `'_` if needed by type declaration)"
-target/lintcheck/sources/regex-1.3.2/src/re_bytes.rs:1133:5 clippy::needless_lifetimes "explicit lifetimes given in parameter types where they could be elided (or replaced with `'_` if needed by type declaration)"
-target/lintcheck/sources/regex-1.3.2/src/re_bytes.rs:118:5 clippy::missing_errors_doc "docs for function returning `Result` missing `# Errors` section"
-target/lintcheck/sources/regex-1.3.2/src/re_bytes.rs:256:13 clippy::redundant_field_names "redundant field names in struct initialization"
-target/lintcheck/sources/regex-1.3.2/src/re_bytes.rs:29:5 clippy::must_use_candidate "this method could have a `#[must_use]` attribute"
-target/lintcheck/sources/regex-1.3.2/src/re_bytes.rs:35:5 clippy::must_use_candidate "this method could have a `#[must_use]` attribute"
-target/lintcheck/sources/regex-1.3.2/src/re_bytes.rs:42:5 clippy::must_use_candidate "this method could have a `#[must_use]` attribute"
-target/lintcheck/sources/regex-1.3.2/src/re_bytes.rs:483:5 clippy::missing_panics_doc "docs for function which may panic missing `# Panics` section"
-target/lintcheck/sources/regex-1.3.2/src/re_bytes.rs:48:5 clippy::must_use_candidate "this method could have a `#[must_use]` attribute"
-target/lintcheck/sources/regex-1.3.2/src/re_bytes.rs:558:29 clippy::doc_markdown "you should put `shortest_match` between ticks in the documentation"
-target/lintcheck/sources/regex-1.3.2/src/re_bytes.rs:55:33 clippy::redundant_field_names "redundant field names in struct initialization"
-target/lintcheck/sources/regex-1.3.2/src/re_bytes.rs:55:47 clippy::redundant_field_names "redundant field names in struct initialization"
-target/lintcheck/sources/regex-1.3.2/src/re_bytes.rs:572:29 clippy::doc_markdown "you should put `is_match` between ticks in the documentation"
-target/lintcheck/sources/regex-1.3.2/src/re_bytes.rs:720:13 clippy::redundant_field_names "redundant field names in struct initialization"
-target/lintcheck/sources/regex-1.3.2/src/re_bytes.rs:817:5 clippy::doc_markdown "you should put `CaptureLocations` between ticks in the documentation"
-target/lintcheck/sources/regex-1.3.2/src/re_bytes.rs:849:5 clippy::must_use_candidate "this method could have a `#[must_use]` attribute"
-target/lintcheck/sources/regex-1.3.2/src/re_bytes.rs:858:5 clippy::len_without_is_empty "struct `CaptureLocations` has a public `len` method, but no `is_empty` method"
-target/lintcheck/sources/regex-1.3.2/src/re_bytes.rs:858:5 clippy::must_use_candidate "this method could have a `#[must_use]` attribute"
-target/lintcheck/sources/regex-1.3.2/src/re_bytes.rs:869:5 clippy::must_use_candidate "this method could have a `#[must_use]` attribute"
-target/lintcheck/sources/regex-1.3.2/src/re_bytes.rs:911:5 clippy::must_use_candidate "this method could have a `#[must_use]` attribute"
-target/lintcheck/sources/regex-1.3.2/src/re_bytes.rs:917:5 clippy::must_use_candidate "this method could have a `#[must_use]` attribute"
-target/lintcheck/sources/regex-1.3.2/src/re_bytes.rs:926:5 clippy::must_use_candidate "this method could have a `#[must_use]` attribute"
-target/lintcheck/sources/regex-1.3.2/src/re_bytes.rs:955:5 clippy::len_without_is_empty "struct `Captures` has a public `len` method, but no `is_empty` method"
-target/lintcheck/sources/regex-1.3.2/src/re_bytes.rs:955:5 clippy::must_use_candidate "this method could have a `#[must_use]` attribute"
-target/lintcheck/sources/regex-1.3.2/src/re_set.rs:179:13 clippy::redundant_field_names "redundant field names in struct initialization"
-target/lintcheck/sources/regex-1.3.2/src/re_set.rs:179:13 clippy::redundant_field_names "redundant field names in struct initialization"
-target/lintcheck/sources/regex-1.3.2/src/re_set.rs:206:5 clippy::len_without_is_empty "struct `RegexSet` has a public `len` method, but no `is_empty` method"
-target/lintcheck/sources/regex-1.3.2/src/re_set.rs:206:5 clippy::len_without_is_empty "struct `RegexSet` has a public `len` method, but no `is_empty` method"
-target/lintcheck/sources/regex-1.3.2/src/re_set.rs:251:5 clippy::must_use_candidate "this method could have a `#[must_use]` attribute"
-target/lintcheck/sources/regex-1.3.2/src/re_set.rs:251:5 clippy::must_use_candidate "this method could have a `#[must_use]` attribute"
-target/lintcheck/sources/regex-1.3.2/src/re_set.rs:263:5 clippy::must_use_candidate "this method could have a `#[must_use]` attribute"
-target/lintcheck/sources/regex-1.3.2/src/re_set.rs:263:5 clippy::must_use_candidate "this method could have a `#[must_use]` attribute"
-target/lintcheck/sources/regex-1.3.2/src/re_set.rs:268:5 clippy::len_without_is_empty "struct `SetMatches` has a public `len` method, but no `is_empty` method"
-target/lintcheck/sources/regex-1.3.2/src/re_set.rs:268:5 clippy::len_without_is_empty "struct `SetMatches` has a public `len` method, but no `is_empty` method"
-target/lintcheck/sources/regex-1.3.2/src/re_set.rs:268:5 clippy::must_use_candidate "this method could have a `#[must_use]` attribute"
-target/lintcheck/sources/regex-1.3.2/src/re_set.rs:268:5 clippy::must_use_candidate "this method could have a `#[must_use]` attribute"
-target/lintcheck/sources/regex-1.3.2/src/re_set.rs:277:5 clippy::must_use_candidate "this method could have a `#[must_use]` attribute"
-target/lintcheck/sources/regex-1.3.2/src/re_set.rs:277:5 clippy::must_use_candidate "this method could have a `#[must_use]` attribute"
-target/lintcheck/sources/regex-1.3.2/src/re_set.rs:94:5 clippy::missing_errors_doc "docs for function returning `Result` missing `# Errors` section"
-target/lintcheck/sources/regex-1.3.2/src/re_set.rs:94:5 clippy::missing_errors_doc "docs for function returning `Result` missing `# Errors` section"
-target/lintcheck/sources/regex-1.3.2/src/re_trait.rs:136:29 clippy::redundant_field_names "redundant field names in struct initialization"
-target/lintcheck/sources/regex-1.3.2/src/re_unicode.rs:1019:9 clippy::map_unwrap_or "called `map(<f>).unwrap_or_else(<g>)` on an `Option` value. This can be done more directly by calling `map_or_else(<g>, <f>)` instead"
-target/lintcheck/sources/regex-1.3.2/src/re_unicode.rs:1041:9 clippy::map_unwrap_or "called `map(<f>).unwrap_or_else(<g>)` on an `Option` value. This can be done more directly by calling `map_or_else(<g>, <f>)` instead"
-target/lintcheck/sources/regex-1.3.2/src/re_unicode.rs:1088:13 clippy::redundant_field_names "redundant field names in struct initialization"
-target/lintcheck/sources/regex-1.3.2/src/re_unicode.rs:1135:5 clippy::needless_lifetimes "explicit lifetimes given in parameter types where they could be elided (or replaced with `'_` if needed by type declaration)"
-target/lintcheck/sources/regex-1.3.2/src/re_unicode.rs:1160:5 clippy::needless_lifetimes "explicit lifetimes given in parameter types where they could be elided (or replaced with `'_` if needed by type declaration)"
-target/lintcheck/sources/regex-1.3.2/src/re_unicode.rs:174:5 clippy::missing_errors_doc "docs for function returning `Result` missing `# Errors` section"
-target/lintcheck/sources/regex-1.3.2/src/re_unicode.rs:21:1 clippy::must_use_candidate "this function could have a `#[must_use]` attribute"
-target/lintcheck/sources/regex-1.3.2/src/re_unicode.rs:313:13 clippy::redundant_field_names "redundant field names in struct initialization"
-target/lintcheck/sources/regex-1.3.2/src/re_unicode.rs:38:5 clippy::must_use_candidate "this method could have a `#[must_use]` attribute"
-target/lintcheck/sources/regex-1.3.2/src/re_unicode.rs:44:5 clippy::must_use_candidate "this method could have a `#[must_use]` attribute"
-target/lintcheck/sources/regex-1.3.2/src/re_unicode.rs:51:5 clippy::must_use_candidate "this method could have a `#[must_use]` attribute"
-target/lintcheck/sources/regex-1.3.2/src/re_unicode.rs:533:5 clippy::missing_panics_doc "docs for function which may panic missing `# Panics` section"
-target/lintcheck/sources/regex-1.3.2/src/re_unicode.rs:57:5 clippy::must_use_candidate "this method could have a `#[must_use]` attribute"
-target/lintcheck/sources/regex-1.3.2/src/re_unicode.rs:617:29 clippy::doc_markdown "you should put `shortest_match` between ticks in the documentation"
-target/lintcheck/sources/regex-1.3.2/src/re_unicode.rs:631:29 clippy::doc_markdown "you should put `is_match` between ticks in the documentation"
-target/lintcheck/sources/regex-1.3.2/src/re_unicode.rs:64:33 clippy::redundant_field_names "redundant field names in struct initialization"
-target/lintcheck/sources/regex-1.3.2/src/re_unicode.rs:64:47 clippy::redundant_field_names "redundant field names in struct initialization"
-target/lintcheck/sources/regex-1.3.2/src/re_unicode.rs:834:5 clippy::doc_markdown "you should put `CaptureLocations` between ticks in the documentation"
-target/lintcheck/sources/regex-1.3.2/src/re_unicode.rs:866:5 clippy::must_use_candidate "this method could have a `#[must_use]` attribute"
-target/lintcheck/sources/regex-1.3.2/src/re_unicode.rs:875:5 clippy::len_without_is_empty "struct `CaptureLocations` has a public `len` method, but no `is_empty` method"
-target/lintcheck/sources/regex-1.3.2/src/re_unicode.rs:875:5 clippy::must_use_candidate "this method could have a `#[must_use]` attribute"
-target/lintcheck/sources/regex-1.3.2/src/re_unicode.rs:886:5 clippy::must_use_candidate "this method could have a `#[must_use]` attribute"
-target/lintcheck/sources/regex-1.3.2/src/re_unicode.rs:928:5 clippy::must_use_candidate "this method could have a `#[must_use]` attribute"
-target/lintcheck/sources/regex-1.3.2/src/re_unicode.rs:934:5 clippy::must_use_candidate "this method could have a `#[must_use]` attribute"
-target/lintcheck/sources/regex-1.3.2/src/re_unicode.rs:943:5 clippy::must_use_candidate "this method could have a `#[must_use]` attribute"
-target/lintcheck/sources/regex-1.3.2/src/re_unicode.rs:972:5 clippy::len_without_is_empty "struct `Captures` has a public `len` method, but no `is_empty` method"
-target/lintcheck/sources/regex-1.3.2/src/re_unicode.rs:972:5 clippy::must_use_candidate "this method could have a `#[must_use]` attribute"
-target/lintcheck/sources/regex-1.3.2/src/sparse.rs:10:37 clippy::doc_markdown "you should put bare URLs between `<`/`>` or make a proper Markdown link"
-target/lintcheck/sources/regex-1.3.2/src/sparse.rs:15:1 clippy::module_name_repetitions "item name starts with its containing module's name"
-target/lintcheck/sources/regex-1.3.2/src/utf8.rs:100:16 clippy::unusual_byte_groupings "digits of hex or binary literal not grouped by four"
-target/lintcheck/sources/regex-1.3.2/src/utf8.rs:103:16 clippy::unusual_byte_groupings "digits of hex or binary literal not grouped by four"
-target/lintcheck/sources/regex-1.3.2/src/utf8.rs:106:22 clippy::cast_lossless "casting `u8` to `u32` may become silently lossy if you later change the type"
-target/lintcheck/sources/regex-1.3.2/src/utf8.rs:107:19 clippy::cast_lossless "casting `u8` to `u32` may become silently lossy if you later change the type"
-target/lintcheck/sources/regex-1.3.2/src/utf8.rs:108:19 clippy::cast_lossless "casting `u8` to `u32` may become silently lossy if you later change the type"
-target/lintcheck/sources/regex-1.3.2/src/utf8.rs:109:19 clippy::cast_lossless "casting `u8` to `u32` may become silently lossy if you later change the type"
-target/lintcheck/sources/regex-1.3.2/src/utf8.rs:111:27 clippy::unreadable_literal "long literal lacking separators"
-target/lintcheck/sources/regex-1.3.2/src/utf8.rs:121:1 clippy::module_name_repetitions "item name ends with its containing module's name"
-target/lintcheck/sources/regex-1.3.2/src/utf8.rs:143:24 clippy::unusual_byte_groupings "digits of hex or binary literal not grouped by four"
-target/lintcheck/sources/regex-1.3.2/src/utf8.rs:143:9 clippy::unusual_byte_groupings "digits of hex or binary literal not grouped by four"
-target/lintcheck/sources/regex-1.3.2/src/utf8.rs:23:1 clippy::module_name_repetitions "item name ends with its containing module's name"
-target/lintcheck/sources/regex-1.3.2/src/utf8.rs:30:20 clippy::unusual_byte_groupings "digits of hex or binary literal not grouped by four"
-target/lintcheck/sources/regex-1.3.2/src/utf8.rs:51:1 clippy::module_name_repetitions "item name ends with its containing module's name"
-target/lintcheck/sources/regex-1.3.2/src/utf8.rs:58:23 clippy::unusual_byte_groupings "digits of hex or binary literal not grouped by four"
-target/lintcheck/sources/regex-1.3.2/src/utf8.rs:58:9 clippy::unusual_byte_groupings "digits of hex or binary literal not grouped by four"
-target/lintcheck/sources/regex-1.3.2/src/utf8.rs:63:16 clippy::unusual_byte_groupings "digits of hex or binary literal not grouped by four"
-target/lintcheck/sources/regex-1.3.2/src/utf8.rs:66:22 clippy::cast_lossless "casting `u8` to `u32` may become silently lossy if you later change the type"
-target/lintcheck/sources/regex-1.3.2/src/utf8.rs:66:54 clippy::cast_lossless "casting `u8` to `u32` may become silently lossy if you later change the type"
-target/lintcheck/sources/regex-1.3.2/src/utf8.rs:77:16 clippy::unusual_byte_groupings "digits of hex or binary literal not grouped by four"
-target/lintcheck/sources/regex-1.3.2/src/utf8.rs:80:16 clippy::unusual_byte_groupings "digits of hex or binary literal not grouped by four"
-target/lintcheck/sources/regex-1.3.2/src/utf8.rs:83:22 clippy::cast_lossless "casting `u8` to `u32` may become silently lossy if you later change the type"
-target/lintcheck/sources/regex-1.3.2/src/utf8.rs:84:19 clippy::cast_lossless "casting `u8` to `u32` may become silently lossy if you later change the type"
-target/lintcheck/sources/regex-1.3.2/src/utf8.rs:85:19 clippy::cast_lossless "casting `u8` to `u32` may become silently lossy if you later change the type"
-target/lintcheck/sources/regex-1.3.2/src/utf8.rs:92:23 clippy::unusual_byte_groupings "digits of hex or binary literal not grouped by four"
-target/lintcheck/sources/regex-1.3.2/src/utf8.rs:92:9 clippy::unusual_byte_groupings "digits of hex or binary literal not grouped by four"
-target/lintcheck/sources/regex-1.3.2/src/utf8.rs:97:16 clippy::unusual_byte_groupings "digits of hex or binary literal not grouped by four"
-target/lintcheck/sources/ripgrep-12.1.1/build.rs:133:19 clippy::option_as_ref_deref "called `.as_ref().map(|x| &**x)` on an Option value. This can be done more directly by calling `githash.as_deref()` instead"
-target/lintcheck/sources/ripgrep-12.1.1/build.rs:18:18 clippy::single_match_else "you seem to be trying to use `match` for destructuring a single pattern. Consider using `if let`"
-target/lintcheck/sources/ripgrep-12.1.1/build.rs:225:14 clippy::redundant_closure_for_method_calls "redundant closure"
-target/lintcheck/sources/ripgrep-12.1.1/build.rs:92:19 clippy::option_as_ref_deref "called `.as_ref().map(|x| &**x)` on an Option value. This can be done more directly by calling `githash.as_deref()` instead"
-target/lintcheck/sources/ripgrep-12.1.1/crates/core/app.rs:1408:5 clippy::items_after_statements "adding items after statements is confusing, since items exist from the start of the scope"
-target/lintcheck/sources/ripgrep-12.1.1/crates/core/app.rs:1408:5 clippy::items_after_statements "adding items after statements is confusing, since items exist from the start of the scope"
-target/lintcheck/sources/ripgrep-12.1.1/crates/core/app.rs:1409:5 clippy::items_after_statements "adding items after statements is confusing, since items exist from the start of the scope"
-target/lintcheck/sources/ripgrep-12.1.1/crates/core/app.rs:1409:5 clippy::items_after_statements "adding items after statements is confusing, since items exist from the start of the scope"
-target/lintcheck/sources/ripgrep-12.1.1/crates/core/app.rs:152:32 clippy::doc_markdown "you should put `clap::Arg` between ticks in the documentation"
-target/lintcheck/sources/ripgrep-12.1.1/crates/core/app.rs:152:32 clippy::doc_markdown "you should put `clap::Arg` between ticks in the documentation"
-target/lintcheck/sources/ripgrep-12.1.1/crates/core/app.rs:156:39 clippy::doc_markdown "you should put `clap::Arg` between ticks in the documentation"
-target/lintcheck/sources/ripgrep-12.1.1/crates/core/app.rs:156:39 clippy::doc_markdown "you should put `clap::Arg` between ticks in the documentation"
-target/lintcheck/sources/ripgrep-12.1.1/crates/core/app.rs:156:5 clippy::doc_markdown "you should put `RGArg` between ticks in the documentation"
-target/lintcheck/sources/ripgrep-12.1.1/crates/core/app.rs:156:5 clippy::doc_markdown "you should put `RGArg` between ticks in the documentation"
-target/lintcheck/sources/ripgrep-12.1.1/crates/core/app.rs:1668:5 clippy::items_after_statements "adding items after statements is confusing, since items exist from the start of the scope"
-target/lintcheck/sources/ripgrep-12.1.1/crates/core/app.rs:1668:5 clippy::items_after_statements "adding items after statements is confusing, since items exist from the start of the scope"
-target/lintcheck/sources/ripgrep-12.1.1/crates/core/app.rs:1669:5 clippy::items_after_statements "adding items after statements is confusing, since items exist from the start of the scope"
-target/lintcheck/sources/ripgrep-12.1.1/crates/core/app.rs:1669:5 clippy::items_after_statements "adding items after statements is confusing, since items exist from the start of the scope"
-target/lintcheck/sources/ripgrep-12.1.1/crates/core/app.rs:1821:5 clippy::items_after_statements "adding items after statements is confusing, since items exist from the start of the scope"
-target/lintcheck/sources/ripgrep-12.1.1/crates/core/app.rs:1821:5 clippy::items_after_statements "adding items after statements is confusing, since items exist from the start of the scope"
-target/lintcheck/sources/ripgrep-12.1.1/crates/core/app.rs:1822:5 clippy::items_after_statements "adding items after statements is confusing, since items exist from the start of the scope"
-target/lintcheck/sources/ripgrep-12.1.1/crates/core/app.rs:1822:5 clippy::items_after_statements "adding items after statements is confusing, since items exist from the start of the scope"
-target/lintcheck/sources/ripgrep-12.1.1/crates/core/app.rs:2999:5 clippy::items_after_statements "adding items after statements is confusing, since items exist from the start of the scope"
-target/lintcheck/sources/ripgrep-12.1.1/crates/core/app.rs:2999:5 clippy::items_after_statements "adding items after statements is confusing, since items exist from the start of the scope"
-target/lintcheck/sources/ripgrep-12.1.1/crates/core/app.rs:3000:5 clippy::items_after_statements "adding items after statements is confusing, since items exist from the start of the scope"
-target/lintcheck/sources/ripgrep-12.1.1/crates/core/app.rs:3000:5 clippy::items_after_statements "adding items after statements is confusing, since items exist from the start of the scope"
-target/lintcheck/sources/ripgrep-12.1.1/crates/core/app.rs:367:54 clippy::match_same_arms "this `match` has identical arm bodies"
-target/lintcheck/sources/ripgrep-12.1.1/crates/core/app.rs:367:54 clippy::match_same_arms "this `match` has identical arm bodies"
-target/lintcheck/sources/ripgrep-12.1.1/crates/core/app.rs:414:59 clippy::match_same_arms "this `match` has identical arm bodies"
-target/lintcheck/sources/ripgrep-12.1.1/crates/core/app.rs:414:59 clippy::match_same_arms "this `match` has identical arm bodies"
-target/lintcheck/sources/ripgrep-12.1.1/crates/core/app.rs:417:57 clippy::match_same_arms "this `match` has identical arm bodies"
-target/lintcheck/sources/ripgrep-12.1.1/crates/core/app.rs:417:57 clippy::match_same_arms "this `match` has identical arm bodies"
-target/lintcheck/sources/ripgrep-12.1.1/crates/core/app.rs:417:57 clippy::match_same_arms "this `match` has identical arm bodies"
-target/lintcheck/sources/ripgrep-12.1.1/crates/core/app.rs:417:57 clippy::match_same_arms "this `match` has identical arm bodies"
-target/lintcheck/sources/ripgrep-12.1.1/crates/core/app.rs:75:9 clippy::doc_markdown "you should put `RIPGREP_BUILD_GIT_HASH` between ticks in the documentation"
-target/lintcheck/sources/ripgrep-12.1.1/crates/core/app.rs:75:9 clippy::doc_markdown "you should put `RIPGREP_BUILD_GIT_HASH` between ticks in the documentation"
-target/lintcheck/sources/ripgrep-12.1.1/crates/core/app.rs:87:5 clippy::if_not_else "unnecessary boolean `not` operation"
-target/lintcheck/sources/ripgrep-12.1.1/crates/core/app.rs:87:5 clippy::if_not_else "unnecessary boolean `not` operation"
-target/lintcheck/sources/ripgrep-12.1.1/crates/core/args.rs:1143:22 clippy::unused_self "unused `self` argument"
-target/lintcheck/sources/ripgrep-12.1.1/crates/core/args.rs:11:1 clippy::single_component_path_imports "this import is redundant"
-target/lintcheck/sources/ripgrep-12.1.1/crates/core/args.rs:1209:74 clippy::if_same_then_else "this `if` has identical blocks"
-target/lintcheck/sources/ripgrep-12.1.1/crates/core/args.rs:1282:13 clippy::similar_names "binding's name is too similar to existing binding"
-target/lintcheck/sources/ripgrep-12.1.1/crates/core/args.rs:1430:22 clippy::unused_self "unused `self` argument"
-target/lintcheck/sources/ripgrep-12.1.1/crates/core/args.rs:1438:21 clippy::doc_markdown "you should put `OsStr` between ticks in the documentation"
-target/lintcheck/sources/ripgrep-12.1.1/crates/core/args.rs:1520:44 clippy::redundant_closure_for_method_calls "redundant closure"
-target/lintcheck/sources/ripgrep-12.1.1/crates/core/args.rs:1524:5 clippy::unnecessary_wraps "this function's return value is unnecessarily wrapped by `Result`"
-target/lintcheck/sources/ripgrep-12.1.1/crates/core/args.rs:1635:14 clippy::doc_markdown "you should put `values_of_lossy` between ticks in the documentation"
-target/lintcheck/sources/ripgrep-12.1.1/crates/core/args.rs:1693:41 clippy::redundant_closure_for_method_calls "redundant closure"
-target/lintcheck/sources/ripgrep-12.1.1/crates/core/args.rs:1770:17 clippy::cast_possible_truncation "casting `u64` to `usize` may truncate the value on targets with 32-bit wide pointers"
-target/lintcheck/sources/ripgrep-12.1.1/crates/core/args.rs:1829:5 clippy::let_underscore_drop "non-binding `let` on a type that implements `Drop`"
-target/lintcheck/sources/ripgrep-12.1.1/crates/core/args.rs:287:13 clippy::similar_names "binding's name is too similar to existing binding"
-target/lintcheck/sources/ripgrep-12.1.1/crates/core/args.rs:33:1 clippy::single_component_path_imports "this import is redundant"
-target/lintcheck/sources/ripgrep-12.1.1/crates/core/args.rs:34:1 clippy::single_component_path_imports "this import is redundant"
-target/lintcheck/sources/ripgrep-12.1.1/crates/core/args.rs:35:1 clippy::single_component_path_imports "this import is redundant"
-target/lintcheck/sources/ripgrep-12.1.1/crates/core/args.rs:369:5 clippy::upper_case_acronyms "name `JSON` contains a capitalized acronym"
-target/lintcheck/sources/ripgrep-12.1.1/crates/core/args.rs:410:14 clippy::trivially_copy_pass_by_ref "this argument (2 byte) is passed by reference, but would be more efficient if passed by value (limit: 8 byte)"
-target/lintcheck/sources/ripgrep-12.1.1/crates/core/args.rs:475:18 clippy::match_same_arms "this `match` has identical arm bodies"
-target/lintcheck/sources/ripgrep-12.1.1/crates/core/args.rs:512:19 clippy::doc_markdown "you should put `ArgMatches` between ticks in the documentation"
-target/lintcheck/sources/ripgrep-12.1.1/crates/core/args.rs:549:16 clippy::wrong_self_convention "methods with the following characteristics: (`to_*` and `self` type is not `Copy`) usually take `self` by reference"
-target/lintcheck/sources/ripgrep-12.1.1/crates/core/args.rs:76:18 clippy::trivially_copy_pass_by_ref "this argument (1 byte) is passed by reference, but would be more efficient if passed by value (limit: 8 byte)"
-target/lintcheck/sources/ripgrep-12.1.1/crates/core/args.rs:77:13 clippy::enum_glob_use "usage of wildcard import for enum variants"
-target/lintcheck/sources/ripgrep-12.1.1/crates/core/args.rs:923:42 clippy::doc_markdown "you should put `BinaryDetection::quit` between ticks in the documentation"
-target/lintcheck/sources/ripgrep-12.1.1/crates/core/config.rs:13:1 clippy::single_component_path_imports "this import is redundant"
-target/lintcheck/sources/ripgrep-12.1.1/crates/core/config.rs:58:6 clippy::type_complexity "very complex type used. Consider factoring parts into `type` definitions"
-target/lintcheck/sources/ripgrep-12.1.1/crates/core/config.rs:79:6 clippy::type_complexity "very complex type used. Consider factoring parts into `type` definitions"
-target/lintcheck/sources/ripgrep-12.1.1/crates/core/logger.rs:11:30 clippy::doc_markdown "you should put `max_level` between ticks in the documentation"
-target/lintcheck/sources/ripgrep-12.1.1/crates/core/logger.rs:15:16 clippy::redundant_static_lifetimes "constants have by default a `'static` lifetime"
-target/lintcheck/sources/ripgrep-12.1.1/crates/core/main.rs:114:9 clippy::let_underscore_drop "non-binding `let` on a type that implements `Drop`"
-target/lintcheck/sources/ripgrep-12.1.1/crates/core/main.rs:189:9 clippy::let_underscore_drop "non-binding `let` on a type that implements `Drop`"
-target/lintcheck/sources/ripgrep-12.1.1/crates/core/main.rs:55:19 clippy::needless_pass_by_value "this argument is passed by value, but not consumed in the function body"
-target/lintcheck/sources/ripgrep-12.1.1/crates/core/main.rs:56:9 clippy::enum_glob_use "usage of wildcard import for enum variants"
-target/lintcheck/sources/ripgrep-12.1.1/crates/core/messages.rs:46:1 clippy::module_name_repetitions "item name ends with its containing module's name"
-target/lintcheck/sources/ripgrep-12.1.1/crates/core/messages.rs:51:1 clippy::module_name_repetitions "item name ends with its containing module's name"
-target/lintcheck/sources/ripgrep-12.1.1/crates/core/messages.rs:62:1 clippy::module_name_repetitions "item name ends with its containing module's name"
-target/lintcheck/sources/ripgrep-12.1.1/crates/core/path_printer.rs:27:1 clippy::module_name_repetitions "item name starts with its containing module's name"
-target/lintcheck/sources/ripgrep-12.1.1/crates/core/path_printer.rs:89:9 clippy::if_not_else "unnecessary boolean `not` operation"
-target/lintcheck/sources/ripgrep-12.1.1/crates/core/search.rs:185:1 clippy::module_name_repetitions "item name starts with its containing module's name"
-target/lintcheck/sources/ripgrep-12.1.1/crates/core/search.rs:224:5 clippy::upper_case_acronyms "name `JSON` contains a capitalized acronym"
-target/lintcheck/sources/ripgrep-12.1.1/crates/core/search.rs:292:9 clippy::write_with_newline "using `write!()` with a format string that ends in a single newline"
-target/lintcheck/sources/ripgrep-12.1.1/crates/core/search.rs:311:1 clippy::module_name_repetitions "item name starts with its containing module's name"
-target/lintcheck/sources/ripgrep-12.1.1/crates/core/search.rs:377:12 clippy::nonminimal_bool "this boolean expression can be simplified"
-target/lintcheck/sources/ripgrep-12.1.1/crates/core/search.rs:423:13 clippy::enum_glob_use "usage of wildcard import for enum variants"
-target/lintcheck/sources/ripgrep-12.1.1/crates/core/search.rs:447:13 clippy::enum_glob_use "usage of wildcard import for enum variants"
-target/lintcheck/sources/ripgrep-12.1.1/crates/core/search.rs:472:24 clippy::map_clone "you are using an explicit closure for cloning elements"
-target/lintcheck/sources/ripgrep-12.1.1/crates/core/search.rs:472:41 clippy::redundant_closure_for_method_calls "redundant closure"
-target/lintcheck/sources/ripgrep-12.1.1/crates/core/search.rs:480:24 clippy::map_clone "you are using an explicit closure for cloning elements"
-target/lintcheck/sources/ripgrep-12.1.1/crates/core/search.rs:480:41 clippy::redundant_closure_for_method_calls "redundant closure"
-target/lintcheck/sources/ripgrep-12.1.1/crates/core/search.rs:49:1 clippy::module_name_repetitions "item name starts with its containing module's name"
-target/lintcheck/sources/ripgrep-12.1.1/crates/core/search.rs:509:24 clippy::map_clone "you are using an explicit closure for cloning elements"
-target/lintcheck/sources/ripgrep-12.1.1/crates/core/search.rs:509:41 clippy::redundant_closure_for_method_calls "redundant closure"
-target/lintcheck/sources/ripgrep-12.1.1/crates/core/search.rs:517:24 clippy::map_clone "you are using an explicit closure for cloning elements"
-target/lintcheck/sources/ripgrep-12.1.1/crates/core/search.rs:517:41 clippy::redundant_closure_for_method_calls "redundant closure"
-target/lintcheck/sources/ripgrep-12.1.1/crates/core/search.rs:533:36 clippy::cast_lossless "casting `u32` to `f64` may become silently lossy if you later change the type"
-target/lintcheck/sources/ripgrep-12.1.1/crates/core/search.rs:533:5 clippy::cast_precision_loss "casting `u64` to `f64` causes a loss of precision (`u64` is 64 bits wide, but `f64`'s mantissa is only 52 bits wide)"
-target/lintcheck/sources/ripgrep-12.1.1/crates/core/subject.rs:20:1 clippy::module_name_repetitions "item name starts with its containing module's name"
-target/lintcheck/sources/ripgrep-12.1.1/crates/core/subject.rs:4:1 clippy::single_component_path_imports "this import is redundant"
-target/lintcheck/sources/rpmalloc-0.2.0/src/lib.rs:103:5 clippy::must_use_candidate "this method could have a `#[must_use]` attribute"
-target/lintcheck/sources/rpmalloc-0.2.0/src/lib.rs:114:5 clippy::must_use_candidate "this method could have a `#[must_use]` attribute"
-target/lintcheck/sources/rpmalloc-0.2.0/src/lib.rs:71:73 clippy::doc_markdown "you should put bare URLs between `<`/`>` or make a proper Markdown link"
-target/lintcheck/sources/rpmalloc-0.2.0/src/lib.rs:72:50 clippy::doc_markdown "you should put bare URLs between `<`/`>` or make a proper Markdown link"
-target/lintcheck/sources/rpmalloc-0.2.0/src/lib.rs:92:9 clippy::ptr_as_ptr "`as` casting between raw pointers without changing its mutability"
-target/lintcheck/sources/rpmalloc-0.2.0/src/lib.rs:95:21 clippy::ptr_as_ptr "`as` casting between raw pointers without changing its mutability"
-target/lintcheck/sources/serde-1.0.118/src/de/from_primitive.rs:103:24 clippy::wrong_self_convention "methods called `from_*` usually take no `self`"
-target/lintcheck/sources/serde-1.0.118/src/de/from_primitive.rs:107:25 clippy::wrong_self_convention "methods called `from_*` usually take no `self`"
-target/lintcheck/sources/serde-1.0.118/src/de/from_primitive.rs:111:25 clippy::wrong_self_convention "methods called `from_*` usually take no `self`"
-target/lintcheck/sources/serde-1.0.118/src/de/from_primitive.rs:115:25 clippy::wrong_self_convention "methods called `from_*` usually take no `self`"
-target/lintcheck/sources/serde-1.0.118/src/de/from_primitive.rs:48:24 clippy::wrong_self_convention "methods called `from_*` usually take no `self`"
-target/lintcheck/sources/serde-1.0.118/src/de/from_primitive.rs:52:25 clippy::wrong_self_convention "methods called `from_*` usually take no `self`"
-target/lintcheck/sources/serde-1.0.118/src/de/from_primitive.rs:56:25 clippy::wrong_self_convention "methods called `from_*` usually take no `self`"
-target/lintcheck/sources/serde-1.0.118/src/de/from_primitive.rs:60:25 clippy::wrong_self_convention "methods called `from_*` usually take no `self`"
-target/lintcheck/sources/serde-1.0.118/src/de/mod.rs:1592:9 clippy::let_underscore_drop "non-binding `let` on a type that implements `Drop`"
-target/lintcheck/sources/serde-1.0.118/src/de/mod.rs:1616:9 clippy::let_underscore_drop "non-binding `let` on a type that implements `Drop`"
-target/lintcheck/sources/serde-1.0.118/src/de/mod.rs:1627:9 clippy::let_underscore_drop "non-binding `let` on a type that implements `Drop`"
-target/lintcheck/sources/serde-1.0.118/src/de/mod.rs:1638:9 clippy::let_underscore_drop "non-binding `let` on a type that implements `Drop`"
-target/lintcheck/sources/serde-1.0.118/src/de/mod.rs:1649:9 clippy::let_underscore_drop "non-binding `let` on a type that implements `Drop`"
-target/lintcheck/sources/serde-1.0.118/src/de/mod.rs:952:13 clippy::let_underscore_drop "non-binding `let` on a type that implements `Drop`"
-target/lintcheck/sources/serde-1.0.118/src/de/mod.rs:986:13 clippy::let_underscore_drop "non-binding `let` on a type that implements `Drop`"
-target/lintcheck/sources/serde_yaml-0.8.17/src/lib.rs:1:null clippy::cargo_common_metadata "package `serde_yaml` is missing `package.categories` metadata"
-target/lintcheck/sources/syn-1.0.54/build.rs:1:null clippy::cargo_common_metadata "package `syn` is missing `package.keywords` metadata"
-target/lintcheck/sources/syn-1.0.54/src/custom_keyword.rs:177:26 clippy::wrong_self_convention "methods with the following characteristics: (`to_*` and `self` type is `Copy`) usually take `self` by value"
-target/lintcheck/sources/syn-1.0.54/src/gen/clone.rs:1900:13 clippy::match_wildcard_for_single_variants "wildcard matches only a single variant and will also match any future added variants"
-target/lintcheck/sources/syn-1.0.54/src/generics.rs:1227:22 clippy::wrong_self_convention "methods with the following characteristics: (`to_*` and `self` type is `Copy`) usually take `self` by value"
-target/lintcheck/sources/syn-1.0.54/src/lib.rs:1:null clippy::cargo_common_metadata "package `syn` is missing `package.keywords` metadata"
-target/lintcheck/sources/syn-1.0.54/src/lit.rs:1397:40 clippy::redundant_else "redundant else block"
-target/lintcheck/sources/syn-1.0.54/src/lit.rs:1405:28 clippy::redundant_else "redundant else block"
-target/lintcheck/sources/syn-1.0.54/src/lit.rs:1485:32 clippy::redundant_else "redundant else block"
-target/lintcheck/sources/syn-1.0.54/src/op.rs:190:22 clippy::wrong_self_convention "methods with the following characteristics: (`to_*` and `self` type is `Copy`) usually take `self` by value"
-target/lintcheck/sources/syn-1.0.54/src/op.rs:226:22 clippy::wrong_self_convention "methods with the following characteristics: (`to_*` and `self` type is `Copy`) usually take `self` by value"
-target/lintcheck/sources/syn-1.0.54/src/token.rs:311:30 clippy::wrong_self_convention "methods with the following characteristics: (`to_*` and `self` type is `Copy`) usually take `self` by value"
-target/lintcheck/sources/syn-1.0.54/src/token.rs:446:30 clippy::wrong_self_convention "methods with the following characteristics: (`to_*` and `self` type is `Copy`) usually take `self` by value"
-target/lintcheck/sources/syn-1.0.54/src/token.rs:563:18 clippy::wrong_self_convention "methods with the following characteristics: (`to_*` and `self` type is `Copy`) usually take `self` by value"
-target/lintcheck/sources/syn-1.0.54/src/token.rs:974:5 clippy::missing_panics_doc "docs for function which may panic missing `# Panics` section"
-target/lintcheck/sources/tame-oidc-0.1.0/src/errors.rs:9:5 clippy::upper_case_acronyms "name `HTTP` contains a capitalized acronym"
-target/lintcheck/sources/tame-oidc-0.1.0/src/lib.rs:1:null clippy::cargo_common_metadata "package `tame-oidc` is missing `package.categories` metadata"
-target/lintcheck/sources/tame-oidc-0.1.0/src/oidc.rs:111:1 clippy::missing_errors_doc "docs for function returning `Result` missing `# Errors` section"
-target/lintcheck/sources/tame-oidc-0.1.0/src/oidc.rs:127:1 clippy::missing_errors_doc "docs for function returning `Result` missing `# Errors` section"
-target/lintcheck/sources/tame-oidc-0.1.0/src/oidc.rs:52:5 clippy::missing_errors_doc "docs for function returning `Result` missing `# Errors` section"
-target/lintcheck/sources/tame-oidc-0.1.0/src/oidc.rs:60:1 clippy::from_over_into "an implementation of `From` is preferred since it gives you `Into<_>` for free where the reverse isn't true"
-target/lintcheck/sources/tame-oidc-0.1.0/src/oidc.rs:76:1 clippy::missing_errors_doc "docs for function returning `Result` missing `# Errors` section"
-target/lintcheck/sources/tame-oidc-0.1.0/src/provider.rs:107:1 clippy::missing_panics_doc "docs for function which may panic missing `# Panics` section"
-target/lintcheck/sources/tame-oidc-0.1.0/src/provider.rs:107:1 clippy::must_use_candidate "this function could have a `#[must_use]` attribute"
-target/lintcheck/sources/tame-oidc-0.1.0/src/provider.rs:118:1 clippy::missing_errors_doc "docs for function returning `Result` missing `# Errors` section"
-target/lintcheck/sources/tame-oidc-0.1.0/src/provider.rs:143:1 clippy::missing_errors_doc "docs for function returning `Result` missing `# Errors` section"
-target/lintcheck/sources/tame-oidc-0.1.0/src/provider.rs:159:1 clippy::missing_errors_doc "docs for function returning `Result` missing `# Errors` section"
-target/lintcheck/sources/tame-oidc-0.1.0/src/provider.rs:26:5 clippy::missing_errors_doc "docs for function returning `Result` missing `# Errors` section"
-target/lintcheck/sources/tame-oidc-0.1.0/src/provider.rs:38:5 clippy::missing_errors_doc "docs for function returning `Result` missing `# Errors` section"
-target/lintcheck/sources/tame-oidc-0.1.0/src/provider.rs:57:5 clippy::missing_errors_doc "docs for function returning `Result` missing `# Errors` section"
-target/lintcheck/sources/tame-oidc-0.1.0/src/provider.rs:71:5 clippy::missing_errors_doc "docs for function returning `Result` missing `# Errors` section"
-target/lintcheck/sources/tame-oidc-0.1.0/src/provider.rs:95:5 clippy::missing_errors_doc "docs for function returning `Result` missing `# Errors` section"
-target/lintcheck/sources/thiserror-1.0.24/src/lib.rs:1:null clippy::cargo_common_metadata "package `thiserror` is missing `package.keywords` metadata"
-target/lintcheck/sources/unicode-xid-0.2.1/src/lib.rs:1:null clippy::cargo_common_metadata "package `unicode-xid` is missing `package.categories` metadata"
-target/lintcheck/sources/unicode-xid-0.2.1/src/lib.rs:57:64 clippy::doc_markdown "you should put `XID_Start` between ticks in the documentation"
-target/lintcheck/sources/unicode-xid-0.2.1/src/lib.rs:60:10 clippy::doc_markdown "you should put `XID_Start` between ticks in the documentation"
-target/lintcheck/sources/unicode-xid-0.2.1/src/lib.rs:62:27 clippy::doc_markdown "you should put `ID_Start` between ticks in the documentation"
-target/lintcheck/sources/unicode-xid-0.2.1/src/lib.rs:62:67 clippy::doc_markdown "you should put `NFKx` between ticks in the documentation"
-target/lintcheck/sources/unicode-xid-0.2.1/src/lib.rs:63:21 clippy::wrong_self_convention "methods called `is_*` usually take `self` by reference or no `self`"
-target/lintcheck/sources/unicode-xid-0.2.1/src/lib.rs:65:61 clippy::doc_markdown "you should put `XID_Continue` between ticks in the documentation"
-target/lintcheck/sources/unicode-xid-0.2.1/src/lib.rs:68:10 clippy::doc_markdown "you should put `XID_Continue` between ticks in the documentation"
-target/lintcheck/sources/unicode-xid-0.2.1/src/lib.rs:70:28 clippy::doc_markdown "you should put `ID_Continue` between ticks in the documentation"
-target/lintcheck/sources/unicode-xid-0.2.1/src/lib.rs:70:72 clippy::doc_markdown "you should put `NFKx` between ticks in the documentation"
-target/lintcheck/sources/unicode-xid-0.2.1/src/lib.rs:71:24 clippy::wrong_self_convention "methods called `is_*` usually take `self` by reference or no `self`"
-target/lintcheck/sources/xsv-0.13.0/src/cmd/cat.rs:101:34 clippy::redundant_closure_for_method_calls "redundant closure"
-target/lintcheck/sources/xsv-0.13.0/src/cmd/cat.rs:42:1 clippy::struct_excessive_bools "more than 3 bools in a struct"
-target/lintcheck/sources/xsv-0.13.0/src/cmd/cat.rs:53:9 clippy::similar_names "binding's name is too similar to existing binding"
-target/lintcheck/sources/xsv-0.13.0/src/cmd/cat.rs:7:16 clippy::redundant_static_lifetimes "statics have by default a `'static` lifetime"
-target/lintcheck/sources/xsv-0.13.0/src/cmd/count.rs:32:9 clippy::similar_names "binding's name is too similar to existing binding"
-target/lintcheck/sources/xsv-0.13.0/src/cmd/count.rs:38:9 clippy::single_match_else "you seem to be trying to use `match` for destructuring a single pattern. Consider using `if let`"
-target/lintcheck/sources/xsv-0.13.0/src/cmd/count.rs:42:33 clippy::unseparated_literal_suffix "integer type suffix should be separated by an underscore"
-target/lintcheck/sources/xsv-0.13.0/src/cmd/count.rs:7:16 clippy::redundant_static_lifetimes "statics have by default a `'static` lifetime"
-target/lintcheck/sources/xsv-0.13.0/src/cmd/fixlengths.rs:45:9 clippy::similar_names "binding's name is too similar to existing binding"
-target/lintcheck/sources/xsv-0.13.0/src/cmd/fixlengths.rs:50:18 clippy::single_match_else "you seem to be trying to use `match` for destructuring a single pattern. Consider using `if let`"
-target/lintcheck/sources/xsv-0.13.0/src/cmd/fixlengths.rs:62:30 clippy::unseparated_literal_suffix "integer type suffix should be separated by an underscore"
-target/lintcheck/sources/xsv-0.13.0/src/cmd/fixlengths.rs:9:16 clippy::redundant_static_lifetimes "statics have by default a `'static` lifetime"
-target/lintcheck/sources/xsv-0.13.0/src/cmd/flatten.rs:10:16 clippy::redundant_static_lifetimes "statics have by default a `'static` lifetime"
-target/lintcheck/sources/xsv-0.13.0/src/cmd/flatten.rs:51:9 clippy::similar_names "binding's name is too similar to existing binding"
-target/lintcheck/sources/xsv-0.13.0/src/cmd/fmt.rs:50:9 clippy::similar_names "binding's name is too similar to existing binding"
-target/lintcheck/sources/xsv-0.13.0/src/cmd/fmt.rs:55:13 clippy::similar_names "binding's name is too similar to existing binding"
-target/lintcheck/sources/xsv-0.13.0/src/cmd/fmt.rs:7:16 clippy::redundant_static_lifetimes "statics have by default a `'static` lifetime"
-target/lintcheck/sources/xsv-0.13.0/src/cmd/frequency.rs:148:43 clippy::cast_possible_truncation "casting `u64` to `usize` may truncate the value on targets with 32-bit wide pointers"
-target/lintcheck/sources/xsv-0.13.0/src/cmd/frequency.rs:149:43 clippy::cast_possible_truncation "casting `u64` to `usize` may truncate the value on targets with 32-bit wide pointers"
-target/lintcheck/sources/xsv-0.13.0/src/cmd/frequency.rs:15:16 clippy::redundant_static_lifetimes "statics have by default a `'static` lifetime"
-target/lintcheck/sources/xsv-0.13.0/src/cmd/frequency.rs:169:13 clippy::similar_names "binding's name is too similar to existing binding"
-target/lintcheck/sources/xsv-0.13.0/src/cmd/frequency.rs:176:17 clippy::if_not_else "unnecessary boolean `not` operation"
-target/lintcheck/sources/xsv-0.13.0/src/cmd/frequency.rs:178:24 clippy::collapsible_else_if "this `else { if .. }` block can be collapsed"
-target/lintcheck/sources/xsv-0.13.0/src/cmd/frequency.rs:77:9 clippy::similar_names "binding's name is too similar to existing binding"
-target/lintcheck/sources/xsv-0.13.0/src/cmd/frequency.rs:93:31 clippy::explicit_into_iter_loop "it is more concise to loop over containers instead of using explicit iteration methods"
-target/lintcheck/sources/xsv-0.13.0/src/cmd/headers.rs:43:9 clippy::similar_names "binding's name is too similar to existing binding"
-target/lintcheck/sources/xsv-0.13.0/src/cmd/headers.rs:49:17 clippy::explicit_into_iter_loop "it is more concise to loop over containers instead of using explicit iteration methods"
-target/lintcheck/sources/xsv-0.13.0/src/cmd/headers.rs:9:16 clippy::redundant_static_lifetimes "statics have by default a `'static` lifetime"
-target/lintcheck/sources/xsv-0.13.0/src/cmd/index.rs:11:16 clippy::redundant_static_lifetimes "statics have by default a `'static` lifetime"
-target/lintcheck/sources/xsv-0.13.0/src/cmd/index.rs:45:9 clippy::similar_names "binding's name is too similar to existing binding"
-target/lintcheck/sources/xsv-0.13.0/src/cmd/input.rs:42:9 clippy::similar_names "binding's name is too similar to existing binding"
-target/lintcheck/sources/xsv-0.13.0/src/cmd/input.rs:47:9 clippy::similar_names "binding's name is too similar to existing binding"
-target/lintcheck/sources/xsv-0.13.0/src/cmd/input.rs:7:16 clippy::redundant_static_lifetimes "statics have by default a `'static` lifetime"
-target/lintcheck/sources/xsv-0.13.0/src/cmd/join.rs:17:16 clippy::redundant_static_lifetimes "statics have by default a `'static` lifetime"
-target/lintcheck/sources/xsv-0.13.0/src/cmd/join.rs:194:29 clippy::similar_names "binding's name is too similar to existing binding"
-target/lintcheck/sources/xsv-0.13.0/src/cmd/join.rs:224:22 clippy::similar_names "binding's name is too similar to existing binding"
-target/lintcheck/sources/xsv-0.13.0/src/cmd/join.rs:293:14 clippy::similar_names "binding's name is too similar to existing binding"
-target/lintcheck/sources/xsv-0.13.0/src/cmd/join.rs:293:20 clippy::similar_names "binding's name is too similar to existing binding"
-target/lintcheck/sources/xsv-0.13.0/src/cmd/join.rs:297:13 clippy::redundant_field_names "redundant field names in struct initialization"
-target/lintcheck/sources/xsv-0.13.0/src/cmd/join.rs:298:13 clippy::redundant_field_names "redundant field names in struct initialization"
-target/lintcheck/sources/xsv-0.13.0/src/cmd/join.rs:299:13 clippy::redundant_field_names "redundant field names in struct initialization"
-target/lintcheck/sources/xsv-0.13.0/src/cmd/join.rs:300:13 clippy::redundant_field_names "redundant field names in struct initialization"
-target/lintcheck/sources/xsv-0.13.0/src/cmd/join.rs:308:9 clippy::unused_self "unused `self` argument"
-target/lintcheck/sources/xsv-0.13.0/src/cmd/join.rs:342:38 clippy::unseparated_literal_suffix "integer type suffix should be separated by an underscore"
-target/lintcheck/sources/xsv-0.13.0/src/cmd/join.rs:342:46 clippy::unseparated_literal_suffix "integer type suffix should be separated by an underscore"
-target/lintcheck/sources/xsv-0.13.0/src/cmd/join.rs:347:9 clippy::if_not_else "unnecessary boolean `not` operation"
-target/lintcheck/sources/xsv-0.13.0/src/cmd/join.rs:372:44 clippy::redundant_closure_for_method_calls "redundant closure"
-target/lintcheck/sources/xsv-0.13.0/src/cmd/join.rs:375:33 clippy::similar_names "binding's name is too similar to existing binding"
-target/lintcheck/sources/xsv-0.13.0/src/cmd/join.rs:392:13 clippy::redundant_field_names "redundant field names in struct initialization"
-target/lintcheck/sources/xsv-0.13.0/src/cmd/join.rs:403:29 clippy::explicit_into_iter_loop "it is more concise to loop over containers instead of using explicit iteration methods"
-target/lintcheck/sources/xsv-0.13.0/src/cmd/join.rs:406:57 clippy::implicit_clone "implicitly cloning a `Vec` by calling `to_vec` on its dereferenced type"
-target/lintcheck/sources/xsv-0.13.0/src/cmd/join.rs:426:13 clippy::if_not_else "unnecessary boolean `not` operation"
-target/lintcheck/sources/xsv-0.13.0/src/cmd/join.rs:77:1 clippy::struct_excessive_bools "more than 3 bools in a struct"
-target/lintcheck/sources/xsv-0.13.0/src/cmd/join.rs:94:9 clippy::similar_names "binding's name is too similar to existing binding"
-target/lintcheck/sources/xsv-0.13.0/src/cmd/partition.rs:105:22 clippy::similar_names "binding's name is too similar to existing binding"
-target/lintcheck/sources/xsv-0.13.0/src/cmd/partition.rs:106:22 clippy::redundant_slicing "redundant slicing of the whole range"
-target/lintcheck/sources/xsv-0.13.0/src/cmd/partition.rs:139:13 clippy::redundant_field_names "redundant field names in struct initialization"
-target/lintcheck/sources/xsv-0.13.0/src/cmd/partition.rs:15:16 clippy::redundant_static_lifetimes "statics have by default a `'static` lifetime"
-target/lintcheck/sources/xsv-0.13.0/src/cmd/partition.rs:169:9 clippy::if_not_else "unnecessary boolean `not` operation"
-target/lintcheck/sources/xsv-0.13.0/src/cmd/partition.rs:56:9 clippy::similar_names "binding's name is too similar to existing binding"
-target/lintcheck/sources/xsv-0.13.0/src/cmd/partition.rs:77:9 clippy::unused_self "unused `self` argument"
-target/lintcheck/sources/xsv-0.13.0/src/cmd/sample.rs:105:44 clippy::cast_possible_truncation "casting `u64` to `usize` may truncate the value on targets with 32-bit wide pointers"
-target/lintcheck/sources/xsv-0.13.0/src/cmd/sample.rs:115:21 clippy::cast_possible_truncation "casting `u64` to `usize` may truncate the value on targets with 32-bit wide pointers"
-target/lintcheck/sources/xsv-0.13.0/src/cmd/sample.rs:11:16 clippy::redundant_static_lifetimes "statics have by default a `'static` lifetime"
-target/lintcheck/sources/xsv-0.13.0/src/cmd/sample.rs:51:9 clippy::similar_names "binding's name is too similar to existing binding"
-target/lintcheck/sources/xsv-0.13.0/src/cmd/sample.rs:58:19 clippy::single_match_else "you seem to be trying to use `match` for destructuring a single pattern. Consider using `if let`"
-target/lintcheck/sources/xsv-0.13.0/src/cmd/sample.rs:75:16 clippy::explicit_into_iter_loop "it is more concise to loop over containers instead of using explicit iteration methods"
-target/lintcheck/sources/xsv-0.13.0/src/cmd/sample.rs:91:42 clippy::cast_possible_truncation "casting `u64` to `usize` may truncate the value on targets with 32-bit wide pointers"
-target/lintcheck/sources/xsv-0.13.0/src/cmd/sample.rs:92:43 clippy::cast_possible_truncation "casting `u64` to `usize` may truncate the value on targets with 32-bit wide pointers"
-target/lintcheck/sources/xsv-0.13.0/src/cmd/search.rs:51:9 clippy::similar_names "binding's name is too similar to existing binding"
-target/lintcheck/sources/xsv-0.13.0/src/cmd/search.rs:9:16 clippy::redundant_static_lifetimes "statics have by default a `'static` lifetime"
-target/lintcheck/sources/xsv-0.13.0/src/cmd/select.rs:60:9 clippy::similar_names "binding's name is too similar to existing binding"
-target/lintcheck/sources/xsv-0.13.0/src/cmd/select.rs:8:16 clippy::redundant_static_lifetimes "statics have by default a `'static` lifetime"
-target/lintcheck/sources/xsv-0.13.0/src/cmd/slice.rs:57:9 clippy::similar_names "binding's name is too similar to existing binding"
-target/lintcheck/sources/xsv-0.13.0/src/cmd/slice.rs:9:16 clippy::redundant_static_lifetimes "statics have by default a `'static` lifetime"
-target/lintcheck/sources/xsv-0.13.0/src/cmd/sort.rs:11:16 clippy::redundant_static_lifetimes "statics have by default a `'static` lifetime"
-target/lintcheck/sources/xsv-0.13.0/src/cmd/sort.rs:138:47 clippy::cast_precision_loss "casting `i64` to `f64` causes a loss of precision (`i64` is 64 bits wide, but `f64`'s mantissa is only 52 bits wide)"
-target/lintcheck/sources/xsv-0.13.0/src/cmd/sort.rs:139:51 clippy::cast_precision_loss "casting `i64` to `f64` causes a loss of precision (`i64` is 64 bits wide, but `f64`'s mantissa is only 52 bits wide)"
-target/lintcheck/sources/xsv-0.13.0/src/cmd/sort.rs:48:9 clippy::similar_names "binding's name is too similar to existing binding"
-target/lintcheck/sources/xsv-0.13.0/src/cmd/sort.rs:91:14 clippy::explicit_into_iter_loop "it is more concise to loop over containers instead of using explicit iteration methods"
-target/lintcheck/sources/xsv-0.13.0/src/cmd/split.rs:14:16 clippy::redundant_static_lifetimes "statics have by default a `'static` lifetime"
-target/lintcheck/sources/xsv-0.13.0/src/cmd/split.rs:61:9 clippy::similar_names "binding's name is too similar to existing binding"
-target/lintcheck/sources/xsv-0.13.0/src/cmd/split.rs:94:5 clippy::unnecessary_wraps "this function's return value is unnecessary"
-target/lintcheck/sources/xsv-0.13.0/src/cmd/split.rs:96:14 clippy::needless_pass_by_value "this argument is passed by value, but not consumed in the function body"
-target/lintcheck/sources/xsv-0.13.0/src/cmd/split.rs:99:13 clippy::cast_possible_truncation "casting `u64` to `usize` may truncate the value on targets with 32-bit wide pointers"
-target/lintcheck/sources/xsv-0.13.0/src/cmd/stats.rs:110:36 clippy::redundant_closure_for_method_calls "redundant closure"
-target/lintcheck/sources/xsv-0.13.0/src/cmd/stats.rs:127:14 clippy::needless_pass_by_value "this argument is passed by value, but not consumed in the function body"
-target/lintcheck/sources/xsv-0.13.0/src/cmd/stats.rs:138:43 clippy::cast_possible_truncation "casting `u64` to `usize` may truncate the value on targets with 32-bit wide pointers"
-target/lintcheck/sources/xsv-0.13.0/src/cmd/stats.rs:139:43 clippy::cast_possible_truncation "casting `u64` to `usize` may truncate the value on targets with 32-bit wide pointers"
-target/lintcheck/sources/xsv-0.13.0/src/cmd/stats.rs:162:25 clippy::explicit_into_iter_loop "it is more concise to loop over containers instead of using explicit iteration methods"
-target/lintcheck/sources/xsv-0.13.0/src/cmd/stats.rs:22:16 clippy::redundant_static_lifetimes "statics have by default a `'static` lifetime"
-target/lintcheck/sources/xsv-0.13.0/src/cmd/stats.rs:231:1 clippy::struct_excessive_bools "more than 3 bools in a struct"
-target/lintcheck/sources/xsv-0.13.0/src/cmd/stats.rs:262:35 clippy::default_trait_access "calling `cmd::stats::TypedSum::default()` is more clear than this expression"
-target/lintcheck/sources/xsv-0.13.0/src/cmd/stats.rs:263:40 clippy::default_trait_access "calling `cmd::stats::TypedMinMax::default()` is more clear than this expression"
-target/lintcheck/sources/xsv-0.13.0/src/cmd/stats.rs:264:39 clippy::default_trait_access "calling `stats::OnlineStats::default()` is more clear than this expression"
-target/lintcheck/sources/xsv-0.13.0/src/cmd/stats.rs:265:58 clippy::default_trait_access "calling `stats::Unsorted::default()` is more clear than this expression"
-target/lintcheck/sources/xsv-0.13.0/src/cmd/stats.rs:266:41 clippy::default_trait_access "calling `stats::Unsorted::default()` is more clear than this expression"
-target/lintcheck/sources/xsv-0.13.0/src/cmd/stats.rs:268:18 clippy::default_trait_access "calling `cmd::stats::FieldType::default()` is more clear than this expression"
-target/lintcheck/sources/xsv-0.13.0/src/cmd/stats.rs:269:13 clippy::redundant_field_names "redundant field names in struct initialization"
-target/lintcheck/sources/xsv-0.13.0/src/cmd/stats.rs:270:13 clippy::redundant_field_names "redundant field names in struct initialization"
-target/lintcheck/sources/xsv-0.13.0/src/cmd/stats.rs:271:13 clippy::redundant_field_names "redundant field names in struct initialization"
-target/lintcheck/sources/xsv-0.13.0/src/cmd/stats.rs:272:13 clippy::redundant_field_names "redundant field names in struct initialization"
-target/lintcheck/sources/xsv-0.13.0/src/cmd/stats.rs:273:13 clippy::redundant_field_names "redundant field names in struct initialization"
-target/lintcheck/sources/xsv-0.13.0/src/cmd/stats.rs:274:13 clippy::redundant_field_names "redundant field names in struct initialization"
-target/lintcheck/sources/xsv-0.13.0/src/cmd/stats.rs:283:9 clippy::option_map_unit_fn "called `map(f)` on an `Option` value where `f` is a closure that returns the unit type `()`"
-target/lintcheck/sources/xsv-0.13.0/src/cmd/stats.rs:284:9 clippy::option_map_unit_fn "called `map(f)` on an `Option` value where `f` is a closure that returns the unit type `()`"
-target/lintcheck/sources/xsv-0.13.0/src/cmd/stats.rs:285:9 clippy::option_map_unit_fn "called `map(f)` on an `Option` value where `f` is a closure that returns the unit type `()`"
-target/lintcheck/sources/xsv-0.13.0/src/cmd/stats.rs:290:21 clippy::option_map_unit_fn "called `map(f)` on an `Option` value where `f` is a closure that returns the unit type `()`"
-target/lintcheck/sources/xsv-0.13.0/src/cmd/stats.rs:293:25 clippy::match_same_arms "this `match` has identical arm bodies"
-target/lintcheck/sources/xsv-0.13.0/src/cmd/stats.rs:297:25 clippy::option_map_unit_fn "called `map(f)` on an `Option` value where `f` is a closure that returns the unit type `()`"
-target/lintcheck/sources/xsv-0.13.0/src/cmd/stats.rs:301:21 clippy::option_map_unit_fn "called `map(f)` on an `Option` value where `f` is a closure that returns the unit type `()`"
-target/lintcheck/sources/xsv-0.13.0/src/cmd/stats.rs:302:21 clippy::option_map_unit_fn "called `map(f)` on an `Option` value where `f` is a closure that returns the unit type `()`"
-target/lintcheck/sources/xsv-0.13.0/src/cmd/stats.rs:308:18 clippy::wrong_self_convention "methods with the following characteristics: (`to_*` and `self` type is not `Copy`) usually take `self` by reference"
-target/lintcheck/sources/xsv-0.13.0/src/cmd/stats.rs:318:9 clippy::single_match_else "you seem to be trying to use `match` for destructuring a single pattern. Consider using `if let`"
-target/lintcheck/sources/xsv-0.13.0/src/cmd/stats.rs:322:45 clippy::redundant_closure_for_method_calls "redundant closure"
-target/lintcheck/sources/xsv-0.13.0/src/cmd/stats.rs:322:9 clippy::single_match_else "you seem to be trying to use `match` for destructuring a single pattern. Consider using `if let`"
-target/lintcheck/sources/xsv-0.13.0/src/cmd/stats.rs:327:9 clippy::if_not_else "unnecessary boolean `not` operation"
-target/lintcheck/sources/xsv-0.13.0/src/cmd/stats.rs:330:13 clippy::single_match_else "you seem to be trying to use `match` for destructuring a single pattern. Consider using `if let`"
-target/lintcheck/sources/xsv-0.13.0/src/cmd/stats.rs:338:45 clippy::redundant_closure_for_method_calls "redundant closure"
-target/lintcheck/sources/xsv-0.13.0/src/cmd/stats.rs:402:16 clippy::redundant_pattern_matching "redundant pattern matching, consider using `is_ok()`"
-target/lintcheck/sources/xsv-0.13.0/src/cmd/stats.rs:403:16 clippy::redundant_pattern_matching "redundant pattern matching, consider using `is_ok()`"
-target/lintcheck/sources/xsv-0.13.0/src/cmd/stats.rs:407:18 clippy::trivially_copy_pass_by_ref "this argument (1 byte) is passed by reference, but would be more efficient if passed by value (limit: 8 byte)"
-target/lintcheck/sources/xsv-0.13.0/src/cmd/stats.rs:411:16 clippy::trivially_copy_pass_by_ref "this argument (1 byte) is passed by reference, but would be more efficient if passed by value (limit: 8 byte)"
-target/lintcheck/sources/xsv-0.13.0/src/cmd/stats.rs:427:56 clippy::match_same_arms "this `match` has identical arm bodies"
-target/lintcheck/sources/xsv-0.13.0/src/cmd/stats.rs:429:56 clippy::match_same_arms "this `match` has identical arm bodies"
-target/lintcheck/sources/xsv-0.13.0/src/cmd/stats.rs:430:60 clippy::match_same_arms "this `match` has identical arm bodies"
-target/lintcheck/sources/xsv-0.13.0/src/cmd/stats.rs:430:60 clippy::match_same_arms "this `match` has identical arm bodies"
-target/lintcheck/sources/xsv-0.13.0/src/cmd/stats.rs:454:5 clippy::doc_markdown "you should put `TypedSum` between ticks in the documentation"
-target/lintcheck/sources/xsv-0.13.0/src/cmd/stats.rs:473:43 clippy::cast_precision_loss "casting `i64` to `f64` causes a loss of precision (`i64` is 64 bits wide, but `f64`'s mantissa is only 52 bits wide)"
-target/lintcheck/sources/xsv-0.13.0/src/cmd/stats.rs:504:56 clippy::cast_precision_loss "casting `i64` to `f64` causes a loss of precision (`i64` is 64 bits wide, but `f64`'s mantissa is only 52 bits wide)"
-target/lintcheck/sources/xsv-0.13.0/src/cmd/stats.rs:505:51 clippy::cast_precision_loss "casting `i64` to `f64` causes a loss of precision (`i64` is 64 bits wide, but `f64`'s mantissa is only 52 bits wide)"
-target/lintcheck/sources/xsv-0.13.0/src/cmd/stats.rs:511:5 clippy::doc_markdown "you should put `TypedMinMax` between ticks in the documentation"
-target/lintcheck/sources/xsv-0.13.0/src/cmd/stats.rs:536:35 clippy::cast_possible_truncation "casting `f64` to `i64` may truncate the value"
-target/lintcheck/sources/xsv-0.13.0/src/cmd/stats.rs:544:33 clippy::cast_precision_loss "casting `i64` to `f64` causes a loss of precision (`i64` is 64 bits wide, but `f64`'s mantissa is only 52 bits wide)"
-target/lintcheck/sources/xsv-0.13.0/src/cmd/stats.rs:592:22 clippy::default_trait_access "calling `stats::MinMax::default()` is more clear than this expression"
-target/lintcheck/sources/xsv-0.13.0/src/cmd/stats.rs:593:22 clippy::default_trait_access "calling `stats::MinMax::default()` is more clear than this expression"
-target/lintcheck/sources/xsv-0.13.0/src/cmd/stats.rs:594:23 clippy::default_trait_access "calling `stats::MinMax::default()` is more clear than this expression"
-target/lintcheck/sources/xsv-0.13.0/src/cmd/stats.rs:595:21 clippy::default_trait_access "calling `stats::MinMax::default()` is more clear than this expression"
-target/lintcheck/sources/xsv-0.13.0/src/cmd/stats.rs:71:1 clippy::struct_excessive_bools "more than 3 bools in a struct"
-target/lintcheck/sources/xsv-0.13.0/src/cmd/stats.rs:86:9 clippy::similar_names "binding's name is too similar to existing binding"
-target/lintcheck/sources/xsv-0.13.0/src/cmd/table.rs:10:16 clippy::redundant_static_lifetimes "statics have by default a `'static` lifetime"
-target/lintcheck/sources/xsv-0.13.0/src/cmd/table.rs:50:9 clippy::similar_names "binding's name is too similar to existing binding"
-target/lintcheck/sources/xsv-0.13.0/src/cmd/table.rs:54:9 clippy::similar_names "binding's name is too similar to existing binding"
-target/lintcheck/sources/xsv-0.13.0/src/config.rs:113:43 clippy::or_fun_call "use of `unwrap_or` followed by a function call"
-target/lintcheck/sources/xsv-0.13.0/src/config.rs:58:1 clippy::struct_excessive_bools "more than 3 bools in a struct"
-target/lintcheck/sources/xsv-0.13.0/src/config.rs:77:28 clippy::explicit_deref_methods "explicit `deref` method call"
-target/lintcheck/sources/xsv-0.13.0/src/config.rs:90:13 clippy::redundant_field_names "redundant field names in struct initialization"
-target/lintcheck/sources/xsv-0.13.0/src/index.rs:31:13 clippy::redundant_field_names "redundant field names in struct initialization"
-target/lintcheck/sources/xsv-0.13.0/src/main.rs:164:49 clippy::redundant_clone "redundant clone"
-target/lintcheck/sources/xsv-0.13.0/src/main.rs:164:50 clippy::implicit_clone "implicitly cloning a `String` by calling `to_owned` on its dereferenced type"
-target/lintcheck/sources/xsv-0.13.0/src/main.rs:1:null clippy::cargo_common_metadata "package `xsv` is missing `package.categories` metadata"
-target/lintcheck/sources/xsv-0.13.0/src/main.rs:1:null clippy::multiple_crate_versions "multiple versions for dependency `rand_core`: 0.3.1, 0.4.2"
-target/lintcheck/sources/xsv-0.13.0/src/main.rs:1:null clippy::multiple_crate_versions "multiple versions for dependency `rand`: 0.3.23, 0.4.6"
-target/lintcheck/sources/xsv-0.13.0/src/main.rs:75:16 clippy::redundant_static_lifetimes "statics have by default a `'static` lifetime"
-target/lintcheck/sources/xsv-0.13.0/src/select.rs:13:1 clippy::module_name_repetitions "item name starts with its containing module's name"
-target/lintcheck/sources/xsv-0.13.0/src/select.rs:154:5 clippy::unnecessary_wraps "this function's return value is unnecessarily wrapped by `Result`"
-target/lintcheck/sources/xsv-0.13.0/src/select.rs:250:33 clippy::similar_names "binding's name is too similar to existing binding"
-target/lintcheck/sources/xsv-0.13.0/src/select.rs:250:43 clippy::similar_names "binding's name is too similar to existing binding"
-target/lintcheck/sources/xsv-0.13.0/src/select.rs:255:39 clippy::range_plus_one "an inclusive range would be more readable"
-target/lintcheck/sources/xsv-0.13.0/src/select.rs:280:20 clippy::len_zero "length comparison to zero"
-target/lintcheck/sources/xsv-0.13.0/src/select.rs:29:13 clippy::redundant_field_names "redundant field names in struct initialization"
-target/lintcheck/sources/xsv-0.13.0/src/select.rs:360:62 clippy::trivially_copy_pass_by_ref "this argument (8 byte) is passed by reference, but would be more efficient if passed by value (limit: 8 byte)"
-target/lintcheck/sources/xsv-0.13.0/src/select.rs:360:9 clippy::unnecessary_wraps "this function's return value is unnecessarily wrapped by `Option`"
-target/lintcheck/sources/xsv-0.13.0/src/select.rs:375:9 clippy::stable_sort_primitive "used `sort` on primitive type `usize`"
-target/lintcheck/sources/xsv-0.13.0/src/select.rs:379:18 clippy::explicit_into_iter_loop "it is more concise to loop over containers instead of using explicit iteration methods"
-target/lintcheck/sources/xsv-0.13.0/src/select.rs:416:5 clippy::needless_lifetimes "explicit lifetimes given in parameter types where they could be elided (or replaced with `'_` if needed by type declaration)"
-target/lintcheck/sources/xsv-0.13.0/src/select.rs:419:9 clippy::unnecessary_wraps "this function's return value is unnecessarily wrapped by `Option`"
-target/lintcheck/sources/xsv-0.13.0/src/select.rs:420:27 clippy::option_option "consider using `Option<T>` instead of `Option<Option<T>>` or a custom enum if you need to distinguish all 3 cases"
-target/lintcheck/sources/xsv-0.13.0/src/select.rs:99:17 clippy::similar_names "binding's name is too similar to existing binding"
-target/lintcheck/sources/xsv-0.13.0/src/util.rs:150:5 clippy::doc_markdown "you should put bare URLs between `<`/`>` or make a proper Markdown link"
-target/lintcheck/sources/xsv-0.13.0/src/util.rs:37:33 clippy::map_clone "you are using an explicit closure for copying elements"
-target/lintcheck/sources/xsv-0.13.0/src/util.rs:90:1 clippy::needless_lifetimes "explicit lifetimes given in parameter types where they could be elided (or replaced with `'_` if needed by type declaration)"
-
-
-
-
-Stats:
-clippy::clone_on_copy 1
-clippy::comparison_chain 1
-clippy::expect_fun_call 1
-clippy::explicit_deref_methods 1
-clippy::from_iter_instead_of_collect 1
-clippy::int_plus_one 1
-clippy::manual_flatten 1
-clippy::manual_saturating_arithmetic 1
-clippy::nonminimal_bool 1
-clippy::or_fun_call 1
-clippy::precedence 1
-clippy::pub_enum_variant_names 1
-clippy::redundant_clone 1
-clippy::same_item_push 1
-clippy::should_implement_trait 1
-clippy::stable_sort_primitive 1
-clippy::unnecessary_lazy_evaluations 1
-clippy::unsafe_derive_deserialize 1
-clippy::used_underscore_binding 1
-clippy::verbose_bit_mask 1
-clippy::while_let_on_iterator 1
-clippy::comparison_to_empty 2
-clippy::filter_map 2
-clippy::from_over_into 2
-clippy::len_zero 2
-clippy::manual_non_exhaustive 2
-clippy::match_on_vec_items 2
-clippy::option_as_ref_deref 2
-clippy::option_option 2
-clippy::question_mark 2
-clippy::redundant_pattern_matching 2
-clippy::redundant_slicing 2
-clippy::type_complexity 2
-clippy::unnecessary_cast 2
-clippy::unused_unit 2
-clippy::vec_init_then_push 2
-clippy::write_with_newline 2
-clippy::filter_map_next 3
-clippy::fn_params_excessive_bools 3
-clippy::if_same_then_else 3
-clippy::inconsistent_struct_constructor 3
-clippy::manual_map 3
-clippy::mut_mut 3
-clippy::ptr_arg 3
-clippy::upper_case_acronyms 3
-clippy::zero_ptr 3
-clippy::mem_replace_with_default 4
-clippy::too_many_arguments 4
-clippy::explicit_iter_loop 5
-clippy::field_reassign_with_default 5
-clippy::identity_op 5
-clippy::match_like_matches_macro 5
-clippy::needless_return 5
-clippy::new_without_default 5
-clippy::collapsible_else_if 6
-clippy::manual_strip 6
-clippy::non_ascii_literal 6
-clippy::single_component_path_imports 6
-clippy::case_sensitive_file_extension_comparisons 7
-clippy::explicit_into_iter_loop 7
-clippy::implicit_clone 7
-clippy::map_clone 7
-clippy::option_map_unit_fn 7
-clippy::range_plus_one 7
-clippy::invalid_upcast_comparisons 8
-clippy::needless_question_mark 8
-clippy::len_without_is_empty 9
-clippy::multiple_crate_versions 9
-clippy::manual_range_contains 10
-clippy::missing_safety_doc 10
-clippy::needless_doctest_main 10
-clippy::match_wildcard_for_single_variants 11
-clippy::needless_lifetimes 12
-clippy::linkedlist 14
-clippy::single_char_add_str 14
-clippy::option_if_let_else 15
-clippy::shadow_unrelated 15
-clippy::needless_pass_by_value 18
-clippy::cast_possible_wrap 19
-clippy::cast_sign_loss 19
-clippy::unnecessary_wraps 19
-clippy::unused_self 19
-clippy::unusual_byte_groupings 19
-clippy::map_unwrap_or 20
-clippy::struct_excessive_bools 20
-clippy::cargo_common_metadata 21
-clippy::ptr_as_ptr 21
-clippy::redundant_static_lifetimes 21
-clippy::cast_lossless 23
-clippy::unnested_or_patterns 25
-clippy::default_trait_access 26
-clippy::let_underscore_drop 26
-clippy::trivially_copy_pass_by_ref 26
-clippy::redundant_else 29
-clippy::too_many_lines 36
-clippy::if_not_else 38
-clippy::unseparated_literal_suffix 41
-clippy::cast_precision_loss 44
-clippy::enum_glob_use 44
-clippy::single_match_else 48
-clippy::inline_always 59
-clippy::missing_panics_doc 59
-clippy::match_same_arms 62
-clippy::similar_names 83
-clippy::wrong_self_convention 94
-clippy::cast_possible_truncation 95
-clippy::redundant_field_names 111
-clippy::redundant_closure_for_method_calls 131
-clippy::items_after_statements 143
-clippy::module_name_repetitions 146
-clippy::expl_impl_clone_on_copy 164
-clippy::wildcard_imports 164
-clippy::doc_markdown 184
-clippy::missing_errors_doc 356
-clippy::unreadable_literal 365
-clippy::must_use_candidate 571
-ICEs:
diff --git a/src/tools/clippy/lintcheck/src/main.rs b/src/tools/clippy/lintcheck/src/main.rs
index 97d3794fb84..53e669254cf 100644
--- a/src/tools/clippy/lintcheck/src/main.rs
+++ b/src/tools/clippy/lintcheck/src/main.rs
@@ -12,7 +12,7 @@ use std::process::Command;
use std::sync::atomic::{AtomicUsize, Ordering};
use std::{collections::HashMap, io::ErrorKind};
use std::{
- env, fmt,
+ env,
fs::write,
path::{Path, PathBuf},
thread,
@@ -101,13 +101,28 @@ struct ClippyWarning {
is_ice: bool,
}
-impl std::fmt::Display for ClippyWarning {
- fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
- writeln!(
- f,
- r#"target/lintcheck/sources/{}-{}/{}:{}:{} {} "{}""#,
- &self.crate_name, &self.crate_version, &self.file, &self.line, &self.column, &self.linttype, &self.message
- )
+#[allow(unused)]
+impl ClippyWarning {
+ fn to_output(&self, markdown: bool) -> String {
+ let file = format!("{}-{}/{}", &self.crate_name, &self.crate_version, &self.file);
+ let file_with_pos = format!("{}:{}:{}", &file, &self.line, &self.column);
+ if markdown {
+ let lint = format!("`{}`", self.linttype);
+
+ let mut output = String::from("| ");
+ output.push_str(&format!(
+ "[`{}`](../target/lintcheck/sources/{}#L{})",
+ file_with_pos, file, self.line
+ ));
+ output.push_str(&format!(r#" | {:<50} | "{}" |"#, lint, self.message));
+ output.push('\n');
+ output
+ } else {
+ format!(
+ "target/lintcheck/sources/{} {} \"{}\"\n",
+ file_with_pos, self.linttype, self.message
+ )
+ }
}
}
@@ -264,6 +279,7 @@ impl Crate {
thread_limit: usize,
total_crates_to_lint: usize,
fix: bool,
+ lint_filter: &Vec<String>,
) -> Vec<ClippyWarning> {
// advance the atomic index by one
let index = target_dir_index.fetch_add(1, Ordering::SeqCst);
@@ -288,9 +304,9 @@ impl Crate {
let shared_target_dir = clippy_project_root().join("target/lintcheck/shared_target_dir");
let mut args = if fix {
- vec!["--fix", "--allow-no-vcs", "--", "--cap-lints=warn"]
+ vec!["--fix", "--allow-no-vcs", "--"]
} else {
- vec!["--", "--message-format=json", "--", "--cap-lints=warn"]
+ vec!["--", "--message-format=json", "--"]
};
if let Some(options) = &self.options {
@@ -301,6 +317,13 @@ impl Crate {
args.extend(&["-Wclippy::pedantic", "-Wclippy::cargo"])
}
+ if lint_filter.is_empty() {
+ args.push("--cap-lints=warn");
+ } else {
+ args.push("--cap-lints=allow");
+ args.extend(lint_filter.iter().map(|filter| filter.as_str()))
+ }
+
let all_output = std::process::Command::new(&cargo_clippy_path)
// use the looping index to create individual target dirs
.env(
@@ -360,14 +383,18 @@ impl Crate {
#[derive(Debug)]
struct LintcheckConfig {
- // max number of jobs to spawn (default 1)
+ /// max number of jobs to spawn (default 1)
max_jobs: usize,
- // we read the sources to check from here
+ /// we read the sources to check from here
sources_toml_path: PathBuf,
- // we save the clippy lint results here
+ /// we save the clippy lint results here
lintcheck_results_path: PathBuf,
- // whether to just run --fix and not collect all the warnings
+ /// whether to just run --fix and not collect all the warnings
fix: bool,
+ /// A list of lint that this lintcheck run shound focus on
+ lint_filter: Vec<String>,
+ /// Indicate if the output should support markdown syntax
+ markdown: bool,
}
impl LintcheckConfig {
@@ -383,12 +410,17 @@ impl LintcheckConfig {
.to_string()
});
+ let markdown = clap_config.is_present("markdown");
let sources_toml_path = PathBuf::from(sources_toml);
// for the path where we save the lint results, get the filename without extension (so for
// wasd.toml, use "wasd"...)
let filename: PathBuf = sources_toml_path.file_stem().unwrap().into();
- let lintcheck_results_path = PathBuf::from(format!("lintcheck-logs/{}_logs.txt", filename.display()));
+ let lintcheck_results_path = PathBuf::from(format!(
+ "lintcheck-logs/{}_logs.{}",
+ filename.display(),
+ if markdown { "md" } else { "txt" }
+ ));
// look at the --threads arg, if 0 is passed, ask rayon rayon how many threads it would spawn and
// use half of that for the physical core count
@@ -410,12 +442,27 @@ impl LintcheckConfig {
None => 1,
};
let fix: bool = clap_config.is_present("fix");
+ let lint_filter: Vec<String> = clap_config
+ .values_of("filter")
+ .map(|iter| {
+ iter.map(|lint_name| {
+ let mut filter = lint_name.replace('_', "-");
+ if !filter.starts_with("clippy::") {
+ filter.insert_str(0, "clippy::");
+ }
+ filter
+ })
+ .collect()
+ })
+ .unwrap_or_default();
LintcheckConfig {
max_jobs,
sources_toml_path,
lintcheck_results_path,
fix,
+ lint_filter,
+ markdown,
}
}
}
@@ -563,7 +610,7 @@ fn parse_json_message(json_message: &str, krate: &Crate) -> ClippyWarning {
}
}
-/// Generate a short list of occuring lints-types and their count
+/// Generate a short list of occurring lints-types and their count
fn gather_stats(clippy_warnings: &[ClippyWarning]) -> (String, HashMap<&String, usize>) {
// count lint type occurrences
let mut counter: HashMap<&String, usize> = HashMap::new();
@@ -577,10 +624,15 @@ fn gather_stats(clippy_warnings: &[ClippyWarning]) -> (String, HashMap<&String,
// to not have a lint with 200 and 2 warnings take the same spot
stats.sort_by_key(|(lint, count)| format!("{:0>4}, {}", count, lint));
+ let mut header = String::from("| lint | count |\n");
+ header.push_str("| -------------------------------------------------- | ----- |\n");
let stats_string = stats
.iter()
- .map(|(lint, count)| format!("{} {}\n", lint, count))
- .collect::<String>();
+ .map(|(lint, count)| format!("| {:<50} | {:>4} |\n", lint, count))
+ .fold(header, |mut table, line| {
+ table.push_str(&line);
+ table
+ });
(stats_string, counter)
}
@@ -682,6 +734,15 @@ pub fn main() {
let old_stats = read_stats_from_file(&config.lintcheck_results_path);
let counter = AtomicUsize::new(1);
+ let lint_filter: Vec<String> = config
+ .lint_filter
+ .iter()
+ .map(|filter| {
+ let mut filter = filter.clone();
+ filter.insert_str(0, "--force-warn=");
+ filter
+ })
+ .collect();
let clippy_warnings: Vec<ClippyWarning> = if let Some(only_one_crate) = clap_config.value_of("only") {
// if we don't have the specified crate in the .toml, throw an error
@@ -705,7 +766,9 @@ pub fn main() {
.into_iter()
.map(|krate| krate.download_and_extract())
.filter(|krate| krate.name == only_one_crate)
- .flat_map(|krate| krate.run_clippy_lints(&cargo_clippy_path, &AtomicUsize::new(0), 1, 1, config.fix))
+ .flat_map(|krate| {
+ krate.run_clippy_lints(&cargo_clippy_path, &AtomicUsize::new(0), 1, 1, config.fix, &lint_filter)
+ })
.collect()
} else {
if config.max_jobs > 1 {
@@ -718,7 +781,7 @@ pub fn main() {
// quarter of the time which might result in a longer wall clock runtime
// This helps when we check many small crates with dep-trees that don't have a lot of branches in
- // order to achive some kind of parallelism
+ // order to achieve some kind of parallelism
// by default, use a single thread
let num_cpus = config.max_jobs;
@@ -729,7 +792,14 @@ pub fn main() {
.into_par_iter()
.map(|krate| krate.download_and_extract())
.flat_map(|krate| {
- krate.run_clippy_lints(&cargo_clippy_path, &counter, num_cpus, num_crates, config.fix)
+ krate.run_clippy_lints(
+ &cargo_clippy_path,
+ &counter,
+ num_cpus,
+ num_crates,
+ config.fix,
+ &lint_filter,
+ )
})
.collect()
} else {
@@ -738,7 +808,9 @@ pub fn main() {
crates
.into_iter()
.map(|krate| krate.download_and_extract())
- .flat_map(|krate| krate.run_clippy_lints(&cargo_clippy_path, &counter, 1, num_crates, config.fix))
+ .flat_map(|krate| {
+ krate.run_clippy_lints(&cargo_clippy_path, &counter, 1, num_crates, config.fix, &lint_filter)
+ })
.collect()
}
};
@@ -758,22 +830,31 @@ pub fn main() {
.map(|w| (&w.crate_name, &w.message))
.collect();
- let mut all_msgs: Vec<String> = clippy_warnings.iter().map(ToString::to_string).collect();
+ let mut all_msgs: Vec<String> = clippy_warnings
+ .iter()
+ .map(|warn| warn.to_output(config.markdown))
+ .collect();
all_msgs.sort();
- all_msgs.push("\n\n\n\nStats:\n".into());
+ all_msgs.push("\n\n### Stats:\n\n".into());
all_msgs.push(stats_formatted);
// save the text into lintcheck-logs/logs.txt
let mut text = clippy_ver; // clippy version number on top
- text.push_str(&format!("\n{}", all_msgs.join("")));
- text.push_str("ICEs:\n");
+ text.push_str("\n### Reports\n\n");
+ if config.markdown {
+ text.push_str("| file | lint | message |\n");
+ text.push_str("| --- | --- | --- |\n");
+ }
+ text.push_str(&format!("{}", all_msgs.join("")));
+ text.push_str("\n\n### ICEs:\n");
ices.iter()
.for_each(|(cratename, msg)| text.push_str(&format!("{}: '{}'", cratename, msg)));
println!("Writing logs to {}", config.lintcheck_results_path.display());
+ std::fs::create_dir_all(config.lintcheck_results_path.parent().unwrap()).unwrap();
write(&config.lintcheck_results_path, text).unwrap();
- print_stats(old_stats, new_stats);
+ print_stats(old_stats, new_stats, &config.lint_filter);
}
/// read the previous stats from the lintcheck-log file
@@ -787,26 +868,27 @@ fn read_stats_from_file(file_path: &Path) -> HashMap<String, usize> {
let lines: Vec<String> = file_content.lines().map(ToString::to_string).collect();
- // search for the beginning "Stats:" and the end "ICEs:" of the section we want
- let start = lines.iter().position(|line| line == "Stats:").unwrap();
- let end = lines.iter().position(|line| line == "ICEs:").unwrap();
-
- let stats_lines = &lines[start + 1..end];
-
- stats_lines
+ lines
.iter()
- .map(|line| {
- let mut spl = line.split(' ');
- (
- spl.next().unwrap().to_string(),
- spl.next().unwrap().parse::<usize>().unwrap(),
- )
+ .skip_while(|line| line.as_str() != "### Stats:")
+ // Skipping the table header and the `Stats:` label
+ .skip(4)
+ .take_while(|line| line.starts_with("| "))
+ .filter_map(|line| {
+ let mut spl = line.split('|');
+ // Skip the first `|` symbol
+ spl.next();
+ if let (Some(lint), Some(count)) = (spl.next(), spl.next()) {
+ Some((lint.trim().to_string(), count.trim().parse::<usize>().unwrap()))
+ } else {
+ None
+ }
})
.collect::<HashMap<String, usize>>()
}
/// print how lint counts changed between runs
-fn print_stats(old_stats: HashMap<String, usize>, new_stats: HashMap<&String, usize>) {
+fn print_stats(old_stats: HashMap<String, usize>, new_stats: HashMap<&String, usize>, lint_filter: &Vec<String>) {
let same_in_both_hashmaps = old_stats
.iter()
.filter(|(old_key, old_val)| new_stats.get::<&String>(&old_key) == Some(old_val))
@@ -845,6 +927,7 @@ fn print_stats(old_stats: HashMap<String, usize>, new_stats: HashMap<&String, us
old_stats_deduped
.iter()
.filter(|(old_key, _)| new_stats_deduped.get::<&String>(&old_key).is_none())
+ .filter(|(old_key, _)| lint_filter.is_empty() || lint_filter.contains(old_key))
.for_each(|(old_key, old_value)| {
println!("{} {} => 0", old_key, old_value);
});
@@ -903,6 +986,19 @@ fn get_clap_config<'a>() -> ArgMatches<'a> {
.long("--fix")
.help("runs cargo clippy --fix and checks if all suggestions apply"),
)
+ .arg(
+ Arg::with_name("filter")
+ .long("--filter")
+ .takes_value(true)
+ .multiple(true)
+ .value_name("clippy_lint_name")
+ .help("apply a filter to only collect specified lints, this also overrides `allow` attributes"),
+ )
+ .arg(
+ Arg::with_name("markdown")
+ .long("--markdown")
+ .help("change the reports table to use markdown links"),
+ )
.get_matches()
}
diff --git a/src/tools/clippy/rust-toolchain b/src/tools/clippy/rust-toolchain
index 09554c08987..3a5dfa6a8c7 100644
--- a/src/tools/clippy/rust-toolchain
+++ b/src/tools/clippy/rust-toolchain
@@ -1,3 +1,3 @@
[toolchain]
-channel = "nightly-2021-11-04"
-components = ["llvm-tools-preview", "rustc-dev", "rust-src"]
+channel = "nightly-2021-12-17"
+components = ["cargo", "llvm-tools-preview", "rust-src", "rust-std", "rustc", "rustc-dev", "rustfmt"]
diff --git a/src/tools/clippy/src/driver.rs b/src/tools/clippy/src/driver.rs
index 0c82f37d6a2..a8aa3a76abc 100644
--- a/src/tools/clippy/src/driver.rs
+++ b/src/tools/clippy/src/driver.rs
@@ -108,7 +108,7 @@ impl rustc_driver::Callbacks for ClippyCallbacks {
let conf = clippy_lints::read_conf(sess);
clippy_lints::register_plugins(lint_store, sess, &conf);
- clippy_lints::register_pre_expansion_lints(lint_store);
+ clippy_lints::register_pre_expansion_lints(lint_store, sess, &conf);
clippy_lints::register_renamed(lint_store);
}));
diff --git a/src/tools/clippy/tests/compile-test.rs b/src/tools/clippy/tests/compile-test.rs
index f25cf1d3ef5..a2d58491872 100644
--- a/src/tools/clippy/tests/compile-test.rs
+++ b/src/tools/clippy/tests/compile-test.rs
@@ -28,6 +28,7 @@ static TEST_DEPENDENCIES: &[&str] = &[
"serde",
"serde_derive",
"syn",
+ "parking_lot",
];
// Test dependencies may need an `extern crate` here to ensure that they show up
@@ -41,6 +42,8 @@ extern crate if_chain;
#[allow(unused_extern_crates)]
extern crate itertools;
#[allow(unused_extern_crates)]
+extern crate parking_lot;
+#[allow(unused_extern_crates)]
extern crate quote;
#[allow(unused_extern_crates)]
extern crate syn;
diff --git a/src/tools/clippy/tests/fmt.rs b/src/tools/clippy/tests/fmt.rs
index be42f1fbb20..383702dd439 100644
--- a/src/tools/clippy/tests/fmt.rs
+++ b/src/tools/clippy/tests/fmt.rs
@@ -11,10 +11,7 @@ fn fmt() {
}
// Skip this test if nightly rustfmt is unavailable
- let rustup_output = Command::new("rustup")
- .args(&["component", "list", "--toolchain", "nightly"])
- .output()
- .unwrap();
+ let rustup_output = Command::new("rustup").args(&["component", "list"]).output().unwrap();
assert!(rustup_output.status.success());
let component_output = String::from_utf8_lossy(&rustup_output.stdout);
if !component_output.contains("rustfmt") {
diff --git a/src/tools/clippy/tests/ui-internal/check_clippy_version_attribute.rs b/src/tools/clippy/tests/ui-internal/check_clippy_version_attribute.rs
new file mode 100644
index 00000000000..31acac89cc6
--- /dev/null
+++ b/src/tools/clippy/tests/ui-internal/check_clippy_version_attribute.rs
@@ -0,0 +1,87 @@
+#![deny(clippy::internal)]
+#![feature(rustc_private)]
+
+#[macro_use]
+extern crate rustc_middle;
+#[macro_use]
+extern crate rustc_session;
+extern crate rustc_lint;
+
+///////////////////////
+// Valid descriptions
+///////////////////////
+declare_tool_lint! {
+ #[clippy::version = "pre 1.29.0"]
+ pub clippy::VALID_ONE,
+ Warn,
+ "One",
+ report_in_external_macro: true
+}
+
+declare_tool_lint! {
+ #[clippy::version = "1.29.0"]
+ pub clippy::VALID_TWO,
+ Warn,
+ "Two",
+ report_in_external_macro: true
+}
+
+declare_tool_lint! {
+ #[clippy::version = "1.59.0"]
+ pub clippy::VALID_THREE,
+ Warn,
+ "Three",
+ report_in_external_macro: true
+}
+
+///////////////////////
+// Invalid attributes
+///////////////////////
+declare_tool_lint! {
+ #[clippy::version = "1.2.3.4.5.6"]
+ pub clippy::INVALID_ONE,
+ Warn,
+ "One",
+ report_in_external_macro: true
+}
+
+declare_tool_lint! {
+ #[clippy::version = "I'm a string"]
+ pub clippy::INVALID_TWO,
+ Warn,
+ "Two",
+ report_in_external_macro: true
+}
+
+///////////////////////
+// Missing attribute test
+///////////////////////
+declare_tool_lint! {
+ #[clippy::version]
+ pub clippy::MISSING_ATTRIBUTE_ONE,
+ Warn,
+ "Two",
+ report_in_external_macro: true
+}
+
+declare_tool_lint! {
+ pub clippy::MISSING_ATTRIBUTE_TWO,
+ Warn,
+ "Two",
+ report_in_external_macro: true
+}
+
+#[allow(clippy::missing_clippy_version_attribute)]
+mod internal_clippy_lints {
+ declare_tool_lint! {
+ pub clippy::ALLOW_MISSING_ATTRIBUTE_ONE,
+ Warn,
+ "Two",
+ report_in_external_macro: true
+ }
+}
+
+use crate::internal_clippy_lints::ALLOW_MISSING_ATTRIBUTE_ONE;
+declare_lint_pass!(Pass2 => [VALID_ONE, VALID_TWO, VALID_THREE, INVALID_ONE, INVALID_TWO, MISSING_ATTRIBUTE_ONE, MISSING_ATTRIBUTE_TWO, ALLOW_MISSING_ATTRIBUTE_ONE]);
+
+fn main() {}
diff --git a/src/tools/clippy/tests/ui-internal/check_clippy_version_attribute.stderr b/src/tools/clippy/tests/ui-internal/check_clippy_version_attribute.stderr
new file mode 100644
index 00000000000..9302e02ccb9
--- /dev/null
+++ b/src/tools/clippy/tests/ui-internal/check_clippy_version_attribute.stderr
@@ -0,0 +1,73 @@
+error: this item has an invalid `clippy::version` attribute
+ --> $DIR/check_clippy_version_attribute.rs:40:1
+ |
+LL | / declare_tool_lint! {
+LL | | #[clippy::version = "1.2.3.4.5.6"]
+LL | | pub clippy::INVALID_ONE,
+LL | | Warn,
+LL | | "One",
+LL | | report_in_external_macro: true
+LL | | }
+ | |_^
+ |
+note: the lint level is defined here
+ --> $DIR/check_clippy_version_attribute.rs:1:9
+ |
+LL | #![deny(clippy::internal)]
+ | ^^^^^^^^^^^^^^^^
+ = note: `#[deny(clippy::invalid_clippy_version_attribute)]` implied by `#[deny(clippy::internal)]`
+ = help: please use a valid sematic version, see `doc/adding_lints.md`
+ = note: this error originates in the macro `$crate::declare_tool_lint` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error: this item has an invalid `clippy::version` attribute
+ --> $DIR/check_clippy_version_attribute.rs:48:1
+ |
+LL | / declare_tool_lint! {
+LL | | #[clippy::version = "I'm a string"]
+LL | | pub clippy::INVALID_TWO,
+LL | | Warn,
+LL | | "Two",
+LL | | report_in_external_macro: true
+LL | | }
+ | |_^
+ |
+ = help: please use a valid sematic version, see `doc/adding_lints.md`
+ = note: this error originates in the macro `$crate::declare_tool_lint` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error: this lint is missing the `clippy::version` attribute or version value
+ --> $DIR/check_clippy_version_attribute.rs:59:1
+ |
+LL | / declare_tool_lint! {
+LL | | #[clippy::version]
+LL | | pub clippy::MISSING_ATTRIBUTE_ONE,
+LL | | Warn,
+LL | | "Two",
+LL | | report_in_external_macro: true
+LL | | }
+ | |_^
+ |
+note: the lint level is defined here
+ --> $DIR/check_clippy_version_attribute.rs:1:9
+ |
+LL | #![deny(clippy::internal)]
+ | ^^^^^^^^^^^^^^^^
+ = note: `#[deny(clippy::missing_clippy_version_attribute)]` implied by `#[deny(clippy::internal)]`
+ = help: please use a `clippy::version` attribute, see `doc/adding_lints.md`
+ = note: this error originates in the macro `$crate::declare_tool_lint` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error: this lint is missing the `clippy::version` attribute or version value
+ --> $DIR/check_clippy_version_attribute.rs:67:1
+ |
+LL | / declare_tool_lint! {
+LL | | pub clippy::MISSING_ATTRIBUTE_TWO,
+LL | | Warn,
+LL | | "Two",
+LL | | report_in_external_macro: true
+LL | | }
+ | |_^
+ |
+ = help: please use a `clippy::version` attribute, see `doc/adding_lints.md`
+ = note: this error originates in the macro `$crate::declare_tool_lint` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error: aborting due to 4 previous errors
+
diff --git a/src/tools/clippy/tests/ui-internal/collapsible_span_lint_calls.fixed b/src/tools/clippy/tests/ui-internal/collapsible_span_lint_calls.fixed
index 7764cc8da78..a5a6f20ddd5 100644
--- a/src/tools/clippy/tests/ui-internal/collapsible_span_lint_calls.fixed
+++ b/src/tools/clippy/tests/ui-internal/collapsible_span_lint_calls.fixed
@@ -1,5 +1,6 @@
// run-rustfix
#![deny(clippy::internal)]
+#![allow(clippy::missing_clippy_version_attribute)]
#![feature(rustc_private)]
extern crate clippy_utils;
diff --git a/src/tools/clippy/tests/ui-internal/collapsible_span_lint_calls.rs b/src/tools/clippy/tests/ui-internal/collapsible_span_lint_calls.rs
index bdd296db832..6d783aa0786 100644
--- a/src/tools/clippy/tests/ui-internal/collapsible_span_lint_calls.rs
+++ b/src/tools/clippy/tests/ui-internal/collapsible_span_lint_calls.rs
@@ -1,5 +1,6 @@
// run-rustfix
#![deny(clippy::internal)]
+#![allow(clippy::missing_clippy_version_attribute)]
#![feature(rustc_private)]
extern crate clippy_utils;
diff --git a/src/tools/clippy/tests/ui-internal/collapsible_span_lint_calls.stderr b/src/tools/clippy/tests/ui-internal/collapsible_span_lint_calls.stderr
index 0632b038577..558d1299160 100644
--- a/src/tools/clippy/tests/ui-internal/collapsible_span_lint_calls.stderr
+++ b/src/tools/clippy/tests/ui-internal/collapsible_span_lint_calls.stderr
@@ -1,5 +1,5 @@
error: this call is collapsible
- --> $DIR/collapsible_span_lint_calls.rs:35:9
+ --> $DIR/collapsible_span_lint_calls.rs:36:9
|
LL | / span_lint_and_then(cx, TEST_LINT, expr.span, lint_msg, |db| {
LL | | db.span_suggestion(expr.span, help_msg, sugg.to_string(), Applicability::MachineApplicable);
@@ -14,7 +14,7 @@ LL | #![deny(clippy::internal)]
= note: `#[deny(clippy::collapsible_span_lint_calls)]` implied by `#[deny(clippy::internal)]`
error: this call is collapsible
- --> $DIR/collapsible_span_lint_calls.rs:38:9
+ --> $DIR/collapsible_span_lint_calls.rs:39:9
|
LL | / span_lint_and_then(cx, TEST_LINT, expr.span, lint_msg, |db| {
LL | | db.span_help(expr.span, help_msg);
@@ -22,7 +22,7 @@ LL | | });
| |__________^ help: collapse into: `span_lint_and_help(cx, TEST_LINT, expr.span, lint_msg, Some(expr.span), help_msg)`
error: this call is collapsible
- --> $DIR/collapsible_span_lint_calls.rs:41:9
+ --> $DIR/collapsible_span_lint_calls.rs:42:9
|
LL | / span_lint_and_then(cx, TEST_LINT, expr.span, lint_msg, |db| {
LL | | db.help(help_msg);
@@ -30,7 +30,7 @@ LL | | });
| |__________^ help: collapse into: `span_lint_and_help(cx, TEST_LINT, expr.span, lint_msg, None, help_msg)`
error: this call is collspible
- --> $DIR/collapsible_span_lint_calls.rs:44:9
+ --> $DIR/collapsible_span_lint_calls.rs:45:9
|
LL | / span_lint_and_then(cx, TEST_LINT, expr.span, lint_msg, |db| {
LL | | db.span_note(expr.span, note_msg);
@@ -38,7 +38,7 @@ LL | | });
| |__________^ help: collapse into: `span_lint_and_note(cx, TEST_LINT, expr.span, lint_msg, Some(expr.span), note_msg)`
error: this call is collspible
- --> $DIR/collapsible_span_lint_calls.rs:47:9
+ --> $DIR/collapsible_span_lint_calls.rs:48:9
|
LL | / span_lint_and_then(cx, TEST_LINT, expr.span, lint_msg, |db| {
LL | | db.note(note_msg);
diff --git a/src/tools/clippy/tests/ui-internal/custom_ice_message.rs b/src/tools/clippy/tests/ui-internal/custom_ice_message.rs
index 5b30c9d5721..5057a018300 100644
--- a/src/tools/clippy/tests/ui-internal/custom_ice_message.rs
+++ b/src/tools/clippy/tests/ui-internal/custom_ice_message.rs
@@ -4,6 +4,7 @@
// normalize-stderr-test: "', .*clippy_lints" -> "', clippy_lints"
#![deny(clippy::internal)]
+#![allow(clippy::missing_clippy_version_attribute)]
fn it_looks_like_you_are_trying_to_kill_clippy() {}
diff --git a/src/tools/clippy/tests/ui-internal/default_lint.rs b/src/tools/clippy/tests/ui-internal/default_lint.rs
index 053faae02ce..da29aedb2a3 100644
--- a/src/tools/clippy/tests/ui-internal/default_lint.rs
+++ b/src/tools/clippy/tests/ui-internal/default_lint.rs
@@ -1,4 +1,5 @@
#![deny(clippy::internal)]
+#![allow(clippy::missing_clippy_version_attribute)]
#![feature(rustc_private)]
#[macro_use]
diff --git a/src/tools/clippy/tests/ui-internal/default_lint.stderr b/src/tools/clippy/tests/ui-internal/default_lint.stderr
index 4735573a47d..af6735f4e4d 100644
--- a/src/tools/clippy/tests/ui-internal/default_lint.stderr
+++ b/src/tools/clippy/tests/ui-internal/default_lint.stderr
@@ -1,5 +1,5 @@
error: the lint `TEST_LINT_DEFAULT` has the default lint description
- --> $DIR/default_lint.rs:17:1
+ --> $DIR/default_lint.rs:18:1
|
LL | / declare_tool_lint! {
LL | | pub clippy::TEST_LINT_DEFAULT,
diff --git a/src/tools/clippy/tests/ui-internal/if_chain_style.rs b/src/tools/clippy/tests/ui-internal/if_chain_style.rs
index 8e871707aa8..b0d89e038aa 100644
--- a/src/tools/clippy/tests/ui-internal/if_chain_style.rs
+++ b/src/tools/clippy/tests/ui-internal/if_chain_style.rs
@@ -1,5 +1,5 @@
#![warn(clippy::if_chain_style)]
-#![allow(clippy::no_effect)]
+#![allow(clippy::no_effect, clippy::nonminimal_bool, clippy::missing_clippy_version_attribute)]
extern crate if_chain;
diff --git a/src/tools/clippy/tests/ui-internal/interning_defined_symbol.fixed b/src/tools/clippy/tests/ui-internal/interning_defined_symbol.fixed
index 9ab845a573a..6b7fd6efe39 100644
--- a/src/tools/clippy/tests/ui-internal/interning_defined_symbol.fixed
+++ b/src/tools/clippy/tests/ui-internal/interning_defined_symbol.fixed
@@ -1,5 +1,6 @@
// run-rustfix
#![deny(clippy::internal)]
+#![allow(clippy::missing_clippy_version_attribute)]
#![feature(rustc_private)]
extern crate rustc_span;
diff --git a/src/tools/clippy/tests/ui-internal/interning_defined_symbol.rs b/src/tools/clippy/tests/ui-internal/interning_defined_symbol.rs
index a58e182971d..98d7d7adad1 100644
--- a/src/tools/clippy/tests/ui-internal/interning_defined_symbol.rs
+++ b/src/tools/clippy/tests/ui-internal/interning_defined_symbol.rs
@@ -1,5 +1,6 @@
// run-rustfix
#![deny(clippy::internal)]
+#![allow(clippy::missing_clippy_version_attribute)]
#![feature(rustc_private)]
extern crate rustc_span;
diff --git a/src/tools/clippy/tests/ui-internal/interning_defined_symbol.stderr b/src/tools/clippy/tests/ui-internal/interning_defined_symbol.stderr
index 50c1c268eb1..4e99636e683 100644
--- a/src/tools/clippy/tests/ui-internal/interning_defined_symbol.stderr
+++ b/src/tools/clippy/tests/ui-internal/interning_defined_symbol.stderr
@@ -1,5 +1,5 @@
error: interning a defined symbol
- --> $DIR/interning_defined_symbol.rs:17:13
+ --> $DIR/interning_defined_symbol.rs:18:13
|
LL | let _ = Symbol::intern("f32");
| ^^^^^^^^^^^^^^^^^^^^^ help: try: `rustc_span::sym::f32`
@@ -12,19 +12,19 @@ LL | #![deny(clippy::internal)]
= note: `#[deny(clippy::interning_defined_symbol)]` implied by `#[deny(clippy::internal)]`
error: interning a defined symbol
- --> $DIR/interning_defined_symbol.rs:20:13
+ --> $DIR/interning_defined_symbol.rs:21:13
|
LL | let _ = sym!(f32);
| ^^^^^^^^^ help: try: `rustc_span::sym::f32`
error: interning a defined symbol
- --> $DIR/interning_defined_symbol.rs:23:13
+ --> $DIR/interning_defined_symbol.rs:24:13
|
LL | let _ = Symbol::intern("proc-macro");
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `rustc_span::sym::proc_dash_macro`
error: interning a defined symbol
- --> $DIR/interning_defined_symbol.rs:26:13
+ --> $DIR/interning_defined_symbol.rs:27:13
|
LL | let _ = Symbol::intern("self");
| ^^^^^^^^^^^^^^^^^^^^^^ help: try: `rustc_span::symbol::kw::SelfLower`
diff --git a/src/tools/clippy/tests/ui-internal/invalid_paths.rs b/src/tools/clippy/tests/ui-internal/invalid_paths.rs
index a3b19c2e394..b823ff7fe37 100644
--- a/src/tools/clippy/tests/ui-internal/invalid_paths.rs
+++ b/src/tools/clippy/tests/ui-internal/invalid_paths.rs
@@ -1,4 +1,5 @@
#![warn(clippy::internal)]
+#![allow(clippy::missing_clippy_version_attribute)]
mod paths {
// Good path
diff --git a/src/tools/clippy/tests/ui-internal/invalid_paths.stderr b/src/tools/clippy/tests/ui-internal/invalid_paths.stderr
index 20aa81b98a0..0a8e5427978 100644
--- a/src/tools/clippy/tests/ui-internal/invalid_paths.stderr
+++ b/src/tools/clippy/tests/ui-internal/invalid_paths.stderr
@@ -1,5 +1,5 @@
error: invalid path
- --> $DIR/invalid_paths.rs:17:5
+ --> $DIR/invalid_paths.rs:18:5
|
LL | pub const BAD_CRATE_PATH: [&str; 2] = ["bad", "path"];
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -7,7 +7,7 @@ LL | pub const BAD_CRATE_PATH: [&str; 2] = ["bad", "path"];
= note: `-D clippy::invalid-paths` implied by `-D warnings`
error: invalid path
- --> $DIR/invalid_paths.rs:20:5
+ --> $DIR/invalid_paths.rs:21:5
|
LL | pub const BAD_MOD_PATH: [&str; 2] = ["std", "xxx"];
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
diff --git a/src/tools/clippy/tests/ui-internal/lint_without_lint_pass.rs b/src/tools/clippy/tests/ui-internal/lint_without_lint_pass.rs
index beaef79a340..1fd03cfe36d 100644
--- a/src/tools/clippy/tests/ui-internal/lint_without_lint_pass.rs
+++ b/src/tools/clippy/tests/ui-internal/lint_without_lint_pass.rs
@@ -1,4 +1,5 @@
#![deny(clippy::internal)]
+#![allow(clippy::missing_clippy_version_attribute)]
#![feature(rustc_private)]
#[macro_use]
diff --git a/src/tools/clippy/tests/ui-internal/lint_without_lint_pass.stderr b/src/tools/clippy/tests/ui-internal/lint_without_lint_pass.stderr
index e308e13da13..de04920b8e6 100644
--- a/src/tools/clippy/tests/ui-internal/lint_without_lint_pass.stderr
+++ b/src/tools/clippy/tests/ui-internal/lint_without_lint_pass.stderr
@@ -1,5 +1,5 @@
error: the lint `TEST_LINT` is not added to any `LintPass`
- --> $DIR/lint_without_lint_pass.rs:11:1
+ --> $DIR/lint_without_lint_pass.rs:12:1
|
LL | / declare_tool_lint! {
LL | | pub clippy::TEST_LINT,
diff --git a/src/tools/clippy/tests/ui-internal/match_type_on_diag_item.rs b/src/tools/clippy/tests/ui-internal/match_type_on_diag_item.rs
index be7b7a9af19..4b41ff15e80 100644
--- a/src/tools/clippy/tests/ui-internal/match_type_on_diag_item.rs
+++ b/src/tools/clippy/tests/ui-internal/match_type_on_diag_item.rs
@@ -1,4 +1,5 @@
#![deny(clippy::internal)]
+#![allow(clippy::missing_clippy_version_attribute)]
#![feature(rustc_private)]
extern crate clippy_utils;
diff --git a/src/tools/clippy/tests/ui-internal/match_type_on_diag_item.stderr b/src/tools/clippy/tests/ui-internal/match_type_on_diag_item.stderr
index bf1d67e6054..e3cb6b6c22e 100644
--- a/src/tools/clippy/tests/ui-internal/match_type_on_diag_item.stderr
+++ b/src/tools/clippy/tests/ui-internal/match_type_on_diag_item.stderr
@@ -1,5 +1,5 @@
error: usage of `clippy_utils::ty::match_type()` on a type diagnostic item
- --> $DIR/match_type_on_diag_item.rs:30:17
+ --> $DIR/match_type_on_diag_item.rs:31:17
|
LL | let _ = match_type(cx, ty, &OPTION);
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `clippy_utils::ty::is_type_diagnostic_item(cx, ty, sym::Option)`
@@ -12,13 +12,13 @@ LL | #![deny(clippy::internal)]
= note: `#[deny(clippy::match_type_on_diagnostic_item)]` implied by `#[deny(clippy::internal)]`
error: usage of `clippy_utils::ty::match_type()` on a type diagnostic item
- --> $DIR/match_type_on_diag_item.rs:31:17
+ --> $DIR/match_type_on_diag_item.rs:32:17
|
LL | let _ = match_type(cx, ty, &["core", "result", "Result"]);
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `clippy_utils::ty::is_type_diagnostic_item(cx, ty, sym::Result)`
error: usage of `clippy_utils::ty::match_type()` on a type diagnostic item
- --> $DIR/match_type_on_diag_item.rs:34:17
+ --> $DIR/match_type_on_diag_item.rs:35:17
|
LL | let _ = clippy_utils::ty::match_type(cx, ty, rc_path);
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `clippy_utils::ty::is_type_diagnostic_item(cx, ty, sym::Rc)`
diff --git a/src/tools/clippy/tests/ui-internal/outer_expn_data.fixed b/src/tools/clippy/tests/ui-internal/outer_expn_data.fixed
index b0b3498f057..bb82faf0c90 100644
--- a/src/tools/clippy/tests/ui-internal/outer_expn_data.fixed
+++ b/src/tools/clippy/tests/ui-internal/outer_expn_data.fixed
@@ -1,6 +1,7 @@
// run-rustfix
#![deny(clippy::internal)]
+#![allow(clippy::missing_clippy_version_attribute)]
#![feature(rustc_private)]
extern crate rustc_hir;
diff --git a/src/tools/clippy/tests/ui-internal/outer_expn_data.rs b/src/tools/clippy/tests/ui-internal/outer_expn_data.rs
index 55a3fed00d0..187d468b392 100644
--- a/src/tools/clippy/tests/ui-internal/outer_expn_data.rs
+++ b/src/tools/clippy/tests/ui-internal/outer_expn_data.rs
@@ -1,6 +1,7 @@
// run-rustfix
#![deny(clippy::internal)]
+#![allow(clippy::missing_clippy_version_attribute)]
#![feature(rustc_private)]
extern crate rustc_hir;
diff --git a/src/tools/clippy/tests/ui-internal/outer_expn_data.stderr b/src/tools/clippy/tests/ui-internal/outer_expn_data.stderr
index 56b6ce1f78e..afef696785e 100644
--- a/src/tools/clippy/tests/ui-internal/outer_expn_data.stderr
+++ b/src/tools/clippy/tests/ui-internal/outer_expn_data.stderr
@@ -1,5 +1,5 @@
error: usage of `outer_expn().expn_data()`
- --> $DIR/outer_expn_data.rs:24:34
+ --> $DIR/outer_expn_data.rs:25:34
|
LL | let _ = expr.span.ctxt().outer_expn().expn_data();
| ^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `outer_expn_data()`
diff --git a/src/tools/clippy/tests/ui-internal/unnecessary_symbol_str.fixed b/src/tools/clippy/tests/ui-internal/unnecessary_symbol_str.fixed
index 95b8c6dfe89..4f5336663a8 100644
--- a/src/tools/clippy/tests/ui-internal/unnecessary_symbol_str.fixed
+++ b/src/tools/clippy/tests/ui-internal/unnecessary_symbol_str.fixed
@@ -1,7 +1,11 @@
// run-rustfix
#![feature(rustc_private)]
#![deny(clippy::internal)]
-#![allow(clippy::unnecessary_operation, unused_must_use)]
+#![allow(
+ clippy::unnecessary_operation,
+ unused_must_use,
+ clippy::missing_clippy_version_attribute
+)]
extern crate rustc_span;
diff --git a/src/tools/clippy/tests/ui-internal/unnecessary_symbol_str.rs b/src/tools/clippy/tests/ui-internal/unnecessary_symbol_str.rs
index ad6937cf60a..894aa1d3bc6 100644
--- a/src/tools/clippy/tests/ui-internal/unnecessary_symbol_str.rs
+++ b/src/tools/clippy/tests/ui-internal/unnecessary_symbol_str.rs
@@ -1,7 +1,11 @@
// run-rustfix
#![feature(rustc_private)]
#![deny(clippy::internal)]
-#![allow(clippy::unnecessary_operation, unused_must_use)]
+#![allow(
+ clippy::unnecessary_operation,
+ unused_must_use,
+ clippy::missing_clippy_version_attribute
+)]
extern crate rustc_span;
diff --git a/src/tools/clippy/tests/ui-internal/unnecessary_symbol_str.stderr b/src/tools/clippy/tests/ui-internal/unnecessary_symbol_str.stderr
index 12e05eaa7a0..75367bf4bc5 100644
--- a/src/tools/clippy/tests/ui-internal/unnecessary_symbol_str.stderr
+++ b/src/tools/clippy/tests/ui-internal/unnecessary_symbol_str.stderr
@@ -1,5 +1,5 @@
error: unnecessary `Symbol` to string conversion
- --> $DIR/unnecessary_symbol_str.rs:11:5
+ --> $DIR/unnecessary_symbol_str.rs:15:5
|
LL | Symbol::intern("foo").as_str() == "clippy";
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `Symbol::intern("foo") == rustc_span::sym::clippy`
@@ -12,25 +12,25 @@ LL | #![deny(clippy::internal)]
= note: `#[deny(clippy::unnecessary_symbol_str)]` implied by `#[deny(clippy::internal)]`
error: unnecessary `Symbol` to string conversion
- --> $DIR/unnecessary_symbol_str.rs:12:5
+ --> $DIR/unnecessary_symbol_str.rs:16:5
|
LL | Symbol::intern("foo").to_string() == "self";
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `Symbol::intern("foo") == rustc_span::symbol::kw::SelfLower`
error: unnecessary `Symbol` to string conversion
- --> $DIR/unnecessary_symbol_str.rs:13:5
+ --> $DIR/unnecessary_symbol_str.rs:17:5
|
LL | Symbol::intern("foo").to_ident_string() != "Self";
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `Symbol::intern("foo") != rustc_span::symbol::kw::SelfUpper`
error: unnecessary `Symbol` to string conversion
- --> $DIR/unnecessary_symbol_str.rs:14:5
+ --> $DIR/unnecessary_symbol_str.rs:18:5
|
LL | &*Ident::empty().as_str() == "clippy";
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `Ident::empty().name == rustc_span::sym::clippy`
error: unnecessary `Symbol` to string conversion
- --> $DIR/unnecessary_symbol_str.rs:15:5
+ --> $DIR/unnecessary_symbol_str.rs:19:5
|
LL | "clippy" == Ident::empty().to_string();
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `rustc_span::sym::clippy == Ident::empty().name`
diff --git a/src/tools/clippy/tests/ui-toml/max_suggested_slice_pattern_length/clippy.toml b/src/tools/clippy/tests/ui-toml/max_suggested_slice_pattern_length/clippy.toml
new file mode 100644
index 00000000000..78c7e63b410
--- /dev/null
+++ b/src/tools/clippy/tests/ui-toml/max_suggested_slice_pattern_length/clippy.toml
@@ -0,0 +1 @@
+max-suggested-slice-pattern-length = 8
diff --git a/src/tools/clippy/tests/ui-toml/max_suggested_slice_pattern_length/index_refutable_slice.rs b/src/tools/clippy/tests/ui-toml/max_suggested_slice_pattern_length/index_refutable_slice.rs
new file mode 100644
index 00000000000..21849a14fa9
--- /dev/null
+++ b/src/tools/clippy/tests/ui-toml/max_suggested_slice_pattern_length/index_refutable_slice.rs
@@ -0,0 +1,23 @@
+#![deny(clippy::index_refutable_slice)]
+
+fn below_limit() {
+ let slice: Option<&[u32]> = Some(&[1, 2, 3]);
+ if let Some(slice) = slice {
+ // This would usually not be linted but is included now due to the
+ // index limit in the config file
+ println!("{}", slice[7]);
+ }
+}
+
+fn above_limit() {
+ let slice: Option<&[u32]> = Some(&[1, 2, 3]);
+ if let Some(slice) = slice {
+ // This will not be linted as 8 is above the limit
+ println!("{}", slice[8]);
+ }
+}
+
+fn main() {
+ below_limit();
+ above_limit();
+}
diff --git a/src/tools/clippy/tests/ui-toml/max_suggested_slice_pattern_length/index_refutable_slice.stderr b/src/tools/clippy/tests/ui-toml/max_suggested_slice_pattern_length/index_refutable_slice.stderr
new file mode 100644
index 00000000000..d319e65d06c
--- /dev/null
+++ b/src/tools/clippy/tests/ui-toml/max_suggested_slice_pattern_length/index_refutable_slice.stderr
@@ -0,0 +1,22 @@
+error: this binding can be a slice pattern to avoid indexing
+ --> $DIR/index_refutable_slice.rs:5:17
+ |
+LL | if let Some(slice) = slice {
+ | ^^^^^
+ |
+note: the lint level is defined here
+ --> $DIR/index_refutable_slice.rs:1:9
+ |
+LL | #![deny(clippy::index_refutable_slice)]
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+help: try using a slice pattern here
+ |
+LL | if let Some([_, _, _, _, _, _, _, slice_7, ..]) = slice {
+ | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+help: and replace the index expressions here
+ |
+LL | println!("{}", slice_7);
+ | ~~~~~~~
+
+error: aborting due to previous error
+
diff --git a/src/tools/clippy/tests/ui-toml/min_rust_version/min_rust_version.rs b/src/tools/clippy/tests/ui-toml/min_rust_version/min_rust_version.rs
index bc41efa42a1..8e104926524 100644
--- a/src/tools/clippy/tests/ui-toml/min_rust_version/min_rust_version.rs
+++ b/src/tools/clippy/tests/ui-toml/min_rust_version/min_rust_version.rs
@@ -59,10 +59,20 @@ fn manual_strip_msrv() {
}
}
+fn check_index_refutable_slice() {
+ // This shouldn't trigger `clippy::index_refutable_slice` as the suggestion
+ // would only be valid from 1.42.0 onward
+ let slice: Option<&[u32]> = Some(&[1]);
+ if let Some(slice) = slice {
+ println!("{}", slice[0]);
+ }
+}
+
fn main() {
option_as_ref_deref();
match_like_matches();
match_same_arms();
match_same_arms2();
manual_strip_msrv();
+ check_index_refutable_slice();
}
diff --git a/src/tools/clippy/tests/ui-toml/strict_non_send_fields_in_send_ty/test.stderr b/src/tools/clippy/tests/ui-toml/strict_non_send_fields_in_send_ty/test.stderr
index b07f9dd3df3..49eecf18b4c 100644
--- a/src/tools/clippy/tests/ui-toml/strict_non_send_fields_in_send_ty/test.stderr
+++ b/src/tools/clippy/tests/ui-toml/strict_non_send_fields_in_send_ty/test.stderr
@@ -1,86 +1,86 @@
-error: this implementation is unsound, as some fields in `NoGeneric` are `!Send`
+error: some fields in `NoGeneric` are not safe to be sent to another thread
--> $DIR/test.rs:11:1
|
LL | unsafe impl Send for NoGeneric {}
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
= note: `-D clippy::non-send-fields-in-send-ty` implied by `-D warnings`
-note: the type of field `rc_is_not_send` is `!Send`
+note: it is not safe to send field `rc_is_not_send` to another thread
--> $DIR/test.rs:8:5
|
LL | rc_is_not_send: Rc<String>,
| ^^^^^^^^^^^^^^^^^^^^^^^^^^
= help: use a thread-safe type that implements `Send`
-error: this implementation is unsound, as some fields in `MultiField<T>` are `!Send`
+error: some fields in `MultiField<T>` are not safe to be sent to another thread
--> $DIR/test.rs:19:1
|
LL | unsafe impl<T> Send for MultiField<T> {}
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
-note: the type of field `field1` is `!Send`
+note: it is not safe to send field `field1` to another thread
--> $DIR/test.rs:14:5
|
LL | field1: T,
| ^^^^^^^^^
= help: add `T: Send` bound in `Send` impl
-note: the type of field `field2` is `!Send`
+note: it is not safe to send field `field2` to another thread
--> $DIR/test.rs:15:5
|
LL | field2: T,
| ^^^^^^^^^
= help: add `T: Send` bound in `Send` impl
-note: the type of field `field3` is `!Send`
+note: it is not safe to send field `field3` to another thread
--> $DIR/test.rs:16:5
|
LL | field3: T,
| ^^^^^^^^^
= help: add `T: Send` bound in `Send` impl
-error: this implementation is unsound, as some fields in `MyOption<T>` are `!Send`
+error: some fields in `MyOption<T>` are not safe to be sent to another thread
--> $DIR/test.rs:26:1
|
LL | unsafe impl<T> Send for MyOption<T> {}
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
-note: the type of field `0` is `!Send`
+note: it is not safe to send field `0` to another thread
--> $DIR/test.rs:22:12
|
LL | MySome(T),
| ^
= help: add `T: Send` bound in `Send` impl
-error: this implementation is unsound, as some fields in `HeuristicTest` are `!Send`
+error: some fields in `HeuristicTest` are not safe to be sent to another thread
--> $DIR/test.rs:41:1
|
LL | unsafe impl Send for HeuristicTest {}
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
-note: the type of field `field1` is `!Send`
+note: it is not safe to send field `field1` to another thread
--> $DIR/test.rs:34:5
|
LL | field1: Vec<*const NonSend>,
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^
= help: use a thread-safe type that implements `Send`
-note: the type of field `field2` is `!Send`
+note: it is not safe to send field `field2` to another thread
--> $DIR/test.rs:35:5
|
LL | field2: [*const NonSend; 3],
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^
= help: use a thread-safe type that implements `Send`
-note: the type of field `field3` is `!Send`
+note: it is not safe to send field `field3` to another thread
--> $DIR/test.rs:36:5
|
LL | field3: (*const NonSend, *const NonSend, *const NonSend),
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
= help: use a thread-safe type that implements `Send`
-note: the type of field `field4` is `!Send`
+note: it is not safe to send field `field4` to another thread
--> $DIR/test.rs:37:5
|
LL | field4: (*const NonSend, Rc<u8>),
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
= help: use a thread-safe type that implements `Send`
-note: the type of field `field5` is `!Send`
+note: it is not safe to send field `field5` to another thread
--> $DIR/test.rs:38:5
|
LL | field5: Vec<Vec<*const NonSend>>,
diff --git a/src/tools/clippy/tests/ui-toml/toml_disallowed_method/clippy.toml b/src/tools/clippy/tests/ui-toml/toml_disallowed_methods/clippy.toml
index f1d4a4619c5..f1d4a4619c5 100644
--- a/src/tools/clippy/tests/ui-toml/toml_disallowed_method/clippy.toml
+++ b/src/tools/clippy/tests/ui-toml/toml_disallowed_methods/clippy.toml
diff --git a/src/tools/clippy/tests/ui-toml/toml_disallowed_method/conf_disallowed_method.rs b/src/tools/clippy/tests/ui-toml/toml_disallowed_methods/conf_disallowed_methods.rs
index 1901a99377e..cb449b45bde 100644
--- a/src/tools/clippy/tests/ui-toml/toml_disallowed_method/conf_disallowed_method.rs
+++ b/src/tools/clippy/tests/ui-toml/toml_disallowed_methods/conf_disallowed_methods.rs
@@ -1,4 +1,4 @@
-#![warn(clippy::disallowed_method)]
+#![warn(clippy::disallowed_methods)]
extern crate regex;
use regex::Regex;
diff --git a/src/tools/clippy/tests/ui-toml/toml_disallowed_method/conf_disallowed_method.stderr b/src/tools/clippy/tests/ui-toml/toml_disallowed_methods/conf_disallowed_methods.stderr
index 38123220a43..999ead10d51 100644
--- a/src/tools/clippy/tests/ui-toml/toml_disallowed_method/conf_disallowed_method.stderr
+++ b/src/tools/clippy/tests/ui-toml/toml_disallowed_methods/conf_disallowed_methods.stderr
@@ -1,13 +1,13 @@
error: use of a disallowed method `regex::Regex::new`
- --> $DIR/conf_disallowed_method.rs:7:14
+ --> $DIR/conf_disallowed_methods.rs:7:14
|
LL | let re = Regex::new(r"ab.*c").unwrap();
| ^^^^^^^^^^^^^^^^^^^^
|
- = note: `-D clippy::disallowed-method` implied by `-D warnings`
+ = note: `-D clippy::disallowed-methods` implied by `-D warnings`
error: use of a disallowed method `regex::Regex::is_match`
- --> $DIR/conf_disallowed_method.rs:8:5
+ --> $DIR/conf_disallowed_methods.rs:8:5
|
LL | re.is_match("abc");
| ^^^^^^^^^^^^^^^^^^
@@ -15,7 +15,7 @@ LL | re.is_match("abc");
= note: no matching allowed (from clippy.toml)
error: use of a disallowed method `std::iter::Iterator::sum`
- --> $DIR/conf_disallowed_method.rs:11:5
+ --> $DIR/conf_disallowed_methods.rs:11:5
|
LL | a.iter().sum::<i32>();
| ^^^^^^^^^^^^^^^^^^^^^
diff --git a/src/tools/clippy/tests/ui-toml/toml_disallowed_type/clippy.toml b/src/tools/clippy/tests/ui-toml/toml_disallowed_types/clippy.toml
index 6cb9e2ef954..6cb9e2ef954 100644
--- a/src/tools/clippy/tests/ui-toml/toml_disallowed_type/clippy.toml
+++ b/src/tools/clippy/tests/ui-toml/toml_disallowed_types/clippy.toml
diff --git a/src/tools/clippy/tests/ui-toml/toml_disallowed_type/conf_disallowed_type.rs b/src/tools/clippy/tests/ui-toml/toml_disallowed_types/conf_disallowed_types.rs
index 410f0765055..7f28efd676f 100644
--- a/src/tools/clippy/tests/ui-toml/toml_disallowed_type/conf_disallowed_type.rs
+++ b/src/tools/clippy/tests/ui-toml/toml_disallowed_types/conf_disallowed_types.rs
@@ -1,4 +1,4 @@
-#![warn(clippy::disallowed_type)]
+#![warn(clippy::disallowed_types)]
extern crate quote;
extern crate syn;
diff --git a/src/tools/clippy/tests/ui-toml/toml_disallowed_type/conf_disallowed_type.stderr b/src/tools/clippy/tests/ui-toml/toml_disallowed_types/conf_disallowed_types.stderr
index 08a400a8367..e3ece799c7c 100644
--- a/src/tools/clippy/tests/ui-toml/toml_disallowed_type/conf_disallowed_type.stderr
+++ b/src/tools/clippy/tests/ui-toml/toml_disallowed_types/conf_disallowed_types.stderr
@@ -1,67 +1,67 @@
error: `std::sync::atomic::AtomicU32` is not allowed according to config
- --> $DIR/conf_disallowed_type.rs:7:1
+ --> $DIR/conf_disallowed_types.rs:7:1
|
LL | use std::sync::atomic::AtomicU32;
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
- = note: `-D clippy::disallowed-type` implied by `-D warnings`
+ = note: `-D clippy::disallowed-types` implied by `-D warnings`
error: `std::time::Instant` is not allowed according to config
- --> $DIR/conf_disallowed_type.rs:8:1
+ --> $DIR/conf_disallowed_types.rs:8:1
|
LL | use std::time::Instant as Sneaky;
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
error: `std::time::Instant` is not allowed according to config
- --> $DIR/conf_disallowed_type.rs:12:33
+ --> $DIR/conf_disallowed_types.rs:12:33
|
LL | fn bad_return_type() -> fn() -> Sneaky {
| ^^^^^^
error: `std::time::Instant` is not allowed according to config
- --> $DIR/conf_disallowed_type.rs:16:28
+ --> $DIR/conf_disallowed_types.rs:16:28
|
LL | fn bad_arg_type(_: impl Fn(Sneaky) -> foo::atomic::AtomicU32) {}
| ^^^^^^
error: `std::sync::atomic::AtomicU32` is not allowed according to config
- --> $DIR/conf_disallowed_type.rs:16:39
+ --> $DIR/conf_disallowed_types.rs:16:39
|
LL | fn bad_arg_type(_: impl Fn(Sneaky) -> foo::atomic::AtomicU32) {}
| ^^^^^^^^^^^^^^^^^^^^^^
error: `std::io::Read` is not allowed according to config
- --> $DIR/conf_disallowed_type.rs:18:22
+ --> $DIR/conf_disallowed_types.rs:18:22
|
LL | fn trait_obj(_: &dyn std::io::Read) {}
| ^^^^^^^^^^^^^
error: `usize` is not allowed according to config
- --> $DIR/conf_disallowed_type.rs:20:33
+ --> $DIR/conf_disallowed_types.rs:20:33
|
LL | fn full_and_single_path_prim(_: usize, _: bool) {}
| ^^^^^
error: `bool` is not allowed according to config
- --> $DIR/conf_disallowed_type.rs:20:43
+ --> $DIR/conf_disallowed_types.rs:20:43
|
LL | fn full_and_single_path_prim(_: usize, _: bool) {}
| ^^^^
error: `usize` is not allowed according to config
- --> $DIR/conf_disallowed_type.rs:22:28
+ --> $DIR/conf_disallowed_types.rs:22:28
|
LL | fn const_generics<const C: usize>() {}
| ^^^^^
error: `usize` is not allowed according to config
- --> $DIR/conf_disallowed_type.rs:24:24
+ --> $DIR/conf_disallowed_types.rs:24:24
|
LL | struct GenArg<const U: usize>([u8; U]);
| ^^^^^
error: `std::net::Ipv4Addr` is not allowed according to config
- --> $DIR/conf_disallowed_type.rs:28:10
+ --> $DIR/conf_disallowed_types.rs:28:10
|
LL | fn ip(_: std::net::Ipv4Addr) {}
| ^^^^^^^^^^^^^^^^^^
@@ -69,61 +69,61 @@ LL | fn ip(_: std::net::Ipv4Addr) {}
= note: no IPv4 allowed (from clippy.toml)
error: `std::net::TcpListener` is not allowed according to config
- --> $DIR/conf_disallowed_type.rs:30:16
+ --> $DIR/conf_disallowed_types.rs:30:16
|
LL | fn listener(_: std::net::TcpListener) {}
| ^^^^^^^^^^^^^^^^^^^^^
error: `std::collections::HashMap` is not allowed according to config
- --> $DIR/conf_disallowed_type.rs:34:48
+ --> $DIR/conf_disallowed_types.rs:34:48
|
LL | let _: std::collections::HashMap<(), ()> = std::collections::HashMap::new();
| ^^^^^^^^^^^^^^^^^^^^^^^^^
error: `std::collections::HashMap` is not allowed according to config
- --> $DIR/conf_disallowed_type.rs:34:12
+ --> $DIR/conf_disallowed_types.rs:34:12
|
LL | let _: std::collections::HashMap<(), ()> = std::collections::HashMap::new();
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
error: `std::time::Instant` is not allowed according to config
- --> $DIR/conf_disallowed_type.rs:35:13
+ --> $DIR/conf_disallowed_types.rs:35:13
|
LL | let _ = Sneaky::now();
| ^^^^^^
error: `std::sync::atomic::AtomicU32` is not allowed according to config
- --> $DIR/conf_disallowed_type.rs:36:13
+ --> $DIR/conf_disallowed_types.rs:36:13
|
LL | let _ = foo::atomic::AtomicU32::new(0);
| ^^^^^^^^^^^^^^^^^^^^^^
error: `std::sync::atomic::AtomicU32` is not allowed according to config
- --> $DIR/conf_disallowed_type.rs:37:17
+ --> $DIR/conf_disallowed_types.rs:37:17
|
LL | static FOO: std::sync::atomic::AtomicU32 = foo::atomic::AtomicU32::new(1);
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
error: `std::sync::atomic::AtomicU32` is not allowed according to config
- --> $DIR/conf_disallowed_type.rs:37:48
+ --> $DIR/conf_disallowed_types.rs:37:48
|
LL | static FOO: std::sync::atomic::AtomicU32 = foo::atomic::AtomicU32::new(1);
| ^^^^^^^^^^^^^^^^^^^^^^
error: `syn::TypePath` is not allowed according to config
- --> $DIR/conf_disallowed_type.rs:38:43
+ --> $DIR/conf_disallowed_types.rs:38:43
|
LL | let _: std::collections::BTreeMap<(), syn::TypePath> = Default::default();
| ^^^^^^^^^^^^^
error: `syn::Ident` is not allowed according to config
- --> $DIR/conf_disallowed_type.rs:39:13
+ --> $DIR/conf_disallowed_types.rs:39:13
|
LL | let _ = syn::Ident::new("", todo!());
| ^^^^^^^^^^
error: `usize` is not allowed according to config
- --> $DIR/conf_disallowed_type.rs:41:12
+ --> $DIR/conf_disallowed_types.rs:41:12
|
LL | let _: usize = 64_usize;
| ^^^^^
diff --git a/src/tools/clippy/tests/ui-toml/toml_unknown_key/conf_unknown_key.stderr b/src/tools/clippy/tests/ui-toml/toml_unknown_key/conf_unknown_key.stderr
index 97bab1308aa..00ddbd608a7 100644
--- a/src/tools/clippy/tests/ui-toml/toml_unknown_key/conf_unknown_key.stderr
+++ b/src/tools/clippy/tests/ui-toml/toml_unknown_key/conf_unknown_key.stderr
@@ -1,4 +1,4 @@
-error: error reading Clippy's configuration file `$DIR/clippy.toml`: unknown field `foobar`, expected one of `avoid-breaking-exported-api`, `msrv`, `blacklisted-names`, `cognitive-complexity-threshold`, `cyclomatic-complexity-threshold`, `doc-valid-idents`, `too-many-arguments-threshold`, `type-complexity-threshold`, `single-char-binding-names-threshold`, `too-large-for-stack`, `enum-variant-name-threshold`, `enum-variant-size-threshold`, `verbose-bit-mask-threshold`, `literal-representation-threshold`, `trivial-copy-size-limit`, `pass-by-value-size-limit`, `too-many-lines-threshold`, `array-size-threshold`, `vec-box-size-threshold`, `max-trait-bounds`, `max-struct-bools`, `max-fn-params-bools`, `warn-on-all-wildcard-imports`, `disallowed-methods`, `disallowed-types`, `unreadable-literal-lint-fractions`, `upper-case-acronyms-aggressive`, `cargo-ignore-publish`, `standard-macro-braces`, `enforced-import-renames`, `allowed-scripts`, `enable-raw-pointer-heuristic-for-send`, `third-party` at line 5 column 1
+error: error reading Clippy's configuration file `$DIR/clippy.toml`: unknown field `foobar`, expected one of `avoid-breaking-exported-api`, `msrv`, `blacklisted-names`, `cognitive-complexity-threshold`, `cyclomatic-complexity-threshold`, `doc-valid-idents`, `too-many-arguments-threshold`, `type-complexity-threshold`, `single-char-binding-names-threshold`, `too-large-for-stack`, `enum-variant-name-threshold`, `enum-variant-size-threshold`, `verbose-bit-mask-threshold`, `literal-representation-threshold`, `trivial-copy-size-limit`, `pass-by-value-size-limit`, `too-many-lines-threshold`, `array-size-threshold`, `vec-box-size-threshold`, `max-trait-bounds`, `max-struct-bools`, `max-fn-params-bools`, `warn-on-all-wildcard-imports`, `disallowed-methods`, `disallowed-types`, `unreadable-literal-lint-fractions`, `upper-case-acronyms-aggressive`, `cargo-ignore-publish`, `standard-macro-braces`, `enforced-import-renames`, `allowed-scripts`, `enable-raw-pointer-heuristic-for-send`, `max-suggested-slice-pattern-length`, `third-party` at line 5 column 1
error: aborting due to previous error
diff --git a/src/tools/clippy/tests/ui/asm_syntax.rs b/src/tools/clippy/tests/ui/asm_syntax.rs
index 4a62f6f2909..0220bf3331f 100644
--- a/src/tools/clippy/tests/ui/asm_syntax.rs
+++ b/src/tools/clippy/tests/ui/asm_syntax.rs
@@ -1,11 +1,10 @@
// only-x86_64
// ignore-aarch64
-#![feature(asm)]
-
#[warn(clippy::inline_asm_x86_intel_syntax)]
mod warn_intel {
pub(super) unsafe fn use_asm() {
+ use std::arch::asm;
asm!("");
asm!("", options());
asm!("", options(nostack));
@@ -17,6 +16,7 @@ mod warn_intel {
#[warn(clippy::inline_asm_x86_att_syntax)]
mod warn_att {
pub(super) unsafe fn use_asm() {
+ use std::arch::asm;
asm!("");
asm!("", options());
asm!("", options(nostack));
diff --git a/src/tools/clippy/tests/ui/asm_syntax.stderr b/src/tools/clippy/tests/ui/asm_syntax.stderr
index 409f4db76bc..e9b150121aa 100644
--- a/src/tools/clippy/tests/ui/asm_syntax.stderr
+++ b/src/tools/clippy/tests/ui/asm_syntax.stderr
@@ -1,5 +1,5 @@
error: Intel x86 assembly syntax used
- --> $DIR/asm_syntax.rs:9:9
+ --> $DIR/asm_syntax.rs:8:9
|
LL | asm!("");
| ^^^^^^^^
@@ -8,7 +8,7 @@ LL | asm!("");
= help: use AT&T x86 assembly syntax
error: Intel x86 assembly syntax used
- --> $DIR/asm_syntax.rs:10:9
+ --> $DIR/asm_syntax.rs:9:9
|
LL | asm!("", options());
| ^^^^^^^^^^^^^^^^^^^
@@ -16,7 +16,7 @@ LL | asm!("", options());
= help: use AT&T x86 assembly syntax
error: Intel x86 assembly syntax used
- --> $DIR/asm_syntax.rs:11:9
+ --> $DIR/asm_syntax.rs:10:9
|
LL | asm!("", options(nostack));
| ^^^^^^^^^^^^^^^^^^^^^^^^^^
diff --git a/src/tools/clippy/tests/ui/author.stdout b/src/tools/clippy/tests/ui/author.stdout
index 211d11c7c1a..3125863036b 100644
--- a/src/tools/clippy/tests/ui/author.stdout
+++ b/src/tools/clippy/tests/ui/author.stdout
@@ -1,11 +1,11 @@
if_chain! {
- if let StmtKind::Local(ref local) = stmt.kind;
- if let Some(ref init) = local.init;
- if let ExprKind::Cast(ref expr, ref cast_ty) = init.kind;
- if let TyKind::Path(ref qp) = cast_ty.kind;
- if match_qpath(qp, &["char"]);
+ if let StmtKind::Local(local) = stmt.kind;
+ if let Some(init) = local.init;
+ if let ExprKind::Cast(expr, cast_ty) = init.kind;
+ if let TyKind::Path(ref qpath) = cast_ty.kind;
+ if match_qpath(qpath, &["char"]);
if let ExprKind::Lit(ref lit) = expr.kind;
- if let LitKind::Int(69, _) = lit.node;
+ if let LitKind::Int(69, LitIntType::Unsuffixed) = lit.node;
if let PatKind::Binding(BindingAnnotation::Unannotated, _, name, None) = local.pat.kind;
if name.as_str() == "x";
then {
diff --git a/src/tools/clippy/tests/ui/author/blocks.rs b/src/tools/clippy/tests/ui/author/blocks.rs
index c8465cd59aa..a7335c01baa 100644
--- a/src/tools/clippy/tests/ui/author/blocks.rs
+++ b/src/tools/clippy/tests/ui/author/blocks.rs
@@ -1,10 +1,16 @@
+// edition:2018
+
#![allow(redundant_semicolons, clippy::no_effect)]
+#![feature(stmt_expr_attributes)]
+#![feature(async_closure)]
#[rustfmt::skip]
fn main() {
#[clippy::author]
{
let x = 42i32;
+ let _t = 1f32;
+
-x;
};
#[clippy::author]
@@ -12,4 +18,7 @@ fn main() {
let expr = String::new();
drop(expr)
};
+
+ #[clippy::author]
+ async move || {};
}
diff --git a/src/tools/clippy/tests/ui/author/blocks.stdout b/src/tools/clippy/tests/ui/author/blocks.stdout
index 854bc28083a..2fc4a7d1f7f 100644
--- a/src/tools/clippy/tests/ui/author/blocks.stdout
+++ b/src/tools/clippy/tests/ui/author/blocks.stdout
@@ -1,39 +1,63 @@
if_chain! {
- if let ExprKind::Block(ref block) = expr.kind;
- if block.stmts.len() == 2;
- if let StmtKind::Local(ref local) = block.stmts[0].kind;
- if let Some(ref init) = local.init;
+ if let ExprKind::Block(block, None) = expr.kind;
+ if block.stmts.len() == 3;
+ if let StmtKind::Local(local) = block.stmts[0].kind;
+ if let Some(init) = local.init;
if let ExprKind::Lit(ref lit) = init.kind;
- if let LitKind::Int(42, _) = lit.node;
+ if let LitKind::Int(42, LitIntType::Signed(IntTy::I32)) = lit.node;
if let PatKind::Binding(BindingAnnotation::Unannotated, _, name, None) = local.pat.kind;
if name.as_str() == "x";
- if let StmtKind::Semi(ref e, _) = block.stmts[1].kind
- if let ExprKind::Unary(UnOp::Neg, ref inner) = e.kind;
- if let ExprKind::Path(ref path) = inner.kind;
- if match_qpath(path, &["x"]);
+ if let StmtKind::Local(local1) = block.stmts[1].kind;
+ if let Some(init1) = local1.init;
+ if let ExprKind::Lit(ref lit1) = init1.kind;
+ if let LitKind::Float(_, LitFloatType::Suffixed(FloatTy::F32)) = lit1.node;
+ if let PatKind::Binding(BindingAnnotation::Unannotated, _, name1, None) = local1.pat.kind;
+ if name1.as_str() == "_t";
+ if let StmtKind::Semi(e) = block.stmts[2].kind;
+ if let ExprKind::Unary(UnOp::Neg, inner) = e.kind;
+ if let ExprKind::Path(ref qpath) = inner.kind;
+ if match_qpath(qpath, &["x"]);
if block.expr.is_none();
then {
// report your lint here
}
}
if_chain! {
- if let ExprKind::Block(ref block) = expr.kind;
+ if let ExprKind::Block(block, None) = expr.kind;
if block.stmts.len() == 1;
- if let StmtKind::Local(ref local) = block.stmts[0].kind;
- if let Some(ref init) = local.init;
- if let ExprKind::Call(ref func, ref args) = init.kind;
- if let ExprKind::Path(ref path) = func.kind;
- if match_qpath(path, &["String", "new"]);
- if args.len() == 0;
+ if let StmtKind::Local(local) = block.stmts[0].kind;
+ if let Some(init) = local.init;
+ if let ExprKind::Call(func, args) = init.kind;
+ if let ExprKind::Path(ref qpath) = func.kind;
+ if match_qpath(qpath, &["String", "new"]);
+ if args.is_empty();
if let PatKind::Binding(BindingAnnotation::Unannotated, _, name, None) = local.pat.kind;
if name.as_str() == "expr";
- if let Some(trailing_expr) = &block.expr;
- if let ExprKind::Call(ref func1, ref args1) = trailing_expr.kind;
- if let ExprKind::Path(ref path1) = func1.kind;
- if match_qpath(path1, &["drop"]);
+ if let Some(trailing_expr) = block.expr;
+ if let ExprKind::Call(func1, args1) = trailing_expr.kind;
+ if let ExprKind::Path(ref qpath1) = func1.kind;
+ if match_qpath(qpath1, &["drop"]);
if args1.len() == 1;
- if let ExprKind::Path(ref path2) = args1[0].kind;
- if match_qpath(path2, &["expr"]);
+ if let ExprKind::Path(ref qpath2) = args1[0].kind;
+ if match_qpath(qpath2, &["expr"]);
+ then {
+ // report your lint here
+ }
+}
+if_chain! {
+ if let ExprKind::Closure(CaptureBy::Value, fn_decl, body_id, _, None) = expr.kind;
+ if let FnRetTy::DefaultReturn(_) = fn_decl.output;
+ let expr1 = &cx.tcx.hir().body(body_id).value;
+ if let ExprKind::Call(func, args) = expr1.kind;
+ if let ExprKind::Path(ref qpath) = func.kind;
+ if matches!(qpath, QPath::LangItem(LangItem::FromGenerator, _));
+ if args.len() == 1;
+ if let ExprKind::Closure(CaptureBy::Value, fn_decl1, body_id1, _, Some(Movability::Static)) = args[0].kind;
+ if let FnRetTy::DefaultReturn(_) = fn_decl1.output;
+ let expr2 = &cx.tcx.hir().body(body_id1).value;
+ if let ExprKind::Block(block, None) = expr2.kind;
+ if block.stmts.is_empty();
+ if block.expr.is_none();
then {
// report your lint here
}
diff --git a/src/tools/clippy/tests/ui/author/call.stdout b/src/tools/clippy/tests/ui/author/call.stdout
index 4dccf666631..266312d63e5 100644
--- a/src/tools/clippy/tests/ui/author/call.stdout
+++ b/src/tools/clippy/tests/ui/author/call.stdout
@@ -1,14 +1,14 @@
if_chain! {
- if let StmtKind::Local(ref local) = stmt.kind;
- if let Some(ref init) = local.init;
- if let ExprKind::Call(ref func, ref args) = init.kind;
- if let ExprKind::Path(ref path) = func.kind;
- if match_qpath(path, &["{{root}}", "std", "cmp", "min"]);
+ if let StmtKind::Local(local) = stmt.kind;
+ if let Some(init) = local.init;
+ if let ExprKind::Call(func, args) = init.kind;
+ if let ExprKind::Path(ref qpath) = func.kind;
+ if match_qpath(qpath, &["{{root}}", "std", "cmp", "min"]);
if args.len() == 2;
if let ExprKind::Lit(ref lit) = args[0].kind;
- if let LitKind::Int(3, _) = lit.node;
+ if let LitKind::Int(3, LitIntType::Unsuffixed) = lit.node;
if let ExprKind::Lit(ref lit1) = args[1].kind;
- if let LitKind::Int(4, _) = lit1.node;
+ if let LitKind::Int(4, LitIntType::Unsuffixed) = lit1.node;
if let PatKind::Wild = local.pat.kind;
then {
// report your lint here
diff --git a/src/tools/clippy/tests/ui/author/for_loop.rs b/src/tools/clippy/tests/ui/author/for_loop.rs
deleted file mode 100644
index b3dec876535..00000000000
--- a/src/tools/clippy/tests/ui/author/for_loop.rs
+++ /dev/null
@@ -1,8 +0,0 @@
-#![feature(stmt_expr_attributes)]
-
-fn main() {
- #[clippy::author]
- for y in 0..10 {
- let z = y;
- }
-}
diff --git a/src/tools/clippy/tests/ui/author/for_loop.stdout b/src/tools/clippy/tests/ui/author/for_loop.stdout
deleted file mode 100644
index 4d0e13c833f..00000000000
--- a/src/tools/clippy/tests/ui/author/for_loop.stdout
+++ /dev/null
@@ -1,49 +0,0 @@
-if_chain! {
- if let ExprKind::DropTemps(ref expr) = expr.kind;
- if let ExprKind::Match(ref expr1, ref arms, MatchSource::ForLoopDesugar) = expr.kind;
- if let ExprKind::Call(ref func, ref args) = expr1.kind;
- if let ExprKind::Path(ref path) = func.kind;
- if matches!(path, QPath::LangItem(LangItem::IntoIterIntoIter, _));
- if args.len() == 1;
- if let ExprKind::Struct(ref path1, ref fields, None) = args[0].kind;
- if matches!(path1, QPath::LangItem(LangItem::Range, _));
- if fields.len() == 2;
- // unimplemented: field checks
- if arms.len() == 1;
- if let ExprKind::Loop(ref body, ref label, LoopSource::ForLoop) = arms[0].body.kind;
- if body.stmts.len() == 1;
- if let StmtKind::Expr(ref e, _) = body.stmts[0].kind
- if let ExprKind::Match(ref expr2, ref arms1, MatchSource::ForLoopDesugar) = e.kind;
- if let ExprKind::Call(ref func1, ref args1) = expr2.kind;
- if let ExprKind::Path(ref path2) = func1.kind;
- if matches!(path2, QPath::LangItem(LangItem::IteratorNext, _));
- if args1.len() == 1;
- if let ExprKind::AddrOf(BorrowKind::Ref, Mutability::Mut, ref inner) = args1[0].kind;
- if let ExprKind::Path(ref path3) = inner.kind;
- if match_qpath(path3, &["iter"]);
- if arms1.len() == 2;
- if let ExprKind::Break(ref destination, None) = arms1[0].body.kind;
- if let PatKind::Struct(ref path4, ref fields1, false) = arms1[0].pat.kind;
- if matches!(path4, QPath::LangItem(LangItem::OptionNone, _));
- if fields1.len() == 0;
- // unimplemented: field checks
- if let ExprKind::Block(ref block) = arms1[1].body.kind;
- if block.stmts.len() == 1;
- if let StmtKind::Local(ref local) = block.stmts[0].kind;
- if let Some(ref init) = local.init;
- if let ExprKind::Path(ref path5) = init.kind;
- if match_qpath(path5, &["y"]);
- if let PatKind::Binding(BindingAnnotation::Unannotated, _, name, None) = local.pat.kind;
- if name.as_str() == "z";
- if block.expr.is_none();
- if let PatKind::Struct(ref path6, ref fields2, false) = arms1[1].pat.kind;
- if matches!(path6, QPath::LangItem(LangItem::OptionSome, _));
- if fields2.len() == 1;
- // unimplemented: field checks
- if body.expr.is_none();
- if let PatKind::Binding(BindingAnnotation::Mutable, _, name1, None) = arms[0].pat.kind;
- if name1.as_str() == "iter";
- then {
- // report your lint here
- }
-}
diff --git a/src/tools/clippy/tests/ui/author/if.rs b/src/tools/clippy/tests/ui/author/if.rs
index 2e9cb1466d0..946088ab346 100644
--- a/src/tools/clippy/tests/ui/author/if.rs
+++ b/src/tools/clippy/tests/ui/author/if.rs
@@ -7,4 +7,11 @@ fn main() {
} else {
2 == 2;
};
+
+ let a = true;
+
+ #[clippy::author]
+ if let true = a {
+ } else {
+ };
}
diff --git a/src/tools/clippy/tests/ui/author/if.stdout b/src/tools/clippy/tests/ui/author/if.stdout
index 1653de9a6f2..8d92849b366 100644
--- a/src/tools/clippy/tests/ui/author/if.stdout
+++ b/src/tools/clippy/tests/ui/author/if.stdout
@@ -1,32 +1,50 @@
if_chain! {
- if let StmtKind::Local(ref local) = stmt.kind;
- if let Some(ref init) = local.init;
- if let ExprKind::If(ref cond, ref then, Some(ref else_)) = init.kind;
- if let ExprKind::Block(ref block) = else_.kind;
+ if let StmtKind::Local(local) = stmt.kind;
+ if let Some(init) = local.init;
+ if let ExprKind::If(cond, then, Some(else_expr)) = init.kind;
+ if let ExprKind::DropTemps(expr) = cond.kind;
+ if let ExprKind::Lit(ref lit) = expr.kind;
+ if let LitKind::Bool(true) = lit.node;
+ if let ExprKind::Block(block, None) = then.kind;
if block.stmts.len() == 1;
- if let StmtKind::Semi(ref e, _) = block.stmts[0].kind
- if let ExprKind::Binary(ref op, ref left, ref right) = e.kind;
+ if let StmtKind::Semi(e) = block.stmts[0].kind;
+ if let ExprKind::Binary(op, left, right) = e.kind;
if BinOpKind::Eq == op.node;
- if let ExprKind::Lit(ref lit) = left.kind;
- if let LitKind::Int(2, _) = lit.node;
- if let ExprKind::Lit(ref lit1) = right.kind;
- if let LitKind::Int(2, _) = lit1.node;
+ if let ExprKind::Lit(ref lit1) = left.kind;
+ if let LitKind::Int(1, LitIntType::Unsuffixed) = lit1.node;
+ if let ExprKind::Lit(ref lit2) = right.kind;
+ if let LitKind::Int(1, LitIntType::Unsuffixed) = lit2.node;
if block.expr.is_none();
- if let ExprKind::DropTemps(ref expr) = cond.kind;
- if let ExprKind::Lit(ref lit2) = expr.kind;
- if let LitKind::Bool(true) = lit2.node;
- if let ExprKind::Block(ref block1) = then.kind;
+ if let ExprKind::Block(block1, None) = else_expr.kind;
if block1.stmts.len() == 1;
- if let StmtKind::Semi(ref e1, _) = block1.stmts[0].kind
- if let ExprKind::Binary(ref op1, ref left1, ref right1) = e1.kind;
+ if let StmtKind::Semi(e1) = block1.stmts[0].kind;
+ if let ExprKind::Binary(op1, left1, right1) = e1.kind;
if BinOpKind::Eq == op1.node;
if let ExprKind::Lit(ref lit3) = left1.kind;
- if let LitKind::Int(1, _) = lit3.node;
+ if let LitKind::Int(2, LitIntType::Unsuffixed) = lit3.node;
if let ExprKind::Lit(ref lit4) = right1.kind;
- if let LitKind::Int(1, _) = lit4.node;
+ if let LitKind::Int(2, LitIntType::Unsuffixed) = lit4.node;
if block1.expr.is_none();
if let PatKind::Wild = local.pat.kind;
then {
// report your lint here
}
}
+if_chain! {
+ if let ExprKind::If(cond, then, Some(else_expr)) = expr.kind;
+ if let ExprKind::Let(let_expr) = cond.kind;
+ if let PatKind::Lit(lit_expr) = let_expr.pat.kind;
+ if let ExprKind::Lit(ref lit) = lit_expr.kind;
+ if let LitKind::Bool(true) = lit.node;
+ if let ExprKind::Path(ref qpath) = let_expr.init.kind;
+ if match_qpath(qpath, &["a"]);
+ if let ExprKind::Block(block, None) = then.kind;
+ if block.stmts.is_empty();
+ if block.expr.is_none();
+ if let ExprKind::Block(block1, None) = else_expr.kind;
+ if block1.stmts.is_empty();
+ if block1.expr.is_none();
+ then {
+ // report your lint here
+ }
+}
diff --git a/src/tools/clippy/tests/ui/author/issue_3849.stdout b/src/tools/clippy/tests/ui/author/issue_3849.stdout
index 65f93f3cdc0..bce4bc70273 100644
--- a/src/tools/clippy/tests/ui/author/issue_3849.stdout
+++ b/src/tools/clippy/tests/ui/author/issue_3849.stdout
@@ -1,12 +1,12 @@
if_chain! {
- if let StmtKind::Local(ref local) = stmt.kind;
- if let Some(ref init) = local.init;
- if let ExprKind::Call(ref func, ref args) = init.kind;
- if let ExprKind::Path(ref path) = func.kind;
- if match_qpath(path, &["std", "mem", "transmute"]);
+ if let StmtKind::Local(local) = stmt.kind;
+ if let Some(init) = local.init;
+ if let ExprKind::Call(func, args) = init.kind;
+ if let ExprKind::Path(ref qpath) = func.kind;
+ if match_qpath(qpath, &["std", "mem", "transmute"]);
if args.len() == 1;
- if let ExprKind::Path(ref path1) = args[0].kind;
- if match_qpath(path1, &["ZPTR"]);
+ if let ExprKind::Path(ref qpath1) = args[0].kind;
+ if match_qpath(qpath1, &["ZPTR"]);
if let PatKind::Wild = local.pat.kind;
then {
// report your lint here
diff --git a/src/tools/clippy/tests/ui/author/loop.rs b/src/tools/clippy/tests/ui/author/loop.rs
new file mode 100644
index 00000000000..d6de21631e2
--- /dev/null
+++ b/src/tools/clippy/tests/ui/author/loop.rs
@@ -0,0 +1,36 @@
+#![feature(stmt_expr_attributes)]
+#![allow(clippy::never_loop, clippy::while_immutable_condition)]
+
+fn main() {
+ #[clippy::author]
+ for y in 0..10 {
+ let z = y;
+ }
+
+ #[clippy::author]
+ for _ in 0..10 {
+ break;
+ }
+
+ #[clippy::author]
+ 'label: for _ in 0..10 {
+ break 'label;
+ }
+
+ let a = true;
+
+ #[clippy::author]
+ while a {
+ break;
+ }
+
+ #[clippy::author]
+ while let true = a {
+ break;
+ }
+
+ #[clippy::author]
+ loop {
+ break;
+ }
+}
diff --git a/src/tools/clippy/tests/ui/author/loop.stdout b/src/tools/clippy/tests/ui/author/loop.stdout
new file mode 100644
index 00000000000..3d9560f697a
--- /dev/null
+++ b/src/tools/clippy/tests/ui/author/loop.stdout
@@ -0,0 +1,113 @@
+if_chain! {
+ if let Some(higher::ForLoop { pat: pat, arg: arg, body: body, .. }) = higher::ForLoop::hir(expr);
+ if let PatKind::Binding(BindingAnnotation::Unannotated, _, name, None) = pat.kind;
+ if name.as_str() == "y";
+ if let ExprKind::Struct(qpath, fields, None) = arg.kind;
+ if matches!(qpath, QPath::LangItem(LangItem::Range, _));
+ if fields.len() == 2;
+ if fields[0].ident.as_str() == "start";
+ if let ExprKind::Lit(ref lit) = fields[0].expr.kind;
+ if let LitKind::Int(0, LitIntType::Unsuffixed) = lit.node;
+ if fields[1].ident.as_str() == "end";
+ if let ExprKind::Lit(ref lit1) = fields[1].expr.kind;
+ if let LitKind::Int(10, LitIntType::Unsuffixed) = lit1.node;
+ if let ExprKind::Block(block, None) = body.kind;
+ if block.stmts.len() == 1;
+ if let StmtKind::Local(local) = block.stmts[0].kind;
+ if let Some(init) = local.init;
+ if let ExprKind::Path(ref qpath1) = init.kind;
+ if match_qpath(qpath1, &["y"]);
+ if let PatKind::Binding(BindingAnnotation::Unannotated, _, name1, None) = local.pat.kind;
+ if name1.as_str() == "z";
+ if block.expr.is_none();
+ then {
+ // report your lint here
+ }
+}
+if_chain! {
+ if let Some(higher::ForLoop { pat: pat, arg: arg, body: body, .. }) = higher::ForLoop::hir(expr);
+ if let PatKind::Wild = pat.kind;
+ if let ExprKind::Struct(qpath, fields, None) = arg.kind;
+ if matches!(qpath, QPath::LangItem(LangItem::Range, _));
+ if fields.len() == 2;
+ if fields[0].ident.as_str() == "start";
+ if let ExprKind::Lit(ref lit) = fields[0].expr.kind;
+ if let LitKind::Int(0, LitIntType::Unsuffixed) = lit.node;
+ if fields[1].ident.as_str() == "end";
+ if let ExprKind::Lit(ref lit1) = fields[1].expr.kind;
+ if let LitKind::Int(10, LitIntType::Unsuffixed) = lit1.node;
+ if let ExprKind::Block(block, None) = body.kind;
+ if block.stmts.len() == 1;
+ if let StmtKind::Semi(e) = block.stmts[0].kind;
+ if let ExprKind::Break(destination, None) = e.kind;
+ if destination.label.is_none();
+ if block.expr.is_none();
+ then {
+ // report your lint here
+ }
+}
+if_chain! {
+ if let Some(higher::ForLoop { pat: pat, arg: arg, body: body, .. }) = higher::ForLoop::hir(expr);
+ if let PatKind::Wild = pat.kind;
+ if let ExprKind::Struct(qpath, fields, None) = arg.kind;
+ if matches!(qpath, QPath::LangItem(LangItem::Range, _));
+ if fields.len() == 2;
+ if fields[0].ident.as_str() == "start";
+ if let ExprKind::Lit(ref lit) = fields[0].expr.kind;
+ if let LitKind::Int(0, LitIntType::Unsuffixed) = lit.node;
+ if fields[1].ident.as_str() == "end";
+ if let ExprKind::Lit(ref lit1) = fields[1].expr.kind;
+ if let LitKind::Int(10, LitIntType::Unsuffixed) = lit1.node;
+ if let ExprKind::Block(block, None) = body.kind;
+ if block.stmts.len() == 1;
+ if let StmtKind::Semi(e) = block.stmts[0].kind;
+ if let ExprKind::Break(destination, None) = e.kind;
+ if let Some(label) = destination.label;
+ if label.ident.as_str() == "'label";
+ if block.expr.is_none();
+ then {
+ // report your lint here
+ }
+}
+if_chain! {
+ if let Some(higher::While { condition: condition, body: body }) = higher::While::hir(expr);
+ if let ExprKind::Path(ref qpath) = condition.kind;
+ if match_qpath(qpath, &["a"]);
+ if let ExprKind::Block(block, None) = body.kind;
+ if block.stmts.len() == 1;
+ if let StmtKind::Semi(e) = block.stmts[0].kind;
+ if let ExprKind::Break(destination, None) = e.kind;
+ if destination.label.is_none();
+ if block.expr.is_none();
+ then {
+ // report your lint here
+ }
+}
+if_chain! {
+ if let Some(higher::WhileLet { let_pat: let_pat, let_expr: let_expr, if_then: if_then }) = higher::WhileLet::hir(expr);
+ if let PatKind::Lit(lit_expr) = let_pat.kind;
+ if let ExprKind::Lit(ref lit) = lit_expr.kind;
+ if let LitKind::Bool(true) = lit.node;
+ if let ExprKind::Path(ref qpath) = let_expr.kind;
+ if match_qpath(qpath, &["a"]);
+ if let ExprKind::Block(block, None) = if_then.kind;
+ if block.stmts.len() == 1;
+ if let StmtKind::Semi(e) = block.stmts[0].kind;
+ if let ExprKind::Break(destination, None) = e.kind;
+ if destination.label.is_none();
+ if block.expr.is_none();
+ then {
+ // report your lint here
+ }
+}
+if_chain! {
+ if let ExprKind::Loop(body, None, LoopSource::Loop, _) = expr.kind;
+ if body.stmts.len() == 1;
+ if let StmtKind::Semi(e) = body.stmts[0].kind;
+ if let ExprKind::Break(destination, None) = e.kind;
+ if destination.label.is_none();
+ if body.expr.is_none();
+ then {
+ // report your lint here
+ }
+}
diff --git a/src/tools/clippy/tests/ui/author/matches.stdout b/src/tools/clippy/tests/ui/author/matches.stdout
index 68cc2b214eb..38444a0094c 100644
--- a/src/tools/clippy/tests/ui/author/matches.stdout
+++ b/src/tools/clippy/tests/ui/author/matches.stdout
@@ -1,32 +1,35 @@
if_chain! {
- if let StmtKind::Local(ref local) = stmt.kind;
- if let Some(ref init) = local.init;
- if let ExprKind::Match(ref expr, ref arms, MatchSource::Normal) = init.kind;
- if let ExprKind::Lit(ref lit) = expr.kind;
- if let LitKind::Int(42, _) = lit.node;
+ if let StmtKind::Local(local) = stmt.kind;
+ if let Some(init) = local.init;
+ if let ExprKind::Match(scrutinee, arms, MatchSource::Normal) = init.kind;
+ if let ExprKind::Lit(ref lit) = scrutinee.kind;
+ if let LitKind::Int(42, LitIntType::Unsuffixed) = lit.node;
if arms.len() == 3;
- if let ExprKind::Lit(ref lit1) = arms[0].body.kind;
- if let LitKind::Int(5, _) = lit1.node;
- if let PatKind::Lit(ref lit_expr) = arms[0].pat.kind
- if let ExprKind::Lit(ref lit2) = lit_expr.kind;
- if let LitKind::Int(16, _) = lit2.node;
- if let ExprKind::Block(ref block) = arms[1].body.kind;
+ if let PatKind::Lit(lit_expr) = arms[0].pat.kind;
+ if let ExprKind::Lit(ref lit1) = lit_expr.kind;
+ if let LitKind::Int(16, LitIntType::Unsuffixed) = lit1.node;
+ if arms[0].guard.is_none();
+ if let ExprKind::Lit(ref lit2) = arms[0].body.kind;
+ if let LitKind::Int(5, LitIntType::Unsuffixed) = lit2.node;
+ if let PatKind::Lit(lit_expr1) = arms[1].pat.kind;
+ if let ExprKind::Lit(ref lit3) = lit_expr1.kind;
+ if let LitKind::Int(17, LitIntType::Unsuffixed) = lit3.node;
+ if arms[1].guard.is_none();
+ if let ExprKind::Block(block, None) = arms[1].body.kind;
if block.stmts.len() == 1;
- if let StmtKind::Local(ref local1) = block.stmts[0].kind;
- if let Some(ref init1) = local1.init;
- if let ExprKind::Lit(ref lit3) = init1.kind;
- if let LitKind::Int(3, _) = lit3.node;
+ if let StmtKind::Local(local1) = block.stmts[0].kind;
+ if let Some(init1) = local1.init;
+ if let ExprKind::Lit(ref lit4) = init1.kind;
+ if let LitKind::Int(3, LitIntType::Unsuffixed) = lit4.node;
if let PatKind::Binding(BindingAnnotation::Unannotated, _, name, None) = local1.pat.kind;
if name.as_str() == "x";
- if let Some(trailing_expr) = &block.expr;
- if let ExprKind::Path(ref path) = trailing_expr.kind;
- if match_qpath(path, &["x"]);
- if let PatKind::Lit(ref lit_expr1) = arms[1].pat.kind
- if let ExprKind::Lit(ref lit4) = lit_expr1.kind;
- if let LitKind::Int(17, _) = lit4.node;
- if let ExprKind::Lit(ref lit5) = arms[2].body.kind;
- if let LitKind::Int(1, _) = lit5.node;
+ if let Some(trailing_expr) = block.expr;
+ if let ExprKind::Path(ref qpath) = trailing_expr.kind;
+ if match_qpath(qpath, &["x"]);
if let PatKind::Wild = arms[2].pat.kind;
+ if arms[2].guard.is_none();
+ if let ExprKind::Lit(ref lit5) = arms[2].body.kind;
+ if let LitKind::Int(1, LitIntType::Unsuffixed) = lit5.node;
if let PatKind::Binding(BindingAnnotation::Unannotated, _, name1, None) = local.pat.kind;
if name1.as_str() == "a";
then {
diff --git a/src/tools/clippy/tests/ui/author/repeat.rs b/src/tools/clippy/tests/ui/author/repeat.rs
new file mode 100644
index 00000000000..d8e9d589e68
--- /dev/null
+++ b/src/tools/clippy/tests/ui/author/repeat.rs
@@ -0,0 +1,5 @@
+#[allow(clippy::no_effect)]
+fn main() {
+ #[clippy::author]
+ [1_u8; 5];
+}
diff --git a/src/tools/clippy/tests/ui/author/repeat.stdout b/src/tools/clippy/tests/ui/author/repeat.stdout
new file mode 100644
index 00000000000..f16350e4b5e
--- /dev/null
+++ b/src/tools/clippy/tests/ui/author/repeat.stdout
@@ -0,0 +1,11 @@
+if_chain! {
+ if let ExprKind::Repeat(value, length) = expr.kind;
+ if let ExprKind::Lit(ref lit) = value.kind;
+ if let LitKind::Int(1, LitIntType::Unsigned(UintTy::U8)) = lit.node;
+ let expr1 = &cx.tcx.hir().body(length.body).value;
+ if let ExprKind::Lit(ref lit1) = expr1.kind;
+ if let LitKind::Int(5, LitIntType::Unsuffixed) = lit1.node;
+ then {
+ // report your lint here
+ }
+}
diff --git a/src/tools/clippy/tests/ui/author/struct.rs b/src/tools/clippy/tests/ui/author/struct.rs
new file mode 100644
index 00000000000..5fdf3433a37
--- /dev/null
+++ b/src/tools/clippy/tests/ui/author/struct.rs
@@ -0,0 +1,40 @@
+#[allow(clippy::unnecessary_operation, clippy::single_match)]
+fn main() {
+ struct Test {
+ field: u32,
+ }
+
+ #[clippy::author]
+ Test {
+ field: if true { 1 } else { 0 },
+ };
+
+ let test = Test { field: 1 };
+
+ match test {
+ #[clippy::author]
+ Test { field: 1 } => {},
+ _ => {},
+ }
+
+ struct TestTuple(u32);
+
+ let test_tuple = TestTuple(1);
+
+ match test_tuple {
+ #[clippy::author]
+ TestTuple(1) => {},
+ _ => {},
+ }
+
+ struct TestMethodCall(u32);
+
+ impl TestMethodCall {
+ fn test(&self) {}
+ }
+
+ let test_method_call = TestMethodCall(1);
+
+ #[clippy::author]
+ test_method_call.test();
+}
diff --git a/src/tools/clippy/tests/ui/author/struct.stdout b/src/tools/clippy/tests/ui/author/struct.stdout
new file mode 100644
index 00000000000..ded5abd8d33
--- /dev/null
+++ b/src/tools/clippy/tests/ui/author/struct.stdout
@@ -0,0 +1,64 @@
+if_chain! {
+ if let ExprKind::Struct(qpath, fields, None) = expr.kind;
+ if match_qpath(qpath, &["Test"]);
+ if fields.len() == 1;
+ if fields[0].ident.as_str() == "field";
+ if let ExprKind::If(cond, then, Some(else_expr)) = fields[0].expr.kind;
+ if let ExprKind::DropTemps(expr1) = cond.kind;
+ if let ExprKind::Lit(ref lit) = expr1.kind;
+ if let LitKind::Bool(true) = lit.node;
+ if let ExprKind::Block(block, None) = then.kind;
+ if block.stmts.is_empty();
+ if let Some(trailing_expr) = block.expr;
+ if let ExprKind::Lit(ref lit1) = trailing_expr.kind;
+ if let LitKind::Int(1, LitIntType::Unsuffixed) = lit1.node;
+ if let ExprKind::Block(block1, None) = else_expr.kind;
+ if block1.stmts.is_empty();
+ if let Some(trailing_expr1) = block1.expr;
+ if let ExprKind::Lit(ref lit2) = trailing_expr1.kind;
+ if let LitKind::Int(0, LitIntType::Unsuffixed) = lit2.node;
+ then {
+ // report your lint here
+ }
+}
+if_chain! {
+ if let PatKind::Struct(ref qpath, fields, false) = arm.pat.kind;
+ if match_qpath(qpath, &["Test"]);
+ if fields.len() == 1;
+ if fields[0].ident.as_str() == "field";
+ if let PatKind::Lit(lit_expr) = fields[0].pat.kind;
+ if let ExprKind::Lit(ref lit) = lit_expr.kind;
+ if let LitKind::Int(1, LitIntType::Unsuffixed) = lit.node;
+ if arm.guard.is_none();
+ if let ExprKind::Block(block, None) = arm.body.kind;
+ if block.stmts.is_empty();
+ if block.expr.is_none();
+ then {
+ // report your lint here
+ }
+}
+if_chain! {
+ if let PatKind::TupleStruct(ref qpath, fields, None) = arm.pat.kind;
+ if match_qpath(qpath, &["TestTuple"]);
+ if fields.len() == 1;
+ if let PatKind::Lit(lit_expr) = fields[0].kind;
+ if let ExprKind::Lit(ref lit) = lit_expr.kind;
+ if let LitKind::Int(1, LitIntType::Unsuffixed) = lit.node;
+ if arm.guard.is_none();
+ if let ExprKind::Block(block, None) = arm.body.kind;
+ if block.stmts.is_empty();
+ if block.expr.is_none();
+ then {
+ // report your lint here
+ }
+}
+if_chain! {
+ if let ExprKind::MethodCall(method_name, _, args, _) = expr.kind;
+ if method_name.ident.as_str() == "test";
+ if args.len() == 1;
+ if let ExprKind::Path(ref qpath) = args[0].kind;
+ if match_qpath(qpath, &["test_method_call"]);
+ then {
+ // report your lint here
+ }
+}
diff --git a/src/tools/clippy/tests/ui/auxiliary/option_helpers.rs b/src/tools/clippy/tests/ui/auxiliary/option_helpers.rs
index 86a637ce309..f9bc9436b07 100644
--- a/src/tools/clippy/tests/ui/auxiliary/option_helpers.rs
+++ b/src/tools/clippy/tests/ui/auxiliary/option_helpers.rs
@@ -1,4 +1,4 @@
-#![allow(dead_code, unused_variables)]
+#![allow(dead_code, unused_variables, clippy::return_self_not_must_use)]
/// Utility macro to test linting behavior in `option_methods()`
/// The lints included in `option_methods()` should not lint if the call to map is partially
diff --git a/src/tools/clippy/tests/ui/blocks_in_if_conditions_closure.rs b/src/tools/clippy/tests/ui/blocks_in_if_conditions_closure.rs
index 2856943b9be..169589f6d4e 100644
--- a/src/tools/clippy/tests/ui/blocks_in_if_conditions_closure.rs
+++ b/src/tools/clippy/tests/ui/blocks_in_if_conditions_closure.rs
@@ -44,6 +44,14 @@ fn macro_in_closure() {
}
}
+fn closure(_: impl FnMut()) -> bool {
+ true
+}
+
+fn function_with_empty_closure() {
+ if closure(|| {}) {}
+}
+
#[rustfmt::skip]
fn main() {
let mut range = 0..10;
diff --git a/src/tools/clippy/tests/ui/cast_lossless_bool.fixed b/src/tools/clippy/tests/ui/cast_lossless_bool.fixed
new file mode 100644
index 00000000000..9e2da45c378
--- /dev/null
+++ b/src/tools/clippy/tests/ui/cast_lossless_bool.fixed
@@ -0,0 +1,42 @@
+// run-rustfix
+
+#![allow(dead_code)]
+#![warn(clippy::cast_lossless)]
+
+fn main() {
+ // Test clippy::cast_lossless with casts to integer types
+ let _ = u8::from(true);
+ let _ = u16::from(true);
+ let _ = u32::from(true);
+ let _ = u64::from(true);
+ let _ = u128::from(true);
+ let _ = usize::from(true);
+
+ let _ = i8::from(true);
+ let _ = i16::from(true);
+ let _ = i32::from(true);
+ let _ = i64::from(true);
+ let _ = i128::from(true);
+ let _ = isize::from(true);
+
+ // Test with an expression wrapped in parens
+ let _ = u16::from(true | false);
+}
+
+// The lint would suggest using `u32::from(input)` here but the `XX::from` function is not const,
+// so we skip the lint if the expression is in a const fn.
+// See #3656
+const fn abc(input: bool) -> u32 {
+ input as u32
+}
+
+// Same as the above issue. We can't suggest `::from` in const fns in impls
+mod cast_lossless_in_impl {
+ struct A;
+
+ impl A {
+ pub const fn convert(x: bool) -> u64 {
+ x as u64
+ }
+ }
+}
diff --git a/src/tools/clippy/tests/ui/cast_lossless_bool.rs b/src/tools/clippy/tests/ui/cast_lossless_bool.rs
new file mode 100644
index 00000000000..b6f6c59a01f
--- /dev/null
+++ b/src/tools/clippy/tests/ui/cast_lossless_bool.rs
@@ -0,0 +1,42 @@
+// run-rustfix
+
+#![allow(dead_code)]
+#![warn(clippy::cast_lossless)]
+
+fn main() {
+ // Test clippy::cast_lossless with casts to integer types
+ let _ = true as u8;
+ let _ = true as u16;
+ let _ = true as u32;
+ let _ = true as u64;
+ let _ = true as u128;
+ let _ = true as usize;
+
+ let _ = true as i8;
+ let _ = true as i16;
+ let _ = true as i32;
+ let _ = true as i64;
+ let _ = true as i128;
+ let _ = true as isize;
+
+ // Test with an expression wrapped in parens
+ let _ = (true | false) as u16;
+}
+
+// The lint would suggest using `u32::from(input)` here but the `XX::from` function is not const,
+// so we skip the lint if the expression is in a const fn.
+// See #3656
+const fn abc(input: bool) -> u32 {
+ input as u32
+}
+
+// Same as the above issue. We can't suggest `::from` in const fns in impls
+mod cast_lossless_in_impl {
+ struct A;
+
+ impl A {
+ pub const fn convert(x: bool) -> u64 {
+ x as u64
+ }
+ }
+}
diff --git a/src/tools/clippy/tests/ui/cast_lossless_bool.stderr b/src/tools/clippy/tests/ui/cast_lossless_bool.stderr
new file mode 100644
index 00000000000..6b148336011
--- /dev/null
+++ b/src/tools/clippy/tests/ui/cast_lossless_bool.stderr
@@ -0,0 +1,82 @@
+error: casting `bool` to `u8` is more cleanly stated with `u8::from(_)`
+ --> $DIR/cast_lossless_bool.rs:8:13
+ |
+LL | let _ = true as u8;
+ | ^^^^^^^^^^ help: try: `u8::from(true)`
+ |
+ = note: `-D clippy::cast-lossless` implied by `-D warnings`
+
+error: casting `bool` to `u16` is more cleanly stated with `u16::from(_)`
+ --> $DIR/cast_lossless_bool.rs:9:13
+ |
+LL | let _ = true as u16;
+ | ^^^^^^^^^^^ help: try: `u16::from(true)`
+
+error: casting `bool` to `u32` is more cleanly stated with `u32::from(_)`
+ --> $DIR/cast_lossless_bool.rs:10:13
+ |
+LL | let _ = true as u32;
+ | ^^^^^^^^^^^ help: try: `u32::from(true)`
+
+error: casting `bool` to `u64` is more cleanly stated with `u64::from(_)`
+ --> $DIR/cast_lossless_bool.rs:11:13
+ |
+LL | let _ = true as u64;
+ | ^^^^^^^^^^^ help: try: `u64::from(true)`
+
+error: casting `bool` to `u128` is more cleanly stated with `u128::from(_)`
+ --> $DIR/cast_lossless_bool.rs:12:13
+ |
+LL | let _ = true as u128;
+ | ^^^^^^^^^^^^ help: try: `u128::from(true)`
+
+error: casting `bool` to `usize` is more cleanly stated with `usize::from(_)`
+ --> $DIR/cast_lossless_bool.rs:13:13
+ |
+LL | let _ = true as usize;
+ | ^^^^^^^^^^^^^ help: try: `usize::from(true)`
+
+error: casting `bool` to `i8` is more cleanly stated with `i8::from(_)`
+ --> $DIR/cast_lossless_bool.rs:15:13
+ |
+LL | let _ = true as i8;
+ | ^^^^^^^^^^ help: try: `i8::from(true)`
+
+error: casting `bool` to `i16` is more cleanly stated with `i16::from(_)`
+ --> $DIR/cast_lossless_bool.rs:16:13
+ |
+LL | let _ = true as i16;
+ | ^^^^^^^^^^^ help: try: `i16::from(true)`
+
+error: casting `bool` to `i32` is more cleanly stated with `i32::from(_)`
+ --> $DIR/cast_lossless_bool.rs:17:13
+ |
+LL | let _ = true as i32;
+ | ^^^^^^^^^^^ help: try: `i32::from(true)`
+
+error: casting `bool` to `i64` is more cleanly stated with `i64::from(_)`
+ --> $DIR/cast_lossless_bool.rs:18:13
+ |
+LL | let _ = true as i64;
+ | ^^^^^^^^^^^ help: try: `i64::from(true)`
+
+error: casting `bool` to `i128` is more cleanly stated with `i128::from(_)`
+ --> $DIR/cast_lossless_bool.rs:19:13
+ |
+LL | let _ = true as i128;
+ | ^^^^^^^^^^^^ help: try: `i128::from(true)`
+
+error: casting `bool` to `isize` is more cleanly stated with `isize::from(_)`
+ --> $DIR/cast_lossless_bool.rs:20:13
+ |
+LL | let _ = true as isize;
+ | ^^^^^^^^^^^^^ help: try: `isize::from(true)`
+
+error: casting `bool` to `u16` is more cleanly stated with `u16::from(_)`
+ --> $DIR/cast_lossless_bool.rs:23:13
+ |
+LL | let _ = (true | false) as u16;
+ | ^^^^^^^^^^^^^^^^^^^^^ help: try: `u16::from(true | false)`
+
+error: aborting due to 13 previous errors
+
diff --git a/src/tools/clippy/tests/ui/crashes/auxiliary/ice-7934-aux.rs b/src/tools/clippy/tests/ui/crashes/auxiliary/ice-7934-aux.rs
new file mode 100644
index 00000000000..4afbf027b61
--- /dev/null
+++ b/src/tools/clippy/tests/ui/crashes/auxiliary/ice-7934-aux.rs
@@ -0,0 +1,4 @@
+fn zero() {
+ // SAFETY:
+ unsafe { 0 };
+}
diff --git a/src/tools/clippy/tests/ui/crashes/ice-6250.stderr b/src/tools/clippy/tests/ui/crashes/ice-6250.stderr
index 439884b7d27..7ffbd7a64b3 100644
--- a/src/tools/clippy/tests/ui/crashes/ice-6250.stderr
+++ b/src/tools/clippy/tests/ui/crashes/ice-6250.stderr
@@ -1,14 +1,3 @@
-error[E0658]: destructuring assignments are unstable
- --> $DIR/ice-6250.rs:12:25
- |
-LL | Some(reference) = cache.data.get(key) {
- | --------------- ^
- | |
- | cannot assign to this expression
- |
- = note: see issue #71126 <https://github.com/rust-lang/rust/issues/71126> for more information
- = help: add `#![feature(destructuring_assignment)]` to the crate attributes to enable
-
error[E0601]: `main` function not found in crate `ice_6250`
--> $DIR/ice-6250.rs:4:1
|
@@ -24,6 +13,9 @@ LL | | }
error[E0308]: mismatched types
--> $DIR/ice-6250.rs:12:14
|
+LL | for reference in vec![1, 2, 3] {
+ | --------- expected due to the type of this binding
+...
LL | Some(reference) = cache.data.get(key) {
| ^^^^^^^^^ expected integer, found `&i32`
|
@@ -38,7 +30,7 @@ error[E0308]: mismatched types
LL | Some(reference) = cache.data.get(key) {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected `bool`, found `()`
-error: aborting due to 4 previous errors
+error: aborting due to 3 previous errors
-Some errors have detailed explanations: E0308, E0601, E0658.
+Some errors have detailed explanations: E0308, E0601.
For more information about an error, try `rustc --explain E0308`.
diff --git a/src/tools/clippy/tests/ui/crashes/ice-7934.rs b/src/tools/clippy/tests/ui/crashes/ice-7934.rs
new file mode 100644
index 00000000000..a4691c4131b
--- /dev/null
+++ b/src/tools/clippy/tests/ui/crashes/ice-7934.rs
@@ -0,0 +1,7 @@
+#![warn(clippy::undocumented_unsafe_blocks)]
+#![allow(clippy::no_effect)]
+
+#[path = "auxiliary/ice-7934-aux.rs"]
+mod zero;
+
+fn main() {}
diff --git a/src/tools/clippy/tests/ui/crate_level_checks/no_std_swap.rs b/src/tools/clippy/tests/ui/crate_level_checks/no_std_swap.rs
new file mode 100644
index 00000000000..d3571eaf0d7
--- /dev/null
+++ b/src/tools/clippy/tests/ui/crate_level_checks/no_std_swap.rs
@@ -0,0 +1,14 @@
+#![no_std]
+#![feature(lang_items, start, libc)]
+#![crate_type = "lib"]
+
+use core::panic::PanicInfo;
+
+#[warn(clippy::all)]
+fn main() {
+ let mut a = 42;
+ let mut b = 1337;
+
+ a = b;
+ b = a;
+}
diff --git a/src/tools/clippy/tests/ui/crate_level_checks/no_std_swap.stderr b/src/tools/clippy/tests/ui/crate_level_checks/no_std_swap.stderr
new file mode 100644
index 00000000000..48152d8ad77
--- /dev/null
+++ b/src/tools/clippy/tests/ui/crate_level_checks/no_std_swap.stderr
@@ -0,0 +1,12 @@
+error: this looks like you are trying to swap `a` and `b`
+ --> $DIR/no_std_swap.rs:12:5
+ |
+LL | / a = b;
+LL | | b = a;
+ | |_________^ help: try: `core::mem::swap(&mut a, &mut b)`
+ |
+ = note: `-D clippy::almost-swapped` implied by `-D warnings`
+ = note: or maybe you should use `core::mem::replace`?
+
+error: aborting due to previous error
+
diff --git a/src/tools/clippy/tests/ui/deref_addrof.fixed b/src/tools/clippy/tests/ui/deref_addrof.fixed
index 9a150c67a21..0029fc673f1 100644
--- a/src/tools/clippy/tests/ui/deref_addrof.fixed
+++ b/src/tools/clippy/tests/ui/deref_addrof.fixed
@@ -1,4 +1,5 @@
// run-rustfix
+#![allow(clippy::return_self_not_must_use)]
#![warn(clippy::deref_addrof)]
fn get_number() -> usize {
diff --git a/src/tools/clippy/tests/ui/deref_addrof.rs b/src/tools/clippy/tests/ui/deref_addrof.rs
index 80ba7e9bd0b..f2f02dd5e72 100644
--- a/src/tools/clippy/tests/ui/deref_addrof.rs
+++ b/src/tools/clippy/tests/ui/deref_addrof.rs
@@ -1,4 +1,5 @@
// run-rustfix
+#![allow(clippy::return_self_not_must_use)]
#![warn(clippy::deref_addrof)]
fn get_number() -> usize {
diff --git a/src/tools/clippy/tests/ui/deref_addrof.stderr b/src/tools/clippy/tests/ui/deref_addrof.stderr
index 1a14f31af8d..5bc1cbfa215 100644
--- a/src/tools/clippy/tests/ui/deref_addrof.stderr
+++ b/src/tools/clippy/tests/ui/deref_addrof.stderr
@@ -1,5 +1,5 @@
error: immediately dereferencing a reference
- --> $DIR/deref_addrof.rs:18:13
+ --> $DIR/deref_addrof.rs:19:13
|
LL | let b = *&a;
| ^^^ help: try this: `a`
@@ -7,49 +7,49 @@ LL | let b = *&a;
= note: `-D clippy::deref-addrof` implied by `-D warnings`
error: immediately dereferencing a reference
- --> $DIR/deref_addrof.rs:20:13
+ --> $DIR/deref_addrof.rs:21:13
|
LL | let b = *&get_number();
| ^^^^^^^^^^^^^^ help: try this: `get_number()`
error: immediately dereferencing a reference
- --> $DIR/deref_addrof.rs:25:13
+ --> $DIR/deref_addrof.rs:26:13
|
LL | let b = *&bytes[1..2][0];
| ^^^^^^^^^^^^^^^^ help: try this: `bytes[1..2][0]`
error: immediately dereferencing a reference
- --> $DIR/deref_addrof.rs:29:13
+ --> $DIR/deref_addrof.rs:30:13
|
LL | let b = *&(a);
| ^^^^^ help: try this: `(a)`
error: immediately dereferencing a reference
- --> $DIR/deref_addrof.rs:31:13
+ --> $DIR/deref_addrof.rs:32:13
|
LL | let b = *(&a);
| ^^^^^ help: try this: `a`
error: immediately dereferencing a reference
- --> $DIR/deref_addrof.rs:34:13
+ --> $DIR/deref_addrof.rs:35:13
|
LL | let b = *((&a));
| ^^^^^^^ help: try this: `a`
error: immediately dereferencing a reference
- --> $DIR/deref_addrof.rs:36:13
+ --> $DIR/deref_addrof.rs:37:13
|
LL | let b = *&&a;
| ^^^^ help: try this: `&a`
error: immediately dereferencing a reference
- --> $DIR/deref_addrof.rs:38:14
+ --> $DIR/deref_addrof.rs:39:14
|
LL | let b = **&aref;
| ^^^^^^ help: try this: `aref`
error: immediately dereferencing a reference
- --> $DIR/deref_addrof.rs:44:9
+ --> $DIR/deref_addrof.rs:45:9
|
LL | *& $visitor
| ^^^^^^^^^^^ help: try this: `$visitor`
@@ -60,7 +60,7 @@ LL | m!(self)
= note: this error originates in the macro `m` (in Nightly builds, run with -Z macro-backtrace for more info)
error: immediately dereferencing a reference
- --> $DIR/deref_addrof.rs:51:9
+ --> $DIR/deref_addrof.rs:52:9
|
LL | *& mut $visitor
| ^^^^^^^^^^^^^^^ help: try this: `$visitor`
diff --git a/src/tools/clippy/tests/ui/doc/doc-fixable.stderr b/src/tools/clippy/tests/ui/doc/doc-fixable.stderr
index 31132f86edb..40345370c04 100644
--- a/src/tools/clippy/tests/ui/doc/doc-fixable.stderr
+++ b/src/tools/clippy/tests/ui/doc/doc-fixable.stderr
@@ -2,183 +2,332 @@ error: item in documentation is missing backticks
--> $DIR/doc-fixable.rs:9:9
|
LL | /// The foo_bar function does _nothing_. See also foo::bar. (note the dot there)
- | ^^^^^^^ help: try: ``foo_bar``
+ | ^^^^^^^
|
= note: `-D clippy::doc-markdown` implied by `-D warnings`
+help: try
+ |
+LL | /// The `foo_bar` function does _nothing_. See also foo::bar. (note the dot there)
+ | ~~~~~~~~~
error: item in documentation is missing backticks
--> $DIR/doc-fixable.rs:9:51
|
LL | /// The foo_bar function does _nothing_. See also foo::bar. (note the dot there)
- | ^^^^^^^^ help: try: ``foo::bar``
+ | ^^^^^^^^
+ |
+help: try
+ |
+LL | /// The foo_bar function does _nothing_. See also `foo::bar`. (note the dot there)
+ | ~~~~~~~~~~
error: item in documentation is missing backticks
--> $DIR/doc-fixable.rs:10:83
|
LL | /// Markdown is _weird_. I mean _really weird_. This /_ is ok. So is `_`. But not Foo::some_fun
- | ^^^^^^^^^^^^^ help: try: ``Foo::some_fun``
+ | ^^^^^^^^^^^^^
+ |
+help: try
+ |
+LL | /// Markdown is _weird_. I mean _really weird_. This /_ is ok. So is `_`. But not `Foo::some_fun`
+ | ~~~~~~~~~~~~~~~
error: item in documentation is missing backticks
--> $DIR/doc-fixable.rs:12:13
|
LL | /// Here be ::a::global:path, and _::another::global::path_. :: is not a path though.
- | ^^^^^^^^^^^^^^^^ help: try: ``::a::global:path``
+ | ^^^^^^^^^^^^^^^^
+ |
+help: try
+ |
+LL | /// Here be `::a::global:path`, and _::another::global::path_. :: is not a path though.
+ | ~~~~~~~~~~~~~~~~~~
error: item in documentation is missing backticks
--> $DIR/doc-fixable.rs:12:36
|
LL | /// Here be ::a::global:path, and _::another::global::path_. :: is not a path though.
- | ^^^^^^^^^^^^^^^^^^^^^^^ help: try: ``::another::global::path``
+ | ^^^^^^^^^^^^^^^^^^^^^^^
+ |
+help: try
+ |
+LL | /// Here be ::a::global:path, and _`::another::global::path`_. :: is not a path though.
+ | ~~~~~~~~~~~~~~~~~~~~~~~~~
error: item in documentation is missing backticks
--> $DIR/doc-fixable.rs:13:25
|
LL | /// Import an item from ::awesome::global::blob:: (Intended postfix)
- | ^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: ``::awesome::global::blob::``
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^
+ |
+help: try
+ |
+LL | /// Import an item from `::awesome::global::blob::` (Intended postfix)
+ | ~~~~~~~~~~~~~~~~~~~~~~~~~~~
error: item in documentation is missing backticks
--> $DIR/doc-fixable.rs:14:31
|
LL | /// These are the options for ::Cat: (Intended trailing single colon, shouldn't be linted)
- | ^^^^^ help: try: ``::Cat``
+ | ^^^^^
+ |
+help: try
+ |
+LL | /// These are the options for `::Cat`: (Intended trailing single colon, shouldn't be linted)
+ | ~~~~~~~
error: item in documentation is missing backticks
--> $DIR/doc-fixable.rs:15:22
|
LL | /// That's not code ~NotInCodeBlock~.
- | ^^^^^^^^^^^^^^ help: try: ``NotInCodeBlock``
+ | ^^^^^^^^^^^^^^
+ |
+help: try
+ |
+LL | /// That's not code ~`NotInCodeBlock`~.
+ | ~~~~~~~~~~~~~~~~
error: item in documentation is missing backticks
--> $DIR/doc-fixable.rs:16:5
|
LL | /// be_sure_we_got_to_the_end_of_it
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: ``be_sure_we_got_to_the_end_of_it``
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ |
+help: try
+ |
+LL | /// `be_sure_we_got_to_the_end_of_it`
+ | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
error: item in documentation is missing backticks
--> $DIR/doc-fixable.rs:30:5
|
LL | /// be_sure_we_got_to_the_end_of_it
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: ``be_sure_we_got_to_the_end_of_it``
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ |
+help: try
+ |
+LL | /// `be_sure_we_got_to_the_end_of_it`
+ | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
error: item in documentation is missing backticks
--> $DIR/doc-fixable.rs:37:5
|
LL | /// be_sure_we_got_to_the_end_of_it
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: ``be_sure_we_got_to_the_end_of_it``
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ |
+help: try
+ |
+LL | /// `be_sure_we_got_to_the_end_of_it`
+ | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
error: item in documentation is missing backticks
--> $DIR/doc-fixable.rs:51:5
|
LL | /// be_sure_we_got_to_the_end_of_it
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: ``be_sure_we_got_to_the_end_of_it``
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ |
+help: try
+ |
+LL | /// `be_sure_we_got_to_the_end_of_it`
+ | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
error: item in documentation is missing backticks
--> $DIR/doc-fixable.rs:74:5
|
LL | /// be_sure_we_got_to_the_end_of_it
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: ``be_sure_we_got_to_the_end_of_it``
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ |
+help: try
+ |
+LL | /// `be_sure_we_got_to_the_end_of_it`
+ | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
error: item in documentation is missing backticks
--> $DIR/doc-fixable.rs:78:22
|
LL | /// This test has [a link_with_underscores][chunked-example] inside it. See #823.
- | ^^^^^^^^^^^^^^^^^^^^^ help: try: ``link_with_underscores``
+ | ^^^^^^^^^^^^^^^^^^^^^
+ |
+help: try
+ |
+LL | /// This test has [a `link_with_underscores`][chunked-example] inside it. See #823.
+ | ~~~~~~~~~~~~~~~~~~~~~~~
error: item in documentation is missing backticks
--> $DIR/doc-fixable.rs:81:21
|
LL | /// It can also be [inline_link2].
- | ^^^^^^^^^^^^ help: try: ``inline_link2``
+ | ^^^^^^^^^^^^
+ |
+help: try
+ |
+LL | /// It can also be [`inline_link2`].
+ | ~~~~~~~~~~~~~~
error: item in documentation is missing backticks
--> $DIR/doc-fixable.rs:91:5
|
LL | /// be_sure_we_got_to_the_end_of_it
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: ``be_sure_we_got_to_the_end_of_it``
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ |
+help: try
+ |
+LL | /// `be_sure_we_got_to_the_end_of_it`
+ | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
error: item in documentation is missing backticks
--> $DIR/doc-fixable.rs:99:8
|
LL | /// ## CamelCaseThing
- | ^^^^^^^^^^^^^^ help: try: ``CamelCaseThing``
+ | ^^^^^^^^^^^^^^
+ |
+help: try
+ |
+LL | /// ## `CamelCaseThing`
+ | ~~~~~~~~~~~~~~~~
error: item in documentation is missing backticks
--> $DIR/doc-fixable.rs:102:7
|
LL | /// # CamelCaseThing
- | ^^^^^^^^^^^^^^ help: try: ``CamelCaseThing``
+ | ^^^^^^^^^^^^^^
+ |
+help: try
+ |
+LL | /// # `CamelCaseThing`
+ | ~~~~~~~~~~~~~~~~
error: item in documentation is missing backticks
--> $DIR/doc-fixable.rs:104:22
|
LL | /// Not a title #897 CamelCaseThing
- | ^^^^^^^^^^^^^^ help: try: ``CamelCaseThing``
+ | ^^^^^^^^^^^^^^
+ |
+help: try
+ |
+LL | /// Not a title #897 `CamelCaseThing`
+ | ~~~~~~~~~~~~~~~~
error: item in documentation is missing backticks
--> $DIR/doc-fixable.rs:105:5
|
LL | /// be_sure_we_got_to_the_end_of_it
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: ``be_sure_we_got_to_the_end_of_it``
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ |
+help: try
+ |
+LL | /// `be_sure_we_got_to_the_end_of_it`
+ | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
error: item in documentation is missing backticks
--> $DIR/doc-fixable.rs:112:5
|
LL | /// be_sure_we_got_to_the_end_of_it
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: ``be_sure_we_got_to_the_end_of_it``
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ |
+help: try
+ |
+LL | /// `be_sure_we_got_to_the_end_of_it`
+ | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
error: item in documentation is missing backticks
--> $DIR/doc-fixable.rs:125:5
|
LL | /// be_sure_we_got_to_the_end_of_it
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: ``be_sure_we_got_to_the_end_of_it``
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ |
+help: try
+ |
+LL | /// `be_sure_we_got_to_the_end_of_it`
+ | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
error: item in documentation is missing backticks
--> $DIR/doc-fixable.rs:136:43
|
LL | /** E.g., serialization of an empty list: FooBar
- | ^^^^^^ help: try: ``FooBar``
+ | ^^^^^^
+ |
+help: try
+ |
+LL | /** E.g., serialization of an empty list: `FooBar`
+ | ~~~~~~~~
error: item in documentation is missing backticks
--> $DIR/doc-fixable.rs:141:5
|
LL | And BarQuz too.
- | ^^^^^^ help: try: ``BarQuz``
+ | ^^^^^^
+ |
+help: try
+ |
+LL | And `BarQuz` too.
+ | ~~~~~~~~
error: item in documentation is missing backticks
--> $DIR/doc-fixable.rs:142:1
|
LL | be_sure_we_got_to_the_end_of_it
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: ``be_sure_we_got_to_the_end_of_it``
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ |
+help: try
+ |
+LL | `be_sure_we_got_to_the_end_of_it`
+ |
error: item in documentation is missing backticks
--> $DIR/doc-fixable.rs:147:43
|
LL | /** E.g., serialization of an empty list: FooBar
- | ^^^^^^ help: try: ``FooBar``
+ | ^^^^^^
+ |
+help: try
+ |
+LL | /** E.g., serialization of an empty list: `FooBar`
+ | ~~~~~~~~
error: item in documentation is missing backticks
--> $DIR/doc-fixable.rs:152:5
|
LL | And BarQuz too.
- | ^^^^^^ help: try: ``BarQuz``
+ | ^^^^^^
+ |
+help: try
+ |
+LL | And `BarQuz` too.
+ | ~~~~~~~~
error: item in documentation is missing backticks
--> $DIR/doc-fixable.rs:153:1
|
LL | be_sure_we_got_to_the_end_of_it
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: ``be_sure_we_got_to_the_end_of_it``
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ |
+help: try
+ |
+LL | `be_sure_we_got_to_the_end_of_it`
+ |
error: item in documentation is missing backticks
--> $DIR/doc-fixable.rs:164:5
|
LL | /// be_sure_we_got_to_the_end_of_it
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: ``be_sure_we_got_to_the_end_of_it``
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ |
+help: try
+ |
+LL | /// `be_sure_we_got_to_the_end_of_it`
+ | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
error: item in documentation is missing backticks
--> $DIR/doc-fixable.rs:183:22
|
LL | /// An iterator over mycrate::Collection's values.
- | ^^^^^^^^^^^^^^^^^^^ help: try: ``mycrate::Collection``
+ | ^^^^^^^^^^^^^^^^^^^
+ |
+help: try
+ |
+LL | /// An iterator over `mycrate::Collection`'s values.
+ | ~~~~~~~~~~~~~~~~~~~~~
error: aborting due to 30 previous errors
diff --git a/src/tools/clippy/tests/ui/doc/unbalanced_ticks.stderr b/src/tools/clippy/tests/ui/doc/unbalanced_ticks.stderr
index 9670e5c24fb..a462b98871a 100644
--- a/src/tools/clippy/tests/ui/doc/unbalanced_ticks.stderr
+++ b/src/tools/clippy/tests/ui/doc/unbalanced_ticks.stderr
@@ -22,7 +22,12 @@ error: item in documentation is missing backticks
--> $DIR/unbalanced_ticks.rs:15:32
|
LL | /// This paragraph is fine and should_be linted normally.
- | ^^^^^^^^^ help: try: ``should_be``
+ | ^^^^^^^^^
+ |
+help: try
+ |
+LL | /// This paragraph is fine and `should_be` linted normally.
+ | ~~~~~~~~~~~
error: backticks are unbalanced
--> $DIR/unbalanced_ticks.rs:17:1
@@ -36,7 +41,12 @@ error: item in documentation is missing backticks
--> $DIR/unbalanced_ticks.rs:30:8
|
LL | /// ## not_fine
- | ^^^^^^^^ help: try: ``not_fine``
+ | ^^^^^^^^
+ |
+help: try
+ |
+LL | /// ## `not_fine`
+ | ~~~~~~~~~~
error: backticks are unbalanced
--> $DIR/unbalanced_ticks.rs:32:1
@@ -58,7 +68,12 @@ error: item in documentation is missing backticks
--> $DIR/unbalanced_ticks.rs:35:23
|
LL | /// - This item needs backticks_here
- | ^^^^^^^^^^^^^^ help: try: ``backticks_here``
+ | ^^^^^^^^^^^^^^
+ |
+help: try
+ |
+LL | /// - This item needs `backticks_here`
+ | ~~~~~~~~~~~~~~~~
error: aborting due to 8 previous errors
diff --git a/src/tools/clippy/tests/ui/entry.fixed b/src/tools/clippy/tests/ui/entry.fixed
index 8a36ec833d7..e43635abcd1 100644
--- a/src/tools/clippy/tests/ui/entry.fixed
+++ b/src/tools/clippy/tests/ui/entry.fixed
@@ -2,8 +2,8 @@
#![allow(unused, clippy::needless_pass_by_value, clippy::collapsible_if)]
#![warn(clippy::map_entry)]
-#![feature(asm)]
+use std::arch::asm;
use std::collections::HashMap;
use std::hash::Hash;
diff --git a/src/tools/clippy/tests/ui/entry.rs b/src/tools/clippy/tests/ui/entry.rs
index d972a201ad7..d999b3b7dc8 100644
--- a/src/tools/clippy/tests/ui/entry.rs
+++ b/src/tools/clippy/tests/ui/entry.rs
@@ -2,8 +2,8 @@
#![allow(unused, clippy::needless_pass_by_value, clippy::collapsible_if)]
#![warn(clippy::map_entry)]
-#![feature(asm)]
+use std::arch::asm;
use std::collections::HashMap;
use std::hash::Hash;
diff --git a/src/tools/clippy/tests/ui/explicit_counter_loop.rs b/src/tools/clippy/tests/ui/explicit_counter_loop.rs
index 81d8221bd13..aa966761feb 100644
--- a/src/tools/clippy/tests/ui/explicit_counter_loop.rs
+++ b/src/tools/clippy/tests/ui/explicit_counter_loop.rs
@@ -158,3 +158,33 @@ mod issue_4677 {
}
}
}
+
+mod issue_7920 {
+ pub fn test() {
+ let slice = &[1, 2, 3];
+
+ let index_usize: usize = 0;
+ let mut idx_usize: usize = 0;
+
+ // should suggest `enumerate`
+ for _item in slice {
+ if idx_usize == index_usize {
+ break;
+ }
+
+ idx_usize += 1;
+ }
+
+ let index_u32: u32 = 0;
+ let mut idx_u32: u32 = 0;
+
+ // should suggest `zip`
+ for _item in slice {
+ if idx_u32 == index_u32 {
+ break;
+ }
+
+ idx_u32 += 1;
+ }
+ }
+}
diff --git a/src/tools/clippy/tests/ui/explicit_counter_loop.stderr b/src/tools/clippy/tests/ui/explicit_counter_loop.stderr
index 4cbacffe87b..9edddea651c 100644
--- a/src/tools/clippy/tests/ui/explicit_counter_loop.stderr
+++ b/src/tools/clippy/tests/ui/explicit_counter_loop.stderr
@@ -42,5 +42,19 @@ error: the variable `count` is used as a loop counter
LL | for _i in 3..10 {
| ^^^^^^^^^^^^^^^ help: consider using: `for (count, _i) in (3..10).enumerate()`
-error: aborting due to 7 previous errors
+error: the variable `idx_usize` is used as a loop counter
+ --> $DIR/explicit_counter_loop.rs:170:9
+ |
+LL | for _item in slice {
+ | ^^^^^^^^^^^^^^^^^^ help: consider using: `for (idx_usize, _item) in slice.into_iter().enumerate()`
+
+error: the variable `idx_u32` is used as a loop counter
+ --> $DIR/explicit_counter_loop.rs:182:9
+ |
+LL | for _item in slice {
+ | ^^^^^^^^^^^^^^^^^^ help: consider using: `for (idx_u32, _item) in (0_u32..).zip(slice.into_iter())`
+ |
+ = note: `idx_u32` is of type `u32`, making it ineligible for `Iterator::enumerate`
+
+error: aborting due to 9 previous errors
diff --git a/src/tools/clippy/tests/ui/floating_point_abs.fixed b/src/tools/clippy/tests/ui/floating_point_abs.fixed
index cea727257c4..ca747fefc64 100644
--- a/src/tools/clippy/tests/ui/floating_point_abs.fixed
+++ b/src/tools/clippy/tests/ui/floating_point_abs.fixed
@@ -1,6 +1,12 @@
// run-rustfix
+#![feature(const_fn_floating_point_arithmetic)]
#![warn(clippy::suboptimal_flops)]
+/// Allow suboptimal ops in constant context
+pub const fn in_const_context(num: f64) -> f64 {
+ if num >= 0.0 { num } else { -num }
+}
+
struct A {
a: f64,
b: f64,
diff --git a/src/tools/clippy/tests/ui/floating_point_abs.rs b/src/tools/clippy/tests/ui/floating_point_abs.rs
index ba8a8f18fa2..e4b60657497 100644
--- a/src/tools/clippy/tests/ui/floating_point_abs.rs
+++ b/src/tools/clippy/tests/ui/floating_point_abs.rs
@@ -1,6 +1,12 @@
// run-rustfix
+#![feature(const_fn_floating_point_arithmetic)]
#![warn(clippy::suboptimal_flops)]
+/// Allow suboptimal ops in constant context
+pub const fn in_const_context(num: f64) -> f64 {
+ if num >= 0.0 { num } else { -num }
+}
+
struct A {
a: f64,
b: f64,
diff --git a/src/tools/clippy/tests/ui/floating_point_abs.stderr b/src/tools/clippy/tests/ui/floating_point_abs.stderr
index 35af70201fa..db8290423ae 100644
--- a/src/tools/clippy/tests/ui/floating_point_abs.stderr
+++ b/src/tools/clippy/tests/ui/floating_point_abs.stderr
@@ -1,5 +1,5 @@
error: manual implementation of `abs` method
- --> $DIR/floating_point_abs.rs:10:5
+ --> $DIR/floating_point_abs.rs:16:5
|
LL | if num >= 0.0 { num } else { -num }
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `num.abs()`
@@ -7,43 +7,43 @@ LL | if num >= 0.0 { num } else { -num }
= note: `-D clippy::suboptimal-flops` implied by `-D warnings`
error: manual implementation of `abs` method
- --> $DIR/floating_point_abs.rs:14:5
+ --> $DIR/floating_point_abs.rs:20:5
|
LL | if 0.0 < num { num } else { -num }
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `num.abs()`
error: manual implementation of `abs` method
- --> $DIR/floating_point_abs.rs:18:5
+ --> $DIR/floating_point_abs.rs:24:5
|
LL | if a.a > 0.0 { a.a } else { -a.a }
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `a.a.abs()`
error: manual implementation of `abs` method
- --> $DIR/floating_point_abs.rs:22:5
+ --> $DIR/floating_point_abs.rs:28:5
|
LL | if 0.0 >= num { -num } else { num }
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `num.abs()`
error: manual implementation of `abs` method
- --> $DIR/floating_point_abs.rs:26:5
+ --> $DIR/floating_point_abs.rs:32:5
|
LL | if a.a < 0.0 { -a.a } else { a.a }
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `a.a.abs()`
error: manual implementation of negation of `abs` method
- --> $DIR/floating_point_abs.rs:30:5
+ --> $DIR/floating_point_abs.rs:36:5
|
LL | if num < 0.0 { num } else { -num }
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `-num.abs()`
error: manual implementation of negation of `abs` method
- --> $DIR/floating_point_abs.rs:34:5
+ --> $DIR/floating_point_abs.rs:40:5
|
LL | if 0.0 >= num { num } else { -num }
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `-num.abs()`
error: manual implementation of negation of `abs` method
- --> $DIR/floating_point_abs.rs:39:12
+ --> $DIR/floating_point_abs.rs:45:12
|
LL | a: if a.a >= 0.0 { -a.a } else { a.a },
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `-a.a.abs()`
diff --git a/src/tools/clippy/tests/ui/floating_point_mul_add.fixed b/src/tools/clippy/tests/ui/floating_point_mul_add.fixed
index 911700bab00..169ec02f82b 100644
--- a/src/tools/clippy/tests/ui/floating_point_mul_add.fixed
+++ b/src/tools/clippy/tests/ui/floating_point_mul_add.fixed
@@ -1,6 +1,17 @@
// run-rustfix
+#![feature(const_fn_floating_point_arithmetic)]
#![warn(clippy::suboptimal_flops)]
+/// Allow suboptimal_ops in constant context
+pub const fn in_const_context() {
+ let a: f64 = 1234.567;
+ let b: f64 = 45.67834;
+ let c: f64 = 0.0004;
+
+ let _ = a * b + c;
+ let _ = c + a * b;
+}
+
fn main() {
let a: f64 = 1234.567;
let b: f64 = 45.67834;
diff --git a/src/tools/clippy/tests/ui/floating_point_mul_add.rs b/src/tools/clippy/tests/ui/floating_point_mul_add.rs
index d202385fc8a..5338d4fc2b7 100644
--- a/src/tools/clippy/tests/ui/floating_point_mul_add.rs
+++ b/src/tools/clippy/tests/ui/floating_point_mul_add.rs
@@ -1,6 +1,17 @@
// run-rustfix
+#![feature(const_fn_floating_point_arithmetic)]
#![warn(clippy::suboptimal_flops)]
+/// Allow suboptimal_ops in constant context
+pub const fn in_const_context() {
+ let a: f64 = 1234.567;
+ let b: f64 = 45.67834;
+ let c: f64 = 0.0004;
+
+ let _ = a * b + c;
+ let _ = c + a * b;
+}
+
fn main() {
let a: f64 = 1234.567;
let b: f64 = 45.67834;
diff --git a/src/tools/clippy/tests/ui/floating_point_mul_add.stderr b/src/tools/clippy/tests/ui/floating_point_mul_add.stderr
index ac8d0c0cae0..e637bbf90ca 100644
--- a/src/tools/clippy/tests/ui/floating_point_mul_add.stderr
+++ b/src/tools/clippy/tests/ui/floating_point_mul_add.stderr
@@ -1,5 +1,5 @@
error: multiply and add expressions can be calculated more efficiently and accurately
- --> $DIR/floating_point_mul_add.rs:10:13
+ --> $DIR/floating_point_mul_add.rs:21:13
|
LL | let _ = a * b + c;
| ^^^^^^^^^ help: consider using: `a.mul_add(b, c)`
@@ -7,55 +7,55 @@ LL | let _ = a * b + c;
= note: `-D clippy::suboptimal-flops` implied by `-D warnings`
error: multiply and add expressions can be calculated more efficiently and accurately
- --> $DIR/floating_point_mul_add.rs:11:13
+ --> $DIR/floating_point_mul_add.rs:22:13
|
LL | let _ = c + a * b;
| ^^^^^^^^^ help: consider using: `a.mul_add(b, c)`
error: multiply and add expressions can be calculated more efficiently and accurately
- --> $DIR/floating_point_mul_add.rs:12:13
+ --> $DIR/floating_point_mul_add.rs:23:13
|
LL | let _ = a + 2.0 * 4.0;
| ^^^^^^^^^^^^^ help: consider using: `2.0f64.mul_add(4.0, a)`
error: multiply and add expressions can be calculated more efficiently and accurately
- --> $DIR/floating_point_mul_add.rs:13:13
+ --> $DIR/floating_point_mul_add.rs:24:13
|
LL | let _ = a + 2. * 4.;
| ^^^^^^^^^^^ help: consider using: `2.0f64.mul_add(4., a)`
error: multiply and add expressions can be calculated more efficiently and accurately
- --> $DIR/floating_point_mul_add.rs:15:13
+ --> $DIR/floating_point_mul_add.rs:26:13
|
LL | let _ = (a * b) + c;
| ^^^^^^^^^^^ help: consider using: `a.mul_add(b, c)`
error: multiply and add expressions can be calculated more efficiently and accurately
- --> $DIR/floating_point_mul_add.rs:16:13
+ --> $DIR/floating_point_mul_add.rs:27:13
|
LL | let _ = c + (a * b);
| ^^^^^^^^^^^ help: consider using: `a.mul_add(b, c)`
error: multiply and add expressions can be calculated more efficiently and accurately
- --> $DIR/floating_point_mul_add.rs:17:13
+ --> $DIR/floating_point_mul_add.rs:28:13
|
LL | let _ = a * b * c + d;
| ^^^^^^^^^^^^^ help: consider using: `(a * b).mul_add(c, d)`
error: multiply and add expressions can be calculated more efficiently and accurately
- --> $DIR/floating_point_mul_add.rs:19:13
+ --> $DIR/floating_point_mul_add.rs:30:13
|
LL | let _ = a.mul_add(b, c) * a.mul_add(b, c) + a.mul_add(b, c) + c;
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `a.mul_add(b, c).mul_add(a.mul_add(b, c), a.mul_add(b, c))`
error: multiply and add expressions can be calculated more efficiently and accurately
- --> $DIR/floating_point_mul_add.rs:20:13
+ --> $DIR/floating_point_mul_add.rs:31:13
|
LL | let _ = 1234.567_f64 * 45.67834_f64 + 0.0004_f64;
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `1234.567_f64.mul_add(45.67834_f64, 0.0004_f64)`
error: multiply and add expressions can be calculated more efficiently and accurately
- --> $DIR/floating_point_mul_add.rs:22:13
+ --> $DIR/floating_point_mul_add.rs:33:13
|
LL | let _ = (a * a + b).sqrt();
| ^^^^^^^^^^^ help: consider using: `a.mul_add(a, b)`
diff --git a/src/tools/clippy/tests/ui/floating_point_rad.fixed b/src/tools/clippy/tests/ui/floating_point_rad.fixed
index 92480c5db8b..a35bb1c27f3 100644
--- a/src/tools/clippy/tests/ui/floating_point_rad.fixed
+++ b/src/tools/clippy/tests/ui/floating_point_rad.fixed
@@ -1,6 +1,13 @@
// run-rustfix
+#![feature(const_fn_floating_point_arithmetic)]
#![warn(clippy::suboptimal_flops)]
+/// Allow suboptimal_flops in constant context
+pub const fn const_context() {
+ let x = 3f32;
+ let _ = x * 180f32 / std::f32::consts::PI;
+}
+
fn main() {
let x = 3f32;
let _ = x.to_degrees();
diff --git a/src/tools/clippy/tests/ui/floating_point_rad.rs b/src/tools/clippy/tests/ui/floating_point_rad.rs
index 062e7c3fdc1..834db4be533 100644
--- a/src/tools/clippy/tests/ui/floating_point_rad.rs
+++ b/src/tools/clippy/tests/ui/floating_point_rad.rs
@@ -1,6 +1,13 @@
// run-rustfix
+#![feature(const_fn_floating_point_arithmetic)]
#![warn(clippy::suboptimal_flops)]
+/// Allow suboptimal_flops in constant context
+pub const fn const_context() {
+ let x = 3f32;
+ let _ = x * 180f32 / std::f32::consts::PI;
+}
+
fn main() {
let x = 3f32;
let _ = x * 180f32 / std::f32::consts::PI;
diff --git a/src/tools/clippy/tests/ui/floating_point_rad.stderr b/src/tools/clippy/tests/ui/floating_point_rad.stderr
index a6ffdca64ee..acecddbca53 100644
--- a/src/tools/clippy/tests/ui/floating_point_rad.stderr
+++ b/src/tools/clippy/tests/ui/floating_point_rad.stderr
@@ -1,5 +1,5 @@
error: conversion to degrees can be done more accurately
- --> $DIR/floating_point_rad.rs:6:13
+ --> $DIR/floating_point_rad.rs:13:13
|
LL | let _ = x * 180f32 / std::f32::consts::PI;
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `x.to_degrees()`
@@ -7,7 +7,7 @@ LL | let _ = x * 180f32 / std::f32::consts::PI;
= note: `-D clippy::suboptimal-flops` implied by `-D warnings`
error: conversion to radians can be done more accurately
- --> $DIR/floating_point_rad.rs:7:13
+ --> $DIR/floating_point_rad.rs:14:13
|
LL | let _ = x * std::f32::consts::PI / 180f32;
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `x.to_radians()`
diff --git a/src/tools/clippy/tests/ui/future_not_send.stderr b/src/tools/clippy/tests/ui/future_not_send.stderr
index 3cc05e2fdbe..a9f2ad36d0a 100644
--- a/src/tools/clippy/tests/ui/future_not_send.stderr
+++ b/src/tools/clippy/tests/ui/future_not_send.stderr
@@ -6,22 +6,22 @@ LL | async fn private_future(rc: Rc<[u8]>, cell: &Cell<usize>) -> bool {
|
= note: `-D clippy::future-not-send` implied by `-D warnings`
note: future is not `Send` as this value is used across an await
- --> $DIR/future_not_send.rs:8:5
+ --> $DIR/future_not_send.rs:8:19
|
LL | async fn private_future(rc: Rc<[u8]>, cell: &Cell<usize>) -> bool {
| -- has type `std::rc::Rc<[u8]>` which is not `Send`
LL | async { true }.await
- | ^^^^^^^^^^^^^^^^^^^^ await occurs here, with `rc` maybe used later
+ | ^^^^^^ await occurs here, with `rc` maybe used later
LL | }
| - `rc` is later dropped here
= note: `std::rc::Rc<[u8]>` doesn't implement `std::marker::Send`
note: future is not `Send` as this value is used across an await
- --> $DIR/future_not_send.rs:8:5
+ --> $DIR/future_not_send.rs:8:19
|
LL | async fn private_future(rc: Rc<[u8]>, cell: &Cell<usize>) -> bool {
| ---- has type `&std::cell::Cell<usize>` which is not `Send`
LL | async { true }.await
- | ^^^^^^^^^^^^^^^^^^^^ await occurs here, with `cell` maybe used later
+ | ^^^^^^ await occurs here, with `cell` maybe used later
LL | }
| - `cell` is later dropped here
= note: `std::cell::Cell<usize>` doesn't implement `std::marker::Sync`
@@ -33,12 +33,12 @@ LL | pub async fn public_future(rc: Rc<[u8]>) {
| ^ future returned by `public_future` is not `Send`
|
note: future is not `Send` as this value is used across an await
- --> $DIR/future_not_send.rs:12:5
+ --> $DIR/future_not_send.rs:12:19
|
LL | pub async fn public_future(rc: Rc<[u8]>) {
| -- has type `std::rc::Rc<[u8]>` which is not `Send`
LL | async { true }.await;
- | ^^^^^^^^^^^^^^^^^^^^ await occurs here, with `rc` maybe used later
+ | ^^^^^^ await occurs here, with `rc` maybe used later
LL | }
| - `rc` is later dropped here
= note: `std::rc::Rc<[u8]>` doesn't implement `std::marker::Send`
@@ -82,12 +82,12 @@ LL | async fn private_future(&self) -> usize {
| ^^^^^ future returned by `private_future` is not `Send`
|
note: future is not `Send` as this value is used across an await
- --> $DIR/future_not_send.rs:35:9
+ --> $DIR/future_not_send.rs:35:23
|
LL | async fn private_future(&self) -> usize {
| ----- has type `&Dummy` which is not `Send`
LL | async { true }.await;
- | ^^^^^^^^^^^^^^^^^^^^ await occurs here, with `&self` maybe used later
+ | ^^^^^^ await occurs here, with `&self` maybe used later
LL | self.rc.len()
LL | }
| - `&self` is later dropped here
@@ -100,12 +100,12 @@ LL | pub async fn public_future(&self) {
| ^ future returned by `public_future` is not `Send`
|
note: future is not `Send` as this value is used across an await
- --> $DIR/future_not_send.rs:40:9
+ --> $DIR/future_not_send.rs:40:30
|
LL | pub async fn public_future(&self) {
| ----- has type `&Dummy` which is not `Send`
LL | self.private_future().await;
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ await occurs here, with `&self` maybe used later
+ | ^^^^^^ await occurs here, with `&self` maybe used later
LL | }
| - `&self` is later dropped here
= note: `std::rc::Rc<[u8]>` doesn't implement `std::marker::Sync`
@@ -117,12 +117,12 @@ LL | async fn generic_future<T>(t: T) -> T
| ^ future returned by `generic_future` is not `Send`
|
note: future is not `Send` as this value is used across an await
- --> $DIR/future_not_send.rs:54:5
+ --> $DIR/future_not_send.rs:54:19
|
LL | let rt = &t;
| -- has type `&T` which is not `Send`
LL | async { true }.await;
- | ^^^^^^^^^^^^^^^^^^^^ await occurs here, with `rt` maybe used later
+ | ^^^^^^ await occurs here, with `rt` maybe used later
LL | t
LL | }
| - `rt` is later dropped here
diff --git a/src/tools/clippy/tests/ui/if_then_some_else_none.rs b/src/tools/clippy/tests/ui/if_then_some_else_none.rs
index 54789bf9320..3bc3a039524 100644
--- a/src/tools/clippy/tests/ui/if_then_some_else_none.rs
+++ b/src/tools/clippy/tests/ui/if_then_some_else_none.rs
@@ -102,3 +102,14 @@ fn into_some<T>(v: T) -> Option<T> {
fn into_none<T>() -> Option<T> {
None
}
+
+// Should not warn
+fn f(b: bool, v: Option<()>) -> Option<()> {
+ if b {
+ v?; // This is a potential early return, is not equivalent with `bool::then`
+
+ Some(())
+ } else {
+ None
+ }
+}
diff --git a/src/tools/clippy/tests/ui/index_refutable_slice/if_let_slice_binding.rs b/src/tools/clippy/tests/ui/index_refutable_slice/if_let_slice_binding.rs
new file mode 100644
index 00000000000..c2c0c520dc6
--- /dev/null
+++ b/src/tools/clippy/tests/ui/index_refutable_slice/if_let_slice_binding.rs
@@ -0,0 +1,166 @@
+#![deny(clippy::index_refutable_slice)]
+
+enum SomeEnum<T> {
+ One(T),
+ Two(T),
+ Three(T),
+ Four(T),
+}
+
+fn lintable_examples() {
+ // Try with reference
+ let slice: Option<&[u32]> = Some(&[1, 2, 3]);
+ if let Some(slice) = slice {
+ println!("{}", slice[0]);
+ }
+
+ // Try with copy
+ let slice: Option<[u32; 3]> = Some([1, 2, 3]);
+ if let Some(slice) = slice {
+ println!("{}", slice[0]);
+ }
+
+ // Try with long slice and small indices
+ let slice: Option<[u32; 9]> = Some([1, 2, 3, 4, 5, 6, 7, 8, 9]);
+ if let Some(slice) = slice {
+ println!("{}", slice[2]);
+ println!("{}", slice[0]);
+ }
+
+ // Multiple bindings
+ let slice_wrapped: SomeEnum<[u32; 3]> = SomeEnum::One([5, 6, 7]);
+ if let SomeEnum::One(slice) | SomeEnum::Three(slice) = slice_wrapped {
+ println!("{}", slice[0]);
+ }
+
+ // Two lintable slices in one if let
+ let a_wrapped: SomeEnum<[u32; 3]> = SomeEnum::One([9, 5, 1]);
+ let b_wrapped: Option<[u32; 2]> = Some([4, 6]);
+ if let (SomeEnum::Three(a), Some(b)) = (a_wrapped, b_wrapped) {
+ println!("{} -> {}", a[2], b[1]);
+ }
+
+ // This requires the slice values to be borrowed as the slice values can only be
+ // borrowed and `String` doesn't implement copy
+ let slice: Option<[String; 2]> = Some([String::from("1"), String::from("2")]);
+ if let Some(ref slice) = slice {
+ println!("{:?}", slice[1]);
+ }
+ println!("{:?}", slice);
+
+ // This should not suggest using the `ref` keyword as the scrutinee is already
+ // a reference
+ let slice: Option<[String; 2]> = Some([String::from("1"), String::from("2")]);
+ if let Some(slice) = &slice {
+ println!("{:?}", slice[0]);
+ }
+ println!("{:?}", slice);
+}
+
+fn slice_index_above_limit() {
+ let slice: Option<&[u32]> = Some(&[1, 2, 3]);
+
+ if let Some(slice) = slice {
+ // Would cause a panic, IDK
+ println!("{}", slice[7]);
+ }
+}
+
+fn slice_is_used() {
+ let slice: Option<&[u32]> = Some(&[1, 2, 3]);
+ if let Some(slice) = slice {
+ println!("{:?}", slice.len());
+ }
+
+ let slice: Option<&[u32]> = Some(&[1, 2, 3]);
+ if let Some(slice) = slice {
+ println!("{:?}", slice.to_vec());
+ }
+
+ let opt: Option<[String; 2]> = Some([String::from("Hello"), String::from("world")]);
+ if let Some(slice) = opt {
+ if !slice.is_empty() {
+ println!("first: {}", slice[0]);
+ }
+ }
+}
+
+/// The slice is used by an external function and should therefore not be linted
+fn check_slice_as_arg() {
+ fn is_interesting<T>(slice: &[T; 2]) -> bool {
+ !slice.is_empty()
+ }
+
+ let slice_wrapped: Option<[String; 2]> = Some([String::from("Hello"), String::from("world")]);
+ if let Some(slice) = &slice_wrapped {
+ if is_interesting(slice) {
+ println!("This is interesting {}", slice[0]);
+ }
+ }
+ println!("{:?}", slice_wrapped);
+}
+
+fn check_slice_in_struct() {
+ #[derive(Debug)]
+ struct Wrapper<'a> {
+ inner: Option<&'a [String]>,
+ is_awesome: bool,
+ }
+
+ impl<'a> Wrapper<'a> {
+ fn is_super_awesome(&self) -> bool {
+ self.is_awesome
+ }
+ }
+
+ let inner = &[String::from("New"), String::from("World")];
+ let wrap = Wrapper {
+ inner: Some(inner),
+ is_awesome: true,
+ };
+
+ // Test 1: Field access
+ if let Some(slice) = wrap.inner {
+ if wrap.is_awesome {
+ println!("This is awesome! {}", slice[0]);
+ }
+ }
+
+ // Test 2: function access
+ if let Some(slice) = wrap.inner {
+ if wrap.is_super_awesome() {
+ println!("This is super awesome! {}", slice[0]);
+ }
+ }
+ println!("Complete wrap: {:?}", wrap);
+}
+
+/// This would be a nice additional feature to have in the future, but adding it
+/// now would make the PR too large. This is therefore only a test that we don't
+/// lint cases we can't make a reasonable suggestion for
+fn mutable_slice_index() {
+ // Mut access
+ let mut slice: Option<[String; 1]> = Some([String::from("Penguin")]);
+ if let Some(ref mut slice) = slice {
+ slice[0] = String::from("Mr. Penguin");
+ }
+ println!("Use after modification: {:?}", slice);
+
+ // Mut access on reference
+ let mut slice: Option<[String; 1]> = Some([String::from("Cat")]);
+ if let Some(slice) = &mut slice {
+ slice[0] = String::from("Lord Meow Meow");
+ }
+ println!("Use after modification: {:?}", slice);
+}
+
+/// The lint will ignore bindings with sub patterns as it would be hard
+/// to build correct suggestions for these instances :)
+fn binding_with_sub_pattern() {
+ let slice: Option<&[u32]> = Some(&[1, 2, 3]);
+ if let Some(slice @ [_, _, _]) = slice {
+ println!("{:?}", slice[2]);
+ }
+}
+
+fn main() {}
diff --git a/src/tools/clippy/tests/ui/index_refutable_slice/if_let_slice_binding.stderr b/src/tools/clippy/tests/ui/index_refutable_slice/if_let_slice_binding.stderr
new file mode 100644
index 00000000000..a607df9b876
--- /dev/null
+++ b/src/tools/clippy/tests/ui/index_refutable_slice/if_let_slice_binding.stderr
@@ -0,0 +1,158 @@
+error: this binding can be a slice pattern to avoid indexing
+ --> $DIR/if_let_slice_binding.rs:13:17
+ |
+LL | if let Some(slice) = slice {
+ | ^^^^^
+ |
+note: the lint level is defined here
+ --> $DIR/if_let_slice_binding.rs:1:9
+ |
+LL | #![deny(clippy::index_refutable_slice)]
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+help: try using a slice pattern here
+ |
+LL | if let Some([slice_0, ..]) = slice {
+ | ~~~~~~~~~~~~~
+help: and replace the index expressions here
+ |
+LL | println!("{}", slice_0);
+ | ~~~~~~~
+
+error: this binding can be a slice pattern to avoid indexing
+ --> $DIR/if_let_slice_binding.rs:19:17
+ |
+LL | if let Some(slice) = slice {
+ | ^^^^^
+ |
+help: try using a slice pattern here
+ |
+LL | if let Some([slice_0, ..]) = slice {
+ | ~~~~~~~~~~~~~
+help: and replace the index expressions here
+ |
+LL | println!("{}", slice_0);
+ | ~~~~~~~
+
+error: this binding can be a slice pattern to avoid indexing
+ --> $DIR/if_let_slice_binding.rs:25:17
+ |
+LL | if let Some(slice) = slice {
+ | ^^^^^
+ |
+help: try using a slice pattern here
+ |
+LL | if let Some([slice_0, _, slice_2, ..]) = slice {
+ | ~~~~~~~~~~~~~~~~~~~~~~~~~
+help: and replace the index expressions here
+ |
+LL ~ println!("{}", slice_2);
+LL ~ println!("{}", slice_0);
+ |
+
+error: this binding can be a slice pattern to avoid indexing
+ --> $DIR/if_let_slice_binding.rs:32:26
+ |
+LL | if let SomeEnum::One(slice) | SomeEnum::Three(slice) = slice_wrapped {
+ | ^^^^^
+ |
+help: try using a slice pattern here
+ |
+LL | if let SomeEnum::One([slice_0, ..]) | SomeEnum::Three([slice_0, ..]) = slice_wrapped {
+ | ~~~~~~~~~~~~~ ~~~~~~~~~~~~~
+help: and replace the index expressions here
+ |
+LL | println!("{}", slice_0);
+ | ~~~~~~~
+
+error: this binding can be a slice pattern to avoid indexing
+ --> $DIR/if_let_slice_binding.rs:39:29
+ |
+LL | if let (SomeEnum::Three(a), Some(b)) = (a_wrapped, b_wrapped) {
+ | ^
+ |
+help: try using a slice pattern here
+ |
+LL | if let (SomeEnum::Three([_, _, a_2, ..]), Some(b)) = (a_wrapped, b_wrapped) {
+ | ~~~~~~~~~~~~~~~
+help: and replace the index expressions here
+ |
+LL | println!("{} -> {}", a_2, b[1]);
+ | ~~~
+
+error: this binding can be a slice pattern to avoid indexing
+ --> $DIR/if_let_slice_binding.rs:39:38
+ |
+LL | if let (SomeEnum::Three(a), Some(b)) = (a_wrapped, b_wrapped) {
+ | ^
+ |
+help: try using a slice pattern here
+ |
+LL | if let (SomeEnum::Three(a), Some([_, b_1, ..])) = (a_wrapped, b_wrapped) {
+ | ~~~~~~~~~~~~
+help: and replace the index expressions here
+ |
+LL | println!("{} -> {}", a[2], b_1);
+ | ~~~
+
+error: this binding can be a slice pattern to avoid indexing
+ --> $DIR/if_let_slice_binding.rs:46:21
+ |
+LL | if let Some(ref slice) = slice {
+ | ^^^^^
+ |
+help: try using a slice pattern here
+ |
+LL | if let Some([_, ref slice_1, ..]) = slice {
+ | ~~~~~~~~~~~~~~~~~~~~
+help: and replace the index expressions here
+ |
+LL | println!("{:?}", slice_1);
+ | ~~~~~~~
+
+error: this binding can be a slice pattern to avoid indexing
+ --> $DIR/if_let_slice_binding.rs:54:17
+ |
+LL | if let Some(slice) = &slice {
+ | ^^^^^
+ |
+help: try using a slice pattern here
+ |
+LL | if let Some([slice_0, ..]) = &slice {
+ | ~~~~~~~~~~~~~
+help: and replace the index expressions here
+ |
+LL | println!("{:?}", slice_0);
+ | ~~~~~~~
+
+error: this binding can be a slice pattern to avoid indexing
+ --> $DIR/if_let_slice_binding.rs:123:17
+ |
+LL | if let Some(slice) = wrap.inner {
+ | ^^^^^
+ |
+help: try using a slice pattern here
+ |
+LL | if let Some([slice_0, ..]) = wrap.inner {
+ | ~~~~~~~~~~~~~
+help: and replace the index expressions here
+ |
+LL | println!("This is awesome! {}", slice_0);
+ | ~~~~~~~
+
+error: this binding can be a slice pattern to avoid indexing
+ --> $DIR/if_let_slice_binding.rs:130:17
+ |
+LL | if let Some(slice) = wrap.inner {
+ | ^^^^^
+ |
+help: try using a slice pattern here
+ |
+LL | if let Some([slice_0, ..]) = wrap.inner {
+ | ~~~~~~~~~~~~~
+help: and replace the index expressions here
+ |
+LL | println!("This is super awesome! {}", slice_0);
+ | ~~~~~~~
+
+error: aborting due to 10 previous errors
+
diff --git a/src/tools/clippy/tests/ui/index_refutable_slice/slice_indexing_in_macro.rs b/src/tools/clippy/tests/ui/index_refutable_slice/slice_indexing_in_macro.rs
new file mode 100644
index 00000000000..406e82083f8
--- /dev/null
+++ b/src/tools/clippy/tests/ui/index_refutable_slice/slice_indexing_in_macro.rs
@@ -0,0 +1,28 @@
+#![deny(clippy::index_refutable_slice)]
+
+extern crate if_chain;
+use if_chain::if_chain;
+
+macro_rules! if_let_slice_macro {
+ () => {
+ // This would normally be linted
+ let slice: Option<&[u32]> = Some(&[1, 2, 3]);
+ if let Some(slice) = slice {
+ println!("{}", slice[0]);
+ }
+ };
+}
+
+fn main() {
+ // Don't lint this
+ if_let_slice_macro!();
+
+ // Do lint this
+ if_chain! {
+ let slice: Option<&[u32]> = Some(&[1, 2, 3]);
+ if let Some(slice) = slice;
+ then {
+ println!("{}", slice[0]);
+ }
+ }
+}
diff --git a/src/tools/clippy/tests/ui/index_refutable_slice/slice_indexing_in_macro.stderr b/src/tools/clippy/tests/ui/index_refutable_slice/slice_indexing_in_macro.stderr
new file mode 100644
index 00000000000..11b19428b4f
--- /dev/null
+++ b/src/tools/clippy/tests/ui/index_refutable_slice/slice_indexing_in_macro.stderr
@@ -0,0 +1,22 @@
+error: this binding can be a slice pattern to avoid indexing
+ --> $DIR/slice_indexing_in_macro.rs:23:21
+ |
+LL | if let Some(slice) = slice;
+ | ^^^^^
+ |
+note: the lint level is defined here
+ --> $DIR/slice_indexing_in_macro.rs:1:9
+ |
+LL | #![deny(clippy::index_refutable_slice)]
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+help: try using a slice pattern here
+ |
+LL | if let Some([slice_0, ..]) = slice;
+ | ~~~~~~~~~~~~~
+help: and replace the index expressions here
+ |
+LL | println!("{}", slice_0);
+ | ~~~~~~~
+
+error: aborting due to previous error
+
diff --git a/src/tools/clippy/tests/ui/iter_cloned_collect.fixed b/src/tools/clippy/tests/ui/iter_cloned_collect.fixed
index 39cc58cd298..9b862133580 100644
--- a/src/tools/clippy/tests/ui/iter_cloned_collect.fixed
+++ b/src/tools/clippy/tests/ui/iter_cloned_collect.fixed
@@ -23,4 +23,7 @@ fn main() {
// Issue #6808
let arr: [u8; 64] = [0; 64];
let _: Vec<_> = arr.to_vec();
+
+ // Issue #6703
+ let _: Vec<isize> = v.to_vec();
}
diff --git a/src/tools/clippy/tests/ui/iter_cloned_collect.rs b/src/tools/clippy/tests/ui/iter_cloned_collect.rs
index c2a036ec09f..639f50665f2 100644
--- a/src/tools/clippy/tests/ui/iter_cloned_collect.rs
+++ b/src/tools/clippy/tests/ui/iter_cloned_collect.rs
@@ -26,4 +26,7 @@ fn main() {
// Issue #6808
let arr: [u8; 64] = [0; 64];
let _: Vec<_> = arr.iter().cloned().collect();
+
+ // Issue #6703
+ let _: Vec<isize> = v.iter().copied().collect();
}
diff --git a/src/tools/clippy/tests/ui/iter_cloned_collect.stderr b/src/tools/clippy/tests/ui/iter_cloned_collect.stderr
index e1df61794ce..b2cc497bf43 100644
--- a/src/tools/clippy/tests/ui/iter_cloned_collect.stderr
+++ b/src/tools/clippy/tests/ui/iter_cloned_collect.stderr
@@ -28,5 +28,11 @@ error: called `iter().cloned().collect()` on a slice to create a `Vec`. Calling
LL | let _: Vec<_> = arr.iter().cloned().collect();
| ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `.to_vec()`
-error: aborting due to 4 previous errors
+error: called `iter().copied().collect()` on a slice to create a `Vec`. Calling `to_vec()` is both faster and more readable
+ --> $DIR/iter_cloned_collect.rs:31:26
+ |
+LL | let _: Vec<isize> = v.iter().copied().collect();
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `.to_vec()`
+
+error: aborting due to 5 previous errors
diff --git a/src/tools/clippy/tests/ui/let_if_seq.rs b/src/tools/clippy/tests/ui/let_if_seq.rs
index 2d8f3c2f0e7..c5cb2eb1fe1 100644
--- a/src/tools/clippy/tests/ui/let_if_seq.rs
+++ b/src/tools/clippy/tests/ui/let_if_seq.rs
@@ -3,7 +3,8 @@
unused_assignments,
clippy::similar_names,
clippy::blacklisted_name,
- clippy::branches_sharing_code
+ clippy::branches_sharing_code,
+ clippy::needless_late_init
)]
#![warn(clippy::useless_let_if_seq)]
diff --git a/src/tools/clippy/tests/ui/let_if_seq.stderr b/src/tools/clippy/tests/ui/let_if_seq.stderr
index 9cf2e10a5ee..271ccce681c 100644
--- a/src/tools/clippy/tests/ui/let_if_seq.stderr
+++ b/src/tools/clippy/tests/ui/let_if_seq.stderr
@@ -1,5 +1,5 @@
error: `if _ { .. } else { .. }` is an expression
- --> $DIR/let_if_seq.rs:65:5
+ --> $DIR/let_if_seq.rs:66:5
|
LL | / let mut foo = 0;
LL | | if f() {
@@ -11,7 +11,7 @@ LL | | }
= note: you might not need `mut` at all
error: `if _ { .. } else { .. }` is an expression
- --> $DIR/let_if_seq.rs:70:5
+ --> $DIR/let_if_seq.rs:71:5
|
LL | / let mut bar = 0;
LL | | if f() {
@@ -25,7 +25,7 @@ LL | | }
= note: you might not need `mut` at all
error: `if _ { .. } else { .. }` is an expression
- --> $DIR/let_if_seq.rs:78:5
+ --> $DIR/let_if_seq.rs:79:5
|
LL | / let quz;
LL | | if f() {
@@ -36,7 +36,7 @@ LL | | }
| |_____^ help: it is more idiomatic to write: `let quz = if f() { 42 } else { 0 };`
error: `if _ { .. } else { .. }` is an expression
- --> $DIR/let_if_seq.rs:107:5
+ --> $DIR/let_if_seq.rs:108:5
|
LL | / let mut baz = 0;
LL | | if f() {
diff --git a/src/tools/clippy/tests/ui/let_underscore_lock.rs b/src/tools/clippy/tests/ui/let_underscore_lock.rs
index 88fb216a743..539d74d1d4c 100644
--- a/src/tools/clippy/tests/ui/let_underscore_lock.rs
+++ b/src/tools/clippy/tests/ui/let_underscore_lock.rs
@@ -1,5 +1,7 @@
#![warn(clippy::let_underscore_lock)]
+extern crate parking_lot;
+
fn main() {
let m = std::sync::Mutex::new(());
let rw = std::sync::RwLock::new(());
@@ -10,4 +12,16 @@ fn main() {
let _ = m.try_lock();
let _ = rw.try_read();
let _ = rw.try_write();
+
+ use parking_lot::{lock_api::RawMutex, Mutex, RwLock};
+
+ let p_m: Mutex<()> = Mutex::const_new(RawMutex::INIT, ());
+ let _ = p_m.lock();
+
+ let p_m1 = Mutex::new(0);
+ let _ = p_m1.lock();
+
+ let p_rw = RwLock::new(0);
+ let _ = p_rw.read();
+ let _ = p_rw.write();
}
diff --git a/src/tools/clippy/tests/ui/let_underscore_lock.stderr b/src/tools/clippy/tests/ui/let_underscore_lock.stderr
index 5d5f6059ef1..3a2bc17bf7b 100644
--- a/src/tools/clippy/tests/ui/let_underscore_lock.stderr
+++ b/src/tools/clippy/tests/ui/let_underscore_lock.stderr
@@ -1,5 +1,5 @@
error: non-binding let on a synchronization lock
- --> $DIR/let_underscore_lock.rs:7:5
+ --> $DIR/let_underscore_lock.rs:9:5
|
LL | let _ = m.lock();
| ^^^^^^^^^^^^^^^^^
@@ -8,7 +8,7 @@ LL | let _ = m.lock();
= help: consider using an underscore-prefixed named binding or dropping explicitly with `std::mem::drop`
error: non-binding let on a synchronization lock
- --> $DIR/let_underscore_lock.rs:8:5
+ --> $DIR/let_underscore_lock.rs:10:5
|
LL | let _ = rw.read();
| ^^^^^^^^^^^^^^^^^^
@@ -16,7 +16,7 @@ LL | let _ = rw.read();
= help: consider using an underscore-prefixed named binding or dropping explicitly with `std::mem::drop`
error: non-binding let on a synchronization lock
- --> $DIR/let_underscore_lock.rs:9:5
+ --> $DIR/let_underscore_lock.rs:11:5
|
LL | let _ = rw.write();
| ^^^^^^^^^^^^^^^^^^^
@@ -24,7 +24,7 @@ LL | let _ = rw.write();
= help: consider using an underscore-prefixed named binding or dropping explicitly with `std::mem::drop`
error: non-binding let on a synchronization lock
- --> $DIR/let_underscore_lock.rs:10:5
+ --> $DIR/let_underscore_lock.rs:12:5
|
LL | let _ = m.try_lock();
| ^^^^^^^^^^^^^^^^^^^^^
@@ -32,7 +32,7 @@ LL | let _ = m.try_lock();
= help: consider using an underscore-prefixed named binding or dropping explicitly with `std::mem::drop`
error: non-binding let on a synchronization lock
- --> $DIR/let_underscore_lock.rs:11:5
+ --> $DIR/let_underscore_lock.rs:13:5
|
LL | let _ = rw.try_read();
| ^^^^^^^^^^^^^^^^^^^^^^
@@ -40,12 +40,44 @@ LL | let _ = rw.try_read();
= help: consider using an underscore-prefixed named binding or dropping explicitly with `std::mem::drop`
error: non-binding let on a synchronization lock
- --> $DIR/let_underscore_lock.rs:12:5
+ --> $DIR/let_underscore_lock.rs:14:5
|
LL | let _ = rw.try_write();
| ^^^^^^^^^^^^^^^^^^^^^^^
|
= help: consider using an underscore-prefixed named binding or dropping explicitly with `std::mem::drop`
-error: aborting due to 6 previous errors
+error: non-binding let on a synchronization lock
+ --> $DIR/let_underscore_lock.rs:19:5
+ |
+LL | let _ = p_m.lock();
+ | ^^^^^^^^^^^^^^^^^^^
+ |
+ = help: consider using an underscore-prefixed named binding or dropping explicitly with `std::mem::drop`
+
+error: non-binding let on a synchronization lock
+ --> $DIR/let_underscore_lock.rs:22:5
+ |
+LL | let _ = p_m1.lock();
+ | ^^^^^^^^^^^^^^^^^^^^
+ |
+ = help: consider using an underscore-prefixed named binding or dropping explicitly with `std::mem::drop`
+
+error: non-binding let on a synchronization lock
+ --> $DIR/let_underscore_lock.rs:25:5
+ |
+LL | let _ = p_rw.read();
+ | ^^^^^^^^^^^^^^^^^^^^
+ |
+ = help: consider using an underscore-prefixed named binding or dropping explicitly with `std::mem::drop`
+
+error: non-binding let on a synchronization lock
+ --> $DIR/let_underscore_lock.rs:26:5
+ |
+LL | let _ = p_rw.write();
+ | ^^^^^^^^^^^^^^^^^^^^^
+ |
+ = help: consider using an underscore-prefixed named binding or dropping explicitly with `std::mem::drop`
+
+error: aborting due to 10 previous errors
diff --git a/src/tools/clippy/tests/ui/manual_assert.edition2018.fixed b/src/tools/clippy/tests/ui/manual_assert.edition2018.fixed
index 11fe06c5724..6c2a25c37d8 100644
--- a/src/tools/clippy/tests/ui/manual_assert.edition2018.fixed
+++ b/src/tools/clippy/tests/ui/manual_assert.edition2018.fixed
@@ -2,7 +2,9 @@
// [edition2018] edition:2018
// [edition2021] edition:2021
// run-rustfix
+
#![warn(clippy::manual_assert)]
+#![allow(clippy::nonminimal_bool)]
fn main() {
let a = vec![1, 2, 3];
diff --git a/src/tools/clippy/tests/ui/manual_assert.edition2018.stderr b/src/tools/clippy/tests/ui/manual_assert.edition2018.stderr
index 03c03472f90..77511631e44 100644
--- a/src/tools/clippy/tests/ui/manual_assert.edition2018.stderr
+++ b/src/tools/clippy/tests/ui/manual_assert.edition2018.stderr
@@ -1,5 +1,5 @@
error: only a `panic!` in `if`-then statement
- --> $DIR/manual_assert.rs:22:5
+ --> $DIR/manual_assert.rs:24:5
|
LL | / if !a.is_empty() {
LL | | panic!("qaqaq{:?}", a);
@@ -9,7 +9,7 @@ LL | | }
= note: `-D clippy::manual-assert` implied by `-D warnings`
error: only a `panic!` in `if`-then statement
- --> $DIR/manual_assert.rs:25:5
+ --> $DIR/manual_assert.rs:27:5
|
LL | / if !a.is_empty() {
LL | | panic!("qwqwq");
@@ -17,7 +17,7 @@ LL | | }
| |_____^ help: try: `assert!(a.is_empty(), "qwqwq");`
error: only a `panic!` in `if`-then statement
- --> $DIR/manual_assert.rs:42:5
+ --> $DIR/manual_assert.rs:44:5
|
LL | / if b.is_empty() {
LL | | panic!("panic1");
@@ -25,7 +25,7 @@ LL | | }
| |_____^ help: try: `assert!(!b.is_empty(), "panic1");`
error: only a `panic!` in `if`-then statement
- --> $DIR/manual_assert.rs:45:5
+ --> $DIR/manual_assert.rs:47:5
|
LL | / if b.is_empty() && a.is_empty() {
LL | | panic!("panic2");
@@ -33,7 +33,7 @@ LL | | }
| |_____^ help: try: `assert!(!(b.is_empty() && a.is_empty()), "panic2");`
error: only a `panic!` in `if`-then statement
- --> $DIR/manual_assert.rs:48:5
+ --> $DIR/manual_assert.rs:50:5
|
LL | / if a.is_empty() && !b.is_empty() {
LL | | panic!("panic3");
@@ -41,7 +41,7 @@ LL | | }
| |_____^ help: try: `assert!(!(a.is_empty() && !b.is_empty()), "panic3");`
error: only a `panic!` in `if`-then statement
- --> $DIR/manual_assert.rs:51:5
+ --> $DIR/manual_assert.rs:53:5
|
LL | / if b.is_empty() || a.is_empty() {
LL | | panic!("panic4");
@@ -49,7 +49,7 @@ LL | | }
| |_____^ help: try: `assert!(!(b.is_empty() || a.is_empty()), "panic4");`
error: only a `panic!` in `if`-then statement
- --> $DIR/manual_assert.rs:54:5
+ --> $DIR/manual_assert.rs:56:5
|
LL | / if a.is_empty() || !b.is_empty() {
LL | | panic!("panic5");
diff --git a/src/tools/clippy/tests/ui/manual_assert.edition2021.fixed b/src/tools/clippy/tests/ui/manual_assert.edition2021.fixed
index 11fe06c5724..6c2a25c37d8 100644
--- a/src/tools/clippy/tests/ui/manual_assert.edition2021.fixed
+++ b/src/tools/clippy/tests/ui/manual_assert.edition2021.fixed
@@ -2,7 +2,9 @@
// [edition2018] edition:2018
// [edition2021] edition:2021
// run-rustfix
+
#![warn(clippy::manual_assert)]
+#![allow(clippy::nonminimal_bool)]
fn main() {
let a = vec![1, 2, 3];
diff --git a/src/tools/clippy/tests/ui/manual_assert.edition2021.stderr b/src/tools/clippy/tests/ui/manual_assert.edition2021.stderr
index 03c03472f90..77511631e44 100644
--- a/src/tools/clippy/tests/ui/manual_assert.edition2021.stderr
+++ b/src/tools/clippy/tests/ui/manual_assert.edition2021.stderr
@@ -1,5 +1,5 @@
error: only a `panic!` in `if`-then statement
- --> $DIR/manual_assert.rs:22:5
+ --> $DIR/manual_assert.rs:24:5
|
LL | / if !a.is_empty() {
LL | | panic!("qaqaq{:?}", a);
@@ -9,7 +9,7 @@ LL | | }
= note: `-D clippy::manual-assert` implied by `-D warnings`
error: only a `panic!` in `if`-then statement
- --> $DIR/manual_assert.rs:25:5
+ --> $DIR/manual_assert.rs:27:5
|
LL | / if !a.is_empty() {
LL | | panic!("qwqwq");
@@ -17,7 +17,7 @@ LL | | }
| |_____^ help: try: `assert!(a.is_empty(), "qwqwq");`
error: only a `panic!` in `if`-then statement
- --> $DIR/manual_assert.rs:42:5
+ --> $DIR/manual_assert.rs:44:5
|
LL | / if b.is_empty() {
LL | | panic!("panic1");
@@ -25,7 +25,7 @@ LL | | }
| |_____^ help: try: `assert!(!b.is_empty(), "panic1");`
error: only a `panic!` in `if`-then statement
- --> $DIR/manual_assert.rs:45:5
+ --> $DIR/manual_assert.rs:47:5
|
LL | / if b.is_empty() && a.is_empty() {
LL | | panic!("panic2");
@@ -33,7 +33,7 @@ LL | | }
| |_____^ help: try: `assert!(!(b.is_empty() && a.is_empty()), "panic2");`
error: only a `panic!` in `if`-then statement
- --> $DIR/manual_assert.rs:48:5
+ --> $DIR/manual_assert.rs:50:5
|
LL | / if a.is_empty() && !b.is_empty() {
LL | | panic!("panic3");
@@ -41,7 +41,7 @@ LL | | }
| |_____^ help: try: `assert!(!(a.is_empty() && !b.is_empty()), "panic3");`
error: only a `panic!` in `if`-then statement
- --> $DIR/manual_assert.rs:51:5
+ --> $DIR/manual_assert.rs:53:5
|
LL | / if b.is_empty() || a.is_empty() {
LL | | panic!("panic4");
@@ -49,7 +49,7 @@ LL | | }
| |_____^ help: try: `assert!(!(b.is_empty() || a.is_empty()), "panic4");`
error: only a `panic!` in `if`-then statement
- --> $DIR/manual_assert.rs:54:5
+ --> $DIR/manual_assert.rs:56:5
|
LL | / if a.is_empty() || !b.is_empty() {
LL | | panic!("panic5");
diff --git a/src/tools/clippy/tests/ui/manual_assert.fixed b/src/tools/clippy/tests/ui/manual_assert.fixed
index 11fe06c5724..6c2a25c37d8 100644
--- a/src/tools/clippy/tests/ui/manual_assert.fixed
+++ b/src/tools/clippy/tests/ui/manual_assert.fixed
@@ -2,7 +2,9 @@
// [edition2018] edition:2018
// [edition2021] edition:2021
// run-rustfix
+
#![warn(clippy::manual_assert)]
+#![allow(clippy::nonminimal_bool)]
fn main() {
let a = vec![1, 2, 3];
diff --git a/src/tools/clippy/tests/ui/manual_assert.rs b/src/tools/clippy/tests/ui/manual_assert.rs
index 8713426fc88..d3e0897488f 100644
--- a/src/tools/clippy/tests/ui/manual_assert.rs
+++ b/src/tools/clippy/tests/ui/manual_assert.rs
@@ -2,7 +2,9 @@
// [edition2018] edition:2018
// [edition2021] edition:2021
// run-rustfix
+
#![warn(clippy::manual_assert)]
+#![allow(clippy::nonminimal_bool)]
fn main() {
let a = vec![1, 2, 3];
diff --git a/src/tools/clippy/tests/ui/manual_map_option_2.fixed b/src/tools/clippy/tests/ui/manual_map_option_2.fixed
index 8cc12149403..ebf3f8cabd4 100644
--- a/src/tools/clippy/tests/ui/manual_map_option_2.fixed
+++ b/src/tools/clippy/tests/ui/manual_map_option_2.fixed
@@ -47,4 +47,14 @@ fn main() {
let _ = s.as_ref().map(|x| {
if let Some(ref s) = s { (x.clone(), s) } else { panic!() }
});
+
+ // Issue #7820
+ unsafe fn f(x: u32) -> u32 {
+ x
+ }
+ unsafe {
+ let _ = Some(0).map(|x| f(x));
+ }
+ let _ = Some(0).map(|x| unsafe { f(x) });
+ let _ = Some(0).map(|x| unsafe { f(x) });
}
diff --git a/src/tools/clippy/tests/ui/manual_map_option_2.rs b/src/tools/clippy/tests/ui/manual_map_option_2.rs
index 0862b201ead..1382d9af0aa 100644
--- a/src/tools/clippy/tests/ui/manual_map_option_2.rs
+++ b/src/tools/clippy/tests/ui/manual_map_option_2.rs
@@ -53,4 +53,23 @@ fn main() {
}),
None => None,
};
+
+ // Issue #7820
+ unsafe fn f(x: u32) -> u32 {
+ x
+ }
+ unsafe {
+ let _ = match Some(0) {
+ Some(x) => Some(f(x)),
+ None => None,
+ };
+ }
+ let _ = match Some(0) {
+ Some(x) => unsafe { Some(f(x)) },
+ None => None,
+ };
+ let _ = match Some(0) {
+ Some(x) => Some(unsafe { f(x) }),
+ None => None,
+ };
}
diff --git a/src/tools/clippy/tests/ui/manual_map_option_2.stderr b/src/tools/clippy/tests/ui/manual_map_option_2.stderr
index 711ff6c4a4b..d35b6252fb8 100644
--- a/src/tools/clippy/tests/ui/manual_map_option_2.stderr
+++ b/src/tools/clippy/tests/ui/manual_map_option_2.stderr
@@ -39,5 +39,35 @@ LL + if let Some(ref s) = s { (x.clone(), s) } else { panic!() }
LL ~ });
|
-error: aborting due to 2 previous errors
+error: manual implementation of `Option::map`
+ --> $DIR/manual_map_option_2.rs:62:17
+ |
+LL | let _ = match Some(0) {
+ | _________________^
+LL | | Some(x) => Some(f(x)),
+LL | | None => None,
+LL | | };
+ | |_________^ help: try this: `Some(0).map(|x| f(x))`
+
+error: manual implementation of `Option::map`
+ --> $DIR/manual_map_option_2.rs:67:13
+ |
+LL | let _ = match Some(0) {
+ | _____________^
+LL | | Some(x) => unsafe { Some(f(x)) },
+LL | | None => None,
+LL | | };
+ | |_____^ help: try this: `Some(0).map(|x| unsafe { f(x) })`
+
+error: manual implementation of `Option::map`
+ --> $DIR/manual_map_option_2.rs:71:13
+ |
+LL | let _ = match Some(0) {
+ | _____________^
+LL | | Some(x) => Some(unsafe { f(x) }),
+LL | | None => None,
+LL | | };
+ | |_____^ help: try this: `Some(0).map(|x| unsafe { f(x) })`
+
+error: aborting due to 5 previous errors
diff --git a/src/tools/clippy/tests/ui/manual_split_once.fixed b/src/tools/clippy/tests/ui/manual_split_once.fixed
index 992baf1f185..d5113df569a 100644
--- a/src/tools/clippy/tests/ui/manual_split_once.fixed
+++ b/src/tools/clippy/tests/ui/manual_split_once.fixed
@@ -2,7 +2,7 @@
#![feature(custom_inner_attributes)]
#![warn(clippy::manual_split_once)]
-#![allow(clippy::iter_skip_next, clippy::iter_nth_zero)]
+#![allow(clippy::iter_skip_next, clippy::iter_nth_zero, clippy::needless_splitn)]
extern crate itertools;
@@ -38,8 +38,8 @@ fn main() {
let _ = [0, 1, 2].splitn(2, |&x| x == 1).nth(1).unwrap();
// `rsplitn` gives the results in the reverse order of `rsplit_once`
- let _ = "key=value".rsplit_once('=').unwrap().1;
- let _ = "key=value".rsplit_once('=').map_or("key=value", |x| x.0);
+ let _ = "key=value".rsplitn(2, '=').next().unwrap();
+ let _ = "key=value".rsplit_once('=').unwrap().0;
let _ = "key=value".rsplit_once('=').map(|x| x.1);
let (_, _) = "key=value".rsplit_once('=').map(|(x, y)| (y, x)).unwrap();
}
diff --git a/src/tools/clippy/tests/ui/manual_split_once.rs b/src/tools/clippy/tests/ui/manual_split_once.rs
index 4f92ab6b812..80e02952dbd 100644
--- a/src/tools/clippy/tests/ui/manual_split_once.rs
+++ b/src/tools/clippy/tests/ui/manual_split_once.rs
@@ -2,7 +2,7 @@
#![feature(custom_inner_attributes)]
#![warn(clippy::manual_split_once)]
-#![allow(clippy::iter_skip_next, clippy::iter_nth_zero)]
+#![allow(clippy::iter_skip_next, clippy::iter_nth_zero, clippy::needless_splitn)]
extern crate itertools;
diff --git a/src/tools/clippy/tests/ui/manual_split_once.stderr b/src/tools/clippy/tests/ui/manual_split_once.stderr
index 7bea2303d92..af9c7a2d41b 100644
--- a/src/tools/clippy/tests/ui/manual_split_once.stderr
+++ b/src/tools/clippy/tests/ui/manual_split_once.stderr
@@ -73,16 +73,10 @@ LL | let _ = s.splitn(2, "key=value").skip(1).next()?;
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `s.split_once("key=value")?.1`
error: manual implementation of `rsplit_once`
- --> $DIR/manual_split_once.rs:41:13
- |
-LL | let _ = "key=value".rsplitn(2, '=').next().unwrap();
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `"key=value".rsplit_once('=').unwrap().1`
-
-error: manual implementation of `rsplit_once`
--> $DIR/manual_split_once.rs:42:13
|
LL | let _ = "key=value".rsplitn(2, '=').nth(1).unwrap();
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `"key=value".rsplit_once('=').map_or("key=value", |x| x.0)`
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `"key=value".rsplit_once('=').unwrap().0`
error: manual implementation of `rsplit_once`
--> $DIR/manual_split_once.rs:43:13
@@ -102,5 +96,5 @@ error: manual implementation of `split_once`
LL | let _ = "key=value".splitn(2, '=').nth(1).unwrap();
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `"key=value".split_once('=').unwrap().1`
-error: aborting due to 17 previous errors
+error: aborting due to 16 previous errors
diff --git a/src/tools/clippy/tests/ui/match_overlapping_arm.rs b/src/tools/clippy/tests/ui/match_overlapping_arm.rs
index 845986a4ead..2f85e635713 100644
--- a/src/tools/clippy/tests/ui/match_overlapping_arm.rs
+++ b/src/tools/clippy/tests/ui/match_overlapping_arm.rs
@@ -100,6 +100,15 @@ fn overlapping() {
_ => (),
}
+ // Issue #7816 - overlap after included range
+ match 42 {
+ 5..=10 => (),
+ 0..=20 => (),
+ 21..=30 => (),
+ 21..=40 => (),
+ _ => (),
+ }
+
// Issue #7829
match 0 {
-1..=1 => (),
@@ -107,6 +116,15 @@ fn overlapping() {
_ => (),
}
+ // Only warn about the first if there are multiple overlaps
+ match 42u128 {
+ 0..=0x0000_0000_0000_00ff => (),
+ 0..=0x0000_0000_0000_ffff => (),
+ 0..=0x0000_0000_ffff_ffff => (),
+ 0..=0xffff_ffff_ffff_ffff => (),
+ _ => (),
+ }
+
if let None = Some(42) {
// nothing
} else if let None = Some(42) {
diff --git a/src/tools/clippy/tests/ui/match_overlapping_arm.stderr b/src/tools/clippy/tests/ui/match_overlapping_arm.stderr
index c2b3f173c2b..b81bb1ecfae 100644
--- a/src/tools/clippy/tests/ui/match_overlapping_arm.stderr
+++ b/src/tools/clippy/tests/ui/match_overlapping_arm.stderr
@@ -71,5 +71,29 @@ note: overlaps with this
LL | ..26 => println!("..26"),
| ^^^^
-error: aborting due to 6 previous errors
+error: some ranges overlap
+ --> $DIR/match_overlapping_arm.rs:107:9
+ |
+LL | 21..=30 => (),
+ | ^^^^^^^
+ |
+note: overlaps with this
+ --> $DIR/match_overlapping_arm.rs:108:9
+ |
+LL | 21..=40 => (),
+ | ^^^^^^^
+
+error: some ranges overlap
+ --> $DIR/match_overlapping_arm.rs:121:9
+ |
+LL | 0..=0x0000_0000_0000_00ff => (),
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^
+ |
+note: overlaps with this
+ --> $DIR/match_overlapping_arm.rs:122:9
+ |
+LL | 0..=0x0000_0000_0000_ffff => (),
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: aborting due to 8 previous errors
diff --git a/src/tools/clippy/tests/ui/min_max.rs b/src/tools/clippy/tests/ui/min_max.rs
index f7ed72a11cf..b2bc97f4744 100644
--- a/src/tools/clippy/tests/ui/min_max.rs
+++ b/src/tools/clippy/tests/ui/min_max.rs
@@ -19,8 +19,7 @@ impl NotOrd {
}
fn main() {
- let x;
- x = 2usize;
+ let x = 2usize;
min(1, max(3, x));
min(max(3, x), 1);
max(min(x, 1), 3);
@@ -35,9 +34,7 @@ fn main() {
let y = 2isize;
min(max(y, -1), 3);
- let s;
- s = "Hello";
-
+ let s = "Hello";
min("Apple", max("Zoo", s));
max(min(s, "Apple"), "Zoo");
diff --git a/src/tools/clippy/tests/ui/min_max.stderr b/src/tools/clippy/tests/ui/min_max.stderr
index 9f8e26fa406..c70b77eabbd 100644
--- a/src/tools/clippy/tests/ui/min_max.stderr
+++ b/src/tools/clippy/tests/ui/min_max.stderr
@@ -1,5 +1,5 @@
error: this `min`/`max` combination leads to constant result
- --> $DIR/min_max.rs:24:5
+ --> $DIR/min_max.rs:23:5
|
LL | min(1, max(3, x));
| ^^^^^^^^^^^^^^^^^
@@ -7,73 +7,73 @@ LL | min(1, max(3, x));
= note: `-D clippy::min-max` implied by `-D warnings`
error: this `min`/`max` combination leads to constant result
- --> $DIR/min_max.rs:25:5
+ --> $DIR/min_max.rs:24:5
|
LL | min(max(3, x), 1);
| ^^^^^^^^^^^^^^^^^
error: this `min`/`max` combination leads to constant result
- --> $DIR/min_max.rs:26:5
+ --> $DIR/min_max.rs:25:5
|
LL | max(min(x, 1), 3);
| ^^^^^^^^^^^^^^^^^
error: this `min`/`max` combination leads to constant result
- --> $DIR/min_max.rs:27:5
+ --> $DIR/min_max.rs:26:5
|
LL | max(3, min(x, 1));
| ^^^^^^^^^^^^^^^^^
error: this `min`/`max` combination leads to constant result
- --> $DIR/min_max.rs:29:5
+ --> $DIR/min_max.rs:28:5
|
LL | my_max(3, my_min(x, 1));
| ^^^^^^^^^^^^^^^^^^^^^^^
error: this `min`/`max` combination leads to constant result
- --> $DIR/min_max.rs:41:5
+ --> $DIR/min_max.rs:38:5
|
LL | min("Apple", max("Zoo", s));
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^
error: this `min`/`max` combination leads to constant result
- --> $DIR/min_max.rs:42:5
+ --> $DIR/min_max.rs:39:5
|
LL | max(min(s, "Apple"), "Zoo");
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^
error: this `min`/`max` combination leads to constant result
- --> $DIR/min_max.rs:47:5
+ --> $DIR/min_max.rs:44:5
|
LL | x.min(1).max(3);
| ^^^^^^^^^^^^^^^
error: this `min`/`max` combination leads to constant result
- --> $DIR/min_max.rs:48:5
+ --> $DIR/min_max.rs:45:5
|
LL | x.max(3).min(1);
| ^^^^^^^^^^^^^^^
error: this `min`/`max` combination leads to constant result
- --> $DIR/min_max.rs:49:5
+ --> $DIR/min_max.rs:46:5
|
LL | f.max(3f32).min(1f32);
| ^^^^^^^^^^^^^^^^^^^^^
error: this `min`/`max` combination leads to constant result
- --> $DIR/min_max.rs:55:5
+ --> $DIR/min_max.rs:52:5
|
LL | max(x.min(1), 3);
| ^^^^^^^^^^^^^^^^
error: this `min`/`max` combination leads to constant result
- --> $DIR/min_max.rs:58:5
+ --> $DIR/min_max.rs:55:5
|
LL | s.max("Zoo").min("Apple");
| ^^^^^^^^^^^^^^^^^^^^^^^^^
error: this `min`/`max` combination leads to constant result
- --> $DIR/min_max.rs:59:5
+ --> $DIR/min_max.rs:56:5
|
LL | s.min("Apple").max("Zoo");
| ^^^^^^^^^^^^^^^^^^^^^^^^^
diff --git a/src/tools/clippy/tests/ui/min_rust_version_attr.rs b/src/tools/clippy/tests/ui/min_rust_version_attr.rs
index 8d9fc5a864d..c5f221220ec 100644
--- a/src/tools/clippy/tests/ui/min_rust_version_attr.rs
+++ b/src/tools/clippy/tests/ui/min_rust_version_attr.rs
@@ -137,6 +137,14 @@ fn unnest_or_patterns() {
if let TS(0, x) | TS(1, x) = TS(0, 0) {}
}
+#[cfg_attr(rustfmt, rustfmt_skip)]
+fn deprecated_cfg_attr() {}
+
+#[warn(clippy::cast_lossless)]
+fn int_from_bool() -> u8 {
+ true as u8
+}
+
fn main() {
filter_map_next();
checked_conversion();
@@ -153,11 +161,12 @@ fn main() {
map_unwrap_or();
missing_const_for_fn();
unnest_or_patterns();
+ int_from_bool();
}
-mod meets_msrv {
+mod just_under_msrv {
#![feature(custom_inner_attributes)]
- #![clippy::msrv = "1.45.0"]
+ #![clippy::msrv = "1.44.0"]
fn main() {
let s = "hello, world!";
@@ -167,9 +176,9 @@ mod meets_msrv {
}
}
-mod just_under_msrv {
+mod meets_msrv {
#![feature(custom_inner_attributes)]
- #![clippy::msrv = "1.46.0"]
+ #![clippy::msrv = "1.45.0"]
fn main() {
let s = "hello, world!";
@@ -181,7 +190,7 @@ mod just_under_msrv {
mod just_above_msrv {
#![feature(custom_inner_attributes)]
- #![clippy::msrv = "1.44.0"]
+ #![clippy::msrv = "1.46.0"]
fn main() {
let s = "hello, world!";
diff --git a/src/tools/clippy/tests/ui/min_rust_version_attr.stderr b/src/tools/clippy/tests/ui/min_rust_version_attr.stderr
index 360dcfb230c..6b3fdb0844b 100644
--- a/src/tools/clippy/tests/ui/min_rust_version_attr.stderr
+++ b/src/tools/clippy/tests/ui/min_rust_version_attr.stderr
@@ -1,12 +1,12 @@
error: stripping a prefix manually
- --> $DIR/min_rust_version_attr.rs:165:24
+ --> $DIR/min_rust_version_attr.rs:186:24
|
LL | assert_eq!(s["hello, ".len()..].to_uppercase(), "WORLD!");
| ^^^^^^^^^^^^^^^^^^^^
|
= note: `-D clippy::manual-strip` implied by `-D warnings`
note: the prefix was tested here
- --> $DIR/min_rust_version_attr.rs:164:9
+ --> $DIR/min_rust_version_attr.rs:185:9
|
LL | if s.starts_with("hello, ") {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -17,13 +17,13 @@ LL ~ assert_eq!(<stripped>.to_uppercase(), "WORLD!");
|
error: stripping a prefix manually
- --> $DIR/min_rust_version_attr.rs:177:24
+ --> $DIR/min_rust_version_attr.rs:198:24
|
LL | assert_eq!(s["hello, ".len()..].to_uppercase(), "WORLD!");
| ^^^^^^^^^^^^^^^^^^^^
|
note: the prefix was tested here
- --> $DIR/min_rust_version_attr.rs:176:9
+ --> $DIR/min_rust_version_attr.rs:197:9
|
LL | if s.starts_with("hello, ") {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
diff --git a/src/tools/clippy/tests/ui/missing-doc.rs b/src/tools/clippy/tests/ui/missing-doc.rs
index 148531c285d..6e2e710e21c 100644
--- a/src/tools/clippy/tests/ui/missing-doc.rs
+++ b/src/tools/clippy/tests/ui/missing-doc.rs
@@ -2,10 +2,11 @@
// When denying at the crate level, be sure to not get random warnings from the
// injected intrinsics by the compiler.
#![allow(dead_code)]
-#![feature(global_asm)]
//! Some garbage docs for the crate here
#![doc = "More garbage"]
+use std::arch::global_asm;
+
type Typedef = String;
pub type PubTypedef = String;
diff --git a/src/tools/clippy/tests/ui/missing-doc.stderr b/src/tools/clippy/tests/ui/missing-doc.stderr
index 7a3a448c9d6..a876dc078eb 100644
--- a/src/tools/clippy/tests/ui/missing-doc.stderr
+++ b/src/tools/clippy/tests/ui/missing-doc.stderr
@@ -1,5 +1,5 @@
error: missing documentation for a type alias
- --> $DIR/missing-doc.rs:9:1
+ --> $DIR/missing-doc.rs:10:1
|
LL | type Typedef = String;
| ^^^^^^^^^^^^^^^^^^^^^^
@@ -7,37 +7,37 @@ LL | type Typedef = String;
= note: `-D clippy::missing-docs-in-private-items` implied by `-D warnings`
error: missing documentation for a type alias
- --> $DIR/missing-doc.rs:10:1
+ --> $DIR/missing-doc.rs:11:1
|
LL | pub type PubTypedef = String;
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
error: missing documentation for a module
- --> $DIR/missing-doc.rs:12:1
+ --> $DIR/missing-doc.rs:13:1
|
LL | mod module_no_dox {}
| ^^^^^^^^^^^^^^^^^^^^
error: missing documentation for a module
- --> $DIR/missing-doc.rs:13:1
+ --> $DIR/missing-doc.rs:14:1
|
LL | pub mod pub_module_no_dox {}
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
error: missing documentation for a function
- --> $DIR/missing-doc.rs:17:1
+ --> $DIR/missing-doc.rs:18:1
|
LL | pub fn foo2() {}
| ^^^^^^^^^^^^^^^^
error: missing documentation for a function
- --> $DIR/missing-doc.rs:18:1
+ --> $DIR/missing-doc.rs:19:1
|
LL | fn foo3() {}
| ^^^^^^^^^^^^
error: missing documentation for an enum
- --> $DIR/missing-doc.rs:32:1
+ --> $DIR/missing-doc.rs:33:1
|
LL | / enum Baz {
LL | | BazA { a: isize, b: isize },
@@ -46,31 +46,31 @@ LL | | }
| |_^
error: missing documentation for a variant
- --> $DIR/missing-doc.rs:33:5
+ --> $DIR/missing-doc.rs:34:5
|
LL | BazA { a: isize, b: isize },
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^
error: missing documentation for a struct field
- --> $DIR/missing-doc.rs:33:12
+ --> $DIR/missing-doc.rs:34:12
|
LL | BazA { a: isize, b: isize },
| ^^^^^^^^
error: missing documentation for a struct field
- --> $DIR/missing-doc.rs:33:22
+ --> $DIR/missing-doc.rs:34:22
|
LL | BazA { a: isize, b: isize },
| ^^^^^^^^
error: missing documentation for a variant
- --> $DIR/missing-doc.rs:34:5
+ --> $DIR/missing-doc.rs:35:5
|
LL | BarB,
| ^^^^
error: missing documentation for an enum
- --> $DIR/missing-doc.rs:37:1
+ --> $DIR/missing-doc.rs:38:1
|
LL | / pub enum PubBaz {
LL | | PubBazA { a: isize },
@@ -78,43 +78,43 @@ LL | | }
| |_^
error: missing documentation for a variant
- --> $DIR/missing-doc.rs:38:5
+ --> $DIR/missing-doc.rs:39:5
|
LL | PubBazA { a: isize },
| ^^^^^^^^^^^^^^^^^^^^
error: missing documentation for a struct field
- --> $DIR/missing-doc.rs:38:15
+ --> $DIR/missing-doc.rs:39:15
|
LL | PubBazA { a: isize },
| ^^^^^^^^
error: missing documentation for a constant
- --> $DIR/missing-doc.rs:58:1
+ --> $DIR/missing-doc.rs:59:1
|
LL | const FOO: u32 = 0;
| ^^^^^^^^^^^^^^^^^^^
error: missing documentation for a constant
- --> $DIR/missing-doc.rs:65:1
+ --> $DIR/missing-doc.rs:66:1
|
LL | pub const FOO4: u32 = 0;
| ^^^^^^^^^^^^^^^^^^^^^^^^
error: missing documentation for a static
- --> $DIR/missing-doc.rs:67:1
+ --> $DIR/missing-doc.rs:68:1
|
LL | static BAR: u32 = 0;
| ^^^^^^^^^^^^^^^^^^^^
error: missing documentation for a static
- --> $DIR/missing-doc.rs:74:1
+ --> $DIR/missing-doc.rs:75:1
|
LL | pub static BAR4: u32 = 0;
| ^^^^^^^^^^^^^^^^^^^^^^^^^
error: missing documentation for a module
- --> $DIR/missing-doc.rs:76:1
+ --> $DIR/missing-doc.rs:77:1
|
LL | / mod internal_impl {
LL | | /// dox
@@ -126,31 +126,31 @@ LL | | }
| |_^
error: missing documentation for a function
- --> $DIR/missing-doc.rs:79:5
+ --> $DIR/missing-doc.rs:80:5
|
LL | pub fn undocumented1() {}
| ^^^^^^^^^^^^^^^^^^^^^^^^^
error: missing documentation for a function
- --> $DIR/missing-doc.rs:80:5
+ --> $DIR/missing-doc.rs:81:5
|
LL | pub fn undocumented2() {}
| ^^^^^^^^^^^^^^^^^^^^^^^^^
error: missing documentation for a function
- --> $DIR/missing-doc.rs:81:5
+ --> $DIR/missing-doc.rs:82:5
|
LL | fn undocumented3() {}
| ^^^^^^^^^^^^^^^^^^^^^
error: missing documentation for a function
- --> $DIR/missing-doc.rs:86:9
+ --> $DIR/missing-doc.rs:87:9
|
LL | pub fn also_undocumented1() {}
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
error: missing documentation for a function
- --> $DIR/missing-doc.rs:87:9
+ --> $DIR/missing-doc.rs:88:9
|
LL | fn also_undocumented2() {}
| ^^^^^^^^^^^^^^^^^^^^^^^^^^
diff --git a/src/tools/clippy/tests/ui/needless_bool/fixable.fixed b/src/tools/clippy/tests/ui/needless_bool/fixable.fixed
index a2e3988daff..85da1f4e104 100644
--- a/src/tools/clippy/tests/ui/needless_bool/fixable.fixed
+++ b/src/tools/clippy/tests/ui/needless_bool/fixable.fixed
@@ -53,6 +53,7 @@ fn main() {
needless_bool(x);
needless_bool2(x);
needless_bool3(x);
+ needless_bool_condition();
}
fn bool_ret3(x: bool) -> bool {
@@ -98,3 +99,19 @@ fn needless_bool_in_the_suggestion_wraps_the_predicate_of_if_else_statement_in_b
true
} else { !returns_bool() };
}
+
+unsafe fn no(v: u8) -> u8 {
+ v
+}
+
+#[allow(clippy::unnecessary_operation)]
+fn needless_bool_condition() -> bool {
+ (unsafe { no(4) } & 1 != 0);
+ let _brackets_unneeded = unsafe { no(4) } & 1 != 0;
+ fn foo() -> bool {
+ // parentheses are needed here
+ (unsafe { no(4) } & 1 != 0)
+ }
+
+ foo()
+}
diff --git a/src/tools/clippy/tests/ui/needless_bool/fixable.rs b/src/tools/clippy/tests/ui/needless_bool/fixable.rs
index 75805e85789..add60630251 100644
--- a/src/tools/clippy/tests/ui/needless_bool/fixable.rs
+++ b/src/tools/clippy/tests/ui/needless_bool/fixable.rs
@@ -65,6 +65,7 @@ fn main() {
needless_bool(x);
needless_bool2(x);
needless_bool3(x);
+ needless_bool_condition();
}
fn bool_ret3(x: bool) -> bool {
@@ -130,3 +131,23 @@ fn needless_bool_in_the_suggestion_wraps_the_predicate_of_if_else_statement_in_b
true
};
}
+
+unsafe fn no(v: u8) -> u8 {
+ v
+}
+
+#[allow(clippy::unnecessary_operation)]
+fn needless_bool_condition() -> bool {
+ if unsafe { no(4) } & 1 != 0 {
+ true
+ } else {
+ false
+ };
+ let _brackets_unneeded = if unsafe { no(4) } & 1 != 0 { true } else { false };
+ fn foo() -> bool {
+ // parentheses are needed here
+ if unsafe { no(4) } & 1 != 0 { true } else { false }
+ }
+
+ foo()
+}
diff --git a/src/tools/clippy/tests/ui/needless_bool/fixable.stderr b/src/tools/clippy/tests/ui/needless_bool/fixable.stderr
index 1fa12add167..22c0a7bb491 100644
--- a/src/tools/clippy/tests/ui/needless_bool/fixable.stderr
+++ b/src/tools/clippy/tests/ui/needless_bool/fixable.stderr
@@ -31,7 +31,7 @@ LL | | };
| |_____^ help: you can reduce it to: `!(x && y)`
error: this if-then-else expression returns a bool literal
- --> $DIR/fixable.rs:71:5
+ --> $DIR/fixable.rs:72:5
|
LL | / if x {
LL | | return true;
@@ -41,7 +41,7 @@ LL | | };
| |_____^ help: you can reduce it to: `return x`
error: this if-then-else expression returns a bool literal
- --> $DIR/fixable.rs:79:5
+ --> $DIR/fixable.rs:80:5
|
LL | / if x {
LL | | return false;
@@ -51,7 +51,7 @@ LL | | };
| |_____^ help: you can reduce it to: `return !x`
error: this if-then-else expression returns a bool literal
- --> $DIR/fixable.rs:87:5
+ --> $DIR/fixable.rs:88:5
|
LL | / if x && y {
LL | | return true;
@@ -61,7 +61,7 @@ LL | | };
| |_____^ help: you can reduce it to: `return x && y`
error: this if-then-else expression returns a bool literal
- --> $DIR/fixable.rs:95:5
+ --> $DIR/fixable.rs:96:5
|
LL | / if x && y {
LL | | return false;
@@ -71,7 +71,7 @@ LL | | };
| |_____^ help: you can reduce it to: `return !(x && y)`
error: equality checks against true are unnecessary
- --> $DIR/fixable.rs:103:8
+ --> $DIR/fixable.rs:104:8
|
LL | if x == true {};
| ^^^^^^^^^ help: try simplifying it as shown: `x`
@@ -79,25 +79,25 @@ LL | if x == true {};
= note: `-D clippy::bool-comparison` implied by `-D warnings`
error: equality checks against false can be replaced by a negation
- --> $DIR/fixable.rs:107:8
+ --> $DIR/fixable.rs:108:8
|
LL | if x == false {};
| ^^^^^^^^^^ help: try simplifying it as shown: `!x`
error: equality checks against true are unnecessary
- --> $DIR/fixable.rs:117:8
+ --> $DIR/fixable.rs:118:8
|
LL | if x == true {};
| ^^^^^^^^^ help: try simplifying it as shown: `x`
error: equality checks against false can be replaced by a negation
- --> $DIR/fixable.rs:118:8
+ --> $DIR/fixable.rs:119:8
|
LL | if x == false {};
| ^^^^^^^^^^ help: try simplifying it as shown: `!x`
error: this if-then-else expression returns a bool literal
- --> $DIR/fixable.rs:127:12
+ --> $DIR/fixable.rs:128:12
|
LL | } else if returns_bool() {
| ____________^
@@ -107,5 +107,27 @@ LL | | true
LL | | };
| |_____^ help: you can reduce it to: `{ !returns_bool() }`
-error: aborting due to 12 previous errors
+error: this if-then-else expression returns a bool literal
+ --> $DIR/fixable.rs:141:5
+ |
+LL | / if unsafe { no(4) } & 1 != 0 {
+LL | | true
+LL | | } else {
+LL | | false
+LL | | };
+ | |_____^ help: you can reduce it to: `(unsafe { no(4) } & 1 != 0)`
+
+error: this if-then-else expression returns a bool literal
+ --> $DIR/fixable.rs:146:30
+ |
+LL | let _brackets_unneeded = if unsafe { no(4) } & 1 != 0 { true } else { false };
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: you can reduce it to: `unsafe { no(4) } & 1 != 0`
+
+error: this if-then-else expression returns a bool literal
+ --> $DIR/fixable.rs:149:9
+ |
+LL | if unsafe { no(4) } & 1 != 0 { true } else { false }
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: you can reduce it to: `(unsafe { no(4) } & 1 != 0)`
+
+error: aborting due to 15 previous errors
diff --git a/src/tools/clippy/tests/ui/needless_borrow.fixed b/src/tools/clippy/tests/ui/needless_borrow.fixed
index 42c2bb9f414..9e37fb92559 100644
--- a/src/tools/clippy/tests/ui/needless_borrow.fixed
+++ b/src/tools/clippy/tests/ui/needless_borrow.fixed
@@ -1,9 +1,10 @@
// run-rustfix
#[warn(clippy::all, clippy::needless_borrow)]
-#[allow(unused_variables)]
+#[allow(unused_variables, clippy::unnecessary_mut_passed)]
fn main() {
let a = 5;
+ let ref_a = &a;
let _ = x(&a); // no warning
let _ = x(&a); // warn
@@ -21,11 +22,29 @@ fn main() {
44 => &a,
45 => {
println!("foo");
- &&a // FIXME: this should lint, too
+ &a
},
46 => &a,
+ 47 => {
+ println!("foo");
+ loop {
+ println!("{}", a);
+ if a == 25 {
+ break ref_a;
+ }
+ }
+ },
_ => panic!(),
};
+
+ let _ = x(&a);
+ let _ = x(&a);
+ let _ = x(&mut b);
+ let _ = x(ref_a);
+ {
+ let b = &mut b;
+ x(b);
+ }
}
#[allow(clippy::needless_borrowed_reference)]
diff --git a/src/tools/clippy/tests/ui/needless_borrow.rs b/src/tools/clippy/tests/ui/needless_borrow.rs
index 31977416bc7..093277784be 100644
--- a/src/tools/clippy/tests/ui/needless_borrow.rs
+++ b/src/tools/clippy/tests/ui/needless_borrow.rs
@@ -1,9 +1,10 @@
// run-rustfix
#[warn(clippy::all, clippy::needless_borrow)]
-#[allow(unused_variables)]
+#[allow(unused_variables, clippy::unnecessary_mut_passed)]
fn main() {
let a = 5;
+ let ref_a = &a;
let _ = x(&a); // no warning
let _ = x(&&a); // warn
@@ -21,11 +22,29 @@ fn main() {
44 => &a,
45 => {
println!("foo");
- &&a // FIXME: this should lint, too
+ &&a
},
46 => &&a,
+ 47 => {
+ println!("foo");
+ loop {
+ println!("{}", a);
+ if a == 25 {
+ break &ref_a;
+ }
+ }
+ },
_ => panic!(),
};
+
+ let _ = x(&&&a);
+ let _ = x(&mut &&a);
+ let _ = x(&&&mut b);
+ let _ = x(&&ref_a);
+ {
+ let b = &mut b;
+ x(&b);
+ }
}
#[allow(clippy::needless_borrowed_reference)]
diff --git a/src/tools/clippy/tests/ui/needless_borrow.stderr b/src/tools/clippy/tests/ui/needless_borrow.stderr
index 012d62e2871..03a5b3d260e 100644
--- a/src/tools/clippy/tests/ui/needless_borrow.stderr
+++ b/src/tools/clippy/tests/ui/needless_borrow.stderr
@@ -1,5 +1,5 @@
error: this expression borrows a reference (`&i32`) that is immediately dereferenced by the compiler
- --> $DIR/needless_borrow.rs:8:15
+ --> $DIR/needless_borrow.rs:9:15
|
LL | let _ = x(&&a); // warn
| ^^^ help: change this to: `&a`
@@ -7,16 +7,58 @@ LL | let _ = x(&&a); // warn
= note: `-D clippy::needless-borrow` implied by `-D warnings`
error: this expression borrows a reference (`&mut i32`) that is immediately dereferenced by the compiler
- --> $DIR/needless_borrow.rs:12:13
+ --> $DIR/needless_borrow.rs:13:13
|
LL | mut_ref(&mut &mut b); // warn
| ^^^^^^^^^^^ help: change this to: `&mut b`
error: this expression borrows a reference (`&i32`) that is immediately dereferenced by the compiler
- --> $DIR/needless_borrow.rs:26:15
+ --> $DIR/needless_borrow.rs:25:13
+ |
+LL | &&a
+ | ^^^ help: change this to: `&a`
+
+error: this expression borrows a reference (`&i32`) that is immediately dereferenced by the compiler
+ --> $DIR/needless_borrow.rs:27:15
|
LL | 46 => &&a,
| ^^^ help: change this to: `&a`
-error: aborting due to 3 previous errors
+error: this expression borrows a reference (`&i32`) that is immediately dereferenced by the compiler
+ --> $DIR/needless_borrow.rs:33:27
+ |
+LL | break &ref_a;
+ | ^^^^^^ help: change this to: `ref_a`
+
+error: this expression borrows a reference (`&i32`) that is immediately dereferenced by the compiler
+ --> $DIR/needless_borrow.rs:40:15
+ |
+LL | let _ = x(&&&a);
+ | ^^^^ help: change this to: `&a`
+
+error: this expression borrows a reference (`&i32`) that is immediately dereferenced by the compiler
+ --> $DIR/needless_borrow.rs:41:15
+ |
+LL | let _ = x(&mut &&a);
+ | ^^^^^^^^ help: change this to: `&a`
+
+error: this expression borrows a reference (`&mut i32`) that is immediately dereferenced by the compiler
+ --> $DIR/needless_borrow.rs:42:15
+ |
+LL | let _ = x(&&&mut b);
+ | ^^^^^^^^ help: change this to: `&mut b`
+
+error: this expression borrows a reference (`&i32`) that is immediately dereferenced by the compiler
+ --> $DIR/needless_borrow.rs:43:15
+ |
+LL | let _ = x(&&ref_a);
+ | ^^^^^^^ help: change this to: `ref_a`
+
+error: this expression borrows a reference (`&mut i32`) that is immediately dereferenced by the compiler
+ --> $DIR/needless_borrow.rs:46:11
+ |
+LL | x(&b);
+ | ^^ help: change this to: `b`
+
+error: aborting due to 10 previous errors
diff --git a/src/tools/clippy/tests/ui/needless_collect_indirect.rs b/src/tools/clippy/tests/ui/needless_collect_indirect.rs
index 2c94235b8f5..1f11d1f8d56 100644
--- a/src/tools/clippy/tests/ui/needless_collect_indirect.rs
+++ b/src/tools/clippy/tests/ui/needless_collect_indirect.rs
@@ -76,6 +76,37 @@ mod issue7110 {
}
}
+mod issue7975 {
+ use super::*;
+
+ fn direct_mapping_with_used_mutable_reference() -> Vec<()> {
+ let test_vec: Vec<()> = vec![];
+ let mut vec_2: Vec<()> = vec![];
+ let mut_ref = &mut vec_2;
+ let collected_vec: Vec<_> = test_vec.into_iter().map(|_| mut_ref.push(())).collect();
+ collected_vec.into_iter().map(|_| mut_ref.push(())).collect()
+ }
+
+ fn indirectly_mapping_with_used_mutable_reference() -> Vec<()> {
+ let test_vec: Vec<()> = vec![];
+ let mut vec_2: Vec<()> = vec![];
+ let mut_ref = &mut vec_2;
+ let collected_vec: Vec<_> = test_vec.into_iter().map(|_| mut_ref.push(())).collect();
+ let iter = collected_vec.into_iter();
+ iter.map(|_| mut_ref.push(())).collect()
+ }
+
+ fn indirect_collect_after_indirect_mapping_with_used_mutable_reference() -> Vec<()> {
+ let test_vec: Vec<()> = vec![];
+ let mut vec_2: Vec<()> = vec![];
+ let mut_ref = &mut vec_2;
+ let collected_vec: Vec<_> = test_vec.into_iter().map(|_| mut_ref.push(())).collect();
+ let iter = collected_vec.into_iter();
+ let mapped_iter = iter.map(|_| mut_ref.push(()));
+ mapped_iter.collect()
+ }
+}
+
fn allow_test() {
#[allow(clippy::needless_collect)]
let v = [1].iter().collect::<Vec<_>>();
diff --git a/src/tools/clippy/tests/ui/needless_late_init.rs b/src/tools/clippy/tests/ui/needless_late_init.rs
new file mode 100644
index 00000000000..89e012c066f
--- /dev/null
+++ b/src/tools/clippy/tests/ui/needless_late_init.rs
@@ -0,0 +1,180 @@
+#![allow(unused)]
+
+fn main() {
+ let a;
+ let n = 1;
+ match n {
+ 1 => a = "one",
+ _ => {
+ a = "two";
+ },
+ }
+
+ let b;
+ if n == 3 {
+ b = "four";
+ } else {
+ b = "five"
+ }
+
+ let c;
+ if let Some(n) = Some(5) {
+ c = n;
+ } else {
+ c = -50;
+ }
+
+ let d;
+ if true {
+ let temp = 5;
+ d = temp;
+ } else {
+ d = 15;
+ }
+
+ let e;
+ if true {
+ e = format!("{} {}", a, b);
+ } else {
+ e = format!("{}", c);
+ }
+
+ let f;
+ match 1 {
+ 1 => f = "three",
+ _ => return,
+ }; // has semi
+
+ let g: usize;
+ if true {
+ g = 5;
+ } else {
+ panic!();
+ }
+
+ println!("{}", a);
+}
+
+async fn in_async() -> &'static str {
+ async fn f() -> &'static str {
+ "one"
+ }
+
+ let a;
+ let n = 1;
+ match n {
+ 1 => a = f().await,
+ _ => {
+ a = "two";
+ },
+ }
+
+ a
+}
+
+const fn in_const() -> &'static str {
+ const fn f() -> &'static str {
+ "one"
+ }
+
+ let a;
+ let n = 1;
+ match n {
+ 1 => a = f(),
+ _ => {
+ a = "two";
+ },
+ }
+
+ a
+}
+
+fn does_not_lint() {
+ let z;
+ if false {
+ z = 1;
+ }
+
+ let x;
+ let y;
+ if true {
+ x = 1;
+ } else {
+ y = 1;
+ }
+
+ let mut x;
+ if true {
+ x = 5;
+ x = 10 / x;
+ } else {
+ x = 2;
+ }
+
+ let x;
+ let _ = match 1 {
+ 1 => x = 10,
+ _ => x = 20,
+ };
+
+ // using tuples would be possible, but not always preferable
+ let x;
+ let y;
+ if true {
+ x = 1;
+ y = 2;
+ } else {
+ x = 3;
+ y = 4;
+ }
+
+ // could match with a smarter heuristic to avoid multiple assignments
+ let x;
+ if true {
+ let mut y = 5;
+ y = 6;
+ x = y;
+ } else {
+ x = 2;
+ }
+
+ let (x, y);
+ if true {
+ x = 1;
+ } else {
+ x = 2;
+ }
+ y = 3;
+
+ macro_rules! assign {
+ ($i:ident) => {
+ $i = 1;
+ };
+ }
+ let x;
+ assign!(x);
+
+ let x;
+ if true {
+ assign!(x);
+ } else {
+ x = 2;
+ }
+
+ macro_rules! in_macro {
+ () => {
+ let x;
+ x = 1;
+
+ let x;
+ if true {
+ x = 1;
+ } else {
+ x = 2;
+ }
+ };
+ }
+ in_macro!();
+
+ println!("{}", x);
+}
diff --git a/src/tools/clippy/tests/ui/needless_late_init.stderr b/src/tools/clippy/tests/ui/needless_late_init.stderr
new file mode 100644
index 00000000000..ef79e635d2a
--- /dev/null
+++ b/src/tools/clippy/tests/ui/needless_late_init.stderr
@@ -0,0 +1,186 @@
+error: unneeded late initalization
+ --> $DIR/needless_late_init.rs:4:5
+ |
+LL | let a;
+ | ^^^^^^
+ |
+ = note: `-D clippy::needless-late-init` implied by `-D warnings`
+help: declare `a` here
+ |
+LL | let a = match n {
+ | +++++++
+help: remove the assignments from the `match` arms
+ |
+LL ~ 1 => "one",
+LL | _ => {
+LL ~ "two"
+ |
+help: add a semicolon after the `match` expression
+ |
+LL | };
+ | +
+
+error: unneeded late initalization
+ --> $DIR/needless_late_init.rs:13:5
+ |
+LL | let b;
+ | ^^^^^^
+ |
+help: declare `b` here
+ |
+LL | let b = if n == 3 {
+ | +++++++
+help: remove the assignments from the branches
+ |
+LL ~ "four"
+LL | } else {
+LL ~ "five"
+ |
+help: add a semicolon after the `if` expression
+ |
+LL | };
+ | +
+
+error: unneeded late initalization
+ --> $DIR/needless_late_init.rs:20:5
+ |
+LL | let c;
+ | ^^^^^^
+ |
+help: declare `c` here
+ |
+LL | let c = if let Some(n) = Some(5) {
+ | +++++++
+help: remove the assignments from the branches
+ |
+LL ~ n
+LL | } else {
+LL ~ -50
+ |
+help: add a semicolon after the `if` expression
+ |
+LL | };
+ | +
+
+error: unneeded late initalization
+ --> $DIR/needless_late_init.rs:27:5
+ |
+LL | let d;
+ | ^^^^^^
+ |
+help: declare `d` here
+ |
+LL | let d = if true {
+ | +++++++
+help: remove the assignments from the branches
+ |
+LL ~ temp
+LL | } else {
+LL ~ 15
+ |
+help: add a semicolon after the `if` expression
+ |
+LL | };
+ | +
+
+error: unneeded late initalization
+ --> $DIR/needless_late_init.rs:35:5
+ |
+LL | let e;
+ | ^^^^^^
+ |
+help: declare `e` here
+ |
+LL | let e = if true {
+ | +++++++
+help: remove the assignments from the branches
+ |
+LL ~ format!("{} {}", a, b)
+LL | } else {
+LL ~ format!("{}", c)
+ |
+help: add a semicolon after the `if` expression
+ |
+LL | };
+ | +
+
+error: unneeded late initalization
+ --> $DIR/needless_late_init.rs:42:5
+ |
+LL | let f;
+ | ^^^^^^
+ |
+help: declare `f` here
+ |
+LL | let f = match 1 {
+ | +++++++
+help: remove the assignments from the `match` arms
+ |
+LL - 1 => f = "three",
+LL + 1 => "three",
+ |
+
+error: unneeded late initalization
+ --> $DIR/needless_late_init.rs:48:5
+ |
+LL | let g: usize;
+ | ^^^^^^^^^^^^^
+ |
+help: declare `g` here
+ |
+LL | let g: usize = if true {
+ | ++++++++++++++
+help: remove the assignments from the branches
+ |
+LL - g = 5;
+LL + 5
+ |
+help: add a semicolon after the `if` expression
+ |
+LL | };
+ | +
+
+error: unneeded late initalization
+ --> $DIR/needless_late_init.rs:63:5
+ |
+LL | let a;
+ | ^^^^^^
+ |
+help: declare `a` here
+ |
+LL | let a = match n {
+ | +++++++
+help: remove the assignments from the `match` arms
+ |
+LL ~ 1 => f().await,
+LL | _ => {
+LL ~ "two"
+ |
+help: add a semicolon after the `match` expression
+ |
+LL | };
+ | +
+
+error: unneeded late initalization
+ --> $DIR/needless_late_init.rs:80:5
+ |
+LL | let a;
+ | ^^^^^^
+ |
+help: declare `a` here
+ |
+LL | let a = match n {
+ | +++++++
+help: remove the assignments from the `match` arms
+ |
+LL ~ 1 => f(),
+LL | _ => {
+LL ~ "two"
+ |
+help: add a semicolon after the `match` expression
+ |
+LL | };
+ | +
+
+error: aborting due to 9 previous errors
+
diff --git a/src/tools/clippy/tests/ui/needless_late_init_fixable.fixed b/src/tools/clippy/tests/ui/needless_late_init_fixable.fixed
new file mode 100644
index 00000000000..b516f9d86b7
--- /dev/null
+++ b/src/tools/clippy/tests/ui/needless_late_init_fixable.fixed
@@ -0,0 +1,25 @@
+// run-rustfix
+
+#![allow(unused, clippy::assign_op_pattern)]
+
+fn main() {
+
+ let a = "zero";
+
+
+
+ let b = 1;
+ let c = 2;
+
+
+ let d: usize = 1;
+
+
+ let mut e = 1;
+ e = 2;
+
+
+ let h = format!("{}", e);
+
+ println!("{}", a);
+}
diff --git a/src/tools/clippy/tests/ui/needless_late_init_fixable.rs b/src/tools/clippy/tests/ui/needless_late_init_fixable.rs
new file mode 100644
index 00000000000..75a4bc916de
--- /dev/null
+++ b/src/tools/clippy/tests/ui/needless_late_init_fixable.rs
@@ -0,0 +1,25 @@
+// run-rustfix
+
+#![allow(unused, clippy::assign_op_pattern)]
+
+fn main() {
+ let a;
+ a = "zero";
+
+ let b;
+ let c;
+ b = 1;
+ c = 2;
+
+ let d: usize;
+ d = 1;
+
+ let mut e;
+ e = 1;
+ e = 2;
+
+ let h;
+ h = format!("{}", e);
+
+ println!("{}", a);
+}
diff --git a/src/tools/clippy/tests/ui/needless_late_init_fixable.stderr b/src/tools/clippy/tests/ui/needless_late_init_fixable.stderr
new file mode 100644
index 00000000000..3f3d4f5286b
--- /dev/null
+++ b/src/tools/clippy/tests/ui/needless_late_init_fixable.stderr
@@ -0,0 +1,69 @@
+error: unneeded late initalization
+ --> $DIR/needless_late_init_fixable.rs:6:5
+ |
+LL | let a;
+ | ^^^^^^
+ |
+ = note: `-D clippy::needless-late-init` implied by `-D warnings`
+help: declare `a` here
+ |
+LL | let a = "zero";
+ | ~~~~~
+
+error: unneeded late initalization
+ --> $DIR/needless_late_init_fixable.rs:9:5
+ |
+LL | let b;
+ | ^^^^^^
+ |
+help: declare `b` here
+ |
+LL | let b = 1;
+ | ~~~~~
+
+error: unneeded late initalization
+ --> $DIR/needless_late_init_fixable.rs:10:5
+ |
+LL | let c;
+ | ^^^^^^
+ |
+help: declare `c` here
+ |
+LL | let c = 2;
+ | ~~~~~
+
+error: unneeded late initalization
+ --> $DIR/needless_late_init_fixable.rs:14:5
+ |
+LL | let d: usize;
+ | ^^^^^^^^^^^^^
+ |
+help: declare `d` here
+ |
+LL | let d: usize = 1;
+ | ~~~~~~~~~~~~
+
+error: unneeded late initalization
+ --> $DIR/needless_late_init_fixable.rs:17:5
+ |
+LL | let mut e;
+ | ^^^^^^^^^^
+ |
+help: declare `e` here
+ |
+LL | let mut e = 1;
+ | ~~~~~~~~~
+
+error: unneeded late initalization
+ --> $DIR/needless_late_init_fixable.rs:21:5
+ |
+LL | let h;
+ | ^^^^^^
+ |
+help: declare `h` here
+ |
+LL | let h = format!("{}", e);
+ | ~~~~~
+
+error: aborting due to 6 previous errors
+
diff --git a/src/tools/clippy/tests/ui/needless_question_mark.stderr b/src/tools/clippy/tests/ui/needless_question_mark.stderr
index 02bf50d077a..57c3d48c761 100644
--- a/src/tools/clippy/tests/ui/needless_question_mark.stderr
+++ b/src/tools/clippy/tests/ui/needless_question_mark.stderr
@@ -2,7 +2,7 @@ error: question mark operator is useless here
--> $DIR/needless_question_mark.rs:23:12
|
LL | return Some(to.magic?);
- | ^^^^^^^^^^^^^^^ help: try: `to.magic`
+ | ^^^^^^^^^^^^^^^ help: try removing question mark and `Some()`: `to.magic`
|
= note: `-D clippy::needless-question-mark` implied by `-D warnings`
@@ -10,67 +10,67 @@ error: question mark operator is useless here
--> $DIR/needless_question_mark.rs:31:12
|
LL | return Some(to.magic?)
- | ^^^^^^^^^^^^^^^ help: try: `to.magic`
+ | ^^^^^^^^^^^^^^^ help: try removing question mark and `Some()`: `to.magic`
error: question mark operator is useless here
--> $DIR/needless_question_mark.rs:36:5
|
LL | Some(to.magic?)
- | ^^^^^^^^^^^^^^^ help: try: `to.magic`
+ | ^^^^^^^^^^^^^^^ help: try removing question mark and `Some()`: `to.magic`
error: question mark operator is useless here
--> $DIR/needless_question_mark.rs:41:21
|
LL | to.and_then(|t| Some(t.magic?))
- | ^^^^^^^^^^^^^^ help: try: `t.magic`
+ | ^^^^^^^^^^^^^^ help: try removing question mark and `Some()`: `t.magic`
error: question mark operator is useless here
--> $DIR/needless_question_mark.rs:50:9
|
LL | Some(t.magic?)
- | ^^^^^^^^^^^^^^ help: try: `t.magic`
+ | ^^^^^^^^^^^^^^ help: try removing question mark and `Some()`: `t.magic`
error: question mark operator is useless here
--> $DIR/needless_question_mark.rs:55:12
|
LL | return Ok(tr.magic?);
- | ^^^^^^^^^^^^^ help: try: `tr.magic`
+ | ^^^^^^^^^^^^^ help: try removing question mark and `Ok()`: `tr.magic`
error: question mark operator is useless here
--> $DIR/needless_question_mark.rs:62:12
|
LL | return Ok(tr.magic?)
- | ^^^^^^^^^^^^^ help: try: `tr.magic`
+ | ^^^^^^^^^^^^^ help: try removing question mark and `Ok()`: `tr.magic`
error: question mark operator is useless here
--> $DIR/needless_question_mark.rs:66:5
|
LL | Ok(tr.magic?)
- | ^^^^^^^^^^^^^ help: try: `tr.magic`
+ | ^^^^^^^^^^^^^ help: try removing question mark and `Ok()`: `tr.magic`
error: question mark operator is useless here
--> $DIR/needless_question_mark.rs:70:21
|
LL | tr.and_then(|t| Ok(t.magic?))
- | ^^^^^^^^^^^^ help: try: `t.magic`
+ | ^^^^^^^^^^^^ help: try removing question mark and `Ok()`: `t.magic`
error: question mark operator is useless here
--> $DIR/needless_question_mark.rs:78:9
|
LL | Ok(t.magic?)
- | ^^^^^^^^^^^^ help: try: `t.magic`
+ | ^^^^^^^^^^^^ help: try removing question mark and `Ok()`: `t.magic`
error: question mark operator is useless here
--> $DIR/needless_question_mark.rs:85:16
|
LL | return Ok(t.magic?);
- | ^^^^^^^^^^^^ help: try: `t.magic`
+ | ^^^^^^^^^^^^ help: try removing question mark and `Ok()`: `t.magic`
error: question mark operator is useless here
--> $DIR/needless_question_mark.rs:120:27
|
LL | || -> Option<_> { Some(Some($expr)?) }()
- | ^^^^^^^^^^^^^^^^^^ help: try: `Some($expr)`
+ | ^^^^^^^^^^^^^^^^^^ help: try removing question mark and `Some()`: `Some($expr)`
...
LL | let _x = some_and_qmark_in_macro!(x?);
| ---------------------------- in this macro invocation
diff --git a/src/tools/clippy/tests/ui/needless_return.fixed b/src/tools/clippy/tests/ui/needless_return.fixed
index 812ce7163cd..83f467c8400 100644
--- a/src/tools/clippy/tests/ui/needless_return.fixed
+++ b/src/tools/clippy/tests/ui/needless_return.fixed
@@ -108,6 +108,7 @@ fn test_return_in_macro() {
}
mod issue6501 {
+ #[allow(clippy::unnecessary_lazy_evaluations)]
fn foo(bar: Result<(), ()>) {
bar.unwrap_or_else(|_| {})
}
diff --git a/src/tools/clippy/tests/ui/needless_return.rs b/src/tools/clippy/tests/ui/needless_return.rs
index c42567b517c..341caf18bd6 100644
--- a/src/tools/clippy/tests/ui/needless_return.rs
+++ b/src/tools/clippy/tests/ui/needless_return.rs
@@ -108,6 +108,7 @@ fn test_return_in_macro() {
}
mod issue6501 {
+ #[allow(clippy::unnecessary_lazy_evaluations)]
fn foo(bar: Result<(), ()>) {
bar.unwrap_or_else(|_| return)
}
diff --git a/src/tools/clippy/tests/ui/needless_return.stderr b/src/tools/clippy/tests/ui/needless_return.stderr
index 74dda971fda..c0abc2c63dd 100644
--- a/src/tools/clippy/tests/ui/needless_return.stderr
+++ b/src/tools/clippy/tests/ui/needless_return.stderr
@@ -85,109 +85,109 @@ LL | return String::new();
| ^^^^^^^^^^^^^^^^^^^^^ help: remove `return`: `String::new()`
error: unneeded `return` statement
- --> $DIR/needless_return.rs:112:32
+ --> $DIR/needless_return.rs:113:32
|
LL | bar.unwrap_or_else(|_| return)
| ^^^^^^ help: replace `return` with an empty block: `{}`
error: unneeded `return` statement
- --> $DIR/needless_return.rs:117:13
+ --> $DIR/needless_return.rs:118:13
|
LL | return;
| ^^^^^^^ help: remove `return`
error: unneeded `return` statement
- --> $DIR/needless_return.rs:119:20
+ --> $DIR/needless_return.rs:120:20
|
LL | let _ = || return;
| ^^^^^^ help: replace `return` with an empty block: `{}`
error: unneeded `return` statement
- --> $DIR/needless_return.rs:125:32
+ --> $DIR/needless_return.rs:126:32
|
LL | res.unwrap_or_else(|_| return Foo)
| ^^^^^^^^^^ help: remove `return`: `Foo`
error: unneeded `return` statement
- --> $DIR/needless_return.rs:134:5
+ --> $DIR/needless_return.rs:135:5
|
LL | return true;
| ^^^^^^^^^^^^ help: remove `return`: `true`
error: unneeded `return` statement
- --> $DIR/needless_return.rs:138:5
+ --> $DIR/needless_return.rs:139:5
|
LL | return true;
| ^^^^^^^^^^^^ help: remove `return`: `true`
error: unneeded `return` statement
- --> $DIR/needless_return.rs:143:9
+ --> $DIR/needless_return.rs:144:9
|
LL | return true;
| ^^^^^^^^^^^^ help: remove `return`: `true`
error: unneeded `return` statement
- --> $DIR/needless_return.rs:145:9
+ --> $DIR/needless_return.rs:146:9
|
LL | return false;
| ^^^^^^^^^^^^^ help: remove `return`: `false`
error: unneeded `return` statement
- --> $DIR/needless_return.rs:151:17
+ --> $DIR/needless_return.rs:152:17
|
LL | true => return false,
| ^^^^^^^^^^^^ help: remove `return`: `false`
error: unneeded `return` statement
- --> $DIR/needless_return.rs:153:13
+ --> $DIR/needless_return.rs:154:13
|
LL | return true;
| ^^^^^^^^^^^^ help: remove `return`: `true`
error: unneeded `return` statement
- --> $DIR/needless_return.rs:160:9
+ --> $DIR/needless_return.rs:161:9
|
LL | return true;
| ^^^^^^^^^^^^ help: remove `return`: `true`
error: unneeded `return` statement
- --> $DIR/needless_return.rs:162:16
+ --> $DIR/needless_return.rs:163:16
|
LL | let _ = || return true;
| ^^^^^^^^^^^ help: remove `return`: `true`
error: unneeded `return` statement
- --> $DIR/needless_return.rs:170:5
+ --> $DIR/needless_return.rs:171:5
|
LL | return;
| ^^^^^^^ help: remove `return`
error: unneeded `return` statement
- --> $DIR/needless_return.rs:175:9
+ --> $DIR/needless_return.rs:176:9
|
LL | return;
| ^^^^^^^ help: remove `return`
error: unneeded `return` statement
- --> $DIR/needless_return.rs:177:9
+ --> $DIR/needless_return.rs:178:9
|
LL | return;
| ^^^^^^^ help: remove `return`
error: unneeded `return` statement
- --> $DIR/needless_return.rs:184:14
+ --> $DIR/needless_return.rs:185:14
|
LL | _ => return,
| ^^^^^^ help: replace `return` with an empty block: `{}`
error: unneeded `return` statement
- --> $DIR/needless_return.rs:199:9
+ --> $DIR/needless_return.rs:200:9
|
LL | return String::from("test");
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: remove `return`: `String::from("test")`
error: unneeded `return` statement
- --> $DIR/needless_return.rs:201:9
+ --> $DIR/needless_return.rs:202:9
|
LL | return String::new();
| ^^^^^^^^^^^^^^^^^^^^^ help: remove `return`: `String::new()`
diff --git a/src/tools/clippy/tests/ui/needless_splitn.fixed b/src/tools/clippy/tests/ui/needless_splitn.fixed
new file mode 100644
index 00000000000..f6a4b2f17d3
--- /dev/null
+++ b/src/tools/clippy/tests/ui/needless_splitn.fixed
@@ -0,0 +1,27 @@
+// run-rustfix
+// edition:2018
+
+#![feature(custom_inner_attributes)]
+#![warn(clippy::needless_splitn)]
+#![allow(clippy::iter_skip_next, clippy::iter_nth_zero, clippy::manual_split_once)]
+
+extern crate itertools;
+
+#[allow(unused_imports)]
+use itertools::Itertools;
+
+fn main() {
+ let str = "key=value=end";
+ let _ = str.split('=').next();
+ let _ = str.split('=').nth(0);
+ let _ = str.splitn(2, '=').nth(1);
+ let (_, _) = str.splitn(2, '=').next_tuple().unwrap();
+ let (_, _) = str.split('=').next_tuple().unwrap();
+ let _: Vec<&str> = str.splitn(3, '=').collect();
+
+ let _ = str.rsplit('=').next();
+ let _ = str.rsplit('=').nth(0);
+ let _ = str.rsplitn(2, '=').nth(1);
+ let (_, _) = str.rsplitn(2, '=').next_tuple().unwrap();
+ let (_, _) = str.rsplit('=').next_tuple().unwrap();
+}
diff --git a/src/tools/clippy/tests/ui/needless_splitn.rs b/src/tools/clippy/tests/ui/needless_splitn.rs
new file mode 100644
index 00000000000..6ba32255bb2
--- /dev/null
+++ b/src/tools/clippy/tests/ui/needless_splitn.rs
@@ -0,0 +1,27 @@
+// run-rustfix
+// edition:2018
+
+#![feature(custom_inner_attributes)]
+#![warn(clippy::needless_splitn)]
+#![allow(clippy::iter_skip_next, clippy::iter_nth_zero, clippy::manual_split_once)]
+
+extern crate itertools;
+
+#[allow(unused_imports)]
+use itertools::Itertools;
+
+fn main() {
+ let str = "key=value=end";
+ let _ = str.splitn(2, '=').next();
+ let _ = str.splitn(2, '=').nth(0);
+ let _ = str.splitn(2, '=').nth(1);
+ let (_, _) = str.splitn(2, '=').next_tuple().unwrap();
+ let (_, _) = str.splitn(3, '=').next_tuple().unwrap();
+ let _: Vec<&str> = str.splitn(3, '=').collect();
+
+ let _ = str.rsplitn(2, '=').next();
+ let _ = str.rsplitn(2, '=').nth(0);
+ let _ = str.rsplitn(2, '=').nth(1);
+ let (_, _) = str.rsplitn(2, '=').next_tuple().unwrap();
+ let (_, _) = str.rsplitn(3, '=').next_tuple().unwrap();
+}
diff --git a/src/tools/clippy/tests/ui/needless_splitn.stderr b/src/tools/clippy/tests/ui/needless_splitn.stderr
new file mode 100644
index 00000000000..66de2256554
--- /dev/null
+++ b/src/tools/clippy/tests/ui/needless_splitn.stderr
@@ -0,0 +1,40 @@
+error: unnecessary use of `splitn`
+ --> $DIR/needless_splitn.rs:15:13
+ |
+LL | let _ = str.splitn(2, '=').next();
+ | ^^^^^^^^^^^^^^^^^^ help: try this: `str.split('=')`
+ |
+ = note: `-D clippy::needless-splitn` implied by `-D warnings`
+
+error: unnecessary use of `splitn`
+ --> $DIR/needless_splitn.rs:16:13
+ |
+LL | let _ = str.splitn(2, '=').nth(0);
+ | ^^^^^^^^^^^^^^^^^^ help: try this: `str.split('=')`
+
+error: unnecessary use of `splitn`
+ --> $DIR/needless_splitn.rs:19:18
+ |
+LL | let (_, _) = str.splitn(3, '=').next_tuple().unwrap();
+ | ^^^^^^^^^^^^^^^^^^ help: try this: `str.split('=')`
+
+error: unnecessary use of `rsplitn`
+ --> $DIR/needless_splitn.rs:22:13
+ |
+LL | let _ = str.rsplitn(2, '=').next();
+ | ^^^^^^^^^^^^^^^^^^^ help: try this: `str.rsplit('=')`
+
+error: unnecessary use of `rsplitn`
+ --> $DIR/needless_splitn.rs:23:13
+ |
+LL | let _ = str.rsplitn(2, '=').nth(0);
+ | ^^^^^^^^^^^^^^^^^^^ help: try this: `str.rsplit('=')`
+
+error: unnecessary use of `rsplitn`
+ --> $DIR/needless_splitn.rs:26:18
+ |
+LL | let (_, _) = str.rsplitn(3, '=').next_tuple().unwrap();
+ | ^^^^^^^^^^^^^^^^^^^ help: try this: `str.rsplit('=')`
+
+error: aborting due to 6 previous errors
+
diff --git a/src/tools/clippy/tests/ui/no_effect.rs b/src/tools/clippy/tests/ui/no_effect.rs
index 7bcc4cad0d3..5427c88faf3 100644
--- a/src/tools/clippy/tests/ui/no_effect.rs
+++ b/src/tools/clippy/tests/ui/no_effect.rs
@@ -1,4 +1,4 @@
-#![feature(box_syntax)]
+#![feature(box_syntax, fn_traits, unboxed_closures)]
#![warn(clippy::no_effect_underscore_binding)]
#![allow(dead_code)]
#![allow(path_statements)]
@@ -58,6 +58,36 @@ unsafe fn unsafe_fn() -> i32 {
0
}
+struct GreetStruct1;
+
+impl FnOnce<(&str,)> for GreetStruct1 {
+ type Output = ();
+
+ extern "rust-call" fn call_once(self, (who,): (&str,)) -> Self::Output {
+ println!("hello {}", who);
+ }
+}
+
+struct GreetStruct2();
+
+impl FnOnce<(&str,)> for GreetStruct2 {
+ type Output = ();
+
+ extern "rust-call" fn call_once(self, (who,): (&str,)) -> Self::Output {
+ println!("hello {}", who);
+ }
+}
+
+struct GreetStruct3 {}
+
+impl FnOnce<(&str,)> for GreetStruct3 {
+ type Output = ();
+
+ extern "rust-call" fn call_once(self, (who,): (&str,)) -> Self::Output {
+ println!("hello {}", who);
+ }
+}
+
fn main() {
let s = get_struct();
let s2 = get_struct();
@@ -108,4 +138,7 @@ fn main() {
DropTuple(0);
DropEnum::Tuple(0);
DropEnum::Struct { field: 0 };
+ GreetStruct1("world");
+ GreetStruct2()("world");
+ GreetStruct3 {}("world");
}
diff --git a/src/tools/clippy/tests/ui/no_effect.stderr b/src/tools/clippy/tests/ui/no_effect.stderr
index a5dbc9fef45..06b88bb5bee 100644
--- a/src/tools/clippy/tests/ui/no_effect.stderr
+++ b/src/tools/clippy/tests/ui/no_effect.stderr
@@ -1,5 +1,5 @@
error: statement with no effect
- --> $DIR/no_effect.rs:65:5
+ --> $DIR/no_effect.rs:95:5
|
LL | 0;
| ^^
@@ -7,157 +7,157 @@ LL | 0;
= note: `-D clippy::no-effect` implied by `-D warnings`
error: statement with no effect
- --> $DIR/no_effect.rs:66:5
+ --> $DIR/no_effect.rs:96:5
|
LL | s2;
| ^^^
error: statement with no effect
- --> $DIR/no_effect.rs:67:5
+ --> $DIR/no_effect.rs:97:5
|
LL | Unit;
| ^^^^^
error: statement with no effect
- --> $DIR/no_effect.rs:68:5
+ --> $DIR/no_effect.rs:98:5
|
LL | Tuple(0);
| ^^^^^^^^^
error: statement with no effect
- --> $DIR/no_effect.rs:69:5
+ --> $DIR/no_effect.rs:99:5
|
LL | Struct { field: 0 };
| ^^^^^^^^^^^^^^^^^^^^
error: statement with no effect
- --> $DIR/no_effect.rs:70:5
+ --> $DIR/no_effect.rs:100:5
|
LL | Struct { ..s };
| ^^^^^^^^^^^^^^^
error: statement with no effect
- --> $DIR/no_effect.rs:71:5
+ --> $DIR/no_effect.rs:101:5
|
LL | Union { a: 0 };
| ^^^^^^^^^^^^^^^
error: statement with no effect
- --> $DIR/no_effect.rs:72:5
+ --> $DIR/no_effect.rs:102:5
|
LL | Enum::Tuple(0);
| ^^^^^^^^^^^^^^^
error: statement with no effect
- --> $DIR/no_effect.rs:73:5
+ --> $DIR/no_effect.rs:103:5
|
LL | Enum::Struct { field: 0 };
| ^^^^^^^^^^^^^^^^^^^^^^^^^^
error: statement with no effect
- --> $DIR/no_effect.rs:74:5
+ --> $DIR/no_effect.rs:104:5
|
LL | 5 + 6;
| ^^^^^^
error: statement with no effect
- --> $DIR/no_effect.rs:75:5
+ --> $DIR/no_effect.rs:105:5
|
LL | *&42;
| ^^^^^
error: statement with no effect
- --> $DIR/no_effect.rs:76:5
+ --> $DIR/no_effect.rs:106:5
|
LL | &6;
| ^^^
error: statement with no effect
- --> $DIR/no_effect.rs:77:5
+ --> $DIR/no_effect.rs:107:5
|
LL | (5, 6, 7);
| ^^^^^^^^^^
error: statement with no effect
- --> $DIR/no_effect.rs:78:5
+ --> $DIR/no_effect.rs:108:5
|
LL | box 42;
| ^^^^^^^
error: statement with no effect
- --> $DIR/no_effect.rs:79:5
+ --> $DIR/no_effect.rs:109:5
|
LL | ..;
| ^^^
error: statement with no effect
- --> $DIR/no_effect.rs:80:5
+ --> $DIR/no_effect.rs:110:5
|
LL | 5..;
| ^^^^
error: statement with no effect
- --> $DIR/no_effect.rs:81:5
+ --> $DIR/no_effect.rs:111:5
|
LL | ..5;
| ^^^^
error: statement with no effect
- --> $DIR/no_effect.rs:82:5
+ --> $DIR/no_effect.rs:112:5
|
LL | 5..6;
| ^^^^^
error: statement with no effect
- --> $DIR/no_effect.rs:83:5
+ --> $DIR/no_effect.rs:113:5
|
LL | 5..=6;
| ^^^^^^
error: statement with no effect
- --> $DIR/no_effect.rs:84:5
+ --> $DIR/no_effect.rs:114:5
|
LL | [42, 55];
| ^^^^^^^^^
error: statement with no effect
- --> $DIR/no_effect.rs:85:5
+ --> $DIR/no_effect.rs:115:5
|
LL | [42, 55][1];
| ^^^^^^^^^^^^
error: statement with no effect
- --> $DIR/no_effect.rs:86:5
+ --> $DIR/no_effect.rs:116:5
|
LL | (42, 55).1;
| ^^^^^^^^^^^
error: statement with no effect
- --> $DIR/no_effect.rs:87:5
+ --> $DIR/no_effect.rs:117:5
|
LL | [42; 55];
| ^^^^^^^^^
error: statement with no effect
- --> $DIR/no_effect.rs:88:5
+ --> $DIR/no_effect.rs:118:5
|
LL | [42; 55][13];
| ^^^^^^^^^^^^^
error: statement with no effect
- --> $DIR/no_effect.rs:90:5
+ --> $DIR/no_effect.rs:120:5
|
LL | || x += 5;
| ^^^^^^^^^^
error: statement with no effect
- --> $DIR/no_effect.rs:92:5
+ --> $DIR/no_effect.rs:122:5
|
LL | FooString { s: s };
| ^^^^^^^^^^^^^^^^^^^
error: binding to `_` prefixed variable with no side-effect
- --> $DIR/no_effect.rs:93:5
+ --> $DIR/no_effect.rs:123:5
|
LL | let _unused = 1;
| ^^^^^^^^^^^^^^^^
@@ -165,19 +165,19 @@ LL | let _unused = 1;
= note: `-D clippy::no-effect-underscore-binding` implied by `-D warnings`
error: binding to `_` prefixed variable with no side-effect
- --> $DIR/no_effect.rs:94:5
+ --> $DIR/no_effect.rs:124:5
|
LL | let _penguin = || println!("Some helpful closure");
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
error: binding to `_` prefixed variable with no side-effect
- --> $DIR/no_effect.rs:95:5
+ --> $DIR/no_effect.rs:125:5
|
LL | let _duck = Struct { field: 0 };
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
error: binding to `_` prefixed variable with no side-effect
- --> $DIR/no_effect.rs:96:5
+ --> $DIR/no_effect.rs:126:5
|
LL | let _cat = [2, 4, 6, 8][2];
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^
diff --git a/src/tools/clippy/tests/ui/non_send_fields_in_send_ty.rs b/src/tools/clippy/tests/ui/non_send_fields_in_send_ty.rs
index eca7f5e5655..828248d922f 100644
--- a/src/tools/clippy/tests/ui/non_send_fields_in_send_ty.rs
+++ b/src/tools/clippy/tests/ui/non_send_fields_in_send_ty.rs
@@ -69,6 +69,11 @@ pub enum MyOption<T> {
unsafe impl<T> Send for MyOption<T> {}
+// Test types that contain `NonNull` instead of raw pointers (#8045)
+pub struct WrappedNonNull(UnsafeCell<NonNull<()>>);
+
+unsafe impl Send for WrappedNonNull {}
+
// Multiple type parameters
pub struct MultiParam<A, B> {
vec: Vec<(A, B)>,
diff --git a/src/tools/clippy/tests/ui/non_send_fields_in_send_ty.stderr b/src/tools/clippy/tests/ui/non_send_fields_in_send_ty.stderr
index 8b8a1d16d9b..60df4e226e4 100644
--- a/src/tools/clippy/tests/ui/non_send_fields_in_send_ty.stderr
+++ b/src/tools/clippy/tests/ui/non_send_fields_in_send_ty.stderr
@@ -1,167 +1,167 @@
-error: this implementation is unsound, as some fields in `RingBuffer<T>` are `!Send`
+error: some fields in `RingBuffer<T>` are not safe to be sent to another thread
--> $DIR/non_send_fields_in_send_ty.rs:16:1
|
LL | unsafe impl<T> Send for RingBuffer<T> {}
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
= note: `-D clippy::non-send-fields-in-send-ty` implied by `-D warnings`
-note: the type of field `data` is `!Send`
+note: it is not safe to send field `data` to another thread
--> $DIR/non_send_fields_in_send_ty.rs:11:5
|
LL | data: Vec<UnsafeCell<T>>,
| ^^^^^^^^^^^^^^^^^^^^^^^^
= help: add bounds on type parameter `T` that satisfy `Vec<UnsafeCell<T>>: Send`
-error: this implementation is unsound, as some fields in `MvccRwLock<T>` are `!Send`
+error: some fields in `MvccRwLock<T>` are not safe to be sent to another thread
--> $DIR/non_send_fields_in_send_ty.rs:24:1
|
LL | unsafe impl<T> Send for MvccRwLock<T> {}
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
-note: the type of field `lock` is `!Send`
+note: it is not safe to send field `lock` to another thread
--> $DIR/non_send_fields_in_send_ty.rs:21:5
|
LL | lock: Mutex<Box<T>>,
| ^^^^^^^^^^^^^^^^^^^
= help: add bounds on type parameter `T` that satisfy `Mutex<Box<T>>: Send`
-error: this implementation is unsound, as some fields in `ArcGuard<RC, T>` are `!Send`
+error: some fields in `ArcGuard<RC, T>` are not safe to be sent to another thread
--> $DIR/non_send_fields_in_send_ty.rs:32:1
|
LL | unsafe impl<RC, T: Send> Send for ArcGuard<RC, T> {}
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
-note: the type of field `head` is `!Send`
+note: it is not safe to send field `head` to another thread
--> $DIR/non_send_fields_in_send_ty.rs:29:5
|
LL | head: Arc<RC>,
| ^^^^^^^^^^^^^
= help: add bounds on type parameter `RC` that satisfy `Arc<RC>: Send`
-error: this implementation is unsound, as some fields in `DeviceHandle<T>` are `!Send`
+error: some fields in `DeviceHandle<T>` are not safe to be sent to another thread
--> $DIR/non_send_fields_in_send_ty.rs:48:1
|
LL | unsafe impl<T: UsbContext> Send for DeviceHandle<T> {}
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
-note: the type of field `context` is `!Send`
+note: it is not safe to send field `context` to another thread
--> $DIR/non_send_fields_in_send_ty.rs:44:5
|
LL | context: T,
| ^^^^^^^^^^
= help: add `T: Send` bound in `Send` impl
-error: this implementation is unsound, as some fields in `NoGeneric` are `!Send`
+error: some fields in `NoGeneric` are not safe to be sent to another thread
--> $DIR/non_send_fields_in_send_ty.rs:55:1
|
LL | unsafe impl Send for NoGeneric {}
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
-note: the type of field `rc_is_not_send` is `!Send`
+note: it is not safe to send field `rc_is_not_send` to another thread
--> $DIR/non_send_fields_in_send_ty.rs:52:5
|
LL | rc_is_not_send: Rc<String>,
| ^^^^^^^^^^^^^^^^^^^^^^^^^^
= help: use a thread-safe type that implements `Send`
-error: this implementation is unsound, as some fields in `MultiField<T>` are `!Send`
+error: some fields in `MultiField<T>` are not safe to be sent to another thread
--> $DIR/non_send_fields_in_send_ty.rs:63:1
|
LL | unsafe impl<T> Send for MultiField<T> {}
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
-note: the type of field `field1` is `!Send`
+note: it is not safe to send field `field1` to another thread
--> $DIR/non_send_fields_in_send_ty.rs:58:5
|
LL | field1: T,
| ^^^^^^^^^
= help: add `T: Send` bound in `Send` impl
-note: the type of field `field2` is `!Send`
+note: it is not safe to send field `field2` to another thread
--> $DIR/non_send_fields_in_send_ty.rs:59:5
|
LL | field2: T,
| ^^^^^^^^^
= help: add `T: Send` bound in `Send` impl
-note: the type of field `field3` is `!Send`
+note: it is not safe to send field `field3` to another thread
--> $DIR/non_send_fields_in_send_ty.rs:60:5
|
LL | field3: T,
| ^^^^^^^^^
= help: add `T: Send` bound in `Send` impl
-error: this implementation is unsound, as some fields in `MyOption<T>` are `!Send`
+error: some fields in `MyOption<T>` are not safe to be sent to another thread
--> $DIR/non_send_fields_in_send_ty.rs:70:1
|
LL | unsafe impl<T> Send for MyOption<T> {}
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
-note: the type of field `0` is `!Send`
+note: it is not safe to send field `0` to another thread
--> $DIR/non_send_fields_in_send_ty.rs:66:12
|
LL | MySome(T),
| ^
= help: add `T: Send` bound in `Send` impl
-error: this implementation is unsound, as some fields in `MultiParam<A, B>` are `!Send`
- --> $DIR/non_send_fields_in_send_ty.rs:77:1
+error: some fields in `MultiParam<A, B>` are not safe to be sent to another thread
+ --> $DIR/non_send_fields_in_send_ty.rs:82:1
|
LL | unsafe impl<A, B> Send for MultiParam<A, B> {}
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
-note: the type of field `vec` is `!Send`
- --> $DIR/non_send_fields_in_send_ty.rs:74:5
+note: it is not safe to send field `vec` to another thread
+ --> $DIR/non_send_fields_in_send_ty.rs:79:5
|
LL | vec: Vec<(A, B)>,
| ^^^^^^^^^^^^^^^^
= help: add bounds on type parameters `A, B` that satisfy `Vec<(A, B)>: Send`
-error: this implementation is unsound, as some fields in `HeuristicTest` are `!Send`
- --> $DIR/non_send_fields_in_send_ty.rs:95:1
+error: some fields in `HeuristicTest` are not safe to be sent to another thread
+ --> $DIR/non_send_fields_in_send_ty.rs:100:1
|
LL | unsafe impl Send for HeuristicTest {}
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
-note: the type of field `field4` is `!Send`
- --> $DIR/non_send_fields_in_send_ty.rs:90:5
+note: it is not safe to send field `field4` to another thread
+ --> $DIR/non_send_fields_in_send_ty.rs:95:5
|
LL | field4: (*const NonSend, Rc<u8>),
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
= help: use a thread-safe type that implements `Send`
-error: this implementation is unsound, as some fields in `AttrTest3<T>` are `!Send`
- --> $DIR/non_send_fields_in_send_ty.rs:114:1
+error: some fields in `AttrTest3<T>` are not safe to be sent to another thread
+ --> $DIR/non_send_fields_in_send_ty.rs:119:1
|
LL | unsafe impl<T> Send for AttrTest3<T> {}
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
-note: the type of field `0` is `!Send`
- --> $DIR/non_send_fields_in_send_ty.rs:109:11
+note: it is not safe to send field `0` to another thread
+ --> $DIR/non_send_fields_in_send_ty.rs:114:11
|
LL | Enum2(T),
| ^
= help: add `T: Send` bound in `Send` impl
-error: this implementation is unsound, as some fields in `Complex<P, u32>` are `!Send`
- --> $DIR/non_send_fields_in_send_ty.rs:122:1
+error: some fields in `Complex<P, u32>` are not safe to be sent to another thread
+ --> $DIR/non_send_fields_in_send_ty.rs:127:1
|
LL | unsafe impl<P> Send for Complex<P, u32> {}
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
-note: the type of field `field1` is `!Send`
- --> $DIR/non_send_fields_in_send_ty.rs:118:5
+note: it is not safe to send field `field1` to another thread
+ --> $DIR/non_send_fields_in_send_ty.rs:123:5
|
LL | field1: A,
| ^^^^^^^^^
= help: add `P: Send` bound in `Send` impl
-error: this implementation is unsound, as some fields in `Complex<Q, MutexGuard<'static, bool>>` are `!Send`
- --> $DIR/non_send_fields_in_send_ty.rs:125:1
+error: some fields in `Complex<Q, MutexGuard<'static, bool>>` are not safe to be sent to another thread
+ --> $DIR/non_send_fields_in_send_ty.rs:130:1
|
LL | unsafe impl<Q: Send> Send for Complex<Q, MutexGuard<'static, bool>> {}
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
-note: the type of field `field2` is `!Send`
- --> $DIR/non_send_fields_in_send_ty.rs:119:5
+note: it is not safe to send field `field2` to another thread
+ --> $DIR/non_send_fields_in_send_ty.rs:124:5
|
LL | field2: B,
| ^^^^^^^^^
diff --git a/src/tools/clippy/tests/ui/octal_escapes.rs b/src/tools/clippy/tests/ui/octal_escapes.rs
new file mode 100644
index 00000000000..53145ef0fd2
--- /dev/null
+++ b/src/tools/clippy/tests/ui/octal_escapes.rs
@@ -0,0 +1,20 @@
+#![warn(clippy::octal_escapes)]
+
+fn main() {
+ let _bad1 = "\033[0m";
+ let _bad2 = b"\033[0m";
+ let _bad3 = "\\\033[0m";
+ // maximum 3 digits (\012 is the escape)
+ let _bad4 = "\01234567";
+ let _bad5 = "\0\03";
+ let _bad6 = "Text-\055\077-MoreText";
+ let _bad7 = "EvenMoreText-\01\02-ShortEscapes";
+ let _bad8 = "锈\01锈";
+ let _bad9 = "锈\011锈";
+
+ let _good1 = "\\033[0m";
+ let _good2 = "\0\\0";
+ let _good3 = "\0\0";
+ let _good4 = "X\0\0X";
+ let _good5 = "锈\0锈";
+}
diff --git a/src/tools/clippy/tests/ui/octal_escapes.stderr b/src/tools/clippy/tests/ui/octal_escapes.stderr
new file mode 100644
index 00000000000..54f5bbb0fc4
--- /dev/null
+++ b/src/tools/clippy/tests/ui/octal_escapes.stderr
@@ -0,0 +1,131 @@
+error: octal-looking escape in string literal
+ --> $DIR/octal_escapes.rs:4:17
+ |
+LL | let _bad1 = "/033[0m";
+ | ^^^^^^^^^
+ |
+ = note: `-D clippy::octal-escapes` implied by `-D warnings`
+ = help: octal escapes are not supported, `/0` is always a null character
+help: if an octal escape was intended, use the hexadecimal representation instead
+ |
+LL | let _bad1 = "/x1b[0m";
+ | ~~~~~~~~~
+help: if the null character is intended, disambiguate using
+ |
+LL | let _bad1 = "/x0033[0m";
+ | ~~~~~~~~~~~
+
+error: octal-looking escape in byte string literal
+ --> $DIR/octal_escapes.rs:5:17
+ |
+LL | let _bad2 = b"/033[0m";
+ | ^^^^^^^^^^
+ |
+ = help: octal escapes are not supported, `/0` is always a null byte
+help: if an octal escape was intended, use the hexadecimal representation instead
+ |
+LL | let _bad2 = b"/x1b[0m";
+ | ~~~~~~~~~~
+help: if the null byte is intended, disambiguate using
+ |
+LL | let _bad2 = b"/x0033[0m";
+ | ~~~~~~~~~~~~
+
+error: octal-looking escape in string literal
+ --> $DIR/octal_escapes.rs:6:17
+ |
+LL | let _bad3 = "//033[0m";
+ | ^^^^^^^^^^^
+ |
+ = help: octal escapes are not supported, `/0` is always a null character
+help: if an octal escape was intended, use the hexadecimal representation instead
+ |
+LL | let _bad3 = "//x1b[0m";
+ | ~~~~~~~~~~~
+help: if the null character is intended, disambiguate using
+ |
+LL | let _bad3 = "//x0033[0m";
+ | ~~~~~~~~~~~~~
+
+error: octal-looking escape in string literal
+ --> $DIR/octal_escapes.rs:8:17
+ |
+LL | let _bad4 = "/01234567";
+ | ^^^^^^^^^^^
+ |
+ = help: octal escapes are not supported, `/0` is always a null character
+help: if an octal escape was intended, use the hexadecimal representation instead
+ |
+LL | let _bad4 = "/x0a34567";
+ | ~~~~~~~~~~~
+help: if the null character is intended, disambiguate using
+ |
+LL | let _bad4 = "/x001234567";
+ | ~~~~~~~~~~~~~
+
+error: octal-looking escape in string literal
+ --> $DIR/octal_escapes.rs:10:17
+ |
+LL | let _bad6 = "Text-/055/077-MoreText";
+ | ^^^^^^^^^^^^^^^^^^^^^^^^
+ |
+ = help: octal escapes are not supported, `/0` is always a null character
+help: if an octal escape was intended, use the hexadecimal representation instead
+ |
+LL | let _bad6 = "Text-/x2d/x3f-MoreText";
+ | ~~~~~~~~~~~~~~~~~~~~~~~~
+help: if the null character is intended, disambiguate using
+ |
+LL | let _bad6 = "Text-/x0055/x0077-MoreText";
+ | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+error: octal-looking escape in string literal
+ --> $DIR/octal_escapes.rs:11:17
+ |
+LL | let _bad7 = "EvenMoreText-/01/02-ShortEscapes";
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ |
+ = help: octal escapes are not supported, `/0` is always a null character
+help: if an octal escape was intended, use the hexadecimal representation instead
+ |
+LL | let _bad7 = "EvenMoreText-/x01/x02-ShortEscapes";
+ | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+help: if the null character is intended, disambiguate using
+ |
+LL | let _bad7 = "EvenMoreText-/x001/x002-ShortEscapes";
+ | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+error: octal-looking escape in string literal
+ --> $DIR/octal_escapes.rs:12:17
+ |
+LL | let _bad8 = "锈/01锈";
+ | ^^^^^^^^^
+ |
+ = help: octal escapes are not supported, `/0` is always a null character
+help: if an octal escape was intended, use the hexadecimal representation instead
+ |
+LL | let _bad8 = "锈/x01锈";
+ | ~~~~~~~~~~
+help: if the null character is intended, disambiguate using
+ |
+LL | let _bad8 = "锈/x001锈";
+ | ~~~~~~~~~~~
+
+error: octal-looking escape in string literal
+ --> $DIR/octal_escapes.rs:13:17
+ |
+LL | let _bad9 = "锈/011锈";
+ | ^^^^^^^^^^
+ |
+ = help: octal escapes are not supported, `/0` is always a null character
+help: if an octal escape was intended, use the hexadecimal representation instead
+ |
+LL | let _bad9 = "锈/x09锈";
+ | ~~~~~~~~~~
+help: if the null character is intended, disambiguate using
+ |
+LL | let _bad9 = "锈/x0011锈";
+ | ~~~~~~~~~~~~
+
+error: aborting due to 8 previous errors
+
diff --git a/src/tools/clippy/tests/ui/option_env_unwrap.rs b/src/tools/clippy/tests/ui/option_env_unwrap.rs
index 642c77460a3..0141fb7856d 100644
--- a/src/tools/clippy/tests/ui/option_env_unwrap.rs
+++ b/src/tools/clippy/tests/ui/option_env_unwrap.rs
@@ -1,5 +1,6 @@
// aux-build:macro_rules.rs
#![warn(clippy::option_env_unwrap)]
+#![allow(clippy::map_flatten)]
#[macro_use]
extern crate macro_rules;
diff --git a/src/tools/clippy/tests/ui/option_env_unwrap.stderr b/src/tools/clippy/tests/ui/option_env_unwrap.stderr
index e6a58b0b2b7..885ac096cc8 100644
--- a/src/tools/clippy/tests/ui/option_env_unwrap.stderr
+++ b/src/tools/clippy/tests/ui/option_env_unwrap.stderr
@@ -1,5 +1,5 @@
error: this will panic at run-time if the environment variable doesn't exist at compile-time
- --> $DIR/option_env_unwrap.rs:17:13
+ --> $DIR/option_env_unwrap.rs:18:13
|
LL | let _ = option_env!("PATH").unwrap();
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -8,7 +8,7 @@ LL | let _ = option_env!("PATH").unwrap();
= help: consider using the `env!` macro instead
error: this will panic at run-time if the environment variable doesn't exist at compile-time
- --> $DIR/option_env_unwrap.rs:18:13
+ --> $DIR/option_env_unwrap.rs:19:13
|
LL | let _ = option_env!("PATH").expect("environment variable PATH isn't set");
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -16,7 +16,7 @@ LL | let _ = option_env!("PATH").expect("environment variable PATH isn't set
= help: consider using the `env!` macro instead
error: this will panic at run-time if the environment variable doesn't exist at compile-time
- --> $DIR/option_env_unwrap.rs:9:9
+ --> $DIR/option_env_unwrap.rs:10:9
|
LL | option_env!($env).unwrap()
| ^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -28,7 +28,7 @@ LL | let _ = option_env_unwrap!("PATH");
= note: this error originates in the macro `option_env_unwrap` (in Nightly builds, run with -Z macro-backtrace for more info)
error: this will panic at run-time if the environment variable doesn't exist at compile-time
- --> $DIR/option_env_unwrap.rs:12:9
+ --> $DIR/option_env_unwrap.rs:13:9
|
LL | option_env!($env).expect($message)
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -40,7 +40,7 @@ LL | let _ = option_env_unwrap!("PATH", "environment variable PATH isn't set
= note: this error originates in the macro `option_env_unwrap` (in Nightly builds, run with -Z macro-backtrace for more info)
error: this will panic at run-time if the environment variable doesn't exist at compile-time
- --> $DIR/option_env_unwrap.rs:21:13
+ --> $DIR/option_env_unwrap.rs:22:13
|
LL | let _ = option_env_unwrap_external!("PATH");
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -49,7 +49,7 @@ LL | let _ = option_env_unwrap_external!("PATH");
= note: this error originates in the macro `option_env_unwrap_external` (in Nightly builds, run with -Z macro-backtrace for more info)
error: this will panic at run-time if the environment variable doesn't exist at compile-time
- --> $DIR/option_env_unwrap.rs:22:13
+ --> $DIR/option_env_unwrap.rs:23:13
|
LL | let _ = option_env_unwrap_external!("PATH", "environment variable PATH isn't set");
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
diff --git a/src/tools/clippy/tests/ui/option_filter_map.fixed b/src/tools/clippy/tests/ui/option_filter_map.fixed
index f9d1825ade0..b20f73f3110 100644
--- a/src/tools/clippy/tests/ui/option_filter_map.fixed
+++ b/src/tools/clippy/tests/ui/option_filter_map.fixed
@@ -1,8 +1,6 @@
-#![warn(clippy::option_filter_map)]
// run-rustfix
-fn odds_out(x: i32) -> Option<i32> {
- if x % 2 == 0 { Some(x) } else { None }
-}
+#![warn(clippy::option_filter_map)]
+#![allow(clippy::map_flatten)]
fn main() {
let _ = Some(Some(1)).flatten();
@@ -21,3 +19,7 @@ fn main() {
.map(odds_out)
.flatten();
}
+
+fn odds_out(x: i32) -> Option<i32> {
+ if x % 2 == 0 { Some(x) } else { None }
+}
diff --git a/src/tools/clippy/tests/ui/option_filter_map.rs b/src/tools/clippy/tests/ui/option_filter_map.rs
index 588e1ccccce..7abaaa0fb83 100644
--- a/src/tools/clippy/tests/ui/option_filter_map.rs
+++ b/src/tools/clippy/tests/ui/option_filter_map.rs
@@ -1,8 +1,6 @@
-#![warn(clippy::option_filter_map)]
// run-rustfix
-fn odds_out(x: i32) -> Option<i32> {
- if x % 2 == 0 { Some(x) } else { None }
-}
+#![warn(clippy::option_filter_map)]
+#![allow(clippy::map_flatten)]
fn main() {
let _ = Some(Some(1)).filter(Option::is_some).map(Option::unwrap);
@@ -23,3 +21,7 @@ fn main() {
.filter(|o| o.is_some())
.map(|o| o.unwrap());
}
+
+fn odds_out(x: i32) -> Option<i32> {
+ if x % 2 == 0 { Some(x) } else { None }
+}
diff --git a/src/tools/clippy/tests/ui/option_filter_map.stderr b/src/tools/clippy/tests/ui/option_filter_map.stderr
index 31a82969d5a..4a030ac9ab0 100644
--- a/src/tools/clippy/tests/ui/option_filter_map.stderr
+++ b/src/tools/clippy/tests/ui/option_filter_map.stderr
@@ -1,5 +1,5 @@
error: `filter` for `Some` followed by `unwrap`
- --> $DIR/option_filter_map.rs:8:27
+ --> $DIR/option_filter_map.rs:6:27
|
LL | let _ = Some(Some(1)).filter(Option::is_some).map(Option::unwrap);
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `flatten` instead: `flatten()`
@@ -7,37 +7,37 @@ LL | let _ = Some(Some(1)).filter(Option::is_some).map(Option::unwrap);
= note: `-D clippy::option-filter-map` implied by `-D warnings`
error: `filter` for `Some` followed by `unwrap`
- --> $DIR/option_filter_map.rs:9:27
+ --> $DIR/option_filter_map.rs:7:27
|
LL | let _ = Some(Some(1)).filter(|o| o.is_some()).map(|o| o.unwrap());
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `flatten` instead: `flatten()`
error: `filter` for `Some` followed by `unwrap`
- --> $DIR/option_filter_map.rs:10:35
+ --> $DIR/option_filter_map.rs:8:35
|
LL | let _ = Some(1).map(odds_out).filter(Option::is_some).map(Option::unwrap);
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `flatten` instead: `flatten()`
error: `filter` for `Some` followed by `unwrap`
- --> $DIR/option_filter_map.rs:11:35
+ --> $DIR/option_filter_map.rs:9:35
|
LL | let _ = Some(1).map(odds_out).filter(|o| o.is_some()).map(|o| o.unwrap());
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `flatten` instead: `flatten()`
error: `filter` for `Some` followed by `unwrap`
- --> $DIR/option_filter_map.rs:13:39
+ --> $DIR/option_filter_map.rs:11:39
|
LL | let _ = vec![Some(1)].into_iter().filter(Option::is_some).map(Option::unwrap);
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `flatten` instead: `flatten()`
error: `filter` for `Some` followed by `unwrap`
- --> $DIR/option_filter_map.rs:14:39
+ --> $DIR/option_filter_map.rs:12:39
|
LL | let _ = vec![Some(1)].into_iter().filter(|o| o.is_some()).map(|o| o.unwrap());
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `flatten` instead: `flatten()`
error: `filter` for `Some` followed by `unwrap`
- --> $DIR/option_filter_map.rs:18:10
+ --> $DIR/option_filter_map.rs:16:10
|
LL | .filter(Option::is_some)
| __________^
@@ -45,7 +45,7 @@ LL | | .map(Option::unwrap);
| |____________________________^ help: consider using `flatten` instead: `flatten()`
error: `filter` for `Some` followed by `unwrap`
- --> $DIR/option_filter_map.rs:23:10
+ --> $DIR/option_filter_map.rs:21:10
|
LL | .filter(|o| o.is_some())
| __________^
diff --git a/src/tools/clippy/tests/ui/option_if_let_else.fixed b/src/tools/clippy/tests/ui/option_if_let_else.fixed
index 9cb6a9d1ecc..7790c816481 100644
--- a/src/tools/clippy/tests/ui/option_if_let_else.fixed
+++ b/src/tools/clippy/tests/ui/option_if_let_else.fixed
@@ -75,6 +75,30 @@ fn negative_tests(arg: Option<u32>) -> u32 {
7
}
+// #7973
+fn pattern_to_vec(pattern: &str) -> Vec<String> {
+ pattern
+ .trim_matches('/')
+ .split('/')
+ .flat_map(|s| {
+ s.find('.').map_or_else(|| vec![s.to_string()], |idx| vec![s[..idx].to_string(), s[idx..].to_string()])
+ })
+ .collect::<Vec<_>>()
+}
+
+enum DummyEnum {
+ One(u8),
+ Two,
+}
+
+// should not warn since there is a compled complex subpat
+// see #7991
+fn complex_subpat() -> DummyEnum {
+ let x = Some(DummyEnum::One(1));
+ let _ = if let Some(_one @ DummyEnum::One(..)) = x { 1 } else { 2 };
+ DummyEnum::Two
+}
+
fn main() {
let optional = Some(5);
let _ = optional.map_or(5, |x| x + 2);
@@ -110,7 +134,7 @@ fn main() {
let s = String::new();
// Lint, both branches immutably borrow `s`.
- let _ = Some(0).map_or_else(|| s.len(), |x| s.len() + x);
+ let _ = Some(0).map_or(s.len(), |x| s.len() + x);
let s = String::new();
// Lint, `Some` branch consumes `s`, but else branch doesn't use `s`.
@@ -146,4 +170,7 @@ fn main() {
// Don't lint. `await` can't be moved into a closure.
let _ = if let Some(x) = Some(0) { _f1(x).await } else { 0 };
}
+
+ let _ = pattern_to_vec("hello world");
+ let _ = complex_subpat();
}
diff --git a/src/tools/clippy/tests/ui/option_if_let_else.rs b/src/tools/clippy/tests/ui/option_if_let_else.rs
index b3ba5eb870a..3d9f76ee4a6 100644
--- a/src/tools/clippy/tests/ui/option_if_let_else.rs
+++ b/src/tools/clippy/tests/ui/option_if_let_else.rs
@@ -94,6 +94,34 @@ fn negative_tests(arg: Option<u32>) -> u32 {
7
}
+// #7973
+fn pattern_to_vec(pattern: &str) -> Vec<String> {
+ pattern
+ .trim_matches('/')
+ .split('/')
+ .flat_map(|s| {
+ if let Some(idx) = s.find('.') {
+ vec![s[..idx].to_string(), s[idx..].to_string()]
+ } else {
+ vec![s.to_string()]
+ }
+ })
+ .collect::<Vec<_>>()
+}
+
+enum DummyEnum {
+ One(u8),
+ Two,
+}
+
+// should not warn since there is a compled complex subpat
+// see #7991
+fn complex_subpat() -> DummyEnum {
+ let x = Some(DummyEnum::One(1));
+ let _ = if let Some(_one @ DummyEnum::One(..)) = x { 1 } else { 2 };
+ DummyEnum::Two
+}
+
fn main() {
let optional = Some(5);
let _ = if let Some(x) = optional { x + 2 } else { 5 };
@@ -171,4 +199,7 @@ fn main() {
// Don't lint. `await` can't be moved into a closure.
let _ = if let Some(x) = Some(0) { _f1(x).await } else { 0 };
}
+
+ let _ = pattern_to_vec("hello world");
+ let _ = complex_subpat();
}
diff --git a/src/tools/clippy/tests/ui/option_if_let_else.stderr b/src/tools/clippy/tests/ui/option_if_let_else.stderr
index 685bb48ea37..546131ceb5b 100644
--- a/src/tools/clippy/tests/ui/option_if_let_else.stderr
+++ b/src/tools/clippy/tests/ui/option_if_let_else.stderr
@@ -142,14 +142,24 @@ LL + y
LL ~ }, |x| x * x * x * x);
|
+error: use Option::map_or_else instead of an if let/else
+ --> $DIR/option_if_let_else.rs:103:13
+ |
+LL | / if let Some(idx) = s.find('.') {
+LL | | vec![s[..idx].to_string(), s[idx..].to_string()]
+LL | | } else {
+LL | | vec![s.to_string()]
+LL | | }
+ | |_____________^ help: try: `s.find('.').map_or_else(|| vec![s.to_string()], |idx| vec![s[..idx].to_string(), s[idx..].to_string()])`
+
error: use Option::map_or instead of an if let/else
- --> $DIR/option_if_let_else.rs:99:13
+ --> $DIR/option_if_let_else.rs:127:13
|
LL | let _ = if let Some(x) = optional { x + 2 } else { 5 };
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `optional.map_or(5, |x| x + 2)`
error: use Option::map_or instead of an if let/else
- --> $DIR/option_if_let_else.rs:108:13
+ --> $DIR/option_if_let_else.rs:136:13
|
LL | let _ = if let Some(x) = Some(0) {
| _____________^
@@ -170,14 +180,14 @@ LL + }
LL ~ });
|
-error: use Option::map_or_else instead of an if let/else
- --> $DIR/option_if_let_else.rs:136:13
+error: use Option::map_or instead of an if let/else
+ --> $DIR/option_if_let_else.rs:164:13
|
LL | let _ = if let Some(x) = Some(0) { s.len() + x } else { s.len() };
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `Some(0).map_or_else(|| s.len(), |x| s.len() + x)`
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `Some(0).map_or(s.len(), |x| s.len() + x)`
error: use Option::map_or instead of an if let/else
- --> $DIR/option_if_let_else.rs:140:13
+ --> $DIR/option_if_let_else.rs:168:13
|
LL | let _ = if let Some(x) = Some(0) {
| _____________^
@@ -196,5 +206,5 @@ LL + s.len() + x
LL ~ });
|
-error: aborting due to 14 previous errors
+error: aborting due to 15 previous errors
diff --git a/src/tools/clippy/tests/ui/option_map_or_none.fixed b/src/tools/clippy/tests/ui/option_map_or_none.fixed
index d80c3c7c1b7..04bfac7735f 100644
--- a/src/tools/clippy/tests/ui/option_map_or_none.fixed
+++ b/src/tools/clippy/tests/ui/option_map_or_none.fixed
@@ -4,13 +4,23 @@
fn main() {
let opt = Some(1);
+ let r: Result<i32, i32> = Ok(1);
+ let bar = |_| Some(1);
// Check `OPTION_MAP_OR_NONE`.
// Single line case.
- let _ = opt.and_then(|x| Some(x + 1));
+ let _: Option<i32> = opt.map(|x| x + 1);
// Multi-line case.
#[rustfmt::skip]
- let _ = opt.and_then(|x| {
- Some(x + 1)
- });
+ let _: Option<i32> = opt.map(|x| x + 1);
+ // function returning `Option`
+ let _: Option<i32> = opt.and_then(bar);
+ let _: Option<i32> = opt.and_then(|x| {
+ let offset = 0;
+ let height = x;
+ Some(offset + height)
+ });
+
+ // Check `RESULT_MAP_OR_INTO_OPTION`.
+ let _: Option<i32> = r.ok();
}
diff --git a/src/tools/clippy/tests/ui/option_map_or_none.rs b/src/tools/clippy/tests/ui/option_map_or_none.rs
index 629842419e5..bb84f8a48f4 100644
--- a/src/tools/clippy/tests/ui/option_map_or_none.rs
+++ b/src/tools/clippy/tests/ui/option_map_or_none.rs
@@ -4,13 +4,25 @@
fn main() {
let opt = Some(1);
+ let r: Result<i32, i32> = Ok(1);
+ let bar = |_| Some(1);
// Check `OPTION_MAP_OR_NONE`.
// Single line case.
- let _ = opt.map_or(None, |x| Some(x + 1));
+ let _: Option<i32> = opt.map_or(None, |x| Some(x + 1));
// Multi-line case.
#[rustfmt::skip]
- let _ = opt.map_or(None, |x| {
+ let _: Option<i32> = opt.map_or(None, |x| {
Some(x + 1)
});
+ // function returning `Option`
+ let _: Option<i32> = opt.map_or(None, bar);
+ let _: Option<i32> = opt.map_or(None, |x| {
+ let offset = 0;
+ let height = x;
+ Some(offset + height)
+ });
+
+ // Check `RESULT_MAP_OR_INTO_OPTION`.
+ let _: Option<i32> = r.map_or(None, Some);
}
diff --git a/src/tools/clippy/tests/ui/option_map_or_none.stderr b/src/tools/clippy/tests/ui/option_map_or_none.stderr
index 27d68b85e6f..7befcb89086 100644
--- a/src/tools/clippy/tests/ui/option_map_or_none.stderr
+++ b/src/tools/clippy/tests/ui/option_map_or_none.stderr
@@ -1,26 +1,53 @@
-error: called `map_or(None, ..)` on an `Option` value. This can be done more directly by calling `and_then(..)` instead
- --> $DIR/option_map_or_none.rs:10:13
+error: called `map_or(None, ..)` on an `Option` value. This can be done more directly by calling `map(..)` instead
+ --> $DIR/option_map_or_none.rs:12:26
|
-LL | let _ = opt.map_or(None, |x| Some(x + 1));
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try using `and_then` instead: `opt.and_then(|x| Some(x + 1))`
+LL | let _: Option<i32> = opt.map_or(None, |x| Some(x + 1));
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try using `map` instead: `opt.map(|x| x + 1)`
|
= note: `-D clippy::option-map-or-none` implied by `-D warnings`
-error: called `map_or(None, ..)` on an `Option` value. This can be done more directly by calling `and_then(..)` instead
- --> $DIR/option_map_or_none.rs:13:13
+error: called `map_or(None, ..)` on an `Option` value. This can be done more directly by calling `map(..)` instead
+ --> $DIR/option_map_or_none.rs:15:26
|
-LL | let _ = opt.map_or(None, |x| {
- | _____________^
+LL | let _: Option<i32> = opt.map_or(None, |x| {
+ | __________________________^
LL | | Some(x + 1)
LL | | });
- | |_________________________^
+ | |_________________________^ help: try using `map` instead: `opt.map(|x| x + 1)`
+
+error: called `map_or(None, ..)` on an `Option` value. This can be done more directly by calling `and_then(..)` instead
+ --> $DIR/option_map_or_none.rs:19:26
+ |
+LL | let _: Option<i32> = opt.map_or(None, bar);
+ | ^^^^^^^^^^^^^^^^^^^^^ help: try using `and_then` instead: `opt.and_then(bar)`
+
+error: called `map_or(None, ..)` on an `Option` value. This can be done more directly by calling `and_then(..)` instead
+ --> $DIR/option_map_or_none.rs:20:26
+ |
+LL | let _: Option<i32> = opt.map_or(None, |x| {
+ | __________________________^
+LL | | let offset = 0;
+LL | | let height = x;
+LL | | Some(offset + height)
+LL | | });
+ | |______^
|
help: try using `and_then` instead
|
-LL ~ let _ = opt.and_then(|x| {
-LL + Some(x + 1)
-LL ~ });
+LL ~ let _: Option<i32> = opt.and_then(|x| {
+LL + let offset = 0;
+LL + let height = x;
+LL + Some(offset + height)
+LL ~ });
+ |
+
+error: called `map_or(None, Some)` on a `Result` value. This can be done more directly by calling `ok()` instead
+ --> $DIR/option_map_or_none.rs:27:26
+ |
+LL | let _: Option<i32> = r.map_or(None, Some);
+ | ^^^^^^^^^^^^^^^^^^^^ help: try using `ok` instead: `r.ok()`
|
+ = note: `-D clippy::result-map-or-into-option` implied by `-D warnings`
-error: aborting due to 2 previous errors
+error: aborting due to 5 previous errors
diff --git a/src/tools/clippy/tests/ui/or_fun_call.fixed b/src/tools/clippy/tests/ui/or_fun_call.fixed
index c2f94d0e857..d6d6ab49734 100644
--- a/src/tools/clippy/tests/ui/or_fun_call.fixed
+++ b/src/tools/clippy/tests/ui/or_fun_call.fixed
@@ -43,7 +43,7 @@ fn or_fun_call() {
with_enum.unwrap_or(Enum::A(5));
let with_const_fn = Some(Duration::from_secs(1));
- with_const_fn.unwrap_or_else(|| Duration::from_secs(5));
+ with_const_fn.unwrap_or(Duration::from_secs(5));
let with_constructor = Some(vec![1]);
with_constructor.unwrap_or_else(make);
@@ -79,16 +79,16 @@ fn or_fun_call() {
without_default.unwrap_or_else(Foo::new);
let mut map = HashMap::<u64, String>::new();
- map.entry(42).or_insert_with(String::new);
+ map.entry(42).or_insert(String::new());
let mut map_vec = HashMap::<u64, Vec<i32>>::new();
- map_vec.entry(42).or_insert_with(Vec::new);
+ map_vec.entry(42).or_insert(vec![]);
let mut btree = BTreeMap::<u64, String>::new();
- btree.entry(42).or_insert_with(String::new);
+ btree.entry(42).or_insert(String::new());
let mut btree_vec = BTreeMap::<u64, Vec<i32>>::new();
- btree_vec.entry(42).or_insert_with(Vec::new);
+ btree_vec.entry(42).or_insert(vec![]);
let stringy = Some(String::from(""));
let _ = stringy.unwrap_or_else(|| "".to_owned());
@@ -129,7 +129,7 @@ fn test_or_with_ctors() {
let b = "b".to_string();
let _ = Some(Bar("a".to_string(), Duration::from_secs(1)))
- .or_else(|| Some(Bar(b, Duration::from_secs(2))));
+ .or(Some(Bar(b, Duration::from_secs(2))));
let vec = vec!["foo"];
let _ = opt.ok_or(vec.len());
@@ -155,16 +155,24 @@ fn f() -> Option<()> {
}
mod issue6675 {
+ unsafe fn ptr_to_ref<'a, T>(p: *const T) -> &'a T {
+ #[allow(unused)]
+ let x = vec![0; 1000]; // future-proofing, make this function expensive.
+ &*p
+ }
+
unsafe fn foo() {
- let mut s = "test".to_owned();
- None.unwrap_or_else(|| s.as_mut_vec());
+ let s = "test".to_owned();
+ let s = &s as *const _;
+ None.unwrap_or_else(|| ptr_to_ref(s));
}
fn bar() {
- let mut s = "test".to_owned();
- None.unwrap_or_else(|| unsafe { s.as_mut_vec() });
+ let s = "test".to_owned();
+ let s = &s as *const _;
+ None.unwrap_or_else(|| unsafe { ptr_to_ref(s) });
#[rustfmt::skip]
- None.unwrap_or_else(|| unsafe { s.as_mut_vec() });
+ None.unwrap_or_else(|| unsafe { ptr_to_ref(s) });
}
}
diff --git a/src/tools/clippy/tests/ui/or_fun_call.rs b/src/tools/clippy/tests/ui/or_fun_call.rs
index afaf92961b0..8eadc6ce3b4 100644
--- a/src/tools/clippy/tests/ui/or_fun_call.rs
+++ b/src/tools/clippy/tests/ui/or_fun_call.rs
@@ -155,16 +155,24 @@ fn f() -> Option<()> {
}
mod issue6675 {
+ unsafe fn ptr_to_ref<'a, T>(p: *const T) -> &'a T {
+ #[allow(unused)]
+ let x = vec![0; 1000]; // future-proofing, make this function expensive.
+ &*p
+ }
+
unsafe fn foo() {
- let mut s = "test".to_owned();
- None.unwrap_or(s.as_mut_vec());
+ let s = "test".to_owned();
+ let s = &s as *const _;
+ None.unwrap_or(ptr_to_ref(s));
}
fn bar() {
- let mut s = "test".to_owned();
- None.unwrap_or(unsafe { s.as_mut_vec() });
+ let s = "test".to_owned();
+ let s = &s as *const _;
+ None.unwrap_or(unsafe { ptr_to_ref(s) });
#[rustfmt::skip]
- None.unwrap_or( unsafe { s.as_mut_vec() } );
+ None.unwrap_or( unsafe { ptr_to_ref(s) } );
}
}
diff --git a/src/tools/clippy/tests/ui/or_fun_call.stderr b/src/tools/clippy/tests/ui/or_fun_call.stderr
index b2bcbd38c2d..9d0c42b10c2 100644
--- a/src/tools/clippy/tests/ui/or_fun_call.stderr
+++ b/src/tools/clippy/tests/ui/or_fun_call.stderr
@@ -1,16 +1,10 @@
error: use of `unwrap_or` followed by a function call
- --> $DIR/or_fun_call.rs:46:19
- |
-LL | with_const_fn.unwrap_or(Duration::from_secs(5));
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `unwrap_or_else(|| Duration::from_secs(5))`
- |
- = note: `-D clippy::or-fun-call` implied by `-D warnings`
-
-error: use of `unwrap_or` followed by a function call
--> $DIR/or_fun_call.rs:49:22
|
LL | with_constructor.unwrap_or(make());
| ^^^^^^^^^^^^^^^^^ help: try this: `unwrap_or_else(make)`
+ |
+ = note: `-D clippy::or-fun-call` implied by `-D warnings`
error: use of `unwrap_or` followed by a call to `new`
--> $DIR/or_fun_call.rs:52:5
@@ -72,30 +66,6 @@ error: use of `unwrap_or` followed by a function call
LL | without_default.unwrap_or(Foo::new());
| ^^^^^^^^^^^^^^^^^^^^^ help: try this: `unwrap_or_else(Foo::new)`
-error: use of `or_insert` followed by a function call
- --> $DIR/or_fun_call.rs:82:19
- |
-LL | map.entry(42).or_insert(String::new());
- | ^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `or_insert_with(String::new)`
-
-error: use of `or_insert` followed by a function call
- --> $DIR/or_fun_call.rs:85:23
- |
-LL | map_vec.entry(42).or_insert(vec![]);
- | ^^^^^^^^^^^^^^^^^ help: try this: `or_insert_with(Vec::new)`
-
-error: use of `or_insert` followed by a function call
- --> $DIR/or_fun_call.rs:88:21
- |
-LL | btree.entry(42).or_insert(String::new());
- | ^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `or_insert_with(String::new)`
-
-error: use of `or_insert` followed by a function call
- --> $DIR/or_fun_call.rs:91:25
- |
-LL | btree_vec.entry(42).or_insert(vec![]);
- | ^^^^^^^^^^^^^^^^^ help: try this: `or_insert_with(Vec::new)`
-
error: use of `unwrap_or` followed by a function call
--> $DIR/or_fun_call.rs:94:21
|
@@ -120,29 +90,23 @@ error: use of `or` followed by a function call
LL | let _ = Some("a".to_string()).or(Some("b".to_string()));
| ^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `or_else(|| Some("b".to_string()))`
-error: use of `or` followed by a function call
- --> $DIR/or_fun_call.rs:132:10
- |
-LL | .or(Some(Bar(b, Duration::from_secs(2))));
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `or_else(|| Some(Bar(b, Duration::from_secs(2))))`
-
error: use of `unwrap_or` followed by a function call
- --> $DIR/or_fun_call.rs:160:14
+ --> $DIR/or_fun_call.rs:167:14
|
-LL | None.unwrap_or(s.as_mut_vec());
- | ^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `unwrap_or_else(|| s.as_mut_vec())`
+LL | None.unwrap_or(ptr_to_ref(s));
+ | ^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `unwrap_or_else(|| ptr_to_ref(s))`
error: use of `unwrap_or` followed by a function call
- --> $DIR/or_fun_call.rs:165:14
+ --> $DIR/or_fun_call.rs:173:14
|
-LL | None.unwrap_or(unsafe { s.as_mut_vec() });
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `unwrap_or_else(|| unsafe { s.as_mut_vec() })`
+LL | None.unwrap_or(unsafe { ptr_to_ref(s) });
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `unwrap_or_else(|| unsafe { ptr_to_ref(s) })`
error: use of `unwrap_or` followed by a function call
- --> $DIR/or_fun_call.rs:167:14
+ --> $DIR/or_fun_call.rs:175:14
|
-LL | None.unwrap_or( unsafe { s.as_mut_vec() } );
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `unwrap_or_else(|| unsafe { s.as_mut_vec() })`
+LL | None.unwrap_or( unsafe { ptr_to_ref(s) } );
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `unwrap_or_else(|| unsafe { ptr_to_ref(s) })`
-error: aborting due to 24 previous errors
+error: aborting due to 18 previous errors
diff --git a/src/tools/clippy/tests/ui/pattern_type_mismatch/mutability.rs b/src/tools/clippy/tests/ui/pattern_type_mismatch/mutability.rs
index 9b4f2f1f579..55a8c26215e 100644
--- a/src/tools/clippy/tests/ui/pattern_type_mismatch/mutability.rs
+++ b/src/tools/clippy/tests/ui/pattern_type_mismatch/mutability.rs
@@ -37,4 +37,13 @@ fn should_not_lint() {
Some(_) => (),
_ => (),
}
+
+ const FOO: &str = "foo";
+
+ fn foo(s: &str) -> i32 {
+ match s {
+ FOO => 1,
+ _ => 0,
+ }
+ }
}
diff --git a/src/tools/clippy/tests/ui/question_mark.fixed b/src/tools/clippy/tests/ui/question_mark.fixed
index e93469e5f55..13ce0f32d4b 100644
--- a/src/tools/clippy/tests/ui/question_mark.fixed
+++ b/src/tools/clippy/tests/ui/question_mark.fixed
@@ -136,6 +136,24 @@ fn result_func(x: Result<i32, i32>) -> Result<i32, i32> {
Ok(y)
}
+// see issue #8019
+pub enum NotOption {
+ None,
+ First,
+ AfterFirst,
+}
+
+fn obj(_: i32) -> Result<(), NotOption> {
+ Err(NotOption::First)
+}
+
+fn f() -> NotOption {
+ if obj(2).is_err() {
+ return NotOption::None;
+ }
+ NotOption::First
+}
+
fn main() {
some_func(Some(42));
some_func(None);
@@ -157,4 +175,5 @@ fn main() {
func();
let _ = result_func(Ok(42));
+ let _ = f();
}
diff --git a/src/tools/clippy/tests/ui/question_mark.rs b/src/tools/clippy/tests/ui/question_mark.rs
index dd179e9bee8..60590fd9311 100644
--- a/src/tools/clippy/tests/ui/question_mark.rs
+++ b/src/tools/clippy/tests/ui/question_mark.rs
@@ -168,6 +168,24 @@ fn result_func(x: Result<i32, i32>) -> Result<i32, i32> {
Ok(y)
}
+// see issue #8019
+pub enum NotOption {
+ None,
+ First,
+ AfterFirst,
+}
+
+fn obj(_: i32) -> Result<(), NotOption> {
+ Err(NotOption::First)
+}
+
+fn f() -> NotOption {
+ if obj(2).is_err() {
+ return NotOption::None;
+ }
+ NotOption::First
+}
+
fn main() {
some_func(Some(42));
some_func(None);
@@ -189,4 +207,5 @@ fn main() {
func();
let _ = result_func(Ok(42));
+ let _ = f();
}
diff --git a/src/tools/clippy/tests/ui/redundant_closure_call_late.rs b/src/tools/clippy/tests/ui/redundant_closure_call_late.rs
index 1f4864b7289..5612827bd39 100644
--- a/src/tools/clippy/tests/ui/redundant_closure_call_late.rs
+++ b/src/tools/clippy/tests/ui/redundant_closure_call_late.rs
@@ -1,6 +1,7 @@
// non rustfixable, see redundant_closure_call_fixable.rs
#![warn(clippy::redundant_closure_call)]
+#![allow(clippy::needless_late_init)]
fn main() {
let mut i = 1;
diff --git a/src/tools/clippy/tests/ui/redundant_closure_call_late.stderr b/src/tools/clippy/tests/ui/redundant_closure_call_late.stderr
index 7c8865f1bd3..4eca43a2b59 100644
--- a/src/tools/clippy/tests/ui/redundant_closure_call_late.stderr
+++ b/src/tools/clippy/tests/ui/redundant_closure_call_late.stderr
@@ -1,5 +1,5 @@
error: closure called just once immediately after it was declared
- --> $DIR/redundant_closure_call_late.rs:15:5
+ --> $DIR/redundant_closure_call_late.rs:16:5
|
LL | i = redun_closure();
| ^^^^^^^^^^^^^^^^^^^
@@ -7,13 +7,13 @@ LL | i = redun_closure();
= note: `-D clippy::redundant-closure-call` implied by `-D warnings`
error: closure called just once immediately after it was declared
- --> $DIR/redundant_closure_call_late.rs:19:5
+ --> $DIR/redundant_closure_call_late.rs:20:5
|
LL | i = shadowed_closure();
| ^^^^^^^^^^^^^^^^^^^^^^
error: closure called just once immediately after it was declared
- --> $DIR/redundant_closure_call_late.rs:21:5
+ --> $DIR/redundant_closure_call_late.rs:22:5
|
LL | i = shadowed_closure();
| ^^^^^^^^^^^^^^^^^^^^^^
diff --git a/src/tools/clippy/tests/ui/redundant_else.rs b/src/tools/clippy/tests/ui/redundant_else.rs
index e8a6e940c01..64f566735cd 100644
--- a/src/tools/clippy/tests/ui/redundant_else.rs
+++ b/src/tools/clippy/tests/ui/redundant_else.rs
@@ -1,5 +1,5 @@
#![warn(clippy::redundant_else)]
-#![allow(clippy::needless_return, clippy::if_same_then_else)]
+#![allow(clippy::needless_return, clippy::if_same_then_else, clippy::needless_late_init)]
fn main() {
loop {
diff --git a/src/tools/clippy/tests/ui/redundant_pattern_matching_option.fixed b/src/tools/clippy/tests/ui/redundant_pattern_matching_option.fixed
index 813e268a60c..cc93859269c 100644
--- a/src/tools/clippy/tests/ui/redundant_pattern_matching_option.fixed
+++ b/src/tools/clippy/tests/ui/redundant_pattern_matching_option.fixed
@@ -80,3 +80,9 @@ const fn issue6067() {
None::<()>.is_none();
}
+
+#[allow(clippy::deref_addrof, dead_code)]
+fn issue7921() {
+ if (&None::<()>).is_none() {}
+ if (&None::<()>).is_none() {}
+}
diff --git a/src/tools/clippy/tests/ui/redundant_pattern_matching_option.rs b/src/tools/clippy/tests/ui/redundant_pattern_matching_option.rs
index 82a98468943..280dca40c01 100644
--- a/src/tools/clippy/tests/ui/redundant_pattern_matching_option.rs
+++ b/src/tools/clippy/tests/ui/redundant_pattern_matching_option.rs
@@ -95,3 +95,9 @@ const fn issue6067() {
None => true,
};
}
+
+#[allow(clippy::deref_addrof, dead_code)]
+fn issue7921() {
+ if let None = *(&None::<()>) {}
+ if let None = *&None::<()> {}
+}
diff --git a/src/tools/clippy/tests/ui/redundant_pattern_matching_option.stderr b/src/tools/clippy/tests/ui/redundant_pattern_matching_option.stderr
index 3a58e5ad7be..27ff812ba45 100644
--- a/src/tools/clippy/tests/ui/redundant_pattern_matching_option.stderr
+++ b/src/tools/clippy/tests/ui/redundant_pattern_matching_option.stderr
@@ -130,5 +130,17 @@ LL | | None => true,
LL | | };
| |_____^ help: try this: `None::<()>.is_none()`
-error: aborting due to 19 previous errors
+error: redundant pattern matching, consider using `is_none()`
+ --> $DIR/redundant_pattern_matching_option.rs:101:12
+ |
+LL | if let None = *(&None::<()>) {}
+ | -------^^^^----------------- help: try this: `if (&None::<()>).is_none()`
+
+error: redundant pattern matching, consider using `is_none()`
+ --> $DIR/redundant_pattern_matching_option.rs:102:12
+ |
+LL | if let None = *&None::<()> {}
+ | -------^^^^--------------- help: try this: `if (&None::<()>).is_none()`
+
+error: aborting due to 21 previous errors
diff --git a/src/tools/clippy/tests/ui/redundant_pattern_matching_result.fixed b/src/tools/clippy/tests/ui/redundant_pattern_matching_result.fixed
index d7af5d762ae..83c783385ef 100644
--- a/src/tools/clippy/tests/ui/redundant_pattern_matching_result.fixed
+++ b/src/tools/clippy/tests/ui/redundant_pattern_matching_result.fixed
@@ -70,8 +70,8 @@ fn issue5504() {
}
fn try_result_opt() -> Result<i32, i32> {
- while r#try!(result_opt()).is_some() {}
- if r#try!(result_opt()).is_some() {}
+ while (r#try!(result_opt())).is_some() {}
+ if (r#try!(result_opt())).is_some() {}
Ok(42)
}
diff --git a/src/tools/clippy/tests/ui/redundant_pattern_matching_result.stderr b/src/tools/clippy/tests/ui/redundant_pattern_matching_result.stderr
index e06f095da20..d674d061e4d 100644
--- a/src/tools/clippy/tests/ui/redundant_pattern_matching_result.stderr
+++ b/src/tools/clippy/tests/ui/redundant_pattern_matching_result.stderr
@@ -88,13 +88,13 @@ error: redundant pattern matching, consider using `is_some()`
--> $DIR/redundant_pattern_matching_result.rs:85:19
|
LL | while let Some(_) = r#try!(result_opt()) {}
- | ----------^^^^^^^----------------------- help: try this: `while r#try!(result_opt()).is_some()`
+ | ----------^^^^^^^----------------------- help: try this: `while (r#try!(result_opt())).is_some()`
error: redundant pattern matching, consider using `is_some()`
--> $DIR/redundant_pattern_matching_result.rs:86:16
|
LL | if let Some(_) = r#try!(result_opt()) {}
- | -------^^^^^^^----------------------- help: try this: `if r#try!(result_opt()).is_some()`
+ | -------^^^^^^^----------------------- help: try this: `if (r#try!(result_opt())).is_some()`
error: redundant pattern matching, consider using `is_some()`
--> $DIR/redundant_pattern_matching_result.rs:92:12
diff --git a/src/tools/clippy/tests/ui/rename.fixed b/src/tools/clippy/tests/ui/rename.fixed
index cc295b509bc..b9425733a8b 100644
--- a/src/tools/clippy/tests/ui/rename.fixed
+++ b/src/tools/clippy/tests/ui/rename.fixed
@@ -6,6 +6,7 @@
#![allow(clippy::module_name_repetitions)]
#![allow(clippy::new_without_default)]
#![allow(clippy::redundant_static_lifetimes)]
+#![allow(clippy::cognitive_complexity)]
#![allow(clippy::bind_instead_of_map)]
#![allow(clippy::box_collection)]
#![allow(clippy::blocks_in_if_conditions)]
@@ -17,6 +18,8 @@
#![allow(clippy::invisible_characters)]
#![allow(clippy::single_char_add_str)]
#![allow(clippy::match_result_ok)]
+#![allow(clippy::disallowed_types)]
+#![allow(clippy::disallowed_methods)]
// uplifted lints
#![allow(invalid_value)]
#![allow(array_into_iter)]
@@ -49,6 +52,8 @@
#![warn(clippy::invisible_characters)]
#![warn(clippy::single_char_add_str)]
#![warn(clippy::match_result_ok)]
+#![warn(clippy::disallowed_types)]
+#![warn(clippy::disallowed_methods)]
// uplifted lints
#![warn(invalid_value)]
#![warn(array_into_iter)]
diff --git a/src/tools/clippy/tests/ui/rename.rs b/src/tools/clippy/tests/ui/rename.rs
index 377075c0246..341c003b9df 100644
--- a/src/tools/clippy/tests/ui/rename.rs
+++ b/src/tools/clippy/tests/ui/rename.rs
@@ -6,6 +6,7 @@
#![allow(clippy::module_name_repetitions)]
#![allow(clippy::new_without_default)]
#![allow(clippy::redundant_static_lifetimes)]
+#![allow(clippy::cognitive_complexity)]
#![allow(clippy::bind_instead_of_map)]
#![allow(clippy::box_collection)]
#![allow(clippy::blocks_in_if_conditions)]
@@ -17,6 +18,8 @@
#![allow(clippy::invisible_characters)]
#![allow(clippy::single_char_add_str)]
#![allow(clippy::match_result_ok)]
+#![allow(clippy::disallowed_types)]
+#![allow(clippy::disallowed_methods)]
// uplifted lints
#![allow(invalid_value)]
#![allow(array_into_iter)]
@@ -49,6 +52,8 @@
#![warn(clippy::zero_width_space)]
#![warn(clippy::single_char_push_str)]
#![warn(clippy::if_let_some_result)]
+#![warn(clippy::disallowed_type)]
+#![warn(clippy::disallowed_method)]
// uplifted lints
#![warn(clippy::invalid_ref)]
#![warn(clippy::into_iter_on_array)]
diff --git a/src/tools/clippy/tests/ui/rename.stderr b/src/tools/clippy/tests/ui/rename.stderr
index d720f10d117..cdec2808f1d 100644
--- a/src/tools/clippy/tests/ui/rename.stderr
+++ b/src/tools/clippy/tests/ui/rename.stderr
@@ -1,5 +1,5 @@
error: lint `clippy::stutter` has been renamed to `clippy::module_name_repetitions`
- --> $DIR/rename.rs:31:9
+ --> $DIR/rename.rs:34:9
|
LL | #![warn(clippy::stutter)]
| ^^^^^^^^^^^^^^^ help: use the new name: `clippy::module_name_repetitions`
@@ -7,178 +7,190 @@ LL | #![warn(clippy::stutter)]
= note: `-D renamed-and-removed-lints` implied by `-D warnings`
error: lint `clippy::new_without_default_derive` has been renamed to `clippy::new_without_default`
- --> $DIR/rename.rs:32:9
+ --> $DIR/rename.rs:35:9
|
LL | #![warn(clippy::new_without_default_derive)]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::new_without_default`
error: lint `clippy::const_static_lifetime` has been renamed to `clippy::redundant_static_lifetimes`
- --> $DIR/rename.rs:33:9
+ --> $DIR/rename.rs:36:9
|
LL | #![warn(clippy::const_static_lifetime)]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::redundant_static_lifetimes`
error: lint `clippy::cyclomatic_complexity` has been renamed to `clippy::cognitive_complexity`
- --> $DIR/rename.rs:34:9
+ --> $DIR/rename.rs:37:9
|
LL | #![warn(clippy::cyclomatic_complexity)]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::cognitive_complexity`
error: lint `clippy::option_and_then_some` has been renamed to `clippy::bind_instead_of_map`
- --> $DIR/rename.rs:35:9
+ --> $DIR/rename.rs:38:9
|
LL | #![warn(clippy::option_and_then_some)]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::bind_instead_of_map`
error: lint `clippy::box_vec` has been renamed to `clippy::box_collection`
- --> $DIR/rename.rs:36:9
+ --> $DIR/rename.rs:39:9
|
LL | #![warn(clippy::box_vec)]
| ^^^^^^^^^^^^^^^ help: use the new name: `clippy::box_collection`
error: lint `clippy::block_in_if_condition_expr` has been renamed to `clippy::blocks_in_if_conditions`
- --> $DIR/rename.rs:37:9
+ --> $DIR/rename.rs:40:9
|
LL | #![warn(clippy::block_in_if_condition_expr)]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::blocks_in_if_conditions`
error: lint `clippy::block_in_if_condition_stmt` has been renamed to `clippy::blocks_in_if_conditions`
- --> $DIR/rename.rs:38:9
+ --> $DIR/rename.rs:41:9
|
LL | #![warn(clippy::block_in_if_condition_stmt)]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::blocks_in_if_conditions`
error: lint `clippy::option_map_unwrap_or` has been renamed to `clippy::map_unwrap_or`
- --> $DIR/rename.rs:39:9
+ --> $DIR/rename.rs:42:9
|
LL | #![warn(clippy::option_map_unwrap_or)]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::map_unwrap_or`
error: lint `clippy::option_map_unwrap_or_else` has been renamed to `clippy::map_unwrap_or`
- --> $DIR/rename.rs:40:9
+ --> $DIR/rename.rs:43:9
|
LL | #![warn(clippy::option_map_unwrap_or_else)]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::map_unwrap_or`
error: lint `clippy::result_map_unwrap_or_else` has been renamed to `clippy::map_unwrap_or`
- --> $DIR/rename.rs:41:9
+ --> $DIR/rename.rs:44:9
|
LL | #![warn(clippy::result_map_unwrap_or_else)]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::map_unwrap_or`
error: lint `clippy::option_unwrap_used` has been renamed to `clippy::unwrap_used`
- --> $DIR/rename.rs:42:9
+ --> $DIR/rename.rs:45:9
|
LL | #![warn(clippy::option_unwrap_used)]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::unwrap_used`
error: lint `clippy::result_unwrap_used` has been renamed to `clippy::unwrap_used`
- --> $DIR/rename.rs:43:9
+ --> $DIR/rename.rs:46:9
|
LL | #![warn(clippy::result_unwrap_used)]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::unwrap_used`
error: lint `clippy::option_expect_used` has been renamed to `clippy::expect_used`
- --> $DIR/rename.rs:44:9
+ --> $DIR/rename.rs:47:9
|
LL | #![warn(clippy::option_expect_used)]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::expect_used`
error: lint `clippy::result_expect_used` has been renamed to `clippy::expect_used`
- --> $DIR/rename.rs:45:9
+ --> $DIR/rename.rs:48:9
|
LL | #![warn(clippy::result_expect_used)]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::expect_used`
error: lint `clippy::for_loop_over_option` has been renamed to `clippy::for_loops_over_fallibles`
- --> $DIR/rename.rs:46:9
+ --> $DIR/rename.rs:49:9
|
LL | #![warn(clippy::for_loop_over_option)]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::for_loops_over_fallibles`
error: lint `clippy::for_loop_over_result` has been renamed to `clippy::for_loops_over_fallibles`
- --> $DIR/rename.rs:47:9
+ --> $DIR/rename.rs:50:9
|
LL | #![warn(clippy::for_loop_over_result)]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::for_loops_over_fallibles`
error: lint `clippy::identity_conversion` has been renamed to `clippy::useless_conversion`
- --> $DIR/rename.rs:48:9
+ --> $DIR/rename.rs:51:9
|
LL | #![warn(clippy::identity_conversion)]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::useless_conversion`
error: lint `clippy::zero_width_space` has been renamed to `clippy::invisible_characters`
- --> $DIR/rename.rs:49:9
+ --> $DIR/rename.rs:52:9
|
LL | #![warn(clippy::zero_width_space)]
| ^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::invisible_characters`
error: lint `clippy::single_char_push_str` has been renamed to `clippy::single_char_add_str`
- --> $DIR/rename.rs:50:9
+ --> $DIR/rename.rs:53:9
|
LL | #![warn(clippy::single_char_push_str)]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::single_char_add_str`
error: lint `clippy::if_let_some_result` has been renamed to `clippy::match_result_ok`
- --> $DIR/rename.rs:51:9
+ --> $DIR/rename.rs:54:9
|
LL | #![warn(clippy::if_let_some_result)]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::match_result_ok`
+error: lint `clippy::disallowed_type` has been renamed to `clippy::disallowed_types`
+ --> $DIR/rename.rs:55:9
+ |
+LL | #![warn(clippy::disallowed_type)]
+ | ^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::disallowed_types`
+
+error: lint `clippy::disallowed_method` has been renamed to `clippy::disallowed_methods`
+ --> $DIR/rename.rs:56:9
+ |
+LL | #![warn(clippy::disallowed_method)]
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::disallowed_methods`
+
error: lint `clippy::invalid_ref` has been renamed to `invalid_value`
- --> $DIR/rename.rs:53:9
+ --> $DIR/rename.rs:58:9
|
LL | #![warn(clippy::invalid_ref)]
| ^^^^^^^^^^^^^^^^^^^ help: use the new name: `invalid_value`
error: lint `clippy::into_iter_on_array` has been renamed to `array_into_iter`
- --> $DIR/rename.rs:54:9
+ --> $DIR/rename.rs:59:9
|
LL | #![warn(clippy::into_iter_on_array)]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `array_into_iter`
error: lint `clippy::unused_label` has been renamed to `unused_labels`
- --> $DIR/rename.rs:55:9
+ --> $DIR/rename.rs:60:9
|
LL | #![warn(clippy::unused_label)]
| ^^^^^^^^^^^^^^^^^^^^ help: use the new name: `unused_labels`
error: lint `clippy::drop_bounds` has been renamed to `drop_bounds`
- --> $DIR/rename.rs:56:9
+ --> $DIR/rename.rs:61:9
|
LL | #![warn(clippy::drop_bounds)]
| ^^^^^^^^^^^^^^^^^^^ help: use the new name: `drop_bounds`
error: lint `clippy::temporary_cstring_as_ptr` has been renamed to `temporary_cstring_as_ptr`
- --> $DIR/rename.rs:57:9
+ --> $DIR/rename.rs:62:9
|
LL | #![warn(clippy::temporary_cstring_as_ptr)]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `temporary_cstring_as_ptr`
error: lint `clippy::panic_params` has been renamed to `non_fmt_panics`
- --> $DIR/rename.rs:58:9
+ --> $DIR/rename.rs:63:9
|
LL | #![warn(clippy::panic_params)]
| ^^^^^^^^^^^^^^^^^^^^ help: use the new name: `non_fmt_panics`
error: lint `clippy::unknown_clippy_lints` has been renamed to `unknown_lints`
- --> $DIR/rename.rs:59:9
+ --> $DIR/rename.rs:64:9
|
LL | #![warn(clippy::unknown_clippy_lints)]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `unknown_lints`
error: lint `clippy::invalid_atomic_ordering` has been renamed to `invalid_atomic_ordering`
- --> $DIR/rename.rs:60:9
+ --> $DIR/rename.rs:65:9
|
LL | #![warn(clippy::invalid_atomic_ordering)]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `invalid_atomic_ordering`
error: lint `clippy::mem_discriminant_non_enum` has been renamed to `enum_intrinsics_non_enums`
- --> $DIR/rename.rs:61:9
+ --> $DIR/rename.rs:66:9
|
LL | #![warn(clippy::mem_discriminant_non_enum)]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `enum_intrinsics_non_enums`
-error: aborting due to 30 previous errors
+error: aborting due to 32 previous errors
diff --git a/src/tools/clippy/tests/ui/return_self_not_must_use.rs b/src/tools/clippy/tests/ui/return_self_not_must_use.rs
new file mode 100644
index 00000000000..bdf3f3d7995
--- /dev/null
+++ b/src/tools/clippy/tests/ui/return_self_not_must_use.rs
@@ -0,0 +1,42 @@
+#![crate_type = "lib"]
+
+#[derive(Clone)]
+pub struct Bar;
+
+pub trait Whatever {
+ fn what(&self) -> Self;
+ // There should be no warning here!
+ fn what2(&self) -> &Self;
+}
+
+impl Bar {
+ // There should be no warning here!
+ pub fn not_new() -> Self {
+ Self
+ }
+ pub fn foo(&self) -> Self {
+ Self
+ }
+ pub fn bar(self) -> Self {
+ self
+ }
+ // There should be no warning here!
+ fn foo2(&self) -> Self {
+ Self
+ }
+ // There should be no warning here!
+ pub fn foo3(&self) -> &Self {
+ self
+ }
+}
+
+impl Whatever for Bar {
+ // There should be no warning here!
+ fn what(&self) -> Self {
+ self.foo2()
+ }
+ // There should be no warning here!
+ fn what2(&self) -> &Self {
+ self
+ }
+}
diff --git a/src/tools/clippy/tests/ui/return_self_not_must_use.stderr b/src/tools/clippy/tests/ui/return_self_not_must_use.stderr
new file mode 100644
index 00000000000..3793a5559ba
--- /dev/null
+++ b/src/tools/clippy/tests/ui/return_self_not_must_use.stderr
@@ -0,0 +1,26 @@
+error: missing `#[must_use]` attribute on a method returning `Self`
+ --> $DIR/return_self_not_must_use.rs:7:5
+ |
+LL | fn what(&self) -> Self;
+ | ^^^^^^^^^^^^^^^^^^^^^^^
+ |
+ = note: `-D clippy::return-self-not-must-use` implied by `-D warnings`
+
+error: missing `#[must_use]` attribute on a method returning `Self`
+ --> $DIR/return_self_not_must_use.rs:17:5
+ |
+LL | / pub fn foo(&self) -> Self {
+LL | | Self
+LL | | }
+ | |_____^
+
+error: missing `#[must_use]` attribute on a method returning `Self`
+ --> $DIR/return_self_not_must_use.rs:20:5
+ |
+LL | / pub fn bar(self) -> Self {
+LL | | self
+LL | | }
+ | |_____^
+
+error: aborting due to 3 previous errors
+
diff --git a/src/tools/clippy/tests/ui/same_name_method.stderr b/src/tools/clippy/tests/ui/same_name_method.stderr
index 0f9139b41b9..c32c3dd9880 100644
--- a/src/tools/clippy/tests/ui/same_name_method.stderr
+++ b/src/tools/clippy/tests/ui/same_name_method.stderr
@@ -1,4 +1,4 @@
-error: method's name is same to an existing method in a trait
+error: method's name is the same as an existing method in a trait
--> $DIR/same_name_method.rs:20:13
|
LL | fn foo() {}
@@ -11,7 +11,7 @@ note: existing `foo` defined here
LL | fn foo() {}
| ^^^^^^^^^^^
-error: method's name is same to an existing method in a trait
+error: method's name is the same as an existing method in a trait
--> $DIR/same_name_method.rs:44:13
|
LL | fn foo() {}
@@ -23,7 +23,7 @@ note: existing `foo` defined here
LL | fn foo() {}
| ^^^^^^^^^^^
-error: method's name is same to an existing method in a trait
+error: method's name is the same as an existing method in a trait
--> $DIR/same_name_method.rs:58:13
|
LL | fn foo() {}
@@ -35,7 +35,7 @@ note: existing `foo` defined here
LL | impl T1 for S {}
| ^^^^^^^^^^^^^^^^
-error: method's name is same to an existing method in a trait
+error: method's name is the same as an existing method in a trait
--> $DIR/same_name_method.rs:70:13
|
LL | fn foo() {}
@@ -47,7 +47,7 @@ note: existing `foo` defined here
LL | impl T1 for S {}
| ^^^^^^^^^^^^^^^^
-error: method's name is same to an existing method in a trait
+error: method's name is the same as an existing method in a trait
--> $DIR/same_name_method.rs:34:13
|
LL | fn clone() {}
diff --git a/src/tools/clippy/tests/ui/search_is_some.rs b/src/tools/clippy/tests/ui/search_is_some.rs
index 72bc6ef35d3..72f335153c1 100644
--- a/src/tools/clippy/tests/ui/search_is_some.rs
+++ b/src/tools/clippy/tests/ui/search_is_some.rs
@@ -36,6 +36,9 @@ fn main() {
// check that we don't lint if `find()` is called with
// `Pattern` that is not a string
let _ = "hello world".find(|c: char| c == 'o' || c == 'l').is_some();
+
+ let some_closure = |x: &u32| *x == 0;
+ let _ = (0..1).find(some_closure).is_some();
}
#[rustfmt::skip]
@@ -70,4 +73,7 @@ fn is_none() {
// check that we don't lint if `find()` is called with
// `Pattern` that is not a string
let _ = "hello world".find(|c: char| c == 'o' || c == 'l').is_none();
+
+ let some_closure = |x: &u32| *x == 0;
+ let _ = (0..1).find(some_closure).is_none();
}
diff --git a/src/tools/clippy/tests/ui/search_is_some.stderr b/src/tools/clippy/tests/ui/search_is_some.stderr
index f3c758e451e..54760545bce 100644
--- a/src/tools/clippy/tests/ui/search_is_some.stderr
+++ b/src/tools/clippy/tests/ui/search_is_some.stderr
@@ -35,8 +35,14 @@ LL | | ).is_some();
|
= help: this is more succinctly expressed by calling `any()`
+error: called `is_some()` after searching an `Iterator` with `find`
+ --> $DIR/search_is_some.rs:41:20
+ |
+LL | let _ = (0..1).find(some_closure).is_some();
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `any()` instead: `any(some_closure)`
+
error: called `is_none()` after searching an `Iterator` with `find`
- --> $DIR/search_is_some.rs:48:13
+ --> $DIR/search_is_some.rs:51:13
|
LL | let _ = v.iter().find(|&x| {
| _____________^
@@ -48,7 +54,7 @@ LL | | ).is_none();
= help: this is more succinctly expressed by calling `any()` with negation
error: called `is_none()` after searching an `Iterator` with `position`
- --> $DIR/search_is_some.rs:54:13
+ --> $DIR/search_is_some.rs:57:13
|
LL | let _ = v.iter().position(|&x| {
| _____________^
@@ -60,7 +66,7 @@ LL | | ).is_none();
= help: this is more succinctly expressed by calling `any()` with negation
error: called `is_none()` after searching an `Iterator` with `rposition`
- --> $DIR/search_is_some.rs:60:13
+ --> $DIR/search_is_some.rs:63:13
|
LL | let _ = v.iter().rposition(|&x| {
| _____________^
@@ -71,5 +77,11 @@ LL | | ).is_none();
|
= help: this is more succinctly expressed by calling `any()` with negation
-error: aborting due to 6 previous errors
+error: called `is_none()` after searching an `Iterator` with `find`
+ --> $DIR/search_is_some.rs:78:13
+ |
+LL | let _ = (0..1).find(some_closure).is_none();
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `!_.any()` instead: `!(0..1).any(some_closure)`
+
+error: aborting due to 8 previous errors
diff --git a/src/tools/clippy/tests/ui/search_is_some_fixable.fixed b/src/tools/clippy/tests/ui/search_is_some_fixable.fixed
deleted file mode 100644
index 62ff16f67f4..00000000000
--- a/src/tools/clippy/tests/ui/search_is_some_fixable.fixed
+++ /dev/null
@@ -1,68 +0,0 @@
-// run-rustfix
-#![allow(dead_code)]
-#![warn(clippy::search_is_some)]
-
-fn main() {
- let v = vec![3, 2, 1, 0, -1, -2, -3];
- let y = &&42;
-
- // Check `find().is_some()`, single-line case.
- let _ = v.iter().any(|x| *x < 0);
- let _ = (0..1).any(|x| **y == x); // one dereference less
- let _ = (0..1).any(|x| x == 0);
- let _ = v.iter().any(|x| *x == 0);
-
- // Check `position().is_some()`, single-line case.
- let _ = v.iter().any(|&x| x < 0);
-
- // Check `rposition().is_some()`, single-line case.
- let _ = v.iter().any(|&x| x < 0);
-
- let s1 = String::from("hello world");
- let s2 = String::from("world");
- // caller of `find()` is a `&`static str`
- let _ = "hello world".contains("world");
- let _ = "hello world".contains(&s2);
- let _ = "hello world".contains(&s2[2..]);
- // caller of `find()` is a `String`
- let _ = s1.contains("world");
- let _ = s1.contains(&s2);
- let _ = s1.contains(&s2[2..]);
- // caller of `find()` is slice of `String`
- let _ = s1[2..].contains("world");
- let _ = s1[2..].contains(&s2);
- let _ = s1[2..].contains(&s2[2..]);
-}
-
-fn is_none() {
- let v = vec![3, 2, 1, 0, -1, -2, -3];
- let y = &&42;
-
- // Check `find().is_none()`, single-line case.
- let _ = !v.iter().any(|x| *x < 0);
- let _ = !(0..1).any(|x| **y == x); // one dereference less
- let _ = !(0..1).any(|x| x == 0);
- let _ = !v.iter().any(|x| *x == 0);
-
- // Check `position().is_none()`, single-line case.
- let _ = !v.iter().any(|&x| x < 0);
-
- // Check `rposition().is_none()`, single-line case.
- let _ = !v.iter().any(|&x| x < 0);
-
- let s1 = String::from("hello world");
- let s2 = String::from("world");
-
- // caller of `find()` is a `&`static str`
- let _ = !"hello world".contains("world");
- let _ = !"hello world".contains(&s2);
- let _ = !"hello world".contains(&s2[2..]);
- // caller of `find()` is a `String`
- let _ = !s1.contains("world");
- let _ = !s1.contains(&s2);
- let _ = !s1.contains(&s2[2..]);
- // caller of `find()` is slice of `String`
- let _ = !s1[2..].contains("world");
- let _ = !s1[2..].contains(&s2);
- let _ = !s1[2..].contains(&s2[2..]);
-}
diff --git a/src/tools/clippy/tests/ui/search_is_some_fixable.rs b/src/tools/clippy/tests/ui/search_is_some_fixable.rs
deleted file mode 100644
index 8407f716647..00000000000
--- a/src/tools/clippy/tests/ui/search_is_some_fixable.rs
+++ /dev/null
@@ -1,68 +0,0 @@
-// run-rustfix
-#![allow(dead_code)]
-#![warn(clippy::search_is_some)]
-
-fn main() {
- let v = vec![3, 2, 1, 0, -1, -2, -3];
- let y = &&42;
-
- // Check `find().is_some()`, single-line case.
- let _ = v.iter().find(|&x| *x < 0).is_some();
- let _ = (0..1).find(|x| **y == *x).is_some(); // one dereference less
- let _ = (0..1).find(|x| *x == 0).is_some();
- let _ = v.iter().find(|x| **x == 0).is_some();
-
- // Check `position().is_some()`, single-line case.
- let _ = v.iter().position(|&x| x < 0).is_some();
-
- // Check `rposition().is_some()`, single-line case.
- let _ = v.iter().rposition(|&x| x < 0).is_some();
-
- let s1 = String::from("hello world");
- let s2 = String::from("world");
- // caller of `find()` is a `&`static str`
- let _ = "hello world".find("world").is_some();
- let _ = "hello world".find(&s2).is_some();
- let _ = "hello world".find(&s2[2..]).is_some();
- // caller of `find()` is a `String`
- let _ = s1.find("world").is_some();
- let _ = s1.find(&s2).is_some();
- let _ = s1.find(&s2[2..]).is_some();
- // caller of `find()` is slice of `String`
- let _ = s1[2..].find("world").is_some();
- let _ = s1[2..].find(&s2).is_some();
- let _ = s1[2..].find(&s2[2..]).is_some();
-}
-
-fn is_none() {
- let v = vec![3, 2, 1, 0, -1, -2, -3];
- let y = &&42;
-
- // Check `find().is_none()`, single-line case.
- let _ = v.iter().find(|&x| *x < 0).is_none();
- let _ = (0..1).find(|x| **y == *x).is_none(); // one dereference less
- let _ = (0..1).find(|x| *x == 0).is_none();
- let _ = v.iter().find(|x| **x == 0).is_none();
-
- // Check `position().is_none()`, single-line case.
- let _ = v.iter().position(|&x| x < 0).is_none();
-
- // Check `rposition().is_none()`, single-line case.
- let _ = v.iter().rposition(|&x| x < 0).is_none();
-
- let s1 = String::from("hello world");
- let s2 = String::from("world");
-
- // caller of `find()` is a `&`static str`
- let _ = "hello world".find("world").is_none();
- let _ = "hello world".find(&s2).is_none();
- let _ = "hello world".find(&s2[2..]).is_none();
- // caller of `find()` is a `String`
- let _ = s1.find("world").is_none();
- let _ = s1.find(&s2).is_none();
- let _ = s1.find(&s2[2..]).is_none();
- // caller of `find()` is slice of `String`
- let _ = s1[2..].find("world").is_none();
- let _ = s1[2..].find(&s2).is_none();
- let _ = s1[2..].find(&s2[2..]).is_none();
-}
diff --git a/src/tools/clippy/tests/ui/search_is_some_fixable.stderr b/src/tools/clippy/tests/ui/search_is_some_fixable.stderr
deleted file mode 100644
index bd1b6955a97..00000000000
--- a/src/tools/clippy/tests/ui/search_is_some_fixable.stderr
+++ /dev/null
@@ -1,184 +0,0 @@
-error: called `is_some()` after searching an `Iterator` with `find`
- --> $DIR/search_is_some_fixable.rs:10:22
- |
-LL | let _ = v.iter().find(|&x| *x < 0).is_some();
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `any()` instead: `any(|x| *x < 0)`
- |
- = note: `-D clippy::search-is-some` implied by `-D warnings`
-
-error: called `is_some()` after searching an `Iterator` with `find`
- --> $DIR/search_is_some_fixable.rs:11:20
- |
-LL | let _ = (0..1).find(|x| **y == *x).is_some(); // one dereference less
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `any()` instead: `any(|x| **y == x)`
-
-error: called `is_some()` after searching an `Iterator` with `find`
- --> $DIR/search_is_some_fixable.rs:12:20
- |
-LL | let _ = (0..1).find(|x| *x == 0).is_some();
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `any()` instead: `any(|x| x == 0)`
-
-error: called `is_some()` after searching an `Iterator` with `find`
- --> $DIR/search_is_some_fixable.rs:13:22
- |
-LL | let _ = v.iter().find(|x| **x == 0).is_some();
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `any()` instead: `any(|x| *x == 0)`
-
-error: called `is_some()` after searching an `Iterator` with `position`
- --> $DIR/search_is_some_fixable.rs:16:22
- |
-LL | let _ = v.iter().position(|&x| x < 0).is_some();
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `any()` instead: `any(|&x| x < 0)`
-
-error: called `is_some()` after searching an `Iterator` with `rposition`
- --> $DIR/search_is_some_fixable.rs:19:22
- |
-LL | let _ = v.iter().rposition(|&x| x < 0).is_some();
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `any()` instead: `any(|&x| x < 0)`
-
-error: called `is_some()` after calling `find()` on a string
- --> $DIR/search_is_some_fixable.rs:24:27
- |
-LL | let _ = "hello world".find("world").is_some();
- | ^^^^^^^^^^^^^^^^^^^^^^^ help: use `contains()` instead: `contains("world")`
-
-error: called `is_some()` after calling `find()` on a string
- --> $DIR/search_is_some_fixable.rs:25:27
- |
-LL | let _ = "hello world".find(&s2).is_some();
- | ^^^^^^^^^^^^^^^^^^^ help: use `contains()` instead: `contains(&s2)`
-
-error: called `is_some()` after calling `find()` on a string
- --> $DIR/search_is_some_fixable.rs:26:27
- |
-LL | let _ = "hello world".find(&s2[2..]).is_some();
- | ^^^^^^^^^^^^^^^^^^^^^^^^ help: use `contains()` instead: `contains(&s2[2..])`
-
-error: called `is_some()` after calling `find()` on a string
- --> $DIR/search_is_some_fixable.rs:28:16
- |
-LL | let _ = s1.find("world").is_some();
- | ^^^^^^^^^^^^^^^^^^^^^^^ help: use `contains()` instead: `contains("world")`
-
-error: called `is_some()` after calling `find()` on a string
- --> $DIR/search_is_some_fixable.rs:29:16
- |
-LL | let _ = s1.find(&s2).is_some();
- | ^^^^^^^^^^^^^^^^^^^ help: use `contains()` instead: `contains(&s2)`
-
-error: called `is_some()` after calling `find()` on a string
- --> $DIR/search_is_some_fixable.rs:30:16
- |
-LL | let _ = s1.find(&s2[2..]).is_some();
- | ^^^^^^^^^^^^^^^^^^^^^^^^ help: use `contains()` instead: `contains(&s2[2..])`
-
-error: called `is_some()` after calling `find()` on a string
- --> $DIR/search_is_some_fixable.rs:32:21
- |
-LL | let _ = s1[2..].find("world").is_some();
- | ^^^^^^^^^^^^^^^^^^^^^^^ help: use `contains()` instead: `contains("world")`
-
-error: called `is_some()` after calling `find()` on a string
- --> $DIR/search_is_some_fixable.rs:33:21
- |
-LL | let _ = s1[2..].find(&s2).is_some();
- | ^^^^^^^^^^^^^^^^^^^ help: use `contains()` instead: `contains(&s2)`
-
-error: called `is_some()` after calling `find()` on a string
- --> $DIR/search_is_some_fixable.rs:34:21
- |
-LL | let _ = s1[2..].find(&s2[2..]).is_some();
- | ^^^^^^^^^^^^^^^^^^^^^^^^ help: use `contains()` instead: `contains(&s2[2..])`
-
-error: called `is_none()` after searching an `Iterator` with `find`
- --> $DIR/search_is_some_fixable.rs:42:13
- |
-LL | let _ = v.iter().find(|&x| *x < 0).is_none();
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `!_.any()` instead: `!v.iter().any(|x| *x < 0)`
-
-error: called `is_none()` after searching an `Iterator` with `find`
- --> $DIR/search_is_some_fixable.rs:43:13
- |
-LL | let _ = (0..1).find(|x| **y == *x).is_none(); // one dereference less
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `!_.any()` instead: `!(0..1).any(|x| **y == x)`
-
-error: called `is_none()` after searching an `Iterator` with `find`
- --> $DIR/search_is_some_fixable.rs:44:13
- |
-LL | let _ = (0..1).find(|x| *x == 0).is_none();
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `!_.any()` instead: `!(0..1).any(|x| x == 0)`
-
-error: called `is_none()` after searching an `Iterator` with `find`
- --> $DIR/search_is_some_fixable.rs:45:13
- |
-LL | let _ = v.iter().find(|x| **x == 0).is_none();
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `!_.any()` instead: `!v.iter().any(|x| *x == 0)`
-
-error: called `is_none()` after searching an `Iterator` with `position`
- --> $DIR/search_is_some_fixable.rs:48:13
- |
-LL | let _ = v.iter().position(|&x| x < 0).is_none();
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `!_.any()` instead: `!v.iter().any(|&x| x < 0)`
-
-error: called `is_none()` after searching an `Iterator` with `rposition`
- --> $DIR/search_is_some_fixable.rs:51:13
- |
-LL | let _ = v.iter().rposition(|&x| x < 0).is_none();
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `!_.any()` instead: `!v.iter().any(|&x| x < 0)`
-
-error: called `is_none()` after calling `find()` on a string
- --> $DIR/search_is_some_fixable.rs:57:13
- |
-LL | let _ = "hello world".find("world").is_none();
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `!_.contains()` instead: `!"hello world".contains("world")`
-
-error: called `is_none()` after calling `find()` on a string
- --> $DIR/search_is_some_fixable.rs:58:13
- |
-LL | let _ = "hello world".find(&s2).is_none();
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `!_.contains()` instead: `!"hello world".contains(&s2)`
-
-error: called `is_none()` after calling `find()` on a string
- --> $DIR/search_is_some_fixable.rs:59:13
- |
-LL | let _ = "hello world".find(&s2[2..]).is_none();
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `!_.contains()` instead: `!"hello world".contains(&s2[2..])`
-
-error: called `is_none()` after calling `find()` on a string
- --> $DIR/search_is_some_fixable.rs:61:13
- |
-LL | let _ = s1.find("world").is_none();
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `!_.contains()` instead: `!s1.contains("world")`
-
-error: called `is_none()` after calling `find()` on a string
- --> $DIR/search_is_some_fixable.rs:62:13
- |
-LL | let _ = s1.find(&s2).is_none();
- | ^^^^^^^^^^^^^^^^^^^^^^ help: use `!_.contains()` instead: `!s1.contains(&s2)`
-
-error: called `is_none()` after calling `find()` on a string
- --> $DIR/search_is_some_fixable.rs:63:13
- |
-LL | let _ = s1.find(&s2[2..]).is_none();
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `!_.contains()` instead: `!s1.contains(&s2[2..])`
-
-error: called `is_none()` after calling `find()` on a string
- --> $DIR/search_is_some_fixable.rs:65:13
- |
-LL | let _ = s1[2..].find("world").is_none();
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `!_.contains()` instead: `!s1[2..].contains("world")`
-
-error: called `is_none()` after calling `find()` on a string
- --> $DIR/search_is_some_fixable.rs:66:13
- |
-LL | let _ = s1[2..].find(&s2).is_none();
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `!_.contains()` instead: `!s1[2..].contains(&s2)`
-
-error: called `is_none()` after calling `find()` on a string
- --> $DIR/search_is_some_fixable.rs:67:13
- |
-LL | let _ = s1[2..].find(&s2[2..]).is_none();
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `!_.contains()` instead: `!s1[2..].contains(&s2[2..])`
-
-error: aborting due to 30 previous errors
-
diff --git a/src/tools/clippy/tests/ui/search_is_some_fixable_none.fixed b/src/tools/clippy/tests/ui/search_is_some_fixable_none.fixed
new file mode 100644
index 00000000000..6831fb2cf59
--- /dev/null
+++ b/src/tools/clippy/tests/ui/search_is_some_fixable_none.fixed
@@ -0,0 +1,216 @@
+// run-rustfix
+#![allow(dead_code)]
+#![warn(clippy::search_is_some)]
+
+fn main() {
+ let v = vec![3, 2, 1, 0, -1, -2, -3];
+ let y = &&42;
+
+ // Check `find().is_none()`, single-line case.
+ let _ = !v.iter().any(|x| *x < 0);
+ let _ = !(0..1).any(|x| **y == x); // one dereference less
+ let _ = !(0..1).any(|x| x == 0);
+ let _ = !v.iter().any(|x| *x == 0);
+ let _ = !(4..5).any(|x| x == 1 || x == 3 || x == 5);
+ let _ = !(1..3).any(|x| [1, 2, 3].contains(&x));
+ let _ = !(1..3).any(|x| x == 0 || [1, 2, 3].contains(&x));
+ let _ = !(1..3).any(|x| [1, 2, 3].contains(&x) || x == 0);
+ let _ = !(1..3).any(|x| [1, 2, 3].contains(&x) || x == 0 || [4, 5, 6].contains(&x) || x == -1);
+
+ // Check `position().is_none()`, single-line case.
+ let _ = !v.iter().any(|&x| x < 0);
+
+ // Check `rposition().is_none()`, single-line case.
+ let _ = !v.iter().any(|&x| x < 0);
+
+ let s1 = String::from("hello world");
+ let s2 = String::from("world");
+
+ // caller of `find()` is a `&`static str`
+ let _ = !"hello world".contains("world");
+ let _ = !"hello world".contains(&s2);
+ let _ = !"hello world".contains(&s2[2..]);
+ // caller of `find()` is a `String`
+ let _ = !s1.contains("world");
+ let _ = !s1.contains(&s2);
+ let _ = !s1.contains(&s2[2..]);
+ // caller of `find()` is slice of `String`
+ let _ = !s1[2..].contains("world");
+ let _ = !s1[2..].contains(&s2);
+ let _ = !s1[2..].contains(&s2[2..]);
+}
+
+#[allow(clippy::clone_on_copy, clippy::map_clone)]
+mod issue7392 {
+ struct Player {
+ hand: Vec<usize>,
+ }
+ fn filter() {
+ let p = Player {
+ hand: vec![1, 2, 3, 4, 5],
+ };
+ let filter_hand = vec![5];
+ let _ = p
+ .hand
+ .iter()
+ .filter(|c| !filter_hand.iter().any(|cc| c == &cc))
+ .map(|c| c.clone())
+ .collect::<Vec<_>>();
+ }
+
+ struct PlayerTuple {
+ hand: Vec<(usize, char)>,
+ }
+ fn filter_tuple() {
+ let p = PlayerTuple {
+ hand: vec![(1, 'a'), (2, 'b'), (3, 'c'), (4, 'd'), (5, 'e')],
+ };
+ let filter_hand = vec![5];
+ let _ = p
+ .hand
+ .iter()
+ .filter(|(c, _)| !filter_hand.iter().any(|cc| c == cc))
+ .map(|c| c.clone())
+ .collect::<Vec<_>>();
+ }
+
+ fn field_projection() {
+ struct Foo {
+ foo: i32,
+ bar: u32,
+ }
+ let vfoo = vec![Foo { foo: 1, bar: 2 }];
+ let _ = !vfoo.iter().any(|v| v.foo == 1 && v.bar == 2);
+
+ let vfoo = vec![(42, Foo { foo: 1, bar: 2 })];
+ let _ = !vfoo
+ .iter().any(|(i, v)| *i == 42 && v.foo == 1 && v.bar == 2);
+ }
+
+ fn index_projection() {
+ let vfoo = vec![[0, 1, 2, 3]];
+ let _ = !vfoo.iter().any(|a| a[0] == 42);
+ }
+
+ #[allow(clippy::match_like_matches_macro)]
+ fn slice_projection() {
+ let vfoo = vec![[0, 1, 2, 3, 0, 1, 2, 3]];
+ let _ = !vfoo.iter().any(|sub| sub[1..4].len() == 3);
+ }
+
+ fn please(x: &u32) -> bool {
+ *x == 9
+ }
+
+ fn deref_enough(x: u32) -> bool {
+ x == 78
+ }
+
+ fn arg_no_deref(x: &&u32) -> bool {
+ **x == 78
+ }
+
+ fn more_projections() {
+ let x = 19;
+ let ppx: &u32 = &x;
+ let _ = ![ppx].iter().any(|ppp_x: &&u32| please(ppp_x));
+ let _ = ![String::from("Hey hey")].iter().any(|s| s.len() == 2);
+
+ let v = vec![3, 2, 1, 0];
+ let _ = !v.iter().any(|x| deref_enough(*x));
+ let _ = !v.iter().any(|x: &u32| deref_enough(*x));
+
+ #[allow(clippy::redundant_closure)]
+ let _ = !v.iter().any(|x| arg_no_deref(&x));
+ #[allow(clippy::redundant_closure)]
+ let _ = !v.iter().any(|x: &u32| arg_no_deref(&x));
+ }
+
+ fn field_index_projection() {
+ struct FooDouble {
+ bar: Vec<Vec<i32>>,
+ }
+ struct Foo {
+ bar: Vec<i32>,
+ }
+ struct FooOuter {
+ inner: Foo,
+ inner_double: FooDouble,
+ }
+ let vfoo = vec![FooOuter {
+ inner: Foo { bar: vec![0, 1, 2, 3] },
+ inner_double: FooDouble {
+ bar: vec![vec![0, 1, 2, 3]],
+ },
+ }];
+ let _ = !vfoo
+ .iter().any(|v| v.inner_double.bar[0][0] == 2 && v.inner.bar[0] == 2);
+ }
+
+ fn index_field_projection() {
+ struct Foo {
+ bar: i32,
+ }
+ struct FooOuter {
+ inner: Vec<Foo>,
+ }
+ let vfoo = vec![FooOuter {
+ inner: vec![Foo { bar: 0 }],
+ }];
+ let _ = !vfoo.iter().any(|v| v.inner[0].bar == 2);
+ }
+
+ fn double_deref_index_projection() {
+ let vfoo = vec![&&[0, 1, 2, 3]];
+ let _ = !vfoo.iter().any(|x| (**x)[0] == 9);
+ }
+
+ fn method_call_by_ref() {
+ struct Foo {
+ bar: u32,
+ }
+ impl Foo {
+ pub fn by_ref(&self, x: &u32) -> bool {
+ *x == self.bar
+ }
+ }
+ let vfoo = vec![Foo { bar: 1 }];
+ let _ = !vfoo.iter().any(|v| v.by_ref(&v.bar));
+ }
+
+ fn ref_bindings() {
+ let _ = ![&(&1, 2), &(&3, 4), &(&5, 4)].iter().any(|(&x, y)| x == *y);
+ let _ = ![&(&1, 2), &(&3, 4), &(&5, 4)].iter().any(|(&x, y)| x == *y);
+ }
+
+ fn test_string_1(s: &str) -> bool {
+ s.is_empty()
+ }
+
+ fn test_u32_1(s: &u32) -> bool {
+ s.is_power_of_two()
+ }
+
+ fn test_u32_2(s: u32) -> bool {
+ s.is_power_of_two()
+ }
+
+ fn projection_in_args_test() {
+ // Index projections
+ let lst = &[String::from("Hello"), String::from("world")];
+ let v: Vec<&[String]> = vec![lst];
+ let _ = !v.iter().any(|s| s[0].is_empty());
+ let _ = !v.iter().any(|s| test_string_1(&s[0]));
+
+ // Field projections
+ struct FieldProjection<'a> {
+ field: &'a u32,
+ }
+ let field = 123456789;
+ let instance = FieldProjection { field: &field };
+ let v = vec![instance];
+ let _ = !v.iter().any(|fp| fp.field.is_power_of_two());
+ let _ = !v.iter().any(|fp| test_u32_1(fp.field));
+ let _ = !v.iter().any(|fp| test_u32_2(*fp.field));
+ }
+}
diff --git a/src/tools/clippy/tests/ui/search_is_some_fixable_none.rs b/src/tools/clippy/tests/ui/search_is_some_fixable_none.rs
new file mode 100644
index 00000000000..778f4f6fa25
--- /dev/null
+++ b/src/tools/clippy/tests/ui/search_is_some_fixable_none.rs
@@ -0,0 +1,222 @@
+// run-rustfix
+#![allow(dead_code)]
+#![warn(clippy::search_is_some)]
+
+fn main() {
+ let v = vec![3, 2, 1, 0, -1, -2, -3];
+ let y = &&42;
+
+ // Check `find().is_none()`, single-line case.
+ let _ = v.iter().find(|&x| *x < 0).is_none();
+ let _ = (0..1).find(|x| **y == *x).is_none(); // one dereference less
+ let _ = (0..1).find(|x| *x == 0).is_none();
+ let _ = v.iter().find(|x| **x == 0).is_none();
+ let _ = (4..5).find(|x| *x == 1 || *x == 3 || *x == 5).is_none();
+ let _ = (1..3).find(|x| [1, 2, 3].contains(x)).is_none();
+ let _ = (1..3).find(|x| *x == 0 || [1, 2, 3].contains(x)).is_none();
+ let _ = (1..3).find(|x| [1, 2, 3].contains(x) || *x == 0).is_none();
+ let _ = (1..3)
+ .find(|x| [1, 2, 3].contains(x) || *x == 0 || [4, 5, 6].contains(x) || *x == -1)
+ .is_none();
+
+ // Check `position().is_none()`, single-line case.
+ let _ = v.iter().position(|&x| x < 0).is_none();
+
+ // Check `rposition().is_none()`, single-line case.
+ let _ = v.iter().rposition(|&x| x < 0).is_none();
+
+ let s1 = String::from("hello world");
+ let s2 = String::from("world");
+
+ // caller of `find()` is a `&`static str`
+ let _ = "hello world".find("world").is_none();
+ let _ = "hello world".find(&s2).is_none();
+ let _ = "hello world".find(&s2[2..]).is_none();
+ // caller of `find()` is a `String`
+ let _ = s1.find("world").is_none();
+ let _ = s1.find(&s2).is_none();
+ let _ = s1.find(&s2[2..]).is_none();
+ // caller of `find()` is slice of `String`
+ let _ = s1[2..].find("world").is_none();
+ let _ = s1[2..].find(&s2).is_none();
+ let _ = s1[2..].find(&s2[2..]).is_none();
+}
+
+#[allow(clippy::clone_on_copy, clippy::map_clone)]
+mod issue7392 {
+ struct Player {
+ hand: Vec<usize>,
+ }
+ fn filter() {
+ let p = Player {
+ hand: vec![1, 2, 3, 4, 5],
+ };
+ let filter_hand = vec![5];
+ let _ = p
+ .hand
+ .iter()
+ .filter(|c| filter_hand.iter().find(|cc| c == cc).is_none())
+ .map(|c| c.clone())
+ .collect::<Vec<_>>();
+ }
+
+ struct PlayerTuple {
+ hand: Vec<(usize, char)>,
+ }
+ fn filter_tuple() {
+ let p = PlayerTuple {
+ hand: vec![(1, 'a'), (2, 'b'), (3, 'c'), (4, 'd'), (5, 'e')],
+ };
+ let filter_hand = vec![5];
+ let _ = p
+ .hand
+ .iter()
+ .filter(|(c, _)| filter_hand.iter().find(|cc| c == *cc).is_none())
+ .map(|c| c.clone())
+ .collect::<Vec<_>>();
+ }
+
+ fn field_projection() {
+ struct Foo {
+ foo: i32,
+ bar: u32,
+ }
+ let vfoo = vec![Foo { foo: 1, bar: 2 }];
+ let _ = vfoo.iter().find(|v| v.foo == 1 && v.bar == 2).is_none();
+
+ let vfoo = vec![(42, Foo { foo: 1, bar: 2 })];
+ let _ = vfoo
+ .iter()
+ .find(|(i, v)| *i == 42 && v.foo == 1 && v.bar == 2)
+ .is_none();
+ }
+
+ fn index_projection() {
+ let vfoo = vec![[0, 1, 2, 3]];
+ let _ = vfoo.iter().find(|a| a[0] == 42).is_none();
+ }
+
+ #[allow(clippy::match_like_matches_macro)]
+ fn slice_projection() {
+ let vfoo = vec![[0, 1, 2, 3, 0, 1, 2, 3]];
+ let _ = vfoo.iter().find(|sub| sub[1..4].len() == 3).is_none();
+ }
+
+ fn please(x: &u32) -> bool {
+ *x == 9
+ }
+
+ fn deref_enough(x: u32) -> bool {
+ x == 78
+ }
+
+ fn arg_no_deref(x: &&u32) -> bool {
+ **x == 78
+ }
+
+ fn more_projections() {
+ let x = 19;
+ let ppx: &u32 = &x;
+ let _ = [ppx].iter().find(|ppp_x: &&&u32| please(**ppp_x)).is_none();
+ let _ = [String::from("Hey hey")].iter().find(|s| s.len() == 2).is_none();
+
+ let v = vec![3, 2, 1, 0];
+ let _ = v.iter().find(|x| deref_enough(**x)).is_none();
+ let _ = v.iter().find(|x: &&u32| deref_enough(**x)).is_none();
+
+ #[allow(clippy::redundant_closure)]
+ let _ = v.iter().find(|x| arg_no_deref(x)).is_none();
+ #[allow(clippy::redundant_closure)]
+ let _ = v.iter().find(|x: &&u32| arg_no_deref(x)).is_none();
+ }
+
+ fn field_index_projection() {
+ struct FooDouble {
+ bar: Vec<Vec<i32>>,
+ }
+ struct Foo {
+ bar: Vec<i32>,
+ }
+ struct FooOuter {
+ inner: Foo,
+ inner_double: FooDouble,
+ }
+ let vfoo = vec![FooOuter {
+ inner: Foo { bar: vec![0, 1, 2, 3] },
+ inner_double: FooDouble {
+ bar: vec![vec![0, 1, 2, 3]],
+ },
+ }];
+ let _ = vfoo
+ .iter()
+ .find(|v| v.inner_double.bar[0][0] == 2 && v.inner.bar[0] == 2)
+ .is_none();
+ }
+
+ fn index_field_projection() {
+ struct Foo {
+ bar: i32,
+ }
+ struct FooOuter {
+ inner: Vec<Foo>,
+ }
+ let vfoo = vec![FooOuter {
+ inner: vec![Foo { bar: 0 }],
+ }];
+ let _ = vfoo.iter().find(|v| v.inner[0].bar == 2).is_none();
+ }
+
+ fn double_deref_index_projection() {
+ let vfoo = vec![&&[0, 1, 2, 3]];
+ let _ = vfoo.iter().find(|x| (**x)[0] == 9).is_none();
+ }
+
+ fn method_call_by_ref() {
+ struct Foo {
+ bar: u32,
+ }
+ impl Foo {
+ pub fn by_ref(&self, x: &u32) -> bool {
+ *x == self.bar
+ }
+ }
+ let vfoo = vec![Foo { bar: 1 }];
+ let _ = vfoo.iter().find(|v| v.by_ref(&v.bar)).is_none();
+ }
+
+ fn ref_bindings() {
+ let _ = [&(&1, 2), &(&3, 4), &(&5, 4)].iter().find(|(&x, y)| x == *y).is_none();
+ let _ = [&(&1, 2), &(&3, 4), &(&5, 4)].iter().find(|&(&x, y)| x == *y).is_none();
+ }
+
+ fn test_string_1(s: &String) -> bool {
+ s.is_empty()
+ }
+
+ fn test_u32_1(s: &u32) -> bool {
+ s.is_power_of_two()
+ }
+
+ fn test_u32_2(s: u32) -> bool {
+ s.is_power_of_two()
+ }
+
+ fn projection_in_args_test() {
+ // Index projections
+ let lst = &[String::from("Hello"), String::from("world")];
+ let v: Vec<&[String]> = vec![lst];
+ let _ = v.iter().find(|s| s[0].is_empty()).is_none();
+ let _ = v.iter().find(|s| test_string_1(&s[0])).is_none();
+
+ // Field projections
+ struct FieldProjection<'a> {
+ field: &'a u32,
+ }
+ let field = 123456789;
+ let instance = FieldProjection { field: &field };
+ let v = vec![instance];
+ let _ = v.iter().find(|fp| fp.field.is_power_of_two()).is_none();
+ let _ = v.iter().find(|fp| test_u32_1(fp.field)).is_none();
+ let _ = v.iter().find(|fp| test_u32_2(*fp.field)).is_none();
+ }
+}
diff --git a/src/tools/clippy/tests/ui/search_is_some_fixable_none.stderr b/src/tools/clippy/tests/ui/search_is_some_fixable_none.stderr
new file mode 100644
index 00000000000..7c5e5eb589c
--- /dev/null
+++ b/src/tools/clippy/tests/ui/search_is_some_fixable_none.stderr
@@ -0,0 +1,293 @@
+error: called `is_none()` after searching an `Iterator` with `find`
+ --> $DIR/search_is_some_fixable_none.rs:10:13
+ |
+LL | let _ = v.iter().find(|&x| *x < 0).is_none();
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `!_.any()` instead: `!v.iter().any(|x| *x < 0)`
+ |
+ = note: `-D clippy::search-is-some` implied by `-D warnings`
+
+error: called `is_none()` after searching an `Iterator` with `find`
+ --> $DIR/search_is_some_fixable_none.rs:11:13
+ |
+LL | let _ = (0..1).find(|x| **y == *x).is_none(); // one dereference less
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `!_.any()` instead: `!(0..1).any(|x| **y == x)`
+
+error: called `is_none()` after searching an `Iterator` with `find`
+ --> $DIR/search_is_some_fixable_none.rs:12:13
+ |
+LL | let _ = (0..1).find(|x| *x == 0).is_none();
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `!_.any()` instead: `!(0..1).any(|x| x == 0)`
+
+error: called `is_none()` after searching an `Iterator` with `find`
+ --> $DIR/search_is_some_fixable_none.rs:13:13
+ |
+LL | let _ = v.iter().find(|x| **x == 0).is_none();
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `!_.any()` instead: `!v.iter().any(|x| *x == 0)`
+
+error: called `is_none()` after searching an `Iterator` with `find`
+ --> $DIR/search_is_some_fixable_none.rs:14:13
+ |
+LL | let _ = (4..5).find(|x| *x == 1 || *x == 3 || *x == 5).is_none();
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `!_.any()` instead: `!(4..5).any(|x| x == 1 || x == 3 || x == 5)`
+
+error: called `is_none()` after searching an `Iterator` with `find`
+ --> $DIR/search_is_some_fixable_none.rs:15:13
+ |
+LL | let _ = (1..3).find(|x| [1, 2, 3].contains(x)).is_none();
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `!_.any()` instead: `!(1..3).any(|x| [1, 2, 3].contains(&x))`
+
+error: called `is_none()` after searching an `Iterator` with `find`
+ --> $DIR/search_is_some_fixable_none.rs:16:13
+ |
+LL | let _ = (1..3).find(|x| *x == 0 || [1, 2, 3].contains(x)).is_none();
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `!_.any()` instead: `!(1..3).any(|x| x == 0 || [1, 2, 3].contains(&x))`
+
+error: called `is_none()` after searching an `Iterator` with `find`
+ --> $DIR/search_is_some_fixable_none.rs:17:13
+ |
+LL | let _ = (1..3).find(|x| [1, 2, 3].contains(x) || *x == 0).is_none();
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `!_.any()` instead: `!(1..3).any(|x| [1, 2, 3].contains(&x) || x == 0)`
+
+error: called `is_none()` after searching an `Iterator` with `find`
+ --> $DIR/search_is_some_fixable_none.rs:18:13
+ |
+LL | let _ = (1..3)
+ | _____________^
+LL | | .find(|x| [1, 2, 3].contains(x) || *x == 0 || [4, 5, 6].contains(x) || *x == -1)
+LL | | .is_none();
+ | |__________________^ help: use `!_.any()` instead: `!(1..3).any(|x| [1, 2, 3].contains(&x) || x == 0 || [4, 5, 6].contains(&x) || x == -1)`
+
+error: called `is_none()` after searching an `Iterator` with `position`
+ --> $DIR/search_is_some_fixable_none.rs:23:13
+ |
+LL | let _ = v.iter().position(|&x| x < 0).is_none();
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `!_.any()` instead: `!v.iter().any(|&x| x < 0)`
+
+error: called `is_none()` after searching an `Iterator` with `rposition`
+ --> $DIR/search_is_some_fixable_none.rs:26:13
+ |
+LL | let _ = v.iter().rposition(|&x| x < 0).is_none();
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `!_.any()` instead: `!v.iter().any(|&x| x < 0)`
+
+error: called `is_none()` after calling `find()` on a string
+ --> $DIR/search_is_some_fixable_none.rs:32:13
+ |
+LL | let _ = "hello world".find("world").is_none();
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `!_.contains()` instead: `!"hello world".contains("world")`
+
+error: called `is_none()` after calling `find()` on a string
+ --> $DIR/search_is_some_fixable_none.rs:33:13
+ |
+LL | let _ = "hello world".find(&s2).is_none();
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `!_.contains()` instead: `!"hello world".contains(&s2)`
+
+error: called `is_none()` after calling `find()` on a string
+ --> $DIR/search_is_some_fixable_none.rs:34:13
+ |
+LL | let _ = "hello world".find(&s2[2..]).is_none();
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `!_.contains()` instead: `!"hello world".contains(&s2[2..])`
+
+error: called `is_none()` after calling `find()` on a string
+ --> $DIR/search_is_some_fixable_none.rs:36:13
+ |
+LL | let _ = s1.find("world").is_none();
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `!_.contains()` instead: `!s1.contains("world")`
+
+error: called `is_none()` after calling `find()` on a string
+ --> $DIR/search_is_some_fixable_none.rs:37:13
+ |
+LL | let _ = s1.find(&s2).is_none();
+ | ^^^^^^^^^^^^^^^^^^^^^^ help: use `!_.contains()` instead: `!s1.contains(&s2)`
+
+error: called `is_none()` after calling `find()` on a string
+ --> $DIR/search_is_some_fixable_none.rs:38:13
+ |
+LL | let _ = s1.find(&s2[2..]).is_none();
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `!_.contains()` instead: `!s1.contains(&s2[2..])`
+
+error: called `is_none()` after calling `find()` on a string
+ --> $DIR/search_is_some_fixable_none.rs:40:13
+ |
+LL | let _ = s1[2..].find("world").is_none();
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `!_.contains()` instead: `!s1[2..].contains("world")`
+
+error: called `is_none()` after calling `find()` on a string
+ --> $DIR/search_is_some_fixable_none.rs:41:13
+ |
+LL | let _ = s1[2..].find(&s2).is_none();
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `!_.contains()` instead: `!s1[2..].contains(&s2)`
+
+error: called `is_none()` after calling `find()` on a string
+ --> $DIR/search_is_some_fixable_none.rs:42:13
+ |
+LL | let _ = s1[2..].find(&s2[2..]).is_none();
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `!_.contains()` instead: `!s1[2..].contains(&s2[2..])`
+
+error: called `is_none()` after searching an `Iterator` with `find`
+ --> $DIR/search_is_some_fixable_none.rs:58:25
+ |
+LL | .filter(|c| filter_hand.iter().find(|cc| c == cc).is_none())
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `!_.any()` instead: `!filter_hand.iter().any(|cc| c == &cc)`
+
+error: called `is_none()` after searching an `Iterator` with `find`
+ --> $DIR/search_is_some_fixable_none.rs:74:30
+ |
+LL | .filter(|(c, _)| filter_hand.iter().find(|cc| c == *cc).is_none())
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `!_.any()` instead: `!filter_hand.iter().any(|cc| c == cc)`
+
+error: called `is_none()` after searching an `Iterator` with `find`
+ --> $DIR/search_is_some_fixable_none.rs:85:17
+ |
+LL | let _ = vfoo.iter().find(|v| v.foo == 1 && v.bar == 2).is_none();
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `!_.any()` instead: `!vfoo.iter().any(|v| v.foo == 1 && v.bar == 2)`
+
+error: called `is_none()` after searching an `Iterator` with `find`
+ --> $DIR/search_is_some_fixable_none.rs:88:17
+ |
+LL | let _ = vfoo
+ | _________________^
+LL | | .iter()
+LL | | .find(|(i, v)| *i == 42 && v.foo == 1 && v.bar == 2)
+LL | | .is_none();
+ | |______________________^
+ |
+help: use `!_.any()` instead
+ |
+LL ~ let _ = !vfoo
+LL ~ .iter().any(|(i, v)| *i == 42 && v.foo == 1 && v.bar == 2);
+ |
+
+error: called `is_none()` after searching an `Iterator` with `find`
+ --> $DIR/search_is_some_fixable_none.rs:96:17
+ |
+LL | let _ = vfoo.iter().find(|a| a[0] == 42).is_none();
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `!_.any()` instead: `!vfoo.iter().any(|a| a[0] == 42)`
+
+error: called `is_none()` after searching an `Iterator` with `find`
+ --> $DIR/search_is_some_fixable_none.rs:102:17
+ |
+LL | let _ = vfoo.iter().find(|sub| sub[1..4].len() == 3).is_none();
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `!_.any()` instead: `!vfoo.iter().any(|sub| sub[1..4].len() == 3)`
+
+error: called `is_none()` after searching an `Iterator` with `find`
+ --> $DIR/search_is_some_fixable_none.rs:120:17
+ |
+LL | let _ = [ppx].iter().find(|ppp_x: &&&u32| please(**ppp_x)).is_none();
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `!_.any()` instead: `![ppx].iter().any(|ppp_x: &&u32| please(ppp_x))`
+
+error: called `is_none()` after searching an `Iterator` with `find`
+ --> $DIR/search_is_some_fixable_none.rs:121:17
+ |
+LL | let _ = [String::from("Hey hey")].iter().find(|s| s.len() == 2).is_none();
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `!_.any()` instead: `![String::from("Hey hey")].iter().any(|s| s.len() == 2)`
+
+error: called `is_none()` after searching an `Iterator` with `find`
+ --> $DIR/search_is_some_fixable_none.rs:124:17
+ |
+LL | let _ = v.iter().find(|x| deref_enough(**x)).is_none();
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `!_.any()` instead: `!v.iter().any(|x| deref_enough(*x))`
+
+error: called `is_none()` after searching an `Iterator` with `find`
+ --> $DIR/search_is_some_fixable_none.rs:125:17
+ |
+LL | let _ = v.iter().find(|x: &&u32| deref_enough(**x)).is_none();
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `!_.any()` instead: `!v.iter().any(|x: &u32| deref_enough(*x))`
+
+error: called `is_none()` after searching an `Iterator` with `find`
+ --> $DIR/search_is_some_fixable_none.rs:128:17
+ |
+LL | let _ = v.iter().find(|x| arg_no_deref(x)).is_none();
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `!_.any()` instead: `!v.iter().any(|x| arg_no_deref(&x))`
+
+error: called `is_none()` after searching an `Iterator` with `find`
+ --> $DIR/search_is_some_fixable_none.rs:130:17
+ |
+LL | let _ = v.iter().find(|x: &&u32| arg_no_deref(x)).is_none();
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `!_.any()` instead: `!v.iter().any(|x: &u32| arg_no_deref(&x))`
+
+error: called `is_none()` after searching an `Iterator` with `find`
+ --> $DIR/search_is_some_fixable_none.rs:150:17
+ |
+LL | let _ = vfoo
+ | _________________^
+LL | | .iter()
+LL | | .find(|v| v.inner_double.bar[0][0] == 2 && v.inner.bar[0] == 2)
+LL | | .is_none();
+ | |______________________^
+ |
+help: use `!_.any()` instead
+ |
+LL ~ let _ = !vfoo
+LL ~ .iter().any(|v| v.inner_double.bar[0][0] == 2 && v.inner.bar[0] == 2);
+ |
+
+error: called `is_none()` after searching an `Iterator` with `find`
+ --> $DIR/search_is_some_fixable_none.rs:166:17
+ |
+LL | let _ = vfoo.iter().find(|v| v.inner[0].bar == 2).is_none();
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `!_.any()` instead: `!vfoo.iter().any(|v| v.inner[0].bar == 2)`
+
+error: called `is_none()` after searching an `Iterator` with `find`
+ --> $DIR/search_is_some_fixable_none.rs:171:17
+ |
+LL | let _ = vfoo.iter().find(|x| (**x)[0] == 9).is_none();
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `!_.any()` instead: `!vfoo.iter().any(|x| (**x)[0] == 9)`
+
+error: called `is_none()` after searching an `Iterator` with `find`
+ --> $DIR/search_is_some_fixable_none.rs:184:17
+ |
+LL | let _ = vfoo.iter().find(|v| v.by_ref(&v.bar)).is_none();
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `!_.any()` instead: `!vfoo.iter().any(|v| v.by_ref(&v.bar))`
+
+error: called `is_none()` after searching an `Iterator` with `find`
+ --> $DIR/search_is_some_fixable_none.rs:188:17
+ |
+LL | let _ = [&(&1, 2), &(&3, 4), &(&5, 4)].iter().find(|(&x, y)| x == *y).is_none();
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `!_.any()` instead: `![&(&1, 2), &(&3, 4), &(&5, 4)].iter().any(|(&x, y)| x == *y)`
+
+error: called `is_none()` after searching an `Iterator` with `find`
+ --> $DIR/search_is_some_fixable_none.rs:189:17
+ |
+LL | let _ = [&(&1, 2), &(&3, 4), &(&5, 4)].iter().find(|&(&x, y)| x == *y).is_none();
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `!_.any()` instead: `![&(&1, 2), &(&3, 4), &(&5, 4)].iter().any(|(&x, y)| x == *y)`
+
+error: writing `&String` instead of `&str` involves a new object where a slice will do
+ --> $DIR/search_is_some_fixable_none.rs:192:25
+ |
+LL | fn test_string_1(s: &String) -> bool {
+ | ^^^^^^^ help: change this to: `&str`
+ |
+ = note: `-D clippy::ptr-arg` implied by `-D warnings`
+
+error: called `is_none()` after searching an `Iterator` with `find`
+ --> $DIR/search_is_some_fixable_none.rs:208:17
+ |
+LL | let _ = v.iter().find(|s| s[0].is_empty()).is_none();
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `!_.any()` instead: `!v.iter().any(|s| s[0].is_empty())`
+
+error: called `is_none()` after searching an `Iterator` with `find`
+ --> $DIR/search_is_some_fixable_none.rs:209:17
+ |
+LL | let _ = v.iter().find(|s| test_string_1(&s[0])).is_none();
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `!_.any()` instead: `!v.iter().any(|s| test_string_1(&s[0]))`
+
+error: called `is_none()` after searching an `Iterator` with `find`
+ --> $DIR/search_is_some_fixable_none.rs:218:17
+ |
+LL | let _ = v.iter().find(|fp| fp.field.is_power_of_two()).is_none();
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `!_.any()` instead: `!v.iter().any(|fp| fp.field.is_power_of_two())`
+
+error: called `is_none()` after searching an `Iterator` with `find`
+ --> $DIR/search_is_some_fixable_none.rs:219:17
+ |
+LL | let _ = v.iter().find(|fp| test_u32_1(fp.field)).is_none();
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `!_.any()` instead: `!v.iter().any(|fp| test_u32_1(fp.field))`
+
+error: called `is_none()` after searching an `Iterator` with `find`
+ --> $DIR/search_is_some_fixable_none.rs:220:17
+ |
+LL | let _ = v.iter().find(|fp| test_u32_2(*fp.field)).is_none();
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `!_.any()` instead: `!v.iter().any(|fp| test_u32_2(*fp.field))`
+
+error: aborting due to 44 previous errors
+
diff --git a/src/tools/clippy/tests/ui/search_is_some_fixable_some.fixed b/src/tools/clippy/tests/ui/search_is_some_fixable_some.fixed
new file mode 100644
index 00000000000..7c940a2b069
--- /dev/null
+++ b/src/tools/clippy/tests/ui/search_is_some_fixable_some.fixed
@@ -0,0 +1,218 @@
+// run-rustfix
+#![allow(dead_code)]
+#![warn(clippy::search_is_some)]
+
+fn main() {
+ let v = vec![3, 2, 1, 0, -1, -2, -3];
+ let y = &&42;
+
+ // Check `find().is_some()`, single-line case.
+ let _ = v.iter().any(|x| *x < 0);
+ let _ = (0..1).any(|x| **y == x); // one dereference less
+ let _ = (0..1).any(|x| x == 0);
+ let _ = v.iter().any(|x| *x == 0);
+ let _ = (4..5).any(|x| x == 1 || x == 3 || x == 5);
+ let _ = (1..3).any(|x| [1, 2, 3].contains(&x));
+ let _ = (1..3).any(|x| x == 0 || [1, 2, 3].contains(&x));
+ let _ = (1..3).any(|x| [1, 2, 3].contains(&x) || x == 0);
+ let _ = (1..3)
+ .any(|x| [1, 2, 3].contains(&x) || x == 0 || [4, 5, 6].contains(&x) || x == -1);
+
+ // Check `position().is_some()`, single-line case.
+ let _ = v.iter().any(|&x| x < 0);
+
+ // Check `rposition().is_some()`, single-line case.
+ let _ = v.iter().any(|&x| x < 0);
+
+ let s1 = String::from("hello world");
+ let s2 = String::from("world");
+ // caller of `find()` is a `&`static str`
+ let _ = "hello world".contains("world");
+ let _ = "hello world".contains(&s2);
+ let _ = "hello world".contains(&s2[2..]);
+ // caller of `find()` is a `String`
+ let _ = s1.contains("world");
+ let _ = s1.contains(&s2);
+ let _ = s1.contains(&s2[2..]);
+ // caller of `find()` is slice of `String`
+ let _ = s1[2..].contains("world");
+ let _ = s1[2..].contains(&s2);
+ let _ = s1[2..].contains(&s2[2..]);
+}
+
+#[allow(clippy::clone_on_copy, clippy::map_clone)]
+mod issue7392 {
+ struct Player {
+ hand: Vec<usize>,
+ }
+ fn filter() {
+ let p = Player {
+ hand: vec![1, 2, 3, 4, 5],
+ };
+ let filter_hand = vec![5];
+ let _ = p
+ .hand
+ .iter()
+ .filter(|c| filter_hand.iter().any(|cc| c == &cc))
+ .map(|c| c.clone())
+ .collect::<Vec<_>>();
+ }
+
+ struct PlayerTuple {
+ hand: Vec<(usize, char)>,
+ }
+ fn filter_tuple() {
+ let p = PlayerTuple {
+ hand: vec![(1, 'a'), (2, 'b'), (3, 'c'), (4, 'd'), (5, 'e')],
+ };
+ let filter_hand = vec![5];
+ let _ = p
+ .hand
+ .iter()
+ .filter(|(c, _)| filter_hand.iter().any(|cc| c == cc))
+ .map(|c| c.clone())
+ .collect::<Vec<_>>();
+ }
+
+ fn field_projection() {
+ struct Foo {
+ foo: i32,
+ bar: u32,
+ }
+ let vfoo = vec![Foo { foo: 1, bar: 2 }];
+ let _ = vfoo.iter().any(|v| v.foo == 1 && v.bar == 2);
+
+ let vfoo = vec![(42, Foo { foo: 1, bar: 2 })];
+ let _ = vfoo
+ .iter()
+ .any(|(i, v)| *i == 42 && v.foo == 1 && v.bar == 2);
+ }
+
+ fn index_projection() {
+ let vfoo = vec![[0, 1, 2, 3]];
+ let _ = vfoo.iter().any(|a| a[0] == 42);
+ }
+
+ #[allow(clippy::match_like_matches_macro)]
+ fn slice_projection() {
+ let vfoo = vec![[0, 1, 2, 3, 0, 1, 2, 3]];
+ let _ = vfoo.iter().any(|sub| sub[1..4].len() == 3);
+ }
+
+ fn please(x: &u32) -> bool {
+ *x == 9
+ }
+
+ fn deref_enough(x: u32) -> bool {
+ x == 78
+ }
+
+ fn arg_no_deref(x: &&u32) -> bool {
+ **x == 78
+ }
+
+ fn more_projections() {
+ let x = 19;
+ let ppx: &u32 = &x;
+ let _ = [ppx].iter().any(|ppp_x: &&u32| please(ppp_x));
+ let _ = [String::from("Hey hey")].iter().any(|s| s.len() == 2);
+
+ let v = vec![3, 2, 1, 0];
+ let _ = v.iter().any(|x| deref_enough(*x));
+ let _ = v.iter().any(|x: &u32| deref_enough(*x));
+
+ #[allow(clippy::redundant_closure)]
+ let _ = v.iter().any(|x| arg_no_deref(&x));
+ #[allow(clippy::redundant_closure)]
+ let _ = v.iter().any(|x: &u32| arg_no_deref(&x));
+ }
+
+ fn field_index_projection() {
+ struct FooDouble {
+ bar: Vec<Vec<i32>>,
+ }
+ struct Foo {
+ bar: Vec<i32>,
+ }
+ struct FooOuter {
+ inner: Foo,
+ inner_double: FooDouble,
+ }
+ let vfoo = vec![FooOuter {
+ inner: Foo { bar: vec![0, 1, 2, 3] },
+ inner_double: FooDouble {
+ bar: vec![vec![0, 1, 2, 3]],
+ },
+ }];
+ let _ = vfoo
+ .iter()
+ .any(|v| v.inner_double.bar[0][0] == 2 && v.inner.bar[0] == 2);
+ }
+
+ fn index_field_projection() {
+ struct Foo {
+ bar: i32,
+ }
+ struct FooOuter {
+ inner: Vec<Foo>,
+ }
+ let vfoo = vec![FooOuter {
+ inner: vec![Foo { bar: 0 }],
+ }];
+ let _ = vfoo.iter().any(|v| v.inner[0].bar == 2);
+ }
+
+ fn double_deref_index_projection() {
+ let vfoo = vec![&&[0, 1, 2, 3]];
+ let _ = vfoo.iter().any(|x| (**x)[0] == 9);
+ }
+
+ fn method_call_by_ref() {
+ struct Foo {
+ bar: u32,
+ }
+ impl Foo {
+ pub fn by_ref(&self, x: &u32) -> bool {
+ *x == self.bar
+ }
+ }
+ let vfoo = vec![Foo { bar: 1 }];
+ let _ = vfoo.iter().any(|v| v.by_ref(&v.bar));
+ }
+
+ fn ref_bindings() {
+ let _ = [&(&1, 2), &(&3, 4), &(&5, 4)].iter().any(|(&x, y)| x == *y);
+ let _ = [&(&1, 2), &(&3, 4), &(&5, 4)].iter().any(|(&x, y)| x == *y);
+ }
+
+ fn test_string_1(s: &str) -> bool {
+ s.is_empty()
+ }
+
+ fn test_u32_1(s: &u32) -> bool {
+ s.is_power_of_two()
+ }
+
+ fn test_u32_2(s: u32) -> bool {
+ s.is_power_of_two()
+ }
+
+ fn projection_in_args_test() {
+ // Index projections
+ let lst = &[String::from("Hello"), String::from("world")];
+ let v: Vec<&[String]> = vec![lst];
+ let _ = v.iter().any(|s| s[0].is_empty());
+ let _ = v.iter().any(|s| test_string_1(&s[0]));
+
+ // Field projections
+ struct FieldProjection<'a> {
+ field: &'a u32,
+ }
+ let field = 123456789;
+ let instance = FieldProjection { field: &field };
+ let v = vec![instance];
+ let _ = v.iter().any(|fp| fp.field.is_power_of_two());
+ let _ = v.iter().any(|fp| test_u32_1(fp.field));
+ let _ = v.iter().any(|fp| test_u32_2(*fp.field));
+ }
+}
diff --git a/src/tools/clippy/tests/ui/search_is_some_fixable_some.rs b/src/tools/clippy/tests/ui/search_is_some_fixable_some.rs
new file mode 100644
index 00000000000..241641fceae
--- /dev/null
+++ b/src/tools/clippy/tests/ui/search_is_some_fixable_some.rs
@@ -0,0 +1,221 @@
+// run-rustfix
+#![allow(dead_code)]
+#![warn(clippy::search_is_some)]
+
+fn main() {
+ let v = vec![3, 2, 1, 0, -1, -2, -3];
+ let y = &&42;
+
+ // Check `find().is_some()`, single-line case.
+ let _ = v.iter().find(|&x| *x < 0).is_some();
+ let _ = (0..1).find(|x| **y == *x).is_some(); // one dereference less
+ let _ = (0..1).find(|x| *x == 0).is_some();
+ let _ = v.iter().find(|x| **x == 0).is_some();
+ let _ = (4..5).find(|x| *x == 1 || *x == 3 || *x == 5).is_some();
+ let _ = (1..3).find(|x| [1, 2, 3].contains(x)).is_some();
+ let _ = (1..3).find(|x| *x == 0 || [1, 2, 3].contains(x)).is_some();
+ let _ = (1..3).find(|x| [1, 2, 3].contains(x) || *x == 0).is_some();
+ let _ = (1..3)
+ .find(|x| [1, 2, 3].contains(x) || *x == 0 || [4, 5, 6].contains(x) || *x == -1)
+ .is_some();
+
+ // Check `position().is_some()`, single-line case.
+ let _ = v.iter().position(|&x| x < 0).is_some();
+
+ // Check `rposition().is_some()`, single-line case.
+ let _ = v.iter().rposition(|&x| x < 0).is_some();
+
+ let s1 = String::from("hello world");
+ let s2 = String::from("world");
+ // caller of `find()` is a `&`static str`
+ let _ = "hello world".find("world").is_some();
+ let _ = "hello world".find(&s2).is_some();
+ let _ = "hello world".find(&s2[2..]).is_some();
+ // caller of `find()` is a `String`
+ let _ = s1.find("world").is_some();
+ let _ = s1.find(&s2).is_some();
+ let _ = s1.find(&s2[2..]).is_some();
+ // caller of `find()` is slice of `String`
+ let _ = s1[2..].find("world").is_some();
+ let _ = s1[2..].find(&s2).is_some();
+ let _ = s1[2..].find(&s2[2..]).is_some();
+}
+
+#[allow(clippy::clone_on_copy, clippy::map_clone)]
+mod issue7392 {
+ struct Player {
+ hand: Vec<usize>,
+ }
+ fn filter() {
+ let p = Player {
+ hand: vec![1, 2, 3, 4, 5],
+ };
+ let filter_hand = vec![5];
+ let _ = p
+ .hand
+ .iter()
+ .filter(|c| filter_hand.iter().find(|cc| c == cc).is_some())
+ .map(|c| c.clone())
+ .collect::<Vec<_>>();
+ }
+
+ struct PlayerTuple {
+ hand: Vec<(usize, char)>,
+ }
+ fn filter_tuple() {
+ let p = PlayerTuple {
+ hand: vec![(1, 'a'), (2, 'b'), (3, 'c'), (4, 'd'), (5, 'e')],
+ };
+ let filter_hand = vec![5];
+ let _ = p
+ .hand
+ .iter()
+ .filter(|(c, _)| filter_hand.iter().find(|cc| c == *cc).is_some())
+ .map(|c| c.clone())
+ .collect::<Vec<_>>();
+ }
+
+ fn field_projection() {
+ struct Foo {
+ foo: i32,
+ bar: u32,
+ }
+ let vfoo = vec![Foo { foo: 1, bar: 2 }];
+ let _ = vfoo.iter().find(|v| v.foo == 1 && v.bar == 2).is_some();
+
+ let vfoo = vec![(42, Foo { foo: 1, bar: 2 })];
+ let _ = vfoo
+ .iter()
+ .find(|(i, v)| *i == 42 && v.foo == 1 && v.bar == 2)
+ .is_some();
+ }
+
+ fn index_projection() {
+ let vfoo = vec![[0, 1, 2, 3]];
+ let _ = vfoo.iter().find(|a| a[0] == 42).is_some();
+ }
+
+ #[allow(clippy::match_like_matches_macro)]
+ fn slice_projection() {
+ let vfoo = vec![[0, 1, 2, 3, 0, 1, 2, 3]];
+ let _ = vfoo.iter().find(|sub| sub[1..4].len() == 3).is_some();
+ }
+
+ fn please(x: &u32) -> bool {
+ *x == 9
+ }
+
+ fn deref_enough(x: u32) -> bool {
+ x == 78
+ }
+
+ fn arg_no_deref(x: &&u32) -> bool {
+ **x == 78
+ }
+
+ fn more_projections() {
+ let x = 19;
+ let ppx: &u32 = &x;
+ let _ = [ppx].iter().find(|ppp_x: &&&u32| please(**ppp_x)).is_some();
+ let _ = [String::from("Hey hey")].iter().find(|s| s.len() == 2).is_some();
+
+ let v = vec![3, 2, 1, 0];
+ let _ = v.iter().find(|x| deref_enough(**x)).is_some();
+ let _ = v.iter().find(|x: &&u32| deref_enough(**x)).is_some();
+
+ #[allow(clippy::redundant_closure)]
+ let _ = v.iter().find(|x| arg_no_deref(x)).is_some();
+ #[allow(clippy::redundant_closure)]
+ let _ = v.iter().find(|x: &&u32| arg_no_deref(x)).is_some();
+ }
+
+ fn field_index_projection() {
+ struct FooDouble {
+ bar: Vec<Vec<i32>>,
+ }
+ struct Foo {
+ bar: Vec<i32>,
+ }
+ struct FooOuter {
+ inner: Foo,
+ inner_double: FooDouble,
+ }
+ let vfoo = vec![FooOuter {
+ inner: Foo { bar: vec![0, 1, 2, 3] },
+ inner_double: FooDouble {
+ bar: vec![vec![0, 1, 2, 3]],
+ },
+ }];
+ let _ = vfoo
+ .iter()
+ .find(|v| v.inner_double.bar[0][0] == 2 && v.inner.bar[0] == 2)
+ .is_some();
+ }
+
+ fn index_field_projection() {
+ struct Foo {
+ bar: i32,
+ }
+ struct FooOuter {
+ inner: Vec<Foo>,
+ }
+ let vfoo = vec![FooOuter {
+ inner: vec![Foo { bar: 0 }],
+ }];
+ let _ = vfoo.iter().find(|v| v.inner[0].bar == 2).is_some();
+ }
+
+ fn double_deref_index_projection() {
+ let vfoo = vec![&&[0, 1, 2, 3]];
+ let _ = vfoo.iter().find(|x| (**x)[0] == 9).is_some();
+ }
+
+ fn method_call_by_ref() {
+ struct Foo {
+ bar: u32,
+ }
+ impl Foo {
+ pub fn by_ref(&self, x: &u32) -> bool {
+ *x == self.bar
+ }
+ }
+ let vfoo = vec![Foo { bar: 1 }];
+ let _ = vfoo.iter().find(|v| v.by_ref(&v.bar)).is_some();
+ }
+
+ fn ref_bindings() {
+ let _ = [&(&1, 2), &(&3, 4), &(&5, 4)].iter().find(|(&x, y)| x == *y).is_some();
+ let _ = [&(&1, 2), &(&3, 4), &(&5, 4)].iter().find(|&(&x, y)| x == *y).is_some();
+ }
+
+ fn test_string_1(s: &String) -> bool {
+ s.is_empty()
+ }
+
+ fn test_u32_1(s: &u32) -> bool {
+ s.is_power_of_two()
+ }
+
+ fn test_u32_2(s: u32) -> bool {
+ s.is_power_of_two()
+ }
+
+ fn projection_in_args_test() {
+ // Index projections
+ let lst = &[String::from("Hello"), String::from("world")];
+ let v: Vec<&[String]> = vec![lst];
+ let _ = v.iter().find(|s| s[0].is_empty()).is_some();
+ let _ = v.iter().find(|s| test_string_1(&s[0])).is_some();
+
+ // Field projections
+ struct FieldProjection<'a> {
+ field: &'a u32,
+ }
+ let field = 123456789;
+ let instance = FieldProjection { field: &field };
+ let v = vec![instance];
+ let _ = v.iter().find(|fp| fp.field.is_power_of_two()).is_some();
+ let _ = v.iter().find(|fp| test_u32_1(fp.field)).is_some();
+ let _ = v.iter().find(|fp| test_u32_2(*fp.field)).is_some();
+ }
+}
diff --git a/src/tools/clippy/tests/ui/search_is_some_fixable_some.stderr b/src/tools/clippy/tests/ui/search_is_some_fixable_some.stderr
new file mode 100644
index 00000000000..9212c6e71ff
--- /dev/null
+++ b/src/tools/clippy/tests/ui/search_is_some_fixable_some.stderr
@@ -0,0 +1,276 @@
+error: called `is_some()` after searching an `Iterator` with `find`
+ --> $DIR/search_is_some_fixable_some.rs:10:22
+ |
+LL | let _ = v.iter().find(|&x| *x < 0).is_some();
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `any()` instead: `any(|x| *x < 0)`
+ |
+ = note: `-D clippy::search-is-some` implied by `-D warnings`
+
+error: called `is_some()` after searching an `Iterator` with `find`
+ --> $DIR/search_is_some_fixable_some.rs:11:20
+ |
+LL | let _ = (0..1).find(|x| **y == *x).is_some(); // one dereference less
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `any()` instead: `any(|x| **y == x)`
+
+error: called `is_some()` after searching an `Iterator` with `find`
+ --> $DIR/search_is_some_fixable_some.rs:12:20
+ |
+LL | let _ = (0..1).find(|x| *x == 0).is_some();
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `any()` instead: `any(|x| x == 0)`
+
+error: called `is_some()` after searching an `Iterator` with `find`
+ --> $DIR/search_is_some_fixable_some.rs:13:22
+ |
+LL | let _ = v.iter().find(|x| **x == 0).is_some();
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `any()` instead: `any(|x| *x == 0)`
+
+error: called `is_some()` after searching an `Iterator` with `find`
+ --> $DIR/search_is_some_fixable_some.rs:14:20
+ |
+LL | let _ = (4..5).find(|x| *x == 1 || *x == 3 || *x == 5).is_some();
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `any()` instead: `any(|x| x == 1 || x == 3 || x == 5)`
+
+error: called `is_some()` after searching an `Iterator` with `find`
+ --> $DIR/search_is_some_fixable_some.rs:15:20
+ |
+LL | let _ = (1..3).find(|x| [1, 2, 3].contains(x)).is_some();
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `any()` instead: `any(|x| [1, 2, 3].contains(&x))`
+
+error: called `is_some()` after searching an `Iterator` with `find`
+ --> $DIR/search_is_some_fixable_some.rs:16:20
+ |
+LL | let _ = (1..3).find(|x| *x == 0 || [1, 2, 3].contains(x)).is_some();
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `any()` instead: `any(|x| x == 0 || [1, 2, 3].contains(&x))`
+
+error: called `is_some()` after searching an `Iterator` with `find`
+ --> $DIR/search_is_some_fixable_some.rs:17:20
+ |
+LL | let _ = (1..3).find(|x| [1, 2, 3].contains(x) || *x == 0).is_some();
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `any()` instead: `any(|x| [1, 2, 3].contains(&x) || x == 0)`
+
+error: called `is_some()` after searching an `Iterator` with `find`
+ --> $DIR/search_is_some_fixable_some.rs:19:10
+ |
+LL | .find(|x| [1, 2, 3].contains(x) || *x == 0 || [4, 5, 6].contains(x) || *x == -1)
+ | __________^
+LL | | .is_some();
+ | |__________________^ help: use `any()` instead: `any(|x| [1, 2, 3].contains(&x) || x == 0 || [4, 5, 6].contains(&x) || x == -1)`
+
+error: called `is_some()` after searching an `Iterator` with `position`
+ --> $DIR/search_is_some_fixable_some.rs:23:22
+ |
+LL | let _ = v.iter().position(|&x| x < 0).is_some();
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `any()` instead: `any(|&x| x < 0)`
+
+error: called `is_some()` after searching an `Iterator` with `rposition`
+ --> $DIR/search_is_some_fixable_some.rs:26:22
+ |
+LL | let _ = v.iter().rposition(|&x| x < 0).is_some();
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `any()` instead: `any(|&x| x < 0)`
+
+error: called `is_some()` after calling `find()` on a string
+ --> $DIR/search_is_some_fixable_some.rs:31:27
+ |
+LL | let _ = "hello world".find("world").is_some();
+ | ^^^^^^^^^^^^^^^^^^^^^^^ help: use `contains()` instead: `contains("world")`
+
+error: called `is_some()` after calling `find()` on a string
+ --> $DIR/search_is_some_fixable_some.rs:32:27
+ |
+LL | let _ = "hello world".find(&s2).is_some();
+ | ^^^^^^^^^^^^^^^^^^^ help: use `contains()` instead: `contains(&s2)`
+
+error: called `is_some()` after calling `find()` on a string
+ --> $DIR/search_is_some_fixable_some.rs:33:27
+ |
+LL | let _ = "hello world".find(&s2[2..]).is_some();
+ | ^^^^^^^^^^^^^^^^^^^^^^^^ help: use `contains()` instead: `contains(&s2[2..])`
+
+error: called `is_some()` after calling `find()` on a string
+ --> $DIR/search_is_some_fixable_some.rs:35:16
+ |
+LL | let _ = s1.find("world").is_some();
+ | ^^^^^^^^^^^^^^^^^^^^^^^ help: use `contains()` instead: `contains("world")`
+
+error: called `is_some()` after calling `find()` on a string
+ --> $DIR/search_is_some_fixable_some.rs:36:16
+ |
+LL | let _ = s1.find(&s2).is_some();
+ | ^^^^^^^^^^^^^^^^^^^ help: use `contains()` instead: `contains(&s2)`
+
+error: called `is_some()` after calling `find()` on a string
+ --> $DIR/search_is_some_fixable_some.rs:37:16
+ |
+LL | let _ = s1.find(&s2[2..]).is_some();
+ | ^^^^^^^^^^^^^^^^^^^^^^^^ help: use `contains()` instead: `contains(&s2[2..])`
+
+error: called `is_some()` after calling `find()` on a string
+ --> $DIR/search_is_some_fixable_some.rs:39:21
+ |
+LL | let _ = s1[2..].find("world").is_some();
+ | ^^^^^^^^^^^^^^^^^^^^^^^ help: use `contains()` instead: `contains("world")`
+
+error: called `is_some()` after calling `find()` on a string
+ --> $DIR/search_is_some_fixable_some.rs:40:21
+ |
+LL | let _ = s1[2..].find(&s2).is_some();
+ | ^^^^^^^^^^^^^^^^^^^ help: use `contains()` instead: `contains(&s2)`
+
+error: called `is_some()` after calling `find()` on a string
+ --> $DIR/search_is_some_fixable_some.rs:41:21
+ |
+LL | let _ = s1[2..].find(&s2[2..]).is_some();
+ | ^^^^^^^^^^^^^^^^^^^^^^^^ help: use `contains()` instead: `contains(&s2[2..])`
+
+error: called `is_some()` after searching an `Iterator` with `find`
+ --> $DIR/search_is_some_fixable_some.rs:57:44
+ |
+LL | .filter(|c| filter_hand.iter().find(|cc| c == cc).is_some())
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `any()` instead: `any(|cc| c == &cc)`
+
+error: called `is_some()` after searching an `Iterator` with `find`
+ --> $DIR/search_is_some_fixable_some.rs:73:49
+ |
+LL | .filter(|(c, _)| filter_hand.iter().find(|cc| c == *cc).is_some())
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `any()` instead: `any(|cc| c == cc)`
+
+error: called `is_some()` after searching an `Iterator` with `find`
+ --> $DIR/search_is_some_fixable_some.rs:84:29
+ |
+LL | let _ = vfoo.iter().find(|v| v.foo == 1 && v.bar == 2).is_some();
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `any()` instead: `any(|v| v.foo == 1 && v.bar == 2)`
+
+error: called `is_some()` after searching an `Iterator` with `find`
+ --> $DIR/search_is_some_fixable_some.rs:89:14
+ |
+LL | .find(|(i, v)| *i == 42 && v.foo == 1 && v.bar == 2)
+ | ______________^
+LL | | .is_some();
+ | |______________________^ help: use `any()` instead: `any(|(i, v)| *i == 42 && v.foo == 1 && v.bar == 2)`
+
+error: called `is_some()` after searching an `Iterator` with `find`
+ --> $DIR/search_is_some_fixable_some.rs:95:29
+ |
+LL | let _ = vfoo.iter().find(|a| a[0] == 42).is_some();
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `any()` instead: `any(|a| a[0] == 42)`
+
+error: called `is_some()` after searching an `Iterator` with `find`
+ --> $DIR/search_is_some_fixable_some.rs:101:29
+ |
+LL | let _ = vfoo.iter().find(|sub| sub[1..4].len() == 3).is_some();
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `any()` instead: `any(|sub| sub[1..4].len() == 3)`
+
+error: called `is_some()` after searching an `Iterator` with `find`
+ --> $DIR/search_is_some_fixable_some.rs:119:30
+ |
+LL | let _ = [ppx].iter().find(|ppp_x: &&&u32| please(**ppp_x)).is_some();
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `any()` instead: `any(|ppp_x: &&u32| please(ppp_x))`
+
+error: called `is_some()` after searching an `Iterator` with `find`
+ --> $DIR/search_is_some_fixable_some.rs:120:50
+ |
+LL | let _ = [String::from("Hey hey")].iter().find(|s| s.len() == 2).is_some();
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `any()` instead: `any(|s| s.len() == 2)`
+
+error: called `is_some()` after searching an `Iterator` with `find`
+ --> $DIR/search_is_some_fixable_some.rs:123:26
+ |
+LL | let _ = v.iter().find(|x| deref_enough(**x)).is_some();
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `any()` instead: `any(|x| deref_enough(*x))`
+
+error: called `is_some()` after searching an `Iterator` with `find`
+ --> $DIR/search_is_some_fixable_some.rs:124:26
+ |
+LL | let _ = v.iter().find(|x: &&u32| deref_enough(**x)).is_some();
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `any()` instead: `any(|x: &u32| deref_enough(*x))`
+
+error: called `is_some()` after searching an `Iterator` with `find`
+ --> $DIR/search_is_some_fixable_some.rs:127:26
+ |
+LL | let _ = v.iter().find(|x| arg_no_deref(x)).is_some();
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `any()` instead: `any(|x| arg_no_deref(&x))`
+
+error: called `is_some()` after searching an `Iterator` with `find`
+ --> $DIR/search_is_some_fixable_some.rs:129:26
+ |
+LL | let _ = v.iter().find(|x: &&u32| arg_no_deref(x)).is_some();
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `any()` instead: `any(|x: &u32| arg_no_deref(&x))`
+
+error: called `is_some()` after searching an `Iterator` with `find`
+ --> $DIR/search_is_some_fixable_some.rs:151:14
+ |
+LL | .find(|v| v.inner_double.bar[0][0] == 2 && v.inner.bar[0] == 2)
+ | ______________^
+LL | | .is_some();
+ | |______________________^ help: use `any()` instead: `any(|v| v.inner_double.bar[0][0] == 2 && v.inner.bar[0] == 2)`
+
+error: called `is_some()` after searching an `Iterator` with `find`
+ --> $DIR/search_is_some_fixable_some.rs:165:29
+ |
+LL | let _ = vfoo.iter().find(|v| v.inner[0].bar == 2).is_some();
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `any()` instead: `any(|v| v.inner[0].bar == 2)`
+
+error: called `is_some()` after searching an `Iterator` with `find`
+ --> $DIR/search_is_some_fixable_some.rs:170:29
+ |
+LL | let _ = vfoo.iter().find(|x| (**x)[0] == 9).is_some();
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `any()` instead: `any(|x| (**x)[0] == 9)`
+
+error: called `is_some()` after searching an `Iterator` with `find`
+ --> $DIR/search_is_some_fixable_some.rs:183:29
+ |
+LL | let _ = vfoo.iter().find(|v| v.by_ref(&v.bar)).is_some();
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `any()` instead: `any(|v| v.by_ref(&v.bar))`
+
+error: called `is_some()` after searching an `Iterator` with `find`
+ --> $DIR/search_is_some_fixable_some.rs:187:55
+ |
+LL | let _ = [&(&1, 2), &(&3, 4), &(&5, 4)].iter().find(|(&x, y)| x == *y).is_some();
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `any()` instead: `any(|(&x, y)| x == *y)`
+
+error: called `is_some()` after searching an `Iterator` with `find`
+ --> $DIR/search_is_some_fixable_some.rs:188:55
+ |
+LL | let _ = [&(&1, 2), &(&3, 4), &(&5, 4)].iter().find(|&(&x, y)| x == *y).is_some();
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `any()` instead: `any(|(&x, y)| x == *y)`
+
+error: writing `&String` instead of `&str` involves a new object where a slice will do
+ --> $DIR/search_is_some_fixable_some.rs:191:25
+ |
+LL | fn test_string_1(s: &String) -> bool {
+ | ^^^^^^^ help: change this to: `&str`
+ |
+ = note: `-D clippy::ptr-arg` implied by `-D warnings`
+
+error: called `is_some()` after searching an `Iterator` with `find`
+ --> $DIR/search_is_some_fixable_some.rs:207:26
+ |
+LL | let _ = v.iter().find(|s| s[0].is_empty()).is_some();
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `any()` instead: `any(|s| s[0].is_empty())`
+
+error: called `is_some()` after searching an `Iterator` with `find`
+ --> $DIR/search_is_some_fixable_some.rs:208:26
+ |
+LL | let _ = v.iter().find(|s| test_string_1(&s[0])).is_some();
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `any()` instead: `any(|s| test_string_1(&s[0]))`
+
+error: called `is_some()` after searching an `Iterator` with `find`
+ --> $DIR/search_is_some_fixable_some.rs:217:26
+ |
+LL | let _ = v.iter().find(|fp| fp.field.is_power_of_two()).is_some();
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `any()` instead: `any(|fp| fp.field.is_power_of_two())`
+
+error: called `is_some()` after searching an `Iterator` with `find`
+ --> $DIR/search_is_some_fixable_some.rs:218:26
+ |
+LL | let _ = v.iter().find(|fp| test_u32_1(fp.field)).is_some();
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `any()` instead: `any(|fp| test_u32_1(fp.field))`
+
+error: called `is_some()` after searching an `Iterator` with `find`
+ --> $DIR/search_is_some_fixable_some.rs:219:26
+ |
+LL | let _ = v.iter().find(|fp| test_u32_2(*fp.field)).is_some();
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `any()` instead: `any(|fp| test_u32_2(*fp.field))`
+
+error: aborting due to 44 previous errors
+
diff --git a/src/tools/clippy/tests/ui/semicolon_if_nothing_returned.rs b/src/tools/clippy/tests/ui/semicolon_if_nothing_returned.rs
index 7a45f1b18d4..91916e7480f 100644
--- a/src/tools/clippy/tests/ui/semicolon_if_nothing_returned.rs
+++ b/src/tools/clippy/tests/ui/semicolon_if_nothing_returned.rs
@@ -1,6 +1,7 @@
#![warn(clippy::semicolon_if_nothing_returned)]
#![allow(clippy::redundant_closure)]
#![feature(label_break_value)]
+#![feature(let_else)]
fn get_unit() {}
@@ -110,3 +111,12 @@ fn macro_with_semicolon() {
}
repro!();
}
+
+fn function_returning_option() -> Option<i32> {
+ Some(1)
+}
+
+// No warning
+fn let_else_stmts() {
+ let Some(x) = function_returning_option() else { return; };
+}
diff --git a/src/tools/clippy/tests/ui/semicolon_if_nothing_returned.stderr b/src/tools/clippy/tests/ui/semicolon_if_nothing_returned.stderr
index 78813e7cc1c..41d2c1cfb87 100644
--- a/src/tools/clippy/tests/ui/semicolon_if_nothing_returned.stderr
+++ b/src/tools/clippy/tests/ui/semicolon_if_nothing_returned.stderr
@@ -1,5 +1,5 @@
error: consider adding a `;` to the last statement for consistent formatting
- --> $DIR/semicolon_if_nothing_returned.rs:9:5
+ --> $DIR/semicolon_if_nothing_returned.rs:10:5
|
LL | println!("Hello")
| ^^^^^^^^^^^^^^^^^ help: add a `;` here: `println!("Hello");`
@@ -7,25 +7,25 @@ LL | println!("Hello")
= note: `-D clippy::semicolon-if-nothing-returned` implied by `-D warnings`
error: consider adding a `;` to the last statement for consistent formatting
- --> $DIR/semicolon_if_nothing_returned.rs:13:5
+ --> $DIR/semicolon_if_nothing_returned.rs:14:5
|
LL | get_unit()
| ^^^^^^^^^^ help: add a `;` here: `get_unit();`
error: consider adding a `;` to the last statement for consistent formatting
- --> $DIR/semicolon_if_nothing_returned.rs:18:5
+ --> $DIR/semicolon_if_nothing_returned.rs:19:5
|
LL | y = x + 1
| ^^^^^^^^^ help: add a `;` here: `y = x + 1;`
error: consider adding a `;` to the last statement for consistent formatting
- --> $DIR/semicolon_if_nothing_returned.rs:24:9
+ --> $DIR/semicolon_if_nothing_returned.rs:25:9
|
LL | hello()
| ^^^^^^^ help: add a `;` here: `hello();`
error: consider adding a `;` to the last statement for consistent formatting
- --> $DIR/semicolon_if_nothing_returned.rs:35:9
+ --> $DIR/semicolon_if_nothing_returned.rs:36:9
|
LL | ptr::drop_in_place(s.as_mut_ptr())
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: add a `;` here: `ptr::drop_in_place(s.as_mut_ptr());`
diff --git a/src/tools/clippy/tests/ui/shadow.rs b/src/tools/clippy/tests/ui/shadow.rs
index 55caef59f7f..06f6949b66f 100644
--- a/src/tools/clippy/tests/ui/shadow.rs
+++ b/src/tools/clippy/tests/ui/shadow.rs
@@ -79,4 +79,10 @@ fn question_mark() -> Option<()> {
None
}
+pub async fn foo1(_a: i32) {}
+
+pub async fn foo2(_a: i32, _b: i64) {
+ let _b = _a;
+}
+
fn main() {}
diff --git a/src/tools/clippy/tests/ui/shadow.stderr b/src/tools/clippy/tests/ui/shadow.stderr
index feed6e1ba8b..dcc7d4e6b2f 100644
--- a/src/tools/clippy/tests/ui/shadow.stderr
+++ b/src/tools/clippy/tests/ui/shadow.stderr
@@ -241,5 +241,17 @@ note: previous binding is here
LL | let _ = |[x]: [u32; 1]| {
| ^
-error: aborting due to 20 previous errors
+error: `_b` shadows a previous, unrelated binding
+ --> $DIR/shadow.rs:85:9
+ |
+LL | let _b = _a;
+ | ^^
+ |
+note: previous binding is here
+ --> $DIR/shadow.rs:84:28
+ |
+LL | pub async fn foo2(_a: i32, _b: i64) {
+ | ^^
+
+error: aborting due to 21 previous errors
diff --git a/src/tools/clippy/tests/ui/should_impl_trait/corner_cases.rs b/src/tools/clippy/tests/ui/should_impl_trait/corner_cases.rs
index d7e8d02bd19..1ccb0a1d167 100644
--- a/src/tools/clippy/tests/ui/should_impl_trait/corner_cases.rs
+++ b/src/tools/clippy/tests/ui/should_impl_trait/corner_cases.rs
@@ -7,7 +7,8 @@
clippy::needless_lifetimes,
clippy::missing_safety_doc,
clippy::wrong_self_convention,
- clippy::missing_panics_doc
+ clippy::missing_panics_doc,
+ clippy::return_self_not_must_use
)]
use std::ops::Mul;
diff --git a/src/tools/clippy/tests/ui/should_impl_trait/method_list_1.rs b/src/tools/clippy/tests/ui/should_impl_trait/method_list_1.rs
index ea962f94317..20d49f5a976 100644
--- a/src/tools/clippy/tests/ui/should_impl_trait/method_list_1.rs
+++ b/src/tools/clippy/tests/ui/should_impl_trait/method_list_1.rs
@@ -7,7 +7,8 @@
clippy::needless_lifetimes,
clippy::missing_safety_doc,
clippy::wrong_self_convention,
- clippy::missing_panics_doc
+ clippy::missing_panics_doc,
+ clippy::return_self_not_must_use
)]
use std::ops::Mul;
diff --git a/src/tools/clippy/tests/ui/should_impl_trait/method_list_1.stderr b/src/tools/clippy/tests/ui/should_impl_trait/method_list_1.stderr
index bf8b47d5626..2b7d4628c3f 100644
--- a/src/tools/clippy/tests/ui/should_impl_trait/method_list_1.stderr
+++ b/src/tools/clippy/tests/ui/should_impl_trait/method_list_1.stderr
@@ -1,5 +1,5 @@
error: method `add` can be confused for the standard trait method `std::ops::Add::add`
- --> $DIR/method_list_1.rs:24:5
+ --> $DIR/method_list_1.rs:25:5
|
LL | / pub fn add(self, other: T) -> T {
LL | | unimplemented!()
@@ -10,7 +10,7 @@ LL | | }
= help: consider implementing the trait `std::ops::Add` or choosing a less ambiguous method name
error: method `as_mut` can be confused for the standard trait method `std::convert::AsMut::as_mut`
- --> $DIR/method_list_1.rs:28:5
+ --> $DIR/method_list_1.rs:29:5
|
LL | / pub fn as_mut(&mut self) -> &mut T {
LL | | unimplemented!()
@@ -20,7 +20,7 @@ LL | | }
= help: consider implementing the trait `std::convert::AsMut` or choosing a less ambiguous method name
error: method `as_ref` can be confused for the standard trait method `std::convert::AsRef::as_ref`
- --> $DIR/method_list_1.rs:32:5
+ --> $DIR/method_list_1.rs:33:5
|
LL | / pub fn as_ref(&self) -> &T {
LL | | unimplemented!()
@@ -30,7 +30,7 @@ LL | | }
= help: consider implementing the trait `std::convert::AsRef` or choosing a less ambiguous method name
error: method `bitand` can be confused for the standard trait method `std::ops::BitAnd::bitand`
- --> $DIR/method_list_1.rs:36:5
+ --> $DIR/method_list_1.rs:37:5
|
LL | / pub fn bitand(self, rhs: T) -> T {
LL | | unimplemented!()
@@ -40,7 +40,7 @@ LL | | }
= help: consider implementing the trait `std::ops::BitAnd` or choosing a less ambiguous method name
error: method `bitor` can be confused for the standard trait method `std::ops::BitOr::bitor`
- --> $DIR/method_list_1.rs:40:5
+ --> $DIR/method_list_1.rs:41:5
|
LL | / pub fn bitor(self, rhs: Self) -> Self {
LL | | unimplemented!()
@@ -50,7 +50,7 @@ LL | | }
= help: consider implementing the trait `std::ops::BitOr` or choosing a less ambiguous method name
error: method `bitxor` can be confused for the standard trait method `std::ops::BitXor::bitxor`
- --> $DIR/method_list_1.rs:44:5
+ --> $DIR/method_list_1.rs:45:5
|
LL | / pub fn bitxor(self, rhs: Self) -> Self {
LL | | unimplemented!()
@@ -60,7 +60,7 @@ LL | | }
= help: consider implementing the trait `std::ops::BitXor` or choosing a less ambiguous method name
error: method `borrow` can be confused for the standard trait method `std::borrow::Borrow::borrow`
- --> $DIR/method_list_1.rs:48:5
+ --> $DIR/method_list_1.rs:49:5
|
LL | / pub fn borrow(&self) -> &str {
LL | | unimplemented!()
@@ -70,7 +70,7 @@ LL | | }
= help: consider implementing the trait `std::borrow::Borrow` or choosing a less ambiguous method name
error: method `borrow_mut` can be confused for the standard trait method `std::borrow::BorrowMut::borrow_mut`
- --> $DIR/method_list_1.rs:52:5
+ --> $DIR/method_list_1.rs:53:5
|
LL | / pub fn borrow_mut(&mut self) -> &mut str {
LL | | unimplemented!()
@@ -80,7 +80,7 @@ LL | | }
= help: consider implementing the trait `std::borrow::BorrowMut` or choosing a less ambiguous method name
error: method `clone` can be confused for the standard trait method `std::clone::Clone::clone`
- --> $DIR/method_list_1.rs:56:5
+ --> $DIR/method_list_1.rs:57:5
|
LL | / pub fn clone(&self) -> Self {
LL | | unimplemented!()
@@ -90,7 +90,7 @@ LL | | }
= help: consider implementing the trait `std::clone::Clone` or choosing a less ambiguous method name
error: method `cmp` can be confused for the standard trait method `std::cmp::Ord::cmp`
- --> $DIR/method_list_1.rs:60:5
+ --> $DIR/method_list_1.rs:61:5
|
LL | / pub fn cmp(&self, other: &Self) -> Self {
LL | | unimplemented!()
@@ -100,7 +100,7 @@ LL | | }
= help: consider implementing the trait `std::cmp::Ord` or choosing a less ambiguous method name
error: method `deref` can be confused for the standard trait method `std::ops::Deref::deref`
- --> $DIR/method_list_1.rs:68:5
+ --> $DIR/method_list_1.rs:69:5
|
LL | / pub fn deref(&self) -> &Self {
LL | | unimplemented!()
@@ -110,7 +110,7 @@ LL | | }
= help: consider implementing the trait `std::ops::Deref` or choosing a less ambiguous method name
error: method `deref_mut` can be confused for the standard trait method `std::ops::DerefMut::deref_mut`
- --> $DIR/method_list_1.rs:72:5
+ --> $DIR/method_list_1.rs:73:5
|
LL | / pub fn deref_mut(&mut self) -> &mut Self {
LL | | unimplemented!()
@@ -120,7 +120,7 @@ LL | | }
= help: consider implementing the trait `std::ops::DerefMut` or choosing a less ambiguous method name
error: method `div` can be confused for the standard trait method `std::ops::Div::div`
- --> $DIR/method_list_1.rs:76:5
+ --> $DIR/method_list_1.rs:77:5
|
LL | / pub fn div(self, rhs: Self) -> Self {
LL | | unimplemented!()
@@ -130,7 +130,7 @@ LL | | }
= help: consider implementing the trait `std::ops::Div` or choosing a less ambiguous method name
error: method `drop` can be confused for the standard trait method `std::ops::Drop::drop`
- --> $DIR/method_list_1.rs:80:5
+ --> $DIR/method_list_1.rs:81:5
|
LL | / pub fn drop(&mut self) {
LL | | unimplemented!()
diff --git a/src/tools/clippy/tests/ui/should_impl_trait/method_list_2.rs b/src/tools/clippy/tests/ui/should_impl_trait/method_list_2.rs
index b663568806d..3efec1c5202 100644
--- a/src/tools/clippy/tests/ui/should_impl_trait/method_list_2.rs
+++ b/src/tools/clippy/tests/ui/should_impl_trait/method_list_2.rs
@@ -7,7 +7,8 @@
clippy::needless_lifetimes,
clippy::missing_safety_doc,
clippy::wrong_self_convention,
- clippy::missing_panics_doc
+ clippy::missing_panics_doc,
+ clippy::return_self_not_must_use
)]
use std::ops::Mul;
diff --git a/src/tools/clippy/tests/ui/should_impl_trait/method_list_2.stderr b/src/tools/clippy/tests/ui/should_impl_trait/method_list_2.stderr
index 426fe3b1adc..b6fd4356956 100644
--- a/src/tools/clippy/tests/ui/should_impl_trait/method_list_2.stderr
+++ b/src/tools/clippy/tests/ui/should_impl_trait/method_list_2.stderr
@@ -1,5 +1,5 @@
error: method `eq` can be confused for the standard trait method `std::cmp::PartialEq::eq`
- --> $DIR/method_list_2.rs:25:5
+ --> $DIR/method_list_2.rs:26:5
|
LL | / pub fn eq(&self, other: &Self) -> bool {
LL | | unimplemented!()
@@ -10,7 +10,7 @@ LL | | }
= help: consider implementing the trait `std::cmp::PartialEq` or choosing a less ambiguous method name
error: method `from_iter` can be confused for the standard trait method `std::iter::FromIterator::from_iter`
- --> $DIR/method_list_2.rs:29:5
+ --> $DIR/method_list_2.rs:30:5
|
LL | / pub fn from_iter<T>(iter: T) -> Self {
LL | | unimplemented!()
@@ -20,7 +20,7 @@ LL | | }
= help: consider implementing the trait `std::iter::FromIterator` or choosing a less ambiguous method name
error: method `from_str` can be confused for the standard trait method `std::str::FromStr::from_str`
- --> $DIR/method_list_2.rs:33:5
+ --> $DIR/method_list_2.rs:34:5
|
LL | / pub fn from_str(s: &str) -> Result<Self, Self> {
LL | | unimplemented!()
@@ -30,7 +30,7 @@ LL | | }
= help: consider implementing the trait `std::str::FromStr` or choosing a less ambiguous method name
error: method `hash` can be confused for the standard trait method `std::hash::Hash::hash`
- --> $DIR/method_list_2.rs:37:5
+ --> $DIR/method_list_2.rs:38:5
|
LL | / pub fn hash(&self, state: &mut T) {
LL | | unimplemented!()
@@ -40,7 +40,7 @@ LL | | }
= help: consider implementing the trait `std::hash::Hash` or choosing a less ambiguous method name
error: method `index` can be confused for the standard trait method `std::ops::Index::index`
- --> $DIR/method_list_2.rs:41:5
+ --> $DIR/method_list_2.rs:42:5
|
LL | / pub fn index(&self, index: usize) -> &Self {
LL | | unimplemented!()
@@ -50,7 +50,7 @@ LL | | }
= help: consider implementing the trait `std::ops::Index` or choosing a less ambiguous method name
error: method `index_mut` can be confused for the standard trait method `std::ops::IndexMut::index_mut`
- --> $DIR/method_list_2.rs:45:5
+ --> $DIR/method_list_2.rs:46:5
|
LL | / pub fn index_mut(&mut self, index: usize) -> &mut Self {
LL | | unimplemented!()
@@ -60,7 +60,7 @@ LL | | }
= help: consider implementing the trait `std::ops::IndexMut` or choosing a less ambiguous method name
error: method `into_iter` can be confused for the standard trait method `std::iter::IntoIterator::into_iter`
- --> $DIR/method_list_2.rs:49:5
+ --> $DIR/method_list_2.rs:50:5
|
LL | / pub fn into_iter(self) -> Self {
LL | | unimplemented!()
@@ -70,7 +70,7 @@ LL | | }
= help: consider implementing the trait `std::iter::IntoIterator` or choosing a less ambiguous method name
error: method `mul` can be confused for the standard trait method `std::ops::Mul::mul`
- --> $DIR/method_list_2.rs:53:5
+ --> $DIR/method_list_2.rs:54:5
|
LL | / pub fn mul(self, rhs: Self) -> Self {
LL | | unimplemented!()
@@ -80,7 +80,7 @@ LL | | }
= help: consider implementing the trait `std::ops::Mul` or choosing a less ambiguous method name
error: method `neg` can be confused for the standard trait method `std::ops::Neg::neg`
- --> $DIR/method_list_2.rs:57:5
+ --> $DIR/method_list_2.rs:58:5
|
LL | / pub fn neg(self) -> Self {
LL | | unimplemented!()
@@ -90,7 +90,7 @@ LL | | }
= help: consider implementing the trait `std::ops::Neg` or choosing a less ambiguous method name
error: method `next` can be confused for the standard trait method `std::iter::Iterator::next`
- --> $DIR/method_list_2.rs:61:5
+ --> $DIR/method_list_2.rs:62:5
|
LL | / pub fn next(&mut self) -> Option<Self> {
LL | | unimplemented!()
@@ -100,7 +100,7 @@ LL | | }
= help: consider implementing the trait `std::iter::Iterator` or choosing a less ambiguous method name
error: method `not` can be confused for the standard trait method `std::ops::Not::not`
- --> $DIR/method_list_2.rs:65:5
+ --> $DIR/method_list_2.rs:66:5
|
LL | / pub fn not(self) -> Self {
LL | | unimplemented!()
@@ -110,7 +110,7 @@ LL | | }
= help: consider implementing the trait `std::ops::Not` or choosing a less ambiguous method name
error: method `rem` can be confused for the standard trait method `std::ops::Rem::rem`
- --> $DIR/method_list_2.rs:69:5
+ --> $DIR/method_list_2.rs:70:5
|
LL | / pub fn rem(self, rhs: Self) -> Self {
LL | | unimplemented!()
@@ -120,7 +120,7 @@ LL | | }
= help: consider implementing the trait `std::ops::Rem` or choosing a less ambiguous method name
error: method `shl` can be confused for the standard trait method `std::ops::Shl::shl`
- --> $DIR/method_list_2.rs:73:5
+ --> $DIR/method_list_2.rs:74:5
|
LL | / pub fn shl(self, rhs: Self) -> Self {
LL | | unimplemented!()
@@ -130,7 +130,7 @@ LL | | }
= help: consider implementing the trait `std::ops::Shl` or choosing a less ambiguous method name
error: method `shr` can be confused for the standard trait method `std::ops::Shr::shr`
- --> $DIR/method_list_2.rs:77:5
+ --> $DIR/method_list_2.rs:78:5
|
LL | / pub fn shr(self, rhs: Self) -> Self {
LL | | unimplemented!()
@@ -140,7 +140,7 @@ LL | | }
= help: consider implementing the trait `std::ops::Shr` or choosing a less ambiguous method name
error: method `sub` can be confused for the standard trait method `std::ops::Sub::sub`
- --> $DIR/method_list_2.rs:81:5
+ --> $DIR/method_list_2.rs:82:5
|
LL | / pub fn sub(self, rhs: Self) -> Self {
LL | | unimplemented!()
diff --git a/src/tools/clippy/tests/ui/single_char_pattern.fixed b/src/tools/clippy/tests/ui/single_char_pattern.fixed
index 1abd2b7883d..68e26726724 100644
--- a/src/tools/clippy/tests/ui/single_char_pattern.fixed
+++ b/src/tools/clippy/tests/ui/single_char_pattern.fixed
@@ -17,6 +17,7 @@ fn main() {
x.split('💣');
// Can't use this lint for unicode code points which don't fit in a char
x.split("❤️");
+ x.split_inclusive('x');
x.contains('x');
x.starts_with('x');
x.ends_with('x');
@@ -27,6 +28,8 @@ fn main() {
x.rsplit_terminator('x');
x.splitn(2, 'x');
x.rsplitn(2, 'x');
+ x.split_once('x');
+ x.rsplit_once('x');
x.matches('x');
x.rmatches('x');
x.match_indices('x');
@@ -35,6 +38,8 @@ fn main() {
x.trim_end_matches('x');
x.strip_prefix('x');
x.strip_suffix('x');
+ x.replace('x', "y");
+ x.replacen('x', "y", 3);
// Make sure we escape characters correctly.
x.split('\n');
x.split('\'');
@@ -43,7 +48,7 @@ fn main() {
let h = HashSet::<String>::new();
h.contains("X"); // should not warn
- x.replace(";", ",").split(','); // issue #2978
+ x.replace(';', ",").split(','); // issue #2978
x.starts_with('\x03'); // issue #2996
// Issue #3204
@@ -56,4 +61,7 @@ fn main() {
x.split('a');
x.split('\'');
x.split('#');
+ // Must escape backslash in raw strings when converting to char #8060
+ x.split('\\');
+ x.split('\\');
}
diff --git a/src/tools/clippy/tests/ui/single_char_pattern.rs b/src/tools/clippy/tests/ui/single_char_pattern.rs
index e662bf34be2..186202d78ec 100644
--- a/src/tools/clippy/tests/ui/single_char_pattern.rs
+++ b/src/tools/clippy/tests/ui/single_char_pattern.rs
@@ -17,6 +17,7 @@ fn main() {
x.split("💣");
// Can't use this lint for unicode code points which don't fit in a char
x.split("❤️");
+ x.split_inclusive("x");
x.contains("x");
x.starts_with("x");
x.ends_with("x");
@@ -27,6 +28,8 @@ fn main() {
x.rsplit_terminator("x");
x.splitn(2, "x");
x.rsplitn(2, "x");
+ x.split_once("x");
+ x.rsplit_once("x");
x.matches("x");
x.rmatches("x");
x.match_indices("x");
@@ -35,6 +38,8 @@ fn main() {
x.trim_end_matches("x");
x.strip_prefix("x");
x.strip_suffix("x");
+ x.replace("x", "y");
+ x.replacen("x", "y", 3);
// Make sure we escape characters correctly.
x.split("\n");
x.split("'");
@@ -43,7 +48,7 @@ fn main() {
let h = HashSet::<String>::new();
h.contains("X"); // should not warn
- x.replace(";", ",").split(","); // issue #2978
+ x.replace(';', ",").split(","); // issue #2978
x.starts_with("\x03"); // issue #2996
// Issue #3204
@@ -56,4 +61,7 @@ fn main() {
x.split(r###"a"###);
x.split(r###"'"###);
x.split(r###"#"###);
+ // Must escape backslash in raw strings when converting to char #8060
+ x.split(r#"\"#);
+ x.split(r"\");
}
diff --git a/src/tools/clippy/tests/ui/single_char_pattern.stderr b/src/tools/clippy/tests/ui/single_char_pattern.stderr
index 22d4b2d460f..5564aac674d 100644
--- a/src/tools/clippy/tests/ui/single_char_pattern.stderr
+++ b/src/tools/clippy/tests/ui/single_char_pattern.stderr
@@ -25,172 +25,214 @@ LL | x.split("💣");
| ^^^^ help: try using a `char` instead: `'💣'`
error: single-character string constant used as pattern
- --> $DIR/single_char_pattern.rs:20:16
+ --> $DIR/single_char_pattern.rs:20:23
+ |
+LL | x.split_inclusive("x");
+ | ^^^ help: try using a `char` instead: `'x'`
+
+error: single-character string constant used as pattern
+ --> $DIR/single_char_pattern.rs:21:16
|
LL | x.contains("x");
| ^^^ help: try using a `char` instead: `'x'`
error: single-character string constant used as pattern
- --> $DIR/single_char_pattern.rs:21:19
+ --> $DIR/single_char_pattern.rs:22:19
|
LL | x.starts_with("x");
| ^^^ help: try using a `char` instead: `'x'`
error: single-character string constant used as pattern
- --> $DIR/single_char_pattern.rs:22:17
+ --> $DIR/single_char_pattern.rs:23:17
|
LL | x.ends_with("x");
| ^^^ help: try using a `char` instead: `'x'`
error: single-character string constant used as pattern
- --> $DIR/single_char_pattern.rs:23:12
+ --> $DIR/single_char_pattern.rs:24:12
|
LL | x.find("x");
| ^^^ help: try using a `char` instead: `'x'`
error: single-character string constant used as pattern
- --> $DIR/single_char_pattern.rs:24:13
+ --> $DIR/single_char_pattern.rs:25:13
|
LL | x.rfind("x");
| ^^^ help: try using a `char` instead: `'x'`
error: single-character string constant used as pattern
- --> $DIR/single_char_pattern.rs:25:14
+ --> $DIR/single_char_pattern.rs:26:14
|
LL | x.rsplit("x");
| ^^^ help: try using a `char` instead: `'x'`
error: single-character string constant used as pattern
- --> $DIR/single_char_pattern.rs:26:24
+ --> $DIR/single_char_pattern.rs:27:24
|
LL | x.split_terminator("x");
| ^^^ help: try using a `char` instead: `'x'`
error: single-character string constant used as pattern
- --> $DIR/single_char_pattern.rs:27:25
+ --> $DIR/single_char_pattern.rs:28:25
|
LL | x.rsplit_terminator("x");
| ^^^ help: try using a `char` instead: `'x'`
error: single-character string constant used as pattern
- --> $DIR/single_char_pattern.rs:28:17
+ --> $DIR/single_char_pattern.rs:29:17
|
LL | x.splitn(2, "x");
| ^^^ help: try using a `char` instead: `'x'`
error: single-character string constant used as pattern
- --> $DIR/single_char_pattern.rs:29:18
+ --> $DIR/single_char_pattern.rs:30:18
|
LL | x.rsplitn(2, "x");
| ^^^ help: try using a `char` instead: `'x'`
error: single-character string constant used as pattern
- --> $DIR/single_char_pattern.rs:30:15
+ --> $DIR/single_char_pattern.rs:31:18
+ |
+LL | x.split_once("x");
+ | ^^^ help: try using a `char` instead: `'x'`
+
+error: single-character string constant used as pattern
+ --> $DIR/single_char_pattern.rs:32:19
+ |
+LL | x.rsplit_once("x");
+ | ^^^ help: try using a `char` instead: `'x'`
+
+error: single-character string constant used as pattern
+ --> $DIR/single_char_pattern.rs:33:15
|
LL | x.matches("x");
| ^^^ help: try using a `char` instead: `'x'`
error: single-character string constant used as pattern
- --> $DIR/single_char_pattern.rs:31:16
+ --> $DIR/single_char_pattern.rs:34:16
|
LL | x.rmatches("x");
| ^^^ help: try using a `char` instead: `'x'`
error: single-character string constant used as pattern
- --> $DIR/single_char_pattern.rs:32:21
+ --> $DIR/single_char_pattern.rs:35:21
|
LL | x.match_indices("x");
| ^^^ help: try using a `char` instead: `'x'`
error: single-character string constant used as pattern
- --> $DIR/single_char_pattern.rs:33:22
+ --> $DIR/single_char_pattern.rs:36:22
|
LL | x.rmatch_indices("x");
| ^^^ help: try using a `char` instead: `'x'`
error: single-character string constant used as pattern
- --> $DIR/single_char_pattern.rs:34:26
+ --> $DIR/single_char_pattern.rs:37:26
|
LL | x.trim_start_matches("x");
| ^^^ help: try using a `char` instead: `'x'`
error: single-character string constant used as pattern
- --> $DIR/single_char_pattern.rs:35:24
+ --> $DIR/single_char_pattern.rs:38:24
|
LL | x.trim_end_matches("x");
| ^^^ help: try using a `char` instead: `'x'`
error: single-character string constant used as pattern
- --> $DIR/single_char_pattern.rs:36:20
+ --> $DIR/single_char_pattern.rs:39:20
|
LL | x.strip_prefix("x");
| ^^^ help: try using a `char` instead: `'x'`
error: single-character string constant used as pattern
- --> $DIR/single_char_pattern.rs:37:20
+ --> $DIR/single_char_pattern.rs:40:20
|
LL | x.strip_suffix("x");
| ^^^ help: try using a `char` instead: `'x'`
error: single-character string constant used as pattern
- --> $DIR/single_char_pattern.rs:39:13
+ --> $DIR/single_char_pattern.rs:41:15
+ |
+LL | x.replace("x", "y");
+ | ^^^ help: try using a `char` instead: `'x'`
+
+error: single-character string constant used as pattern
+ --> $DIR/single_char_pattern.rs:42:16
+ |
+LL | x.replacen("x", "y", 3);
+ | ^^^ help: try using a `char` instead: `'x'`
+
+error: single-character string constant used as pattern
+ --> $DIR/single_char_pattern.rs:44:13
|
LL | x.split("/n");
| ^^^^ help: try using a `char` instead: `'/n'`
error: single-character string constant used as pattern
- --> $DIR/single_char_pattern.rs:40:13
+ --> $DIR/single_char_pattern.rs:45:13
|
LL | x.split("'");
| ^^^ help: try using a `char` instead: `'/''`
error: single-character string constant used as pattern
- --> $DIR/single_char_pattern.rs:41:13
+ --> $DIR/single_char_pattern.rs:46:13
|
LL | x.split("/'");
| ^^^^ help: try using a `char` instead: `'/''`
error: single-character string constant used as pattern
- --> $DIR/single_char_pattern.rs:46:31
+ --> $DIR/single_char_pattern.rs:51:31
|
-LL | x.replace(";", ",").split(","); // issue #2978
+LL | x.replace(';', ",").split(","); // issue #2978
| ^^^ help: try using a `char` instead: `','`
error: single-character string constant used as pattern
- --> $DIR/single_char_pattern.rs:47:19
+ --> $DIR/single_char_pattern.rs:52:19
|
LL | x.starts_with("/x03"); // issue #2996
| ^^^^^^ help: try using a `char` instead: `'/x03'`
error: single-character string constant used as pattern
- --> $DIR/single_char_pattern.rs:54:13
+ --> $DIR/single_char_pattern.rs:59:13
|
LL | x.split(r"a");
| ^^^^ help: try using a `char` instead: `'a'`
error: single-character string constant used as pattern
- --> $DIR/single_char_pattern.rs:55:13
+ --> $DIR/single_char_pattern.rs:60:13
|
LL | x.split(r#"a"#);
| ^^^^^^ help: try using a `char` instead: `'a'`
error: single-character string constant used as pattern
- --> $DIR/single_char_pattern.rs:56:13
+ --> $DIR/single_char_pattern.rs:61:13
|
LL | x.split(r###"a"###);
| ^^^^^^^^^^ help: try using a `char` instead: `'a'`
error: single-character string constant used as pattern
- --> $DIR/single_char_pattern.rs:57:13
+ --> $DIR/single_char_pattern.rs:62:13
|
LL | x.split(r###"'"###);
| ^^^^^^^^^^ help: try using a `char` instead: `'/''`
error: single-character string constant used as pattern
- --> $DIR/single_char_pattern.rs:58:13
+ --> $DIR/single_char_pattern.rs:63:13
|
LL | x.split(r###"#"###);
| ^^^^^^^^^^ help: try using a `char` instead: `'#'`
-error: aborting due to 32 previous errors
+error: single-character string constant used as pattern
+ --> $DIR/single_char_pattern.rs:65:13
+ |
+LL | x.split(r#"/"#);
+ | ^^^^^^ help: try using a `char` instead: `'/'`
+
+error: single-character string constant used as pattern
+ --> $DIR/single_char_pattern.rs:66:13
+ |
+LL | x.split(r"/");
+ | ^^^^ help: try using a `char` instead: `'/'`
+
+error: aborting due to 39 previous errors
diff --git a/src/tools/clippy/tests/ui/strlen_on_c_strings.fixed b/src/tools/clippy/tests/ui/strlen_on_c_strings.fixed
new file mode 100644
index 00000000000..947a59bcc02
--- /dev/null
+++ b/src/tools/clippy/tests/ui/strlen_on_c_strings.fixed
@@ -0,0 +1,34 @@
+// run-rustfix
+
+#![warn(clippy::strlen_on_c_strings)]
+#![allow(dead_code)]
+#![feature(rustc_private)]
+extern crate libc;
+
+#[allow(unused)]
+use libc::strlen;
+use std::ffi::{CStr, CString};
+
+fn main() {
+ // CString
+ let cstring = CString::new("foo").expect("CString::new failed");
+ let _ = cstring.as_bytes().len();
+
+ // CStr
+ let cstr = CStr::from_bytes_with_nul(b"foo\0").expect("CStr::from_bytes_with_nul failed");
+ let _ = cstr.to_bytes().len();
+
+ let _ = cstr.to_bytes().len();
+
+ let pcstr: *const &CStr = &cstr;
+ let _ = unsafe { (*pcstr).to_bytes().len() };
+
+ unsafe fn unsafe_identity<T>(x: T) -> T {
+ x
+ }
+ let _ = unsafe { unsafe_identity(cstr).to_bytes().len() };
+ let _ = unsafe { unsafe_identity(cstr) }.to_bytes().len();
+
+ let f: unsafe fn(_) -> _ = unsafe_identity;
+ let _ = unsafe { f(cstr).to_bytes().len() };
+}
diff --git a/src/tools/clippy/tests/ui/strlen_on_c_strings.rs b/src/tools/clippy/tests/ui/strlen_on_c_strings.rs
index 21902fa8483..1237f1ab03a 100644
--- a/src/tools/clippy/tests/ui/strlen_on_c_strings.rs
+++ b/src/tools/clippy/tests/ui/strlen_on_c_strings.rs
@@ -1,16 +1,34 @@
+// run-rustfix
+
#![warn(clippy::strlen_on_c_strings)]
#![allow(dead_code)]
#![feature(rustc_private)]
extern crate libc;
+#[allow(unused)]
+use libc::strlen;
use std::ffi::{CStr, CString};
fn main() {
// CString
let cstring = CString::new("foo").expect("CString::new failed");
- let len = unsafe { libc::strlen(cstring.as_ptr()) };
+ let _ = unsafe { libc::strlen(cstring.as_ptr()) };
// CStr
let cstr = CStr::from_bytes_with_nul(b"foo\0").expect("CStr::from_bytes_with_nul failed");
- let len = unsafe { libc::strlen(cstr.as_ptr()) };
+ let _ = unsafe { libc::strlen(cstr.as_ptr()) };
+
+ let _ = unsafe { strlen(cstr.as_ptr()) };
+
+ let pcstr: *const &CStr = &cstr;
+ let _ = unsafe { strlen((*pcstr).as_ptr()) };
+
+ unsafe fn unsafe_identity<T>(x: T) -> T {
+ x
+ }
+ let _ = unsafe { strlen(unsafe_identity(cstr).as_ptr()) };
+ let _ = unsafe { strlen(unsafe { unsafe_identity(cstr) }.as_ptr()) };
+
+ let f: unsafe fn(_) -> _ = unsafe_identity;
+ let _ = unsafe { strlen(f(cstr).as_ptr()) };
}
diff --git a/src/tools/clippy/tests/ui/strlen_on_c_strings.stderr b/src/tools/clippy/tests/ui/strlen_on_c_strings.stderr
index e0ca511557c..296268a5f1d 100644
--- a/src/tools/clippy/tests/ui/strlen_on_c_strings.stderr
+++ b/src/tools/clippy/tests/ui/strlen_on_c_strings.stderr
@@ -1,25 +1,46 @@
error: using `libc::strlen` on a `CString` or `CStr` value
- --> $DIR/strlen_on_c_strings.rs:11:24
+ --> $DIR/strlen_on_c_strings.rs:15:13
|
-LL | let len = unsafe { libc::strlen(cstring.as_ptr()) };
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+LL | let _ = unsafe { libc::strlen(cstring.as_ptr()) };
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `cstring.as_bytes().len()`
|
= note: `-D clippy::strlen-on-c-strings` implied by `-D warnings`
-help: try this (you might also need to get rid of `unsafe` block in some cases):
+
+error: using `libc::strlen` on a `CString` or `CStr` value
+ --> $DIR/strlen_on_c_strings.rs:19:13
+ |
+LL | let _ = unsafe { libc::strlen(cstr.as_ptr()) };
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `cstr.to_bytes().len()`
+
+error: using `libc::strlen` on a `CString` or `CStr` value
+ --> $DIR/strlen_on_c_strings.rs:21:13
+ |
+LL | let _ = unsafe { strlen(cstr.as_ptr()) };
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `cstr.to_bytes().len()`
+
+error: using `libc::strlen` on a `CString` or `CStr` value
+ --> $DIR/strlen_on_c_strings.rs:24:22
|
-LL | let len = unsafe { cstring.as_bytes().len() };
- | ~~~~~~~~~~~~~~~~~~~~~~~~
+LL | let _ = unsafe { strlen((*pcstr).as_ptr()) };
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `(*pcstr).to_bytes().len()`
error: using `libc::strlen` on a `CString` or `CStr` value
- --> $DIR/strlen_on_c_strings.rs:15:24
+ --> $DIR/strlen_on_c_strings.rs:29:22
|
-LL | let len = unsafe { libc::strlen(cstr.as_ptr()) };
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^
+LL | let _ = unsafe { strlen(unsafe_identity(cstr).as_ptr()) };
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `unsafe_identity(cstr).to_bytes().len()`
+
+error: using `libc::strlen` on a `CString` or `CStr` value
+ --> $DIR/strlen_on_c_strings.rs:30:13
|
-help: try this (you might also need to get rid of `unsafe` block in some cases):
+LL | let _ = unsafe { strlen(unsafe { unsafe_identity(cstr) }.as_ptr()) };
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `unsafe { unsafe_identity(cstr) }.to_bytes().len()`
+
+error: using `libc::strlen` on a `CString` or `CStr` value
+ --> $DIR/strlen_on_c_strings.rs:33:22
|
-LL | let len = unsafe { cstr.to_bytes().len() };
- | ~~~~~~~~~~~~~~~~~~~~~
+LL | let _ = unsafe { strlen(f(cstr).as_ptr()) };
+ | ^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `f(cstr).to_bytes().len()`
-error: aborting due to 2 previous errors
+error: aborting due to 7 previous errors
diff --git a/src/tools/clippy/tests/ui/suspicious_splitn.rs b/src/tools/clippy/tests/ui/suspicious_splitn.rs
index a21d94cf20b..528f2ddcc86 100644
--- a/src/tools/clippy/tests/ui/suspicious_splitn.rs
+++ b/src/tools/clippy/tests/ui/suspicious_splitn.rs
@@ -1,4 +1,5 @@
#![warn(clippy::suspicious_splitn)]
+#![allow(clippy::needless_splitn)]
fn main() {
let _ = "a,b,c".splitn(3, ',');
diff --git a/src/tools/clippy/tests/ui/suspicious_splitn.stderr b/src/tools/clippy/tests/ui/suspicious_splitn.stderr
index b6220ae2393..3bcd681fa49 100644
--- a/src/tools/clippy/tests/ui/suspicious_splitn.stderr
+++ b/src/tools/clippy/tests/ui/suspicious_splitn.stderr
@@ -1,5 +1,5 @@
error: `splitn` called with `0` splits
- --> $DIR/suspicious_splitn.rs:9:13
+ --> $DIR/suspicious_splitn.rs:10:13
|
LL | let _ = "a,b".splitn(0, ',');
| ^^^^^^^^^^^^^^^^^^^^
@@ -8,7 +8,7 @@ LL | let _ = "a,b".splitn(0, ',');
= note: the resulting iterator will always return `None`
error: `rsplitn` called with `0` splits
- --> $DIR/suspicious_splitn.rs:10:13
+ --> $DIR/suspicious_splitn.rs:11:13
|
LL | let _ = "a,b".rsplitn(0, ',');
| ^^^^^^^^^^^^^^^^^^^^^
@@ -16,7 +16,7 @@ LL | let _ = "a,b".rsplitn(0, ',');
= note: the resulting iterator will always return `None`
error: `splitn` called with `1` split
- --> $DIR/suspicious_splitn.rs:11:13
+ --> $DIR/suspicious_splitn.rs:12:13
|
LL | let _ = "a,b".splitn(1, ',');
| ^^^^^^^^^^^^^^^^^^^^
@@ -24,7 +24,7 @@ LL | let _ = "a,b".splitn(1, ',');
= note: the resulting iterator will always return the entire string followed by `None`
error: `splitn` called with `0` splits
- --> $DIR/suspicious_splitn.rs:12:13
+ --> $DIR/suspicious_splitn.rs:13:13
|
LL | let _ = [0, 1, 2].splitn(0, |&x| x == 1);
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -32,7 +32,7 @@ LL | let _ = [0, 1, 2].splitn(0, |&x| x == 1);
= note: the resulting iterator will always return `None`
error: `splitn_mut` called with `0` splits
- --> $DIR/suspicious_splitn.rs:13:13
+ --> $DIR/suspicious_splitn.rs:14:13
|
LL | let _ = [0, 1, 2].splitn_mut(0, |&x| x == 1);
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -40,7 +40,7 @@ LL | let _ = [0, 1, 2].splitn_mut(0, |&x| x == 1);
= note: the resulting iterator will always return `None`
error: `splitn` called with `1` split
- --> $DIR/suspicious_splitn.rs:14:13
+ --> $DIR/suspicious_splitn.rs:15:13
|
LL | let _ = [0, 1, 2].splitn(1, |&x| x == 1);
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -48,7 +48,7 @@ LL | let _ = [0, 1, 2].splitn(1, |&x| x == 1);
= note: the resulting iterator will always return the entire slice followed by `None`
error: `rsplitn_mut` called with `1` split
- --> $DIR/suspicious_splitn.rs:15:13
+ --> $DIR/suspicious_splitn.rs:16:13
|
LL | let _ = [0, 1, 2].rsplitn_mut(1, |&x| x == 1);
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -56,7 +56,7 @@ LL | let _ = [0, 1, 2].rsplitn_mut(1, |&x| x == 1);
= note: the resulting iterator will always return the entire slice followed by `None`
error: `splitn` called with `1` split
- --> $DIR/suspicious_splitn.rs:18:13
+ --> $DIR/suspicious_splitn.rs:19:13
|
LL | let _ = "a,b".splitn(X + 1, ',');
| ^^^^^^^^^^^^^^^^^^^^^^^^
@@ -64,7 +64,7 @@ LL | let _ = "a,b".splitn(X + 1, ',');
= note: the resulting iterator will always return the entire string followed by `None`
error: `splitn` called with `0` splits
- --> $DIR/suspicious_splitn.rs:19:13
+ --> $DIR/suspicious_splitn.rs:20:13
|
LL | let _ = "a,b".splitn(X, ',');
| ^^^^^^^^^^^^^^^^^^^^
diff --git a/src/tools/clippy/tests/ui/trailing_empty_array.rs b/src/tools/clippy/tests/ui/trailing_empty_array.rs
index 501c9eb7651..c39b0bcaf22 100644
--- a/src/tools/clippy/tests/ui/trailing_empty_array.rs
+++ b/src/tools/clippy/tests/ui/trailing_empty_array.rs
@@ -1,5 +1,4 @@
#![warn(clippy::trailing_empty_array)]
-#![feature(const_generics_defaults)]
// Do lint:
diff --git a/src/tools/clippy/tests/ui/trailing_empty_array.stderr b/src/tools/clippy/tests/ui/trailing_empty_array.stderr
index d88aa0504b5..9e2bd31d9fa 100644
--- a/src/tools/clippy/tests/ui/trailing_empty_array.stderr
+++ b/src/tools/clippy/tests/ui/trailing_empty_array.stderr
@@ -1,5 +1,5 @@
error: trailing zero-sized array in a struct which is not marked with a `repr` attribute
- --> $DIR/trailing_empty_array.rs:6:1
+ --> $DIR/trailing_empty_array.rs:5:1
|
LL | / struct RarelyUseful {
LL | | field: i32,
@@ -11,7 +11,7 @@ LL | | }
= help: consider annotating `RarelyUseful` with `#[repr(C)]` or another `repr` attribute
error: trailing zero-sized array in a struct which is not marked with a `repr` attribute
- --> $DIR/trailing_empty_array.rs:11:1
+ --> $DIR/trailing_empty_array.rs:10:1
|
LL | / struct OnlyField {
LL | | first_and_last: [usize; 0],
@@ -21,7 +21,7 @@ LL | | }
= help: consider annotating `OnlyField` with `#[repr(C)]` or another `repr` attribute
error: trailing zero-sized array in a struct which is not marked with a `repr` attribute
- --> $DIR/trailing_empty_array.rs:15:1
+ --> $DIR/trailing_empty_array.rs:14:1
|
LL | / struct GenericArrayType<T> {
LL | | field: i32,
@@ -32,7 +32,7 @@ LL | | }
= help: consider annotating `GenericArrayType` with `#[repr(C)]` or another `repr` attribute
error: trailing zero-sized array in a struct which is not marked with a `repr` attribute
- --> $DIR/trailing_empty_array.rs:21:1
+ --> $DIR/trailing_empty_array.rs:20:1
|
LL | / struct OnlyAnotherAttribute {
LL | | field: i32,
@@ -43,7 +43,7 @@ LL | | }
= help: consider annotating `OnlyAnotherAttribute` with `#[repr(C)]` or another `repr` attribute
error: trailing zero-sized array in a struct which is not marked with a `repr` attribute
- --> $DIR/trailing_empty_array.rs:27:1
+ --> $DIR/trailing_empty_array.rs:26:1
|
LL | / struct OnlyADeriveAttribute {
LL | | field: i32,
@@ -54,7 +54,7 @@ LL | | }
= help: consider annotating `OnlyADeriveAttribute` with `#[repr(C)]` or another `repr` attribute
error: trailing zero-sized array in a struct which is not marked with a `repr` attribute
- --> $DIR/trailing_empty_array.rs:33:1
+ --> $DIR/trailing_empty_array.rs:32:1
|
LL | / struct ZeroSizedWithConst {
LL | | field: i32,
@@ -65,7 +65,7 @@ LL | | }
= help: consider annotating `ZeroSizedWithConst` with `#[repr(C)]` or another `repr` attribute
error: trailing zero-sized array in a struct which is not marked with a `repr` attribute
- --> $DIR/trailing_empty_array.rs:42:1
+ --> $DIR/trailing_empty_array.rs:41:1
|
LL | / struct ZeroSizedWithConstFunction {
LL | | field: i32,
@@ -76,7 +76,7 @@ LL | | }
= help: consider annotating `ZeroSizedWithConstFunction` with `#[repr(C)]` or another `repr` attribute
error: trailing zero-sized array in a struct which is not marked with a `repr` attribute
- --> $DIR/trailing_empty_array.rs:50:1
+ --> $DIR/trailing_empty_array.rs:49:1
|
LL | / struct ZeroSizedWithConstFunction2 {
LL | | field: i32,
@@ -87,7 +87,7 @@ LL | | }
= help: consider annotating `ZeroSizedWithConstFunction2` with `#[repr(C)]` or another `repr` attribute
error: trailing zero-sized array in a struct which is not marked with a `repr` attribute
- --> $DIR/trailing_empty_array.rs:55:1
+ --> $DIR/trailing_empty_array.rs:54:1
|
LL | struct ZeroSizedArrayWrapper([usize; 0]);
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -95,7 +95,7 @@ LL | struct ZeroSizedArrayWrapper([usize; 0]);
= help: consider annotating `ZeroSizedArrayWrapper` with `#[repr(C)]` or another `repr` attribute
error: trailing zero-sized array in a struct which is not marked with a `repr` attribute
- --> $DIR/trailing_empty_array.rs:57:1
+ --> $DIR/trailing_empty_array.rs:56:1
|
LL | struct TupleStruct(i32, [usize; 0]);
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -103,7 +103,7 @@ LL | struct TupleStruct(i32, [usize; 0]);
= help: consider annotating `TupleStruct` with `#[repr(C)]` or another `repr` attribute
error: trailing zero-sized array in a struct which is not marked with a `repr` attribute
- --> $DIR/trailing_empty_array.rs:59:1
+ --> $DIR/trailing_empty_array.rs:58:1
|
LL | / struct LotsOfFields {
LL | | f1: u32,
diff --git a/src/tools/clippy/tests/ui/type_complexity.rs b/src/tools/clippy/tests/ui/type_complexity.rs
index 383bbb49dbe..86a7bd7b627 100644
--- a/src/tools/clippy/tests/ui/type_complexity.rs
+++ b/src/tools/clippy/tests/ui/type_complexity.rs
@@ -30,6 +30,15 @@ trait T {
fn def_method(&self, p: Vec<Vec<Box<(u32, u32, u32, u32)>>>) {}
}
+// Should not warn since there is likely no way to simplify this (#1013)
+impl T for () {
+ const A: Vec<Vec<Box<(u32, u32, u32, u32)>>> = vec![];
+
+ type B = Vec<Vec<Box<(u32, u32, u32, u32)>>>;
+
+ fn method(&self, p: Vec<Vec<Box<(u32, u32, u32, u32)>>>) {}
+}
+
fn test1() -> Vec<Vec<Box<(u32, u32, u32, u32)>>> {
vec![]
}
diff --git a/src/tools/clippy/tests/ui/type_complexity.stderr b/src/tools/clippy/tests/ui/type_complexity.stderr
index 7879233fdf2..9da7edb1c3b 100644
--- a/src/tools/clippy/tests/ui/type_complexity.stderr
+++ b/src/tools/clippy/tests/ui/type_complexity.stderr
@@ -73,19 +73,19 @@ LL | fn def_method(&self, p: Vec<Vec<Box<(u32, u32, u32, u32)>>>) {}
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
error: very complex type used. Consider factoring parts into `type` definitions
- --> $DIR/type_complexity.rs:33:15
+ --> $DIR/type_complexity.rs:42:15
|
LL | fn test1() -> Vec<Vec<Box<(u32, u32, u32, u32)>>> {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
error: very complex type used. Consider factoring parts into `type` definitions
- --> $DIR/type_complexity.rs:37:14
+ --> $DIR/type_complexity.rs:46:14
|
LL | fn test2(_x: Vec<Vec<Box<(u32, u32, u32, u32)>>>) {}
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
error: very complex type used. Consider factoring parts into `type` definitions
- --> $DIR/type_complexity.rs:40:13
+ --> $DIR/type_complexity.rs:49:13
|
LL | let _y: Vec<Vec<Box<(u32, u32, u32, u32)>>> = vec![];
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
diff --git a/src/tools/clippy/tests/ui/undocumented_unsafe_blocks.rs b/src/tools/clippy/tests/ui/undocumented_unsafe_blocks.rs
index 52577323a58..7e510d89475 100644
--- a/src/tools/clippy/tests/ui/undocumented_unsafe_blocks.rs
+++ b/src/tools/clippy/tests/ui/undocumented_unsafe_blocks.rs
@@ -284,4 +284,8 @@ fn interference() {
unsafe {};
}
+pub fn print_binary_tree() {
+ println!("{}", unsafe { String::from_utf8_unchecked(vec![]) });
+}
+
fn main() {}
diff --git a/src/tools/clippy/tests/ui/undocumented_unsafe_blocks.stderr b/src/tools/clippy/tests/ui/undocumented_unsafe_blocks.stderr
index 613e9ffca45..ebe589001a1 100644
--- a/src/tools/clippy/tests/ui/undocumented_unsafe_blocks.stderr
+++ b/src/tools/clippy/tests/ui/undocumented_unsafe_blocks.stderr
@@ -155,5 +155,17 @@ LL ~ // Safety: ...
LL ~ unsafe {};
|
-error: aborting due to 13 previous errors
+error: unsafe block missing a safety comment
+ --> $DIR/undocumented_unsafe_blocks.rs:288:20
+ |
+LL | println!("{}", unsafe { String::from_utf8_unchecked(vec![]) });
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ |
+help: consider adding a safety comment
+ |
+LL ~ println!("{}", // Safety: ...
+LL ~ unsafe { String::from_utf8_unchecked(vec![]) });
+ |
+
+error: aborting due to 14 previous errors
diff --git a/src/tools/clippy/tests/ui/unicode.rs b/src/tools/clippy/tests/ui/unicode.rs
index 1f596c312fe..e0a4eadce33 100644
--- a/src/tools/clippy/tests/ui/unicode.rs
+++ b/src/tools/clippy/tests/ui/unicode.rs
@@ -20,8 +20,16 @@ fn uni() {
print!("\u{DC}ben!"); // this is ok
}
+// issue 8013
+#[warn(clippy::non_ascii_literal)]
+fn single_quote() {
+ const _EMPTY_BLOCK: char = '▱';
+ const _FULL_BLOCK: char = '▰';
+}
+
fn main() {
zero();
uni();
canon();
+ single_quote();
}
diff --git a/src/tools/clippy/tests/ui/unicode.stderr b/src/tools/clippy/tests/ui/unicode.stderr
index 3fca463c620..3f54e3880e7 100644
--- a/src/tools/clippy/tests/ui/unicode.stderr
+++ b/src/tools/clippy/tests/ui/unicode.stderr
@@ -34,5 +34,17 @@ LL | print!("Üben!");
|
= note: `-D clippy::non-ascii-literal` implied by `-D warnings`
-error: aborting due to 5 previous errors
+error: literal non-ASCII character detected
+ --> $DIR/unicode.rs:26:32
+ |
+LL | const _EMPTY_BLOCK: char = '▱';
+ | ^^^ help: consider replacing the string with: `'/u{25b1}'`
+
+error: literal non-ASCII character detected
+ --> $DIR/unicode.rs:27:31
+ |
+LL | const _FULL_BLOCK: char = '▰';
+ | ^^^ help: consider replacing the string with: `'/u{25b0}'`
+
+error: aborting due to 7 previous errors
diff --git a/src/tools/clippy/tests/ui/unnecessary_iter_cloned.fixed b/src/tools/clippy/tests/ui/unnecessary_iter_cloned.fixed
new file mode 100644
index 00000000000..e01e9f07baf
--- /dev/null
+++ b/src/tools/clippy/tests/ui/unnecessary_iter_cloned.fixed
@@ -0,0 +1,142 @@
+// run-rustfix
+
+#![allow(unused_assignments)]
+#![warn(clippy::unnecessary_to_owned)]
+
+#[allow(dead_code)]
+#[derive(Clone, Copy)]
+enum FileType {
+ Account,
+ PrivateKey,
+ Certificate,
+}
+
+fn main() {
+ let path = std::path::Path::new("x");
+
+ let _ = check_files(&[(FileType::Account, path)]);
+ let _ = check_files_vec(vec![(FileType::Account, path)]);
+
+ // negative tests
+ let _ = check_files_ref(&[(FileType::Account, path)]);
+ let _ = check_files_mut(&[(FileType::Account, path)]);
+ let _ = check_files_ref_mut(&[(FileType::Account, path)]);
+ let _ = check_files_self_and_arg(&[(FileType::Account, path)]);
+ let _ = check_files_mut_path_buf(&[(FileType::Account, std::path::PathBuf::new())]);
+}
+
+// `check_files` and its variants are based on:
+// https://github.com/breard-r/acmed/blob/1f0dcc32aadbc5e52de6d23b9703554c0f925113/acmed/src/storage.rs#L262
+fn check_files(files: &[(FileType, &std::path::Path)]) -> bool {
+ for (t, path) in files {
+ let other = match get_file_path(t) {
+ Ok(p) => p,
+ Err(_) => {
+ return false;
+ },
+ };
+ if !path.is_file() || !other.is_file() {
+ return false;
+ }
+ }
+ true
+}
+
+fn check_files_vec(files: Vec<(FileType, &std::path::Path)>) -> bool {
+ for (t, path) in files.iter() {
+ let other = match get_file_path(t) {
+ Ok(p) => p,
+ Err(_) => {
+ return false;
+ },
+ };
+ if !path.is_file() || !other.is_file() {
+ return false;
+ }
+ }
+ true
+}
+
+fn check_files_ref(files: &[(FileType, &std::path::Path)]) -> bool {
+ for (ref t, path) in files.iter().copied() {
+ let other = match get_file_path(t) {
+ Ok(p) => p,
+ Err(_) => {
+ return false;
+ },
+ };
+ if !path.is_file() || !other.is_file() {
+ return false;
+ }
+ }
+ true
+}
+
+#[allow(unused_assignments)]
+fn check_files_mut(files: &[(FileType, &std::path::Path)]) -> bool {
+ for (mut t, path) in files.iter().copied() {
+ t = FileType::PrivateKey;
+ let other = match get_file_path(&t) {
+ Ok(p) => p,
+ Err(_) => {
+ return false;
+ },
+ };
+ if !path.is_file() || !other.is_file() {
+ return false;
+ }
+ }
+ true
+}
+
+fn check_files_ref_mut(files: &[(FileType, &std::path::Path)]) -> bool {
+ for (ref mut t, path) in files.iter().copied() {
+ *t = FileType::PrivateKey;
+ let other = match get_file_path(t) {
+ Ok(p) => p,
+ Err(_) => {
+ return false;
+ },
+ };
+ if !path.is_file() || !other.is_file() {
+ return false;
+ }
+ }
+ true
+}
+
+fn check_files_self_and_arg(files: &[(FileType, &std::path::Path)]) -> bool {
+ for (t, path) in files.iter().copied() {
+ let other = match get_file_path(&t) {
+ Ok(p) => p,
+ Err(_) => {
+ return false;
+ },
+ };
+ if !path.join(path).is_file() || !other.is_file() {
+ return false;
+ }
+ }
+ true
+}
+
+#[allow(unused_assignments)]
+fn check_files_mut_path_buf(files: &[(FileType, std::path::PathBuf)]) -> bool {
+ for (mut t, path) in files.iter().cloned() {
+ t = FileType::PrivateKey;
+ let other = match get_file_path(&t) {
+ Ok(p) => p,
+ Err(_) => {
+ return false;
+ },
+ };
+ if !path.is_file() || !other.is_file() {
+ return false;
+ }
+ }
+ true
+}
+
+fn get_file_path(_file_type: &FileType) -> Result<std::path::PathBuf, std::io::Error> {
+ Ok(std::path::PathBuf::new())
+}
diff --git a/src/tools/clippy/tests/ui/unnecessary_iter_cloned.rs b/src/tools/clippy/tests/ui/unnecessary_iter_cloned.rs
new file mode 100644
index 00000000000..6ef2966c8b7
--- /dev/null
+++ b/src/tools/clippy/tests/ui/unnecessary_iter_cloned.rs
@@ -0,0 +1,142 @@
+// run-rustfix
+
+#![allow(unused_assignments)]
+#![warn(clippy::unnecessary_to_owned)]
+
+#[allow(dead_code)]
+#[derive(Clone, Copy)]
+enum FileType {
+ Account,
+ PrivateKey,
+ Certificate,
+}
+
+fn main() {
+ let path = std::path::Path::new("x");
+
+ let _ = check_files(&[(FileType::Account, path)]);
+ let _ = check_files_vec(vec![(FileType::Account, path)]);
+
+ // negative tests
+ let _ = check_files_ref(&[(FileType::Account, path)]);
+ let _ = check_files_mut(&[(FileType::Account, path)]);
+ let _ = check_files_ref_mut(&[(FileType::Account, path)]);
+ let _ = check_files_self_and_arg(&[(FileType::Account, path)]);
+ let _ = check_files_mut_path_buf(&[(FileType::Account, std::path::PathBuf::new())]);
+}
+
+// `check_files` and its variants are based on:
+// https://github.com/breard-r/acmed/blob/1f0dcc32aadbc5e52de6d23b9703554c0f925113/acmed/src/storage.rs#L262
+fn check_files(files: &[(FileType, &std::path::Path)]) -> bool {
+ for (t, path) in files.iter().copied() {
+ let other = match get_file_path(&t) {
+ Ok(p) => p,
+ Err(_) => {
+ return false;
+ },
+ };
+ if !path.is_file() || !other.is_file() {
+ return false;
+ }
+ }
+ true
+}
+
+fn check_files_vec(files: Vec<(FileType, &std::path::Path)>) -> bool {
+ for (t, path) in files.iter().copied() {
+ let other = match get_file_path(&t) {
+ Ok(p) => p,
+ Err(_) => {
+ return false;
+ },
+ };
+ if !path.is_file() || !other.is_file() {
+ return false;
+ }
+ }
+ true
+}
+
+fn check_files_ref(files: &[(FileType, &std::path::Path)]) -> bool {
+ for (ref t, path) in files.iter().copied() {
+ let other = match get_file_path(t) {
+ Ok(p) => p,
+ Err(_) => {
+ return false;
+ },
+ };
+ if !path.is_file() || !other.is_file() {
+ return false;
+ }
+ }
+ true
+}
+
+#[allow(unused_assignments)]
+fn check_files_mut(files: &[(FileType, &std::path::Path)]) -> bool {
+ for (mut t, path) in files.iter().copied() {
+ t = FileType::PrivateKey;
+ let other = match get_file_path(&t) {
+ Ok(p) => p,
+ Err(_) => {
+ return false;
+ },
+ };
+ if !path.is_file() || !other.is_file() {
+ return false;
+ }
+ }
+ true
+}
+
+fn check_files_ref_mut(files: &[(FileType, &std::path::Path)]) -> bool {
+ for (ref mut t, path) in files.iter().copied() {
+ *t = FileType::PrivateKey;
+ let other = match get_file_path(t) {
+ Ok(p) => p,
+ Err(_) => {
+ return false;
+ },
+ };
+ if !path.is_file() || !other.is_file() {
+ return false;
+ }
+ }
+ true
+}
+
+fn check_files_self_and_arg(files: &[(FileType, &std::path::Path)]) -> bool {
+ for (t, path) in files.iter().copied() {
+ let other = match get_file_path(&t) {
+ Ok(p) => p,
+ Err(_) => {
+ return false;
+ },
+ };
+ if !path.join(path).is_file() || !other.is_file() {
+ return false;
+ }
+ }
+ true
+}
+
+#[allow(unused_assignments)]
+fn check_files_mut_path_buf(files: &[(FileType, std::path::PathBuf)]) -> bool {
+ for (mut t, path) in files.iter().cloned() {
+ t = FileType::PrivateKey;
+ let other = match get_file_path(&t) {
+ Ok(p) => p,
+ Err(_) => {
+ return false;
+ },
+ };
+ if !path.is_file() || !other.is_file() {
+ return false;
+ }
+ }
+ true
+}
+
+fn get_file_path(_file_type: &FileType) -> Result<std::path::PathBuf, std::io::Error> {
+ Ok(std::path::PathBuf::new())
+}
diff --git a/src/tools/clippy/tests/ui/unnecessary_iter_cloned.stderr b/src/tools/clippy/tests/ui/unnecessary_iter_cloned.stderr
new file mode 100644
index 00000000000..e44379f8aa0
--- /dev/null
+++ b/src/tools/clippy/tests/ui/unnecessary_iter_cloned.stderr
@@ -0,0 +1,35 @@
+error: unnecessary use of `copied`
+ --> $DIR/unnecessary_iter_cloned.rs:31:22
+ |
+LL | for (t, path) in files.iter().copied() {
+ | ^^^^^^^^^^^^^^^^^^^^^
+ |
+ = note: `-D clippy::unnecessary-to-owned` implied by `-D warnings`
+help: use
+ |
+LL | for (t, path) in files {
+ | ~~~~~
+help: remove this `&`
+ |
+LL - let other = match get_file_path(&t) {
+LL + let other = match get_file_path(t) {
+ |
+
+error: unnecessary use of `copied`
+ --> $DIR/unnecessary_iter_cloned.rs:46:22
+ |
+LL | for (t, path) in files.iter().copied() {
+ | ^^^^^^^^^^^^^^^^^^^^^
+ |
+help: use
+ |
+LL | for (t, path) in files.iter() {
+ | ~~~~~~~~~~~~
+help: remove this `&`
+ |
+LL - let other = match get_file_path(&t) {
+LL + let other = match get_file_path(t) {
+ |
+
+error: aborting due to 2 previous errors
+
diff --git a/src/tools/clippy/tests/ui/unnecessary_to_owned.fixed b/src/tools/clippy/tests/ui/unnecessary_to_owned.fixed
new file mode 100644
index 00000000000..720138db137
--- /dev/null
+++ b/src/tools/clippy/tests/ui/unnecessary_to_owned.fixed
@@ -0,0 +1,214 @@
+// run-rustfix
+
+#![allow(clippy::ptr_arg)]
+#![warn(clippy::unnecessary_to_owned)]
+
+use std::borrow::Cow;
+use std::ffi::{CStr, CString, OsStr, OsString};
+use std::ops::Deref;
+
+#[derive(Clone)]
+struct X(String);
+
+impl Deref for X {
+ type Target = [u8];
+ fn deref(&self) -> &[u8] {
+ self.0.as_bytes()
+ }
+}
+
+impl AsRef<str> for X {
+ fn as_ref(&self) -> &str {
+ self.0.as_str()
+ }
+}
+
+impl ToString for X {
+ fn to_string(&self) -> String {
+ self.0.to_string()
+ }
+}
+
+impl X {
+ fn join(&self, other: impl AsRef<str>) -> Self {
+ let mut s = self.0.clone();
+ s.push_str(other.as_ref());
+ Self(s)
+ }
+}
+
+#[allow(dead_code)]
+#[derive(Clone)]
+enum FileType {
+ Account,
+ PrivateKey,
+ Certificate,
+}
+
+fn main() {
+ let c_str = CStr::from_bytes_with_nul(&[0]).unwrap();
+ let os_str = OsStr::new("x");
+ let path = std::path::Path::new("x");
+ let s = "x";
+ let array = ["x"];
+ let array_ref = &["x"];
+ let slice = &["x"][..];
+ let x = X(String::from("x"));
+ let x_ref = &x;
+
+ require_c_str(&Cow::from(c_str));
+ require_c_str(c_str);
+
+ require_os_str(os_str);
+ require_os_str(&Cow::from(os_str));
+ require_os_str(os_str);
+
+ require_path(path);
+ require_path(&Cow::from(path));
+ require_path(path);
+
+ require_str(s);
+ require_str(&Cow::from(s));
+ require_str(s);
+ require_str(x_ref.as_ref());
+
+ require_slice(slice);
+ require_slice(&Cow::from(slice));
+ require_slice(array.as_ref());
+ require_slice(array_ref.as_ref());
+ require_slice(slice);
+ require_slice(x_ref);
+
+ require_x(&Cow::<X>::Owned(x.clone()));
+ require_x(x_ref);
+
+ require_deref_c_str(c_str);
+ require_deref_os_str(os_str);
+ require_deref_path(path);
+ require_deref_str(s);
+ require_deref_slice(slice);
+
+ require_impl_deref_c_str(c_str);
+ require_impl_deref_os_str(os_str);
+ require_impl_deref_path(path);
+ require_impl_deref_str(s);
+ require_impl_deref_slice(slice);
+
+ require_deref_str_slice(s, slice);
+ require_deref_slice_str(slice, s);
+
+ require_as_ref_c_str(c_str);
+ require_as_ref_os_str(os_str);
+ require_as_ref_path(path);
+ require_as_ref_str(s);
+ require_as_ref_str(&x);
+ require_as_ref_slice(array);
+ require_as_ref_slice(array_ref);
+ require_as_ref_slice(slice);
+
+ require_impl_as_ref_c_str(c_str);
+ require_impl_as_ref_os_str(os_str);
+ require_impl_as_ref_path(path);
+ require_impl_as_ref_str(s);
+ require_impl_as_ref_str(&x);
+ require_impl_as_ref_slice(array);
+ require_impl_as_ref_slice(array_ref);
+ require_impl_as_ref_slice(slice);
+
+ require_as_ref_str_slice(s, array);
+ require_as_ref_str_slice(s, array_ref);
+ require_as_ref_str_slice(s, slice);
+ require_as_ref_slice_str(array, s);
+ require_as_ref_slice_str(array_ref, s);
+ require_as_ref_slice_str(slice, s);
+
+ let _ = x.join(x_ref);
+
+ let _ = slice.iter().copied();
+ let _ = slice.iter().copied();
+ let _ = [std::path::PathBuf::new()][..].iter().cloned();
+ let _ = [std::path::PathBuf::new()][..].iter().cloned();
+
+ let _ = slice.iter().copied();
+ let _ = slice.iter().copied();
+ let _ = [std::path::PathBuf::new()][..].iter().cloned();
+ let _ = [std::path::PathBuf::new()][..].iter().cloned();
+
+ let _ = check_files(&[FileType::Account]);
+
+ // negative tests
+ require_string(&s.to_string());
+ require_string(&Cow::from(s).into_owned());
+ require_string(&s.to_owned());
+ require_string(&x_ref.to_string());
+
+ // `X` isn't copy.
+ require_slice(&x.to_owned());
+ require_deref_slice(x.to_owned());
+
+ // The following should be flagged by `redundant_clone`, but not by this lint.
+ require_c_str(&CString::from_vec_with_nul(vec![0]).unwrap());
+ require_os_str(&OsString::from("x"));
+ require_path(&std::path::PathBuf::from("x"));
+ require_str(&String::from("x"));
+}
+
+fn require_c_str(_: &CStr) {}
+fn require_os_str(_: &OsStr) {}
+fn require_path(_: &std::path::Path) {}
+fn require_str(_: &str) {}
+fn require_slice<T>(_: &[T]) {}
+fn require_x(_: &X) {}
+
+fn require_deref_c_str<T: Deref<Target = CStr>>(_: T) {}
+fn require_deref_os_str<T: Deref<Target = OsStr>>(_: T) {}
+fn require_deref_path<T: Deref<Target = std::path::Path>>(_: T) {}
+fn require_deref_str<T: Deref<Target = str>>(_: T) {}
+fn require_deref_slice<T, U: Deref<Target = [T]>>(_: U) {}
+
+fn require_impl_deref_c_str(_: impl Deref<Target = CStr>) {}
+fn require_impl_deref_os_str(_: impl Deref<Target = OsStr>) {}
+fn require_impl_deref_path(_: impl Deref<Target = std::path::Path>) {}
+fn require_impl_deref_str(_: impl Deref<Target = str>) {}
+fn require_impl_deref_slice<T>(_: impl Deref<Target = [T]>) {}
+
+fn require_deref_str_slice<T: Deref<Target = str>, U, V: Deref<Target = [U]>>(_: T, _: V) {}
+fn require_deref_slice_str<T, U: Deref<Target = [T]>, V: Deref<Target = str>>(_: U, _: V) {}
+
+fn require_as_ref_c_str<T: AsRef<CStr>>(_: T) {}
+fn require_as_ref_os_str<T: AsRef<OsStr>>(_: T) {}
+fn require_as_ref_path<T: AsRef<std::path::Path>>(_: T) {}
+fn require_as_ref_str<T: AsRef<str>>(_: T) {}
+fn require_as_ref_slice<T, U: AsRef<[T]>>(_: U) {}
+
+fn require_impl_as_ref_c_str(_: impl AsRef<CStr>) {}
+fn require_impl_as_ref_os_str(_: impl AsRef<OsStr>) {}
+fn require_impl_as_ref_path(_: impl AsRef<std::path::Path>) {}
+fn require_impl_as_ref_str(_: impl AsRef<str>) {}
+fn require_impl_as_ref_slice<T>(_: impl AsRef<[T]>) {}
+
+fn require_as_ref_str_slice<T: AsRef<str>, U, V: AsRef<[U]>>(_: T, _: V) {}
+fn require_as_ref_slice_str<T, U: AsRef<[T]>, V: AsRef<str>>(_: U, _: V) {}
+
+// `check_files` is based on:
+// https://github.com/breard-r/acmed/blob/1f0dcc32aadbc5e52de6d23b9703554c0f925113/acmed/src/storage.rs#L262
+fn check_files(file_types: &[FileType]) -> bool {
+ for t in file_types {
+ let path = match get_file_path(t) {
+ Ok(p) => p,
+ Err(_) => {
+ return false;
+ },
+ };
+ if !path.is_file() {
+ return false;
+ }
+ }
+ true
+}
+
+fn get_file_path(_file_type: &FileType) -> Result<std::path::PathBuf, std::io::Error> {
+ Ok(std::path::PathBuf::new())
+}
+
+fn require_string(_: &String) {}
diff --git a/src/tools/clippy/tests/ui/unnecessary_to_owned.rs b/src/tools/clippy/tests/ui/unnecessary_to_owned.rs
new file mode 100644
index 00000000000..60b2e718f5d
--- /dev/null
+++ b/src/tools/clippy/tests/ui/unnecessary_to_owned.rs
@@ -0,0 +1,214 @@
+// run-rustfix
+
+#![allow(clippy::ptr_arg)]
+#![warn(clippy::unnecessary_to_owned)]
+
+use std::borrow::Cow;
+use std::ffi::{CStr, CString, OsStr, OsString};
+use std::ops::Deref;
+
+#[derive(Clone)]
+struct X(String);
+
+impl Deref for X {
+ type Target = [u8];
+ fn deref(&self) -> &[u8] {
+ self.0.as_bytes()
+ }
+}
+
+impl AsRef<str> for X {
+ fn as_ref(&self) -> &str {
+ self.0.as_str()
+ }
+}
+
+impl ToString for X {
+ fn to_string(&self) -> String {
+ self.0.to_string()
+ }
+}
+
+impl X {
+ fn join(&self, other: impl AsRef<str>) -> Self {
+ let mut s = self.0.clone();
+ s.push_str(other.as_ref());
+ Self(s)
+ }
+}
+
+#[allow(dead_code)]
+#[derive(Clone)]
+enum FileType {
+ Account,
+ PrivateKey,
+ Certificate,
+}
+
+fn main() {
+ let c_str = CStr::from_bytes_with_nul(&[0]).unwrap();
+ let os_str = OsStr::new("x");
+ let path = std::path::Path::new("x");
+ let s = "x";
+ let array = ["x"];
+ let array_ref = &["x"];
+ let slice = &["x"][..];
+ let x = X(String::from("x"));
+ let x_ref = &x;
+
+ require_c_str(&Cow::from(c_str).into_owned());
+ require_c_str(&c_str.to_owned());
+
+ require_os_str(&os_str.to_os_string());
+ require_os_str(&Cow::from(os_str).into_owned());
+ require_os_str(&os_str.to_owned());
+
+ require_path(&path.to_path_buf());
+ require_path(&Cow::from(path).into_owned());
+ require_path(&path.to_owned());
+
+ require_str(&s.to_string());
+ require_str(&Cow::from(s).into_owned());
+ require_str(&s.to_owned());
+ require_str(&x_ref.to_string());
+
+ require_slice(&slice.to_vec());
+ require_slice(&Cow::from(slice).into_owned());
+ require_slice(&array.to_owned());
+ require_slice(&array_ref.to_owned());
+ require_slice(&slice.to_owned());
+ require_slice(&x_ref.to_owned());
+
+ require_x(&Cow::<X>::Owned(x.clone()).into_owned());
+ require_x(&x_ref.to_owned());
+
+ require_deref_c_str(c_str.to_owned());
+ require_deref_os_str(os_str.to_owned());
+ require_deref_path(path.to_owned());
+ require_deref_str(s.to_owned());
+ require_deref_slice(slice.to_owned());
+
+ require_impl_deref_c_str(c_str.to_owned());
+ require_impl_deref_os_str(os_str.to_owned());
+ require_impl_deref_path(path.to_owned());
+ require_impl_deref_str(s.to_owned());
+ require_impl_deref_slice(slice.to_owned());
+
+ require_deref_str_slice(s.to_owned(), slice.to_owned());
+ require_deref_slice_str(slice.to_owned(), s.to_owned());
+
+ require_as_ref_c_str(c_str.to_owned());
+ require_as_ref_os_str(os_str.to_owned());
+ require_as_ref_path(path.to_owned());
+ require_as_ref_str(s.to_owned());
+ require_as_ref_str(x.to_owned());
+ require_as_ref_slice(array.to_owned());
+ require_as_ref_slice(array_ref.to_owned());
+ require_as_ref_slice(slice.to_owned());
+
+ require_impl_as_ref_c_str(c_str.to_owned());
+ require_impl_as_ref_os_str(os_str.to_owned());
+ require_impl_as_ref_path(path.to_owned());
+ require_impl_as_ref_str(s.to_owned());
+ require_impl_as_ref_str(x.to_owned());
+ require_impl_as_ref_slice(array.to_owned());
+ require_impl_as_ref_slice(array_ref.to_owned());
+ require_impl_as_ref_slice(slice.to_owned());
+
+ require_as_ref_str_slice(s.to_owned(), array.to_owned());
+ require_as_ref_str_slice(s.to_owned(), array_ref.to_owned());
+ require_as_ref_str_slice(s.to_owned(), slice.to_owned());
+ require_as_ref_slice_str(array.to_owned(), s.to_owned());
+ require_as_ref_slice_str(array_ref.to_owned(), s.to_owned());
+ require_as_ref_slice_str(slice.to_owned(), s.to_owned());
+
+ let _ = x.join(&x_ref.to_string());
+
+ let _ = slice.to_vec().into_iter();
+ let _ = slice.to_owned().into_iter();
+ let _ = [std::path::PathBuf::new()][..].to_vec().into_iter();
+ let _ = [std::path::PathBuf::new()][..].to_owned().into_iter();
+
+ let _ = IntoIterator::into_iter(slice.to_vec());
+ let _ = IntoIterator::into_iter(slice.to_owned());
+ let _ = IntoIterator::into_iter([std::path::PathBuf::new()][..].to_vec());
+ let _ = IntoIterator::into_iter([std::path::PathBuf::new()][..].to_owned());
+
+ let _ = check_files(&[FileType::Account]);
+
+ // negative tests
+ require_string(&s.to_string());
+ require_string(&Cow::from(s).into_owned());
+ require_string(&s.to_owned());
+ require_string(&x_ref.to_string());
+
+ // `X` isn't copy.
+ require_slice(&x.to_owned());
+ require_deref_slice(x.to_owned());
+
+ // The following should be flagged by `redundant_clone`, but not by this lint.
+ require_c_str(&CString::from_vec_with_nul(vec![0]).unwrap().to_owned());
+ require_os_str(&OsString::from("x").to_os_string());
+ require_path(&std::path::PathBuf::from("x").to_path_buf());
+ require_str(&String::from("x").to_string());
+}
+
+fn require_c_str(_: &CStr) {}
+fn require_os_str(_: &OsStr) {}
+fn require_path(_: &std::path::Path) {}
+fn require_str(_: &str) {}
+fn require_slice<T>(_: &[T]) {}
+fn require_x(_: &X) {}
+
+fn require_deref_c_str<T: Deref<Target = CStr>>(_: T) {}
+fn require_deref_os_str<T: Deref<Target = OsStr>>(_: T) {}
+fn require_deref_path<T: Deref<Target = std::path::Path>>(_: T) {}
+fn require_deref_str<T: Deref<Target = str>>(_: T) {}
+fn require_deref_slice<T, U: Deref<Target = [T]>>(_: U) {}
+
+fn require_impl_deref_c_str(_: impl Deref<Target = CStr>) {}
+fn require_impl_deref_os_str(_: impl Deref<Target = OsStr>) {}
+fn require_impl_deref_path(_: impl Deref<Target = std::path::Path>) {}
+fn require_impl_deref_str(_: impl Deref<Target = str>) {}
+fn require_impl_deref_slice<T>(_: impl Deref<Target = [T]>) {}
+
+fn require_deref_str_slice<T: Deref<Target = str>, U, V: Deref<Target = [U]>>(_: T, _: V) {}
+fn require_deref_slice_str<T, U: Deref<Target = [T]>, V: Deref<Target = str>>(_: U, _: V) {}
+
+fn require_as_ref_c_str<T: AsRef<CStr>>(_: T) {}
+fn require_as_ref_os_str<T: AsRef<OsStr>>(_: T) {}
+fn require_as_ref_path<T: AsRef<std::path::Path>>(_: T) {}
+fn require_as_ref_str<T: AsRef<str>>(_: T) {}
+fn require_as_ref_slice<T, U: AsRef<[T]>>(_: U) {}
+
+fn require_impl_as_ref_c_str(_: impl AsRef<CStr>) {}
+fn require_impl_as_ref_os_str(_: impl AsRef<OsStr>) {}
+fn require_impl_as_ref_path(_: impl AsRef<std::path::Path>) {}
+fn require_impl_as_ref_str(_: impl AsRef<str>) {}
+fn require_impl_as_ref_slice<T>(_: impl AsRef<[T]>) {}
+
+fn require_as_ref_str_slice<T: AsRef<str>, U, V: AsRef<[U]>>(_: T, _: V) {}
+fn require_as_ref_slice_str<T, U: AsRef<[T]>, V: AsRef<str>>(_: U, _: V) {}
+
+// `check_files` is based on:
+// https://github.com/breard-r/acmed/blob/1f0dcc32aadbc5e52de6d23b9703554c0f925113/acmed/src/storage.rs#L262
+fn check_files(file_types: &[FileType]) -> bool {
+ for t in file_types.to_vec() {
+ let path = match get_file_path(&t) {
+ Ok(p) => p,
+ Err(_) => {
+ return false;
+ },
+ };
+ if !path.is_file() {
+ return false;
+ }
+ }
+ true
+}
+
+fn get_file_path(_file_type: &FileType) -> Result<std::path::PathBuf, std::io::Error> {
+ Ok(std::path::PathBuf::new())
+}
+
+fn require_string(_: &String) {}
diff --git a/src/tools/clippy/tests/ui/unnecessary_to_owned.stderr b/src/tools/clippy/tests/ui/unnecessary_to_owned.stderr
new file mode 100644
index 00000000000..1dfc65e22e2
--- /dev/null
+++ b/src/tools/clippy/tests/ui/unnecessary_to_owned.stderr
@@ -0,0 +1,495 @@
+error: redundant clone
+ --> $DIR/unnecessary_to_owned.rs:150:64
+ |
+LL | require_c_str(&CString::from_vec_with_nul(vec![0]).unwrap().to_owned());
+ | ^^^^^^^^^^^ help: remove this
+ |
+ = note: `-D clippy::redundant-clone` implied by `-D warnings`
+note: this value is dropped without further use
+ --> $DIR/unnecessary_to_owned.rs:150:20
+ |
+LL | require_c_str(&CString::from_vec_with_nul(vec![0]).unwrap().to_owned());
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: redundant clone
+ --> $DIR/unnecessary_to_owned.rs:151:40
+ |
+LL | require_os_str(&OsString::from("x").to_os_string());
+ | ^^^^^^^^^^^^^^^ help: remove this
+ |
+note: this value is dropped without further use
+ --> $DIR/unnecessary_to_owned.rs:151:21
+ |
+LL | require_os_str(&OsString::from("x").to_os_string());
+ | ^^^^^^^^^^^^^^^^^^^
+
+error: redundant clone
+ --> $DIR/unnecessary_to_owned.rs:152:48
+ |
+LL | require_path(&std::path::PathBuf::from("x").to_path_buf());
+ | ^^^^^^^^^^^^^^ help: remove this
+ |
+note: this value is dropped without further use
+ --> $DIR/unnecessary_to_owned.rs:152:19
+ |
+LL | require_path(&std::path::PathBuf::from("x").to_path_buf());
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: redundant clone
+ --> $DIR/unnecessary_to_owned.rs:153:35
+ |
+LL | require_str(&String::from("x").to_string());
+ | ^^^^^^^^^^^^ help: remove this
+ |
+note: this value is dropped without further use
+ --> $DIR/unnecessary_to_owned.rs:153:18
+ |
+LL | require_str(&String::from("x").to_string());
+ | ^^^^^^^^^^^^^^^^^
+
+error: unnecessary use of `into_owned`
+ --> $DIR/unnecessary_to_owned.rs:59:36
+ |
+LL | require_c_str(&Cow::from(c_str).into_owned());
+ | ^^^^^^^^^^^^^ help: remove this
+ |
+ = note: `-D clippy::unnecessary-to-owned` implied by `-D warnings`
+
+error: unnecessary use of `to_owned`
+ --> $DIR/unnecessary_to_owned.rs:60:19
+ |
+LL | require_c_str(&c_str.to_owned());
+ | ^^^^^^^^^^^^^^^^^ help: use: `c_str`
+
+error: unnecessary use of `to_os_string`
+ --> $DIR/unnecessary_to_owned.rs:62:20
+ |
+LL | require_os_str(&os_str.to_os_string());
+ | ^^^^^^^^^^^^^^^^^^^^^^ help: use: `os_str`
+
+error: unnecessary use of `into_owned`
+ --> $DIR/unnecessary_to_owned.rs:63:38
+ |
+LL | require_os_str(&Cow::from(os_str).into_owned());
+ | ^^^^^^^^^^^^^ help: remove this
+
+error: unnecessary use of `to_owned`
+ --> $DIR/unnecessary_to_owned.rs:64:20
+ |
+LL | require_os_str(&os_str.to_owned());
+ | ^^^^^^^^^^^^^^^^^^ help: use: `os_str`
+
+error: unnecessary use of `to_path_buf`
+ --> $DIR/unnecessary_to_owned.rs:66:18
+ |
+LL | require_path(&path.to_path_buf());
+ | ^^^^^^^^^^^^^^^^^^^ help: use: `path`
+
+error: unnecessary use of `into_owned`
+ --> $DIR/unnecessary_to_owned.rs:67:34
+ |
+LL | require_path(&Cow::from(path).into_owned());
+ | ^^^^^^^^^^^^^ help: remove this
+
+error: unnecessary use of `to_owned`
+ --> $DIR/unnecessary_to_owned.rs:68:18
+ |
+LL | require_path(&path.to_owned());
+ | ^^^^^^^^^^^^^^^^ help: use: `path`
+
+error: unnecessary use of `to_string`
+ --> $DIR/unnecessary_to_owned.rs:70:17
+ |
+LL | require_str(&s.to_string());
+ | ^^^^^^^^^^^^^^ help: use: `s`
+
+error: unnecessary use of `into_owned`
+ --> $DIR/unnecessary_to_owned.rs:71:30
+ |
+LL | require_str(&Cow::from(s).into_owned());
+ | ^^^^^^^^^^^^^ help: remove this
+
+error: unnecessary use of `to_owned`
+ --> $DIR/unnecessary_to_owned.rs:72:17
+ |
+LL | require_str(&s.to_owned());
+ | ^^^^^^^^^^^^^ help: use: `s`
+
+error: unnecessary use of `to_string`
+ --> $DIR/unnecessary_to_owned.rs:73:17
+ |
+LL | require_str(&x_ref.to_string());
+ | ^^^^^^^^^^^^^^^^^^ help: use: `x_ref.as_ref()`
+
+error: unnecessary use of `to_vec`
+ --> $DIR/unnecessary_to_owned.rs:75:19
+ |
+LL | require_slice(&slice.to_vec());
+ | ^^^^^^^^^^^^^^^ help: use: `slice`
+
+error: unnecessary use of `into_owned`
+ --> $DIR/unnecessary_to_owned.rs:76:36
+ |
+LL | require_slice(&Cow::from(slice).into_owned());
+ | ^^^^^^^^^^^^^ help: remove this
+
+error: unnecessary use of `to_owned`
+ --> $DIR/unnecessary_to_owned.rs:77:19
+ |
+LL | require_slice(&array.to_owned());
+ | ^^^^^^^^^^^^^^^^^ help: use: `array.as_ref()`
+
+error: unnecessary use of `to_owned`
+ --> $DIR/unnecessary_to_owned.rs:78:19
+ |
+LL | require_slice(&array_ref.to_owned());
+ | ^^^^^^^^^^^^^^^^^^^^^ help: use: `array_ref.as_ref()`
+
+error: unnecessary use of `to_owned`
+ --> $DIR/unnecessary_to_owned.rs:79:19
+ |
+LL | require_slice(&slice.to_owned());
+ | ^^^^^^^^^^^^^^^^^ help: use: `slice`
+
+error: unnecessary use of `to_owned`
+ --> $DIR/unnecessary_to_owned.rs:80:19
+ |
+LL | require_slice(&x_ref.to_owned());
+ | ^^^^^^^^^^^^^^^^^ help: use: `x_ref`
+
+error: unnecessary use of `into_owned`
+ --> $DIR/unnecessary_to_owned.rs:82:42
+ |
+LL | require_x(&Cow::<X>::Owned(x.clone()).into_owned());
+ | ^^^^^^^^^^^^^ help: remove this
+
+error: unnecessary use of `to_owned`
+ --> $DIR/unnecessary_to_owned.rs:83:15
+ |
+LL | require_x(&x_ref.to_owned());
+ | ^^^^^^^^^^^^^^^^^ help: use: `x_ref`
+
+error: unnecessary use of `to_owned`
+ --> $DIR/unnecessary_to_owned.rs:85:25
+ |
+LL | require_deref_c_str(c_str.to_owned());
+ | ^^^^^^^^^^^^^^^^ help: use: `c_str`
+
+error: unnecessary use of `to_owned`
+ --> $DIR/unnecessary_to_owned.rs:86:26
+ |
+LL | require_deref_os_str(os_str.to_owned());
+ | ^^^^^^^^^^^^^^^^^ help: use: `os_str`
+
+error: unnecessary use of `to_owned`
+ --> $DIR/unnecessary_to_owned.rs:87:24
+ |
+LL | require_deref_path(path.to_owned());
+ | ^^^^^^^^^^^^^^^ help: use: `path`
+
+error: unnecessary use of `to_owned`
+ --> $DIR/unnecessary_to_owned.rs:88:23
+ |
+LL | require_deref_str(s.to_owned());
+ | ^^^^^^^^^^^^ help: use: `s`
+
+error: unnecessary use of `to_owned`
+ --> $DIR/unnecessary_to_owned.rs:89:25
+ |
+LL | require_deref_slice(slice.to_owned());
+ | ^^^^^^^^^^^^^^^^ help: use: `slice`
+
+error: unnecessary use of `to_owned`
+ --> $DIR/unnecessary_to_owned.rs:91:30
+ |
+LL | require_impl_deref_c_str(c_str.to_owned());
+ | ^^^^^^^^^^^^^^^^ help: use: `c_str`
+
+error: unnecessary use of `to_owned`
+ --> $DIR/unnecessary_to_owned.rs:92:31
+ |
+LL | require_impl_deref_os_str(os_str.to_owned());
+ | ^^^^^^^^^^^^^^^^^ help: use: `os_str`
+
+error: unnecessary use of `to_owned`
+ --> $DIR/unnecessary_to_owned.rs:93:29
+ |
+LL | require_impl_deref_path(path.to_owned());
+ | ^^^^^^^^^^^^^^^ help: use: `path`
+
+error: unnecessary use of `to_owned`
+ --> $DIR/unnecessary_to_owned.rs:94:28
+ |
+LL | require_impl_deref_str(s.to_owned());
+ | ^^^^^^^^^^^^ help: use: `s`
+
+error: unnecessary use of `to_owned`
+ --> $DIR/unnecessary_to_owned.rs:95:30
+ |
+LL | require_impl_deref_slice(slice.to_owned());
+ | ^^^^^^^^^^^^^^^^ help: use: `slice`
+
+error: unnecessary use of `to_owned`
+ --> $DIR/unnecessary_to_owned.rs:97:29
+ |
+LL | require_deref_str_slice(s.to_owned(), slice.to_owned());
+ | ^^^^^^^^^^^^ help: use: `s`
+
+error: unnecessary use of `to_owned`
+ --> $DIR/unnecessary_to_owned.rs:97:43
+ |
+LL | require_deref_str_slice(s.to_owned(), slice.to_owned());
+ | ^^^^^^^^^^^^^^^^ help: use: `slice`
+
+error: unnecessary use of `to_owned`
+ --> $DIR/unnecessary_to_owned.rs:98:29
+ |
+LL | require_deref_slice_str(slice.to_owned(), s.to_owned());
+ | ^^^^^^^^^^^^^^^^ help: use: `slice`
+
+error: unnecessary use of `to_owned`
+ --> $DIR/unnecessary_to_owned.rs:98:47
+ |
+LL | require_deref_slice_str(slice.to_owned(), s.to_owned());
+ | ^^^^^^^^^^^^ help: use: `s`
+
+error: unnecessary use of `to_owned`
+ --> $DIR/unnecessary_to_owned.rs:100:26
+ |
+LL | require_as_ref_c_str(c_str.to_owned());
+ | ^^^^^^^^^^^^^^^^ help: use: `c_str`
+
+error: unnecessary use of `to_owned`
+ --> $DIR/unnecessary_to_owned.rs:101:27
+ |
+LL | require_as_ref_os_str(os_str.to_owned());
+ | ^^^^^^^^^^^^^^^^^ help: use: `os_str`
+
+error: unnecessary use of `to_owned`
+ --> $DIR/unnecessary_to_owned.rs:102:25
+ |
+LL | require_as_ref_path(path.to_owned());
+ | ^^^^^^^^^^^^^^^ help: use: `path`
+
+error: unnecessary use of `to_owned`
+ --> $DIR/unnecessary_to_owned.rs:103:24
+ |
+LL | require_as_ref_str(s.to_owned());
+ | ^^^^^^^^^^^^ help: use: `s`
+
+error: unnecessary use of `to_owned`
+ --> $DIR/unnecessary_to_owned.rs:104:24
+ |
+LL | require_as_ref_str(x.to_owned());
+ | ^^^^^^^^^^^^ help: use: `&x`
+
+error: unnecessary use of `to_owned`
+ --> $DIR/unnecessary_to_owned.rs:105:26
+ |
+LL | require_as_ref_slice(array.to_owned());
+ | ^^^^^^^^^^^^^^^^ help: use: `array`
+
+error: unnecessary use of `to_owned`
+ --> $DIR/unnecessary_to_owned.rs:106:26
+ |
+LL | require_as_ref_slice(array_ref.to_owned());
+ | ^^^^^^^^^^^^^^^^^^^^ help: use: `array_ref`
+
+error: unnecessary use of `to_owned`
+ --> $DIR/unnecessary_to_owned.rs:107:26
+ |
+LL | require_as_ref_slice(slice.to_owned());
+ | ^^^^^^^^^^^^^^^^ help: use: `slice`
+
+error: unnecessary use of `to_owned`
+ --> $DIR/unnecessary_to_owned.rs:109:31
+ |
+LL | require_impl_as_ref_c_str(c_str.to_owned());
+ | ^^^^^^^^^^^^^^^^ help: use: `c_str`
+
+error: unnecessary use of `to_owned`
+ --> $DIR/unnecessary_to_owned.rs:110:32
+ |
+LL | require_impl_as_ref_os_str(os_str.to_owned());
+ | ^^^^^^^^^^^^^^^^^ help: use: `os_str`
+
+error: unnecessary use of `to_owned`
+ --> $DIR/unnecessary_to_owned.rs:111:30
+ |
+LL | require_impl_as_ref_path(path.to_owned());
+ | ^^^^^^^^^^^^^^^ help: use: `path`
+
+error: unnecessary use of `to_owned`
+ --> $DIR/unnecessary_to_owned.rs:112:29
+ |
+LL | require_impl_as_ref_str(s.to_owned());
+ | ^^^^^^^^^^^^ help: use: `s`
+
+error: unnecessary use of `to_owned`
+ --> $DIR/unnecessary_to_owned.rs:113:29
+ |
+LL | require_impl_as_ref_str(x.to_owned());
+ | ^^^^^^^^^^^^ help: use: `&x`
+
+error: unnecessary use of `to_owned`
+ --> $DIR/unnecessary_to_owned.rs:114:31
+ |
+LL | require_impl_as_ref_slice(array.to_owned());
+ | ^^^^^^^^^^^^^^^^ help: use: `array`
+
+error: unnecessary use of `to_owned`
+ --> $DIR/unnecessary_to_owned.rs:115:31
+ |
+LL | require_impl_as_ref_slice(array_ref.to_owned());
+ | ^^^^^^^^^^^^^^^^^^^^ help: use: `array_ref`
+
+error: unnecessary use of `to_owned`
+ --> $DIR/unnecessary_to_owned.rs:116:31
+ |
+LL | require_impl_as_ref_slice(slice.to_owned());
+ | ^^^^^^^^^^^^^^^^ help: use: `slice`
+
+error: unnecessary use of `to_owned`
+ --> $DIR/unnecessary_to_owned.rs:118:30
+ |
+LL | require_as_ref_str_slice(s.to_owned(), array.to_owned());
+ | ^^^^^^^^^^^^ help: use: `s`
+
+error: unnecessary use of `to_owned`
+ --> $DIR/unnecessary_to_owned.rs:118:44
+ |
+LL | require_as_ref_str_slice(s.to_owned(), array.to_owned());
+ | ^^^^^^^^^^^^^^^^ help: use: `array`
+
+error: unnecessary use of `to_owned`
+ --> $DIR/unnecessary_to_owned.rs:119:30
+ |
+LL | require_as_ref_str_slice(s.to_owned(), array_ref.to_owned());
+ | ^^^^^^^^^^^^ help: use: `s`
+
+error: unnecessary use of `to_owned`
+ --> $DIR/unnecessary_to_owned.rs:119:44
+ |
+LL | require_as_ref_str_slice(s.to_owned(), array_ref.to_owned());
+ | ^^^^^^^^^^^^^^^^^^^^ help: use: `array_ref`
+
+error: unnecessary use of `to_owned`
+ --> $DIR/unnecessary_to_owned.rs:120:30
+ |
+LL | require_as_ref_str_slice(s.to_owned(), slice.to_owned());
+ | ^^^^^^^^^^^^ help: use: `s`
+
+error: unnecessary use of `to_owned`
+ --> $DIR/unnecessary_to_owned.rs:120:44
+ |
+LL | require_as_ref_str_slice(s.to_owned(), slice.to_owned());
+ | ^^^^^^^^^^^^^^^^ help: use: `slice`
+
+error: unnecessary use of `to_owned`
+ --> $DIR/unnecessary_to_owned.rs:121:30
+ |
+LL | require_as_ref_slice_str(array.to_owned(), s.to_owned());
+ | ^^^^^^^^^^^^^^^^ help: use: `array`
+
+error: unnecessary use of `to_owned`
+ --> $DIR/unnecessary_to_owned.rs:121:48
+ |
+LL | require_as_ref_slice_str(array.to_owned(), s.to_owned());
+ | ^^^^^^^^^^^^ help: use: `s`
+
+error: unnecessary use of `to_owned`
+ --> $DIR/unnecessary_to_owned.rs:122:30
+ |
+LL | require_as_ref_slice_str(array_ref.to_owned(), s.to_owned());
+ | ^^^^^^^^^^^^^^^^^^^^ help: use: `array_ref`
+
+error: unnecessary use of `to_owned`
+ --> $DIR/unnecessary_to_owned.rs:122:52
+ |
+LL | require_as_ref_slice_str(array_ref.to_owned(), s.to_owned());
+ | ^^^^^^^^^^^^ help: use: `s`
+
+error: unnecessary use of `to_owned`
+ --> $DIR/unnecessary_to_owned.rs:123:30
+ |
+LL | require_as_ref_slice_str(slice.to_owned(), s.to_owned());
+ | ^^^^^^^^^^^^^^^^ help: use: `slice`
+
+error: unnecessary use of `to_owned`
+ --> $DIR/unnecessary_to_owned.rs:123:48
+ |
+LL | require_as_ref_slice_str(slice.to_owned(), s.to_owned());
+ | ^^^^^^^^^^^^ help: use: `s`
+
+error: unnecessary use of `to_string`
+ --> $DIR/unnecessary_to_owned.rs:125:20
+ |
+LL | let _ = x.join(&x_ref.to_string());
+ | ^^^^^^^^^^^^^^^^^^ help: use: `x_ref`
+
+error: unnecessary use of `to_vec`
+ --> $DIR/unnecessary_to_owned.rs:127:13
+ |
+LL | let _ = slice.to_vec().into_iter();
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use: `slice.iter().copied()`
+
+error: unnecessary use of `to_owned`
+ --> $DIR/unnecessary_to_owned.rs:128:13
+ |
+LL | let _ = slice.to_owned().into_iter();
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use: `slice.iter().copied()`
+
+error: unnecessary use of `to_vec`
+ --> $DIR/unnecessary_to_owned.rs:129:13
+ |
+LL | let _ = [std::path::PathBuf::new()][..].to_vec().into_iter();
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use: `[std::path::PathBuf::new()][..].iter().cloned()`
+
+error: unnecessary use of `to_owned`
+ --> $DIR/unnecessary_to_owned.rs:130:13
+ |
+LL | let _ = [std::path::PathBuf::new()][..].to_owned().into_iter();
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use: `[std::path::PathBuf::new()][..].iter().cloned()`
+
+error: unnecessary use of `to_vec`
+ --> $DIR/unnecessary_to_owned.rs:132:13
+ |
+LL | let _ = IntoIterator::into_iter(slice.to_vec());
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use: `slice.iter().copied()`
+
+error: unnecessary use of `to_owned`
+ --> $DIR/unnecessary_to_owned.rs:133:13
+ |
+LL | let _ = IntoIterator::into_iter(slice.to_owned());
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use: `slice.iter().copied()`
+
+error: unnecessary use of `to_vec`
+ --> $DIR/unnecessary_to_owned.rs:134:13
+ |
+LL | let _ = IntoIterator::into_iter([std::path::PathBuf::new()][..].to_vec());
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use: `[std::path::PathBuf::new()][..].iter().cloned()`
+
+error: unnecessary use of `to_owned`
+ --> $DIR/unnecessary_to_owned.rs:135:13
+ |
+LL | let _ = IntoIterator::into_iter([std::path::PathBuf::new()][..].to_owned());
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use: `[std::path::PathBuf::new()][..].iter().cloned()`
+
+error: unnecessary use of `to_vec`
+ --> $DIR/unnecessary_to_owned.rs:196:14
+ |
+LL | for t in file_types.to_vec() {
+ | ^^^^^^^^^^^^^^^^^^^
+ |
+help: use
+ |
+LL | for t in file_types {
+ | ~~~~~~~~~~
+help: remove this `&`
+ |
+LL - let path = match get_file_path(&t) {
+LL + let path = match get_file_path(t) {
+ |
+
+error: aborting due to 76 previous errors
+
diff --git a/src/tools/clippy/triagebot.toml b/src/tools/clippy/triagebot.toml
index b0a13f827d6..80c30393832 100644
--- a/src/tools/clippy/triagebot.toml
+++ b/src/tools/clippy/triagebot.toml
@@ -5,3 +5,8 @@ allow-unauthenticated = [
]
[assign]
+
+# Allows shortcuts like `@rustbot ready`
+#
+# See https://github.com/rust-lang/triagebot/wiki/Shortcuts
+[shortcut]
diff --git a/src/tools/clippy/util/gh-pages/index.html b/src/tools/clippy/util/gh-pages/index.html
index 48421150a54..f175700a3f4 100644
--- a/src/tools/clippy/util/gh-pages/index.html
+++ b/src/tools/clippy/util/gh-pages/index.html
@@ -118,6 +118,12 @@ Otherwise, have a great day =^.^=
background-color: #777777;
margin: auto 5px;
}
+
+ .label-version {
+ background-color: #777777;
+ margin: auto 5px;
+ font-family: monospace;
+ }
</style>
<style>
/* Expanding the mdBoom theme*/
@@ -330,7 +336,7 @@ Otherwise, have a great day =^.^=
</h2>
</header>
- <ul class="list-group lint-docs" ng-class="{collapse: true, in: open[lint.id]}">
+ <div class="list-group lint-docs" ng-class="{collapse: true, in: open[lint.id]}">
<div class="list-group-item lint-doc-md" ng-bind-html="lint.docs | markdown"></div>
<div class="lint-additional-info-container">
<!-- Applicability -->
@@ -339,7 +345,11 @@ Otherwise, have a great day =^.^=
<span class="label label-default label-applicability">{{lint.applicability.applicability}}</span>
<a href="https://doc.rust-lang.org/nightly/nightly-rustc/rustc_lint_defs/enum.Applicability.html#variants">(?)</a>
</div>
- <!-- TODO xFrednet 2021-05-19: Somehow collect and show the version See rust-clippy#6492 -->
+ <!-- Clippy version -->
+ <div class="lint-additional-info-item">
+ <span>{{lint.group == "deprecated" ? "Deprecated" : "Added"}} in: </span>
+ <span class="label label-default label-version">{{lint.version}}</span>
+ </div>
<!-- Open related issues -->
<div class="lint-additional-info-item">
<a href="https://github.com/rust-lang/rust-clippy/issues?q=is%3Aissue+{{lint.id}}">Related Issues</a>
@@ -349,7 +359,7 @@ Otherwise, have a great day =^.^=
<a href="https://github.com/rust-lang/rust-clippy/blob/{{docVersion}}/clippy_lints/{{lint.id_span.path}}#L{{lint.id_span.line}}">View Source</a>
</div>
</div>
- </ul>
+ </div>
</article>
</div>
</div>
diff --git a/src/tools/compiletest/src/runtest.rs b/src/tools/compiletest/src/runtest.rs
index 3c85b9076dd..f039ba59d23 100644
--- a/src/tools/compiletest/src/runtest.rs
+++ b/src/tools/compiletest/src/runtest.rs
@@ -1452,6 +1452,8 @@ impl<'test> TestCx<'test> {
.arg(aux_dir)
.arg("-o")
.arg(out_dir)
+ .arg("--deny")
+ .arg("warnings")
.arg(&self.testpaths.file)
.args(&self.props.compile_flags);
@@ -1800,6 +1802,7 @@ impl<'test> TestCx<'test> {
// patterns still match the raw compiler output.
if self.props.error_patterns.is_empty() {
rustc.args(&["--error-format", "json"]);
+ rustc.args(&["--json", "future-incompat"]);
}
rustc.arg("-Zui-testing");
rustc.arg("-Zdeduplicate-diagnostics=no");
@@ -1807,11 +1810,11 @@ impl<'test> TestCx<'test> {
Ui => {
if !self.props.compile_flags.iter().any(|s| s.starts_with("--error-format")) {
rustc.args(&["--error-format", "json"]);
+ rustc.args(&["--json", "future-incompat"]);
}
rustc.arg("-Ccodegen-units=1");
rustc.arg("-Zui-testing");
rustc.arg("-Zdeduplicate-diagnostics=no");
- rustc.arg("-Zemit-future-incompat-report");
}
MirOpt => {
rustc.args(&[
@@ -2217,12 +2220,12 @@ impl<'test> TestCx<'test> {
self.check_rustdoc_test_option(proc_res);
} else {
let root = self.config.find_rust_src_root().unwrap();
- let res = self.cmd2procres(
- Command::new(&self.config.docck_python)
- .arg(root.join("src/etc/htmldocck.py"))
- .arg(&out_dir)
- .arg(&self.testpaths.file),
- );
+ let mut cmd = Command::new(&self.config.docck_python);
+ cmd.arg(root.join("src/etc/htmldocck.py")).arg(&out_dir).arg(&self.testpaths.file);
+ if self.config.bless {
+ cmd.arg("--bless");
+ }
+ let res = self.cmd2procres(&mut cmd);
if !res.status.success() {
self.fatal_proc_rec_with_ctx("htmldocck failed!", &res, |mut this| {
this.compare_to_default_rustdoc(&out_dir)
@@ -3498,6 +3501,72 @@ impl<'test> TestCx<'test> {
normalized =
Regex::new("\\s*//(\\[.*\\])?~.*").unwrap().replace_all(&normalized, "").into_owned();
+ // This code normalizes various hashes in both
+ // v0 and legacy symbol names that are emitted in
+ // the ui and mir-opt tests.
+ //
+ // Some tests still require normalization with headers.
+ const DEFID_HASH_REGEX: &str = r"\[[0-9a-z]{4}\]";
+ const DEFID_HASH_PLACEHOLDER: &str = r"[HASH]";
+ const V0_DEMANGLING_HASH_REGEX: &str = r"\[[0-9a-z]+\]";
+ const V0_DEMANGLING_HASH_PLACEHOLDER: &str = r"[HASH]";
+ const V0_CRATE_HASH_PREFIX_REGEX: &str = r"_R.*?Cs[0-9a-zA-Z]+_";
+ const V0_CRATE_HASH_REGEX: &str = r"Cs[0-9a-zA-Z]+_";
+ const V0_CRATE_HASH_PLACEHOLDER: &str = r"CsCRATE_HASH_";
+ const V0_BACK_REF_PREFIX_REGEX: &str = r"\(_R.*?B[0-9a-zA-Z]_";
+ const V0_BACK_REF_REGEX: &str = r"B[0-9a-zA-Z]_";
+ const V0_BACK_REF_PLACEHOLDER: &str = r"B<REF>_";
+ const LEGACY_SYMBOL_HASH_REGEX: &str = r"h[\w]{16}E?\)";
+ const LEGACY_SYMBOL_HASH_PLACEHOLDER: &str = r"h<SYMBOL_HASH>)";
+ let test_name = self
+ .output_testname_unique()
+ .into_os_string()
+ .into_string()
+ .unwrap()
+ .split('.')
+ .next()
+ .unwrap()
+ .replace("-", "_");
+ // Normalize `DefId` hashes
+ let defid_regex = format!("{}{}", test_name, DEFID_HASH_REGEX);
+ let defid_placeholder = format!("{}{}", test_name, DEFID_HASH_PLACEHOLDER);
+ normalized = Regex::new(&defid_regex)
+ .unwrap()
+ .replace_all(&normalized, defid_placeholder)
+ .into_owned();
+ // Normalize v0 demangling hashes
+ let demangling_regex = format!("{}{}", test_name, V0_DEMANGLING_HASH_REGEX);
+ let demangling_placeholder = format!("{}{}", test_name, V0_DEMANGLING_HASH_PLACEHOLDER);
+ normalized = Regex::new(&demangling_regex)
+ .unwrap()
+ .replace_all(&normalized, demangling_placeholder)
+ .into_owned();
+ // Normalize v0 crate hashes (see RFC 2603)
+ let symbol_mangle_prefix_re = Regex::new(V0_CRATE_HASH_PREFIX_REGEX).unwrap();
+ if symbol_mangle_prefix_re.is_match(&normalized) {
+ // Normalize crate hash
+ normalized = Regex::new(V0_CRATE_HASH_REGEX)
+ .unwrap()
+ .replace_all(&normalized, V0_CRATE_HASH_PLACEHOLDER)
+ .into_owned();
+ }
+ let back_ref_prefix_re = Regex::new(V0_BACK_REF_PREFIX_REGEX).unwrap();
+ if back_ref_prefix_re.is_match(&normalized) {
+ // Normalize back references (see RFC 2603)
+ let back_ref_regex = format!("{}", V0_BACK_REF_REGEX);
+ let back_ref_placeholder = format!("{}", V0_BACK_REF_PLACEHOLDER);
+ normalized = Regex::new(&back_ref_regex)
+ .unwrap()
+ .replace_all(&normalized, back_ref_placeholder)
+ .into_owned();
+ }
+ // Normalize legacy mangled symbols
+ normalized = Regex::new(LEGACY_SYMBOL_HASH_REGEX)
+ .unwrap()
+ .replace_all(&normalized, LEGACY_SYMBOL_HASH_PLACEHOLDER)
+ .into_owned();
+
+ // Custom normalization rules
for rule in custom_rules {
let re = Regex::new(&rule.0).expect("bad regex in custom normalization rule");
normalized = re.replace_all(&normalized, &rule.1[..]).into_owned();
diff --git a/src/tools/miri b/src/tools/miri
-Subproject 76a3329f51439ff2cacda4d26d478a9dc1682a0
+Subproject dadcbebfbd017aac2358cf652a4bd71a91694ed
diff --git a/src/tools/rust-analyzer b/src/tools/rust-analyzer
-Subproject 73668334f05c3446b04116ccc3156240d2d8ab1
+Subproject db2a7087b994e20f264f26ad6db75184282ad12
diff --git a/src/tools/rustbook/Cargo.toml b/src/tools/rustbook/Cargo.toml
index de1327d74ff..b8c67de2623 100644
--- a/src/tools/rustbook/Cargo.toml
+++ b/src/tools/rustbook/Cargo.toml
@@ -9,6 +9,6 @@ clap = "2.25.0"
env_logger = "0.7.1"
[dependencies.mdbook]
-version = "0.4.12"
+version = "0.4.14"
default-features = false
features = ["search"]
diff --git a/src/tools/rustdoc-gui/tester.js b/src/tools/rustdoc-gui/tester.js
index b598c63f52a..32340ec7eec 100644
--- a/src/tools/rustdoc-gui/tester.js
+++ b/src/tools/rustdoc-gui/tester.js
@@ -133,7 +133,7 @@ async function main(argv) {
// Print successful tests too
let debug = false;
// Run tests in sequentially
- let no_headless = false;
+ let headless = true;
const options = new Options();
try {
// This is more convenient that setting fields one by one.
@@ -150,7 +150,7 @@ async function main(argv) {
}
if (opts["no_headless"]) {
args.push("--no-headless");
- no_headless = true;
+ headless = false;
}
options.parseArguments(args);
} catch (error) {
@@ -172,11 +172,16 @@ async function main(argv) {
}
files.sort();
+ if (!headless) {
+ opts["jobs"] = 1;
+ console.log("`--no-headless` option is active, disabling concurrency for running tests.");
+ }
+
console.log(`Running ${files.length} rustdoc-gui (${opts["jobs"]} concurrently) ...`);
if (opts["jobs"] < 1) {
process.setMaxListeners(files.length + 1);
- } else {
+ } else if (headless) {
process.setMaxListeners(opts["jobs"] + 1);
}
@@ -194,7 +199,7 @@ async function main(argv) {
.then(out => {
const [output, nb_failures] = out;
results[nb_failures === 0 ? "successful" : "failed"].push({
- file_name: file_name,
+ file_name: testPath,
output: output,
});
if (nb_failures > 0) {
@@ -206,7 +211,7 @@ async function main(argv) {
})
.catch(err => {
results.errored.push({
- file_name: file_name,
+ file_name: testPath + file_name,
output: err,
});
status_bar.erroneous();
@@ -217,13 +222,11 @@ async function main(argv) {
tests_queue.splice(tests_queue.indexOf(callback), 1);
});
tests_queue.push(callback);
- if (no_headless) {
- await tests_queue[i];
- } else if (opts["jobs"] > 0 && tests_queue.length >= opts["jobs"]) {
+ if (opts["jobs"] > 0 && tests_queue.length >= opts["jobs"]) {
await Promise.race(tests_queue);
}
}
- if (!no_headless && tests_queue.length > 0) {
+ if (tests_queue.length > 0) {
await Promise.all(tests_queue);
}
status_bar.finish();
@@ -239,7 +242,7 @@ async function main(argv) {
console.log("");
results.failed.sort(by_filename);
results.failed.forEach(r => {
- console.log(r.output);
+ console.log(r.file_name, r.output);
});
}
if (results.errored.length > 0) {
@@ -247,7 +250,7 @@ async function main(argv) {
// print run errors on the bottom so developers see them better
results.errored.sort(by_filename);
results.errored.forEach(r => {
- console.error(r.output);
+ console.error(r.file_name, r.output);
});
}
diff --git a/src/tools/rustfmt/.github/workflows/linux.yml b/src/tools/rustfmt/.github/workflows/linux.yml
index 6eaae69c708..db497941642 100644
--- a/src/tools/rustfmt/.github/workflows/linux.yml
+++ b/src/tools/rustfmt/.github/workflows/linux.yml
@@ -8,7 +8,9 @@ on:
jobs:
test:
runs-on: ubuntu-latest
- name: (${{ matrix.target }}, nightly)
+ name: (${{ matrix.target }}, ${{ matrix.cfg_release_channel }})
+ env:
+ CFG_RELEASE_CHANNEL: ${{ matrix.cfg_release_channel }}
strategy:
# https://help.github.com/en/actions/getting-started-with-github-actions/about-github-actions#usage-limits
# There's a limit of 60 concurrent jobs across all repos in the rust-lang organization.
@@ -20,6 +22,7 @@ jobs:
target: [
x86_64-unknown-linux-gnu,
]
+ cfg_release_channel: [nightly, stable]
steps:
- name: checkout
diff --git a/src/tools/rustfmt/.github/workflows/mac.yml b/src/tools/rustfmt/.github/workflows/mac.yml
index 79e4f69163e..55e1cc9539b 100644
--- a/src/tools/rustfmt/.github/workflows/mac.yml
+++ b/src/tools/rustfmt/.github/workflows/mac.yml
@@ -10,13 +10,16 @@ jobs:
# https://help.github.com/en/actions/automating-your-workflow-with-github-actions/virtual-environments-for-github-hosted-runners#supported-runners-and-hardware-resources
# macOS Catalina 10.15
runs-on: macos-latest
- name: (${{ matrix.target }}, nightly)
+ name: (${{ matrix.target }}, ${{ matrix.cfg_release_channel }})
+ env:
+ CFG_RELEASE_CHANNEL: ${{ matrix.cfg_release_channel }}
strategy:
fail-fast: false
matrix:
target: [
x86_64-apple-darwin,
]
+ cfg_release_channel: [nightly, stable]
steps:
- name: checkout
diff --git a/src/tools/rustfmt/.github/workflows/windows.yml b/src/tools/rustfmt/.github/workflows/windows.yml
index c05e8d4896a..dcb08b5412e 100644
--- a/src/tools/rustfmt/.github/workflows/windows.yml
+++ b/src/tools/rustfmt/.github/workflows/windows.yml
@@ -8,7 +8,9 @@ on:
jobs:
test:
runs-on: windows-latest
- name: (${{ matrix.target }}, nightly)
+ name: (${{ matrix.target }}, ${{ matrix.cfg_release_channel }})
+ env:
+ CFG_RELEASE_CHANNEL: ${{ matrix.cfg_release_channel }}
strategy:
# https://help.github.com/en/actions/getting-started-with-github-actions/about-github-actions#usage-limits
# There's a limit of 60 concurrent jobs across all repos in the rust-lang organization.
@@ -23,6 +25,7 @@ jobs:
x86_64-pc-windows-gnu,
x86_64-pc-windows-msvc,
]
+ cfg_release_channel: [nightly, stable]
steps:
# The Windows runners have autocrlf enabled by default
diff --git a/src/tools/rustfmt/Configurations.md b/src/tools/rustfmt/Configurations.md
index 13826883d2f..a89fbe863e6 100644
--- a/src/tools/rustfmt/Configurations.md
+++ b/src/tools/rustfmt/Configurations.md
@@ -47,7 +47,7 @@ Where to put a binary operator when a binary expression goes multiline.
- **Default value**: `"Front"`
- **Possible values**: `"Front"`, `"Back"`
-- **Stable**: No (tracking issue: #3368)
+- **Stable**: No (tracking issue: [#3368](https://github.com/rust-lang/rustfmt/issues/3368))
#### `"Front"` (default):
@@ -88,7 +88,7 @@ them, additional blank lines are inserted.
- **Default value**: `0`
- **Possible values**: *unsigned integer*
-- **Stable**: No (tracking issue: #3382)
+- **Stable**: No (tracking issue: [#3382](https://github.com/rust-lang/rustfmt/issues/3382))
### Example
Original Code (rustfmt will not change it with the default value of `0`):
@@ -128,7 +128,7 @@ lines are found, they are trimmed down to match this integer.
- **Default value**: `1`
- **Possible values**: any non-negative integer
-- **Stable**: No (tracking issue: #3381)
+- **Stable**: No (tracking issue: [#3381](https://github.com/rust-lang/rustfmt/issues/3381))
### Example
Original Code:
@@ -186,7 +186,7 @@ Brace style for items
- **Default value**: `"SameLineWhere"`
- **Possible values**: `"AlwaysNextLine"`, `"PreferSameLine"`, `"SameLineWhere"`
-- **Stable**: No (tracking issue: #3376)
+- **Stable**: No (tracking issue: [#3376](https://github.com/rust-lang/rustfmt/issues/3376))
### Functions
@@ -313,7 +313,7 @@ Whether to use colored output or not.
- **Default value**: `"Auto"`
- **Possible values**: "Auto", "Always", "Never"
-- **Stable**: No (tracking issue: #3385)
+- **Stable**: No (tracking issue: [#3385](https://github.com/rust-lang/rustfmt/issues/3385))
## `combine_control_expr`
@@ -321,7 +321,7 @@ Combine control expressions with function calls.
- **Default value**: `true`
- **Possible values**: `true`, `false`
-- **Stable**: No (tracking issue: #3369)
+- **Stable**: No (tracking issue: [#3369](https://github.com/rust-lang/rustfmt/issues/3369))
#### `true` (default):
@@ -429,7 +429,7 @@ Maximum length of comments. No effect unless`wrap_comments = true`.
- **Default value**: `80`
- **Possible values**: any positive integer
-- **Stable**: No (tracking issue: #3349)
+- **Stable**: No (tracking issue: [#3349](https://github.com/rust-lang/rustfmt/issues/3349))
**Note:** A value of `0` results in [`wrap_comments`](#wrap_comments) being applied regardless of a line's width.
@@ -452,7 +452,7 @@ Replace strings of _ wildcards by a single .. in tuple patterns
- **Default value**: `false`
- **Possible values**: `true`, `false`
-- **Stable**: No (tracking issue: #3384)
+- **Stable**: No (tracking issue: [#3384](https://github.com/rust-lang/rustfmt/issues/3384))
#### `false` (default):
@@ -477,7 +477,7 @@ Brace style for control flow constructs
- **Default value**: `"AlwaysSameLine"`
- **Possible values**: `"AlwaysNextLine"`, `"AlwaysSameLine"`, `"ClosingNextLine"`
-- **Stable**: No (tracking issue: #3377)
+- **Stable**: No (tracking issue: [#3377](https://github.com/rust-lang/rustfmt/issues/3377))
#### `"AlwaysSameLine"` (default):
@@ -551,7 +551,7 @@ Put empty-body functions and impls on a single line
- **Default value**: `true`
- **Possible values**: `true`, `false`
-- **Stable**: No (tracking issue: #3356)
+- **Stable**: No (tracking issue: [#3356](https://github.com/rust-lang/rustfmt/issues/3356))
#### `true` (default):
@@ -584,7 +584,7 @@ doesn't get ignored when aligning.
- **Default value** : 0
- **Possible values**: any positive integer
-- **Stable**: No (tracking issue: #3372)
+- **Stable**: No (tracking issue: [#3372](https://github.com/rust-lang/rustfmt/issues/3372))
#### `0` (default):
@@ -630,7 +630,7 @@ using a shorter name.
- **Default value**: `false`
- **Possible values**: `true`, `false`
-- **Stable**: No (tracking issue: #3391)
+- **Stable**: No (tracking issue: [#3391](https://github.com/rust-lang/rustfmt/issues/3391))
See also [`max_width`](#max_width).
@@ -641,7 +641,7 @@ trailing whitespaces.
- **Default value**: `false`
- **Possible values**: `true`, `false`
-- **Stable**: No (tracking issue: #3392)
+- **Stable**: No (tracking issue: [#3392](https://github.com/rust-lang/rustfmt/issues/3392))
## `fn_args_layout`
@@ -771,7 +771,7 @@ Put single-expression functions on a single line
- **Default value**: `false`
- **Possible values**: `true`, `false`
-- **Stable**: No (tracking issue: #3358)
+- **Stable**: No (tracking issue: [#3358](https://github.com/rust-lang/rustfmt/issues/3358))
#### `false` (default):
@@ -832,7 +832,7 @@ Force multiline closure and match arm bodies to be wrapped in a block
- **Default value**: `false`
- **Possible values**: `false`, `true`
-- **Stable**: No (tracking issue: #3374)
+- **Stable**: No (tracking issue: [#3374](https://github.com/rust-lang/rustfmt/issues/3374))
#### `false` (default):
@@ -881,7 +881,7 @@ Format code snippet included in doc comments.
- **Default value**: `false`
- **Possible values**: `true`, `false`
-- **Stable**: No (tracking issue: #3348)
+- **Stable**: No (tracking issue: [#3348](https://github.com/rust-lang/rustfmt/issues/3348))
#### `false` (default):
@@ -933,7 +933,7 @@ if any of the first five lines contains `@generated` marker.
- **Default value**: `false`
- **Possible values**: `true`, `false`
-- **Stable**: No
+- **Stable**: No (tracking issue: [#5080](https://github.com/rust-lang/rustfmt/issues/5080))
## `format_macro_matchers`
@@ -941,7 +941,7 @@ Format the metavariable matching patterns in macros.
- **Default value**: `false`
- **Possible values**: `true`, `false`
-- **Stable**: No (tracking issue: #3354)
+- **Stable**: No (tracking issue: [#3354](https://github.com/rust-lang/rustfmt/issues/3354))
#### `false` (default):
@@ -978,7 +978,7 @@ Format the bodies of macros.
- **Default value**: `true`
- **Possible values**: `true`, `false`
-- **Stable**: No (tracking issue: #3355)
+- **Stable**: No (tracking issue: [#3355](https://github.com/rust-lang/rustfmt/issues/3355))
#### `true` (default):
@@ -1011,7 +1011,7 @@ Format string literals where necessary
- **Default value**: `false`
- **Possible values**: `true`, `false`
-- **Stable**: No (tracking issue: #3353)
+- **Stable**: No (tracking issue: [#3353](https://github.com/rust-lang/rustfmt/issues/3353))
#### `false` (default):
@@ -1064,7 +1064,7 @@ Control the case of the letters in hexadecimal literal values
- **Default value**: `Preserve`
- **Possible values**: `Upper`, `Lower`
-- **Stable**: No
+- **Stable**: No (tracking issue: [#5081](https://github.com/rust-lang/rustfmt/issues/5081))
## `hide_parse_errors`
@@ -1072,7 +1072,7 @@ Do not show parse errors if the parser failed to parse files.
- **Default value**: `false`
- **Possible values**: `true`, `false`
-- **Stable**: No (tracking issue: #3390)
+- **Stable**: No (tracking issue: [#3390](https://github.com/rust-lang/rustfmt/issues/3390))
## `ignore`
@@ -1081,7 +1081,7 @@ The pattern format is the same as [.gitignore](https://git-scm.com/docs/gitignor
- **Default value**: format every file
- **Possible values**: See an example below
-- **Stable**: No (tracking issue: #3395)
+- **Stable**: No (tracking issue: [#3395](https://github.com/rust-lang/rustfmt/issues/3395))
### Example
@@ -1114,7 +1114,7 @@ Indent style of imports
- **Default Value**: `"Block"`
- **Possible values**: `"Block"`, `"Visual"`
-- **Stable**: No (tracking issue: #3360)
+- **Stable**: No (tracking issue: [#3360](https://github.com/rust-lang/rustfmt/issues/3360))
#### `"Block"` (default):
@@ -1140,7 +1140,7 @@ Item layout inside a imports block
- **Default value**: "Mixed"
- **Possible values**: "Horizontal", "HorizontalVertical", "Mixed", "Vertical"
-- **Stable**: No (tracking issue: #3361)
+- **Stable**: No (tracking issue: [#3361](https://github.com/rust-lang/rustfmt/issues/3361))
#### `"Mixed"` (default):
@@ -1203,7 +1203,7 @@ Indent on expressions or items.
- **Default value**: `"Block"`
- **Possible values**: `"Block"`, `"Visual"`
-- **Stable**: No (tracking issue: #3346)
+- **Stable**: No (tracking issue: [#3346](https://github.com/rust-lang/rustfmt/issues/3346))
### Array
@@ -1456,7 +1456,7 @@ Write an item and its attribute on the same line if their combined width is belo
- **Default value**: 0
- **Possible values**: any positive integer
-- **Stable**: No (tracking issue: #3343)
+- **Stable**: No (tracking issue: [#3343](https://github.com/rust-lang/rustfmt/issues/3343))
### Example
@@ -1477,7 +1477,7 @@ Check whether beginnings of files match a license template.
- **Default value**: `""`
- **Possible values**: path to a license template file
-- **Stable**: No (tracking issue: #3352)
+- **Stable**: No (tracking issue: [#3352](https://github.com/rust-lang/rustfmt/issues/3352))
A license template is a plain text file which is matched literally against the
beginning of each source file, except for `{}`-delimited blocks, which are
@@ -1499,7 +1499,7 @@ The Style Guide requires that bodies are block wrapped by default if a line brea
- **Default value**: `true`
- **Possible values**: `true`, `false`
-- **Stable**: No (tracking issue: #3373)
+- **Stable**: No (tracking issue: [#3373](https://github.com/rust-lang/rustfmt/issues/3373))
#### `true` (default):
@@ -1701,7 +1701,7 @@ How imports should be grouped into `use` statements. Imports will be merged or s
- **Default value**: `Preserve`
- **Possible values**: `Preserve`, `Crate`, `Module`, `Item`, `One`
-- **Stable**: No
+- **Stable**: No (tracking issue: [#4991](https://github.com/rust-lang/rustfmt/issues/4991))
#### `Preserve` (default):
@@ -1826,7 +1826,7 @@ Convert /* */ comments to // comments where possible
- **Default value**: `false`
- **Possible values**: `true`, `false`
-- **Stable**: No (tracking issue: #3350)
+- **Stable**: No (tracking issue: [#3350](https://github.com/rust-lang/rustfmt/issues/3350))
#### `false` (default):
@@ -1854,7 +1854,7 @@ Convert `#![doc]` and `#[doc]` attributes to `//!` and `///` doc comments.
- **Default value**: `false`
- **Possible values**: `true`, `false`
-- **Stable**: No (tracking issue: #3351)
+- **Stable**: No (tracking issue: [#3351](https://github.com/rust-lang/rustfmt/issues/3351))
#### `false` (default):
@@ -1885,7 +1885,7 @@ instead of being indented on a new line.
- **Default value**: `false`
- **Possible values**: `true`, `false`
-- **Stable**: No (tracking issue: #3370)
+- **Stable**: No (tracking issue: [#3370](https://github.com/rust-lang/rustfmt/issues/3370))
#### `false` (default):
@@ -1992,7 +1992,7 @@ Reorder impl items. `type` and `const` are put first, then macros and methods.
- **Default value**: `false`
- **Possible values**: `true`, `false`
-- **Stable**: No (tracking issue: #3363)
+- **Stable**: No (tracking issue: [#3363](https://github.com/rust-lang/rustfmt/issues/3363))
#### `false` (default)
@@ -2063,7 +2063,7 @@ Controls the strategy for how imports are grouped together.
- **Default value**: `Preserve`
- **Possible values**: `Preserve`, `StdExternalCrate`, `One`
-- **Stable**: No
+- **Stable**: No (tracking issue: [#5083](https://github.com/rust-lang/rustfmt/issues/5083))
#### `Preserve` (default):
@@ -2166,7 +2166,7 @@ Report `FIXME` items in comments.
- **Default value**: `"Never"`
- **Possible values**: `"Always"`, `"Unnumbered"`, `"Never"`
-- **Stable**: No (tracking issue: #3394)
+- **Stable**: No (tracking issue: [#3394](https://github.com/rust-lang/rustfmt/issues/3394))
Warns about any comments containing `FIXME` in them when set to `"Always"`. If
it contains a `#X` (with `X` being a number) in parentheses following the
@@ -2181,7 +2181,7 @@ Report `TODO` items in comments.
- **Default value**: `"Never"`
- **Possible values**: `"Always"`, `"Unnumbered"`, `"Never"`
-- **Stable**: No (tracking issue: #3393)
+- **Stable**: No (tracking issue: [#3393](https://github.com/rust-lang/rustfmt/issues/3393))
Warns about any comments containing `TODO` in them when set to `"Always"`. If
it contains a `#X` (with `X` being a number) in parentheses following the
@@ -2196,7 +2196,7 @@ specific version of rustfmt is used in your CI, use this option.
- **Default value**: `CARGO_PKG_VERSION`
- **Possible values**: any published version (e.g. `"0.3.8"`)
-- **Stable**: No (tracking issue: #3386)
+- **Stable**: No (tracking issue: [#3386](https://github.com/rust-lang/rustfmt/issues/3386))
## `skip_children`
@@ -2204,7 +2204,7 @@ Don't reformat out of line modules
- **Default value**: `false`
- **Possible values**: `true`, `false`
-- **Stable**: No (tracking issue: #3389)
+- **Stable**: No (tracking issue: [#3389](https://github.com/rust-lang/rustfmt/issues/3386))
## `single_line_if_else_max_width`
@@ -2224,7 +2224,7 @@ Leave a space after the colon.
- **Default value**: `true`
- **Possible values**: `true`, `false`
-- **Stable**: No (tracking issue: #3366)
+- **Stable**: No (tracking issue: [#3366](https://github.com/rust-lang/rustfmt/issues/3366))
#### `true` (default):
@@ -2256,7 +2256,7 @@ Leave a space before the colon.
- **Default value**: `false`
- **Possible values**: `true`, `false`
-- **Stable**: No (tracking issue: #3365)
+- **Stable**: No (tracking issue: [#3365](https://github.com/rust-lang/rustfmt/issues/3365))
#### `false` (default):
@@ -2288,7 +2288,7 @@ Put spaces around the .., ..=, and ... range operators
- **Default value**: `false`
- **Possible values**: `true`, `false`
-- **Stable**: No (tracking issue: #3367)
+- **Stable**: No (tracking issue: [#3367](https://github.com/rust-lang/rustfmt/issues/3367))
#### `false` (default):
@@ -2344,7 +2344,7 @@ The maximum diff of width between struct fields to be aligned with each other.
- **Default value** : 0
- **Possible values**: any non-negative integer
-- **Stable**: No (tracking issue: #3371)
+- **Stable**: No (tracking issue: [#3371](https://github.com/rust-lang/rustfmt/issues/3371))
#### `0` (default):
@@ -2372,7 +2372,7 @@ Put small struct literals on a single line
- **Default value**: `true`
- **Possible values**: `true`, `false`
-- **Stable**: No (tracking issue: #3357)
+- **Stable**: No (tracking issue: [#3357](https://github.com/rust-lang/rustfmt/issues/3357))
#### `true` (default):
@@ -2460,7 +2460,7 @@ How to handle trailing commas for lists
- **Default value**: `"Vertical"`
- **Possible values**: `"Always"`, `"Never"`, `"Vertical"`
-- **Stable**: No (tracking issue: #3379)
+- **Stable**: No (tracking issue: [#3379](https://github.com/rust-lang/rustfmt/issues/3379))
#### `"Vertical"` (default):
@@ -2518,7 +2518,7 @@ Add trailing semicolon after break, continue and return
- **Default value**: `true`
- **Possible values**: `true`, `false`
-- **Stable**: No (tracking issue: #3378)
+- **Stable**: No (tracking issue: [#3378](https://github.com/rust-lang/rustfmt/issues/3378))
#### `true` (default):
```rust
@@ -2540,7 +2540,7 @@ Determines if `+` or `=` are wrapped in spaces in the punctuation of types
- **Default value**: `"Wide"`
- **Possible values**: `"Compressed"`, `"Wide"`
-- **Stable**: No (tracking issue: #3364)
+- **Stable**: No (tracking issue: [#3364](https://github.com/rust-lang/rustfmt/issues/3364))
#### `"Wide"` (default):
@@ -2564,7 +2564,7 @@ Enable unstable features on the unstable channel.
- **Default value**: `false`
- **Possible values**: `true`, `false`
-- **Stable**: No (tracking issue: #3387)
+- **Stable**: No (tracking issue: [#3387](https://github.com/rust-lang/rustfmt/issues/3387))
## `use_field_init_shorthand`
@@ -2779,7 +2779,7 @@ version number.
- **Default value**: `One`
- **Possible values**: `One`, `Two`
-- **Stable**: No (tracking issue: #3383)
+- **Stable**: No (tracking issue: [#3383](https://github.com/rust-lang/rustfmt/issues/3383))
### Example
@@ -2793,7 +2793,7 @@ Forces the `where` clause to be laid out on a single line.
- **Default value**: `false`
- **Possible values**: `true`, `false`
-- **Stable**: No (tracking issue: #3359)
+- **Stable**: No (tracking issue: [#3359](https://github.com/rust-lang/rustfmt/issues/3359))
#### `false` (default):
@@ -2825,7 +2825,7 @@ Break comments to fit on the line
- **Default value**: `false`
- **Possible values**: `true`, `false`
-- **Stable**: No (tracking issue: #3347)
+- **Stable**: No (tracking issue: [#3347](https://github.com/rust-lang/rustfmt/issues/3347))
#### `false` (default):
diff --git a/src/tools/rustfmt/README.md b/src/tools/rustfmt/README.md
index b3d21e6fb87..b3a968f0c04 100644
--- a/src/tools/rustfmt/README.md
+++ b/src/tools/rustfmt/README.md
@@ -48,12 +48,11 @@ cargo +nightly fmt
## Limitations
Rustfmt tries to work on as much Rust code as possible. Sometimes, the code
-doesn't even need to compile! As we approach a 1.0 release we are also looking
-to limit areas of instability; in particular, post-1.0, the formatting of most
-code should not change as Rustfmt improves. However, there are some things that
-Rustfmt can't do or can't do well (and thus where formatting might change
-significantly, even post-1.0). We would like to reduce the list of limitations
-over time.
+doesn't even need to compile! In general, we are looking to limit areas of
+instability; in particular, post-1.0, the formatting of most code should not
+change as Rustfmt improves. However, there are some things that Rustfmt can't
+do or can't do well (and thus where formatting might change significantly,
+even post-1.0). We would like to reduce the list of limitations over time.
The following list enumerates areas where Rustfmt does not work or where the
stability guarantees do not apply (we don't make a distinction between the two
diff --git a/src/tools/rustfmt/config_proc_macro/src/lib.rs b/src/tools/rustfmt/config_proc_macro/src/lib.rs
index 78e7e098ed9..51301821319 100644
--- a/src/tools/rustfmt/config_proc_macro/src/lib.rs
+++ b/src/tools/rustfmt/config_proc_macro/src/lib.rs
@@ -8,6 +8,8 @@ mod item_enum;
mod item_struct;
mod utils;
+use std::str::FromStr;
+
use proc_macro::TokenStream;
use syn::parse_macro_input;
@@ -23,3 +25,43 @@ pub fn config_type(_args: TokenStream, input: TokenStream) -> TokenStream {
TokenStream::from(output)
}
+
+/// Used to conditionally output the TokenStream for tests that need to be run on nightly only.
+///
+/// ```rust
+/// #[nightly_only_test]
+/// #[test]
+/// fn test_needs_nightly_rustfmt() {
+/// assert!(true);
+/// }
+/// ```
+#[proc_macro_attribute]
+pub fn nightly_only_test(_args: TokenStream, input: TokenStream) -> TokenStream {
+ // if CFG_RELEASE_CHANNEL is not set we default to nightly, hence why the default is true
+ if option_env!("CFG_RELEASE_CHANNEL").map_or(true, |c| c == "nightly" || c == "dev") {
+ input
+ } else {
+ // output an empty token stream if CFG_RELEASE_CHANNEL is not set to "nightly" or "dev"
+ TokenStream::from_str("").unwrap()
+ }
+}
+
+/// Used to conditionally output the TokenStream for tests that need to be run on stable only.
+///
+/// ```rust
+/// #[stable_only_test]
+/// #[test]
+/// fn test_needs_stable_rustfmt() {
+/// assert!(true);
+/// }
+/// ```
+#[proc_macro_attribute]
+pub fn stable_only_test(_args: TokenStream, input: TokenStream) -> TokenStream {
+ // if CFG_RELEASE_CHANNEL is not set we default to nightly, hence why the default is false
+ if option_env!("CFG_RELEASE_CHANNEL").map_or(false, |c| c == "stable") {
+ input
+ } else {
+ // output an empty token stream if CFG_RELEASE_CHANNEL is not set or is not 'stable'
+ TokenStream::from_str("").unwrap()
+ }
+}
diff --git a/src/tools/rustfmt/src/comment.rs b/src/tools/rustfmt/src/comment.rs
index 7b76c232937..0f850b9b2f2 100644
--- a/src/tools/rustfmt/src/comment.rs
+++ b/src/tools/rustfmt/src/comment.rs
@@ -3,6 +3,8 @@
use std::{self, borrow::Cow, iter};
use itertools::{multipeek, MultiPeek};
+use lazy_static::lazy_static;
+use regex::Regex;
use rustc_span::Span;
use crate::config::Config;
@@ -15,6 +17,17 @@ use crate::utils::{
};
use crate::{ErrorKind, FormattingError};
+lazy_static! {
+ /// A regex matching reference doc links.
+ ///
+ /// ```markdown
+ /// /// An [example].
+ /// ///
+ /// /// [example]: this::is::a::link
+ /// ```
+ static ref REFERENCE_LINK_URL: Regex = Regex::new(r"^\[.+\]\s?:").unwrap();
+}
+
fn is_custom_comment(comment: &str) -> bool {
if !comment.starts_with("//") {
false
@@ -506,6 +519,7 @@ struct CommentRewrite<'a> {
opener: String,
closer: String,
line_start: String,
+ style: CommentStyle<'a>,
}
impl<'a> CommentRewrite<'a> {
@@ -515,10 +529,14 @@ impl<'a> CommentRewrite<'a> {
shape: Shape,
config: &'a Config,
) -> CommentRewrite<'a> {
- let (opener, closer, line_start) = if block_style {
- CommentStyle::SingleBullet.to_str_tuplet()
+ let ((opener, closer, line_start), style) = if block_style {
+ (
+ CommentStyle::SingleBullet.to_str_tuplet(),
+ CommentStyle::SingleBullet,
+ )
} else {
- comment_style(orig, config.normalize_comments()).to_str_tuplet()
+ let style = comment_style(orig, config.normalize_comments());
+ (style.to_str_tuplet(), style)
};
let max_width = shape
@@ -551,6 +569,7 @@ impl<'a> CommentRewrite<'a> {
opener: opener.to_owned(),
closer: closer.to_owned(),
line_start: line_start.to_owned(),
+ style,
};
cr.result.push_str(opener);
cr
@@ -570,6 +589,15 @@ impl<'a> CommentRewrite<'a> {
result
}
+ /// Check if any characters were written to the result buffer after the start of the comment.
+ /// when calling [`CommentRewrite::new()`] the result buffer is initiazlied with the opening
+ /// characters for the comment.
+ fn buffer_contains_comment(&self) -> bool {
+ // if self.result.len() < self.opener.len() then an empty comment is in the buffer
+ // if self.result.len() > self.opener.len() then a non empty comment is in the buffer
+ self.result.len() != self.opener.len()
+ }
+
fn finish(mut self) -> String {
if !self.code_block_buffer.is_empty() {
// There is a code block that is not properly enclosed by backticks.
@@ -585,7 +613,12 @@ impl<'a> CommentRewrite<'a> {
// the last few lines are part of an itemized block
self.fmt.shape = Shape::legacy(self.max_width, self.fmt_indent);
let item_fmt = ib.create_string_format(&self.fmt);
- self.result.push_str(&self.comment_line_separator);
+
+ // only push a comment_line_separator for ItemizedBlocks if the comment is not empty
+ if self.buffer_contains_comment() {
+ self.result.push_str(&self.comment_line_separator);
+ }
+
self.result.push_str(&ib.opener);
match rewrite_string(
&ib.trimmed_block_as_string(),
@@ -619,7 +652,13 @@ impl<'a> CommentRewrite<'a> {
line: &'a str,
has_leading_whitespace: bool,
) -> bool {
- let is_last = i == count_newlines(orig);
+ let num_newlines = count_newlines(orig);
+ let is_last = i == num_newlines;
+ let needs_new_comment_line = if self.style.is_block_comment() {
+ num_newlines > 0 || self.buffer_contains_comment()
+ } else {
+ self.buffer_contains_comment()
+ };
if let Some(ref mut ib) = self.item_block {
if ib.add_line(line) {
@@ -628,7 +667,12 @@ impl<'a> CommentRewrite<'a> {
self.is_prev_line_multi_line = false;
self.fmt.shape = Shape::legacy(self.max_width, self.fmt_indent);
let item_fmt = ib.create_string_format(&self.fmt);
- self.result.push_str(&self.comment_line_separator);
+
+ // only push a comment_line_separator if we need to start a new comment line
+ if needs_new_comment_line {
+ self.result.push_str(&self.comment_line_separator);
+ }
+
self.result.push_str(&ib.opener);
match rewrite_string(
&ib.trimmed_block_as_string(),
@@ -842,7 +886,11 @@ fn trim_custom_comment_prefix(s: &str) -> String {
/// Returns `true` if the given string MAY include URLs or alike.
fn has_url(s: &str) -> bool {
// This function may return false positive, but should get its job done in most cases.
- s.contains("https://") || s.contains("http://") || s.contains("ftp://") || s.contains("file://")
+ s.contains("https://")
+ || s.contains("http://")
+ || s.contains("ftp://")
+ || s.contains("file://")
+ || REFERENCE_LINK_URL.is_match(s)
}
/// Given the span, rewrite the missing comment inside it if available.
diff --git a/src/tools/rustfmt/src/config/mod.rs b/src/tools/rustfmt/src/config/mod.rs
index c5419d860c9..5dbe532ac38 100644
--- a/src/tools/rustfmt/src/config/mod.rs
+++ b/src/tools/rustfmt/src/config/mod.rs
@@ -405,6 +405,8 @@ mod test {
use super::*;
use std::str;
+ use rustfmt_config_proc_macro::{nightly_only_test, stable_only_test};
+
#[allow(dead_code)]
mod mock {
use super::super::*;
@@ -525,21 +527,17 @@ mod test {
assert!(config.license_template.is_none());
}
+ #[nightly_only_test]
#[test]
fn test_valid_license_template_path() {
- if !crate::is_nightly_channel!() {
- return;
- }
let toml = r#"license_template_path = "tests/license-template/lt.txt""#;
let config = Config::from_toml(toml, Path::new("")).unwrap();
assert!(config.license_template.is_some());
}
+ #[nightly_only_test]
#[test]
fn test_override_existing_license_with_no_license() {
- if !crate::is_nightly_channel!() {
- return;
- }
let toml = r#"license_template_path = "tests/license-template/lt.txt""#;
let mut config = Config::from_toml(toml, Path::new("")).unwrap();
assert!(config.license_template.is_some());
@@ -634,48 +632,42 @@ make_backup = false
assert_eq!(&toml, &default_config);
}
- // FIXME(#2183): these tests cannot be run in parallel because they use env vars.
- // #[test]
- // fn test_as_not_nightly_channel() {
- // let mut config = Config::default();
- // assert_eq!(config.was_set().unstable_features(), false);
- // config.set().unstable_features(true);
- // assert_eq!(config.was_set().unstable_features(), false);
- // }
-
- // #[test]
- // fn test_as_nightly_channel() {
- // let v = ::std::env::var("CFG_RELEASE_CHANNEL").unwrap_or(String::from(""));
- // ::std::env::set_var("CFG_RELEASE_CHANNEL", "nightly");
- // let mut config = Config::default();
- // config.set().unstable_features(true);
- // assert_eq!(config.was_set().unstable_features(), false);
- // config.set().unstable_features(true);
- // assert_eq!(config.unstable_features(), true);
- // ::std::env::set_var("CFG_RELEASE_CHANNEL", v);
- // }
-
- // #[test]
- // fn test_unstable_from_toml() {
- // let mut config = Config::from_toml("unstable_features = true").unwrap();
- // assert_eq!(config.was_set().unstable_features(), false);
- // let v = ::std::env::var("CFG_RELEASE_CHANNEL").unwrap_or(String::from(""));
- // ::std::env::set_var("CFG_RELEASE_CHANNEL", "nightly");
- // config = Config::from_toml("unstable_features = true").unwrap();
- // assert_eq!(config.was_set().unstable_features(), true);
- // assert_eq!(config.unstable_features(), true);
- // ::std::env::set_var("CFG_RELEASE_CHANNEL", v);
- // }
+ #[stable_only_test]
+ #[test]
+ fn test_as_not_nightly_channel() {
+ let mut config = Config::default();
+ assert_eq!(config.was_set().unstable_features(), false);
+ config.set().unstable_features(true);
+ assert_eq!(config.was_set().unstable_features(), false);
+ }
+
+ #[nightly_only_test]
+ #[test]
+ fn test_as_nightly_channel() {
+ let mut config = Config::default();
+ config.set().unstable_features(true);
+ // When we don't set the config from toml or command line options it
+ // doesn't get marked as set by the user.
+ assert_eq!(config.was_set().unstable_features(), false);
+ config.set().unstable_features(true);
+ assert_eq!(config.unstable_features(), true);
+ }
+
+ #[nightly_only_test]
+ #[test]
+ fn test_unstable_from_toml() {
+ let config = Config::from_toml("unstable_features = true", Path::new("")).unwrap();
+ assert_eq!(config.was_set().unstable_features(), true);
+ assert_eq!(config.unstable_features(), true);
+ }
#[cfg(test)]
mod deprecated_option_merge_imports {
use super::*;
+ #[nightly_only_test]
#[test]
fn test_old_option_set() {
- if !crate::is_nightly_channel!() {
- return;
- }
let toml = r#"
unstable_features = true
merge_imports = true
@@ -684,11 +676,9 @@ make_backup = false
assert_eq!(config.imports_granularity(), ImportGranularity::Crate);
}
+ #[nightly_only_test]
#[test]
fn test_both_set() {
- if !crate::is_nightly_channel!() {
- return;
- }
let toml = r#"
unstable_features = true
merge_imports = true
@@ -698,11 +688,9 @@ make_backup = false
assert_eq!(config.imports_granularity(), ImportGranularity::Preserve);
}
+ #[nightly_only_test]
#[test]
fn test_new_overridden() {
- if !crate::is_nightly_channel!() {
- return;
- }
let toml = r#"
unstable_features = true
merge_imports = true
@@ -712,11 +700,9 @@ make_backup = false
assert_eq!(config.imports_granularity(), ImportGranularity::Preserve);
}
+ #[nightly_only_test]
#[test]
fn test_old_overridden() {
- if !crate::is_nightly_channel!() {
- return;
- }
let toml = r#"
unstable_features = true
imports_granularity = "Module"
diff --git a/src/tools/rustfmt/src/expr.rs b/src/tools/rustfmt/src/expr.rs
index 58942e442de..5fd86c1a4ea 100644
--- a/src/tools/rustfmt/src/expr.rs
+++ b/src/tools/rustfmt/src/expr.rs
@@ -196,9 +196,10 @@ pub(crate) fn format_expr(
capture, is_async, movability, fn_decl, body, expr.span, context, shape,
)
}
- ast::ExprKind::Try(..) | ast::ExprKind::Field(..) | ast::ExprKind::MethodCall(..) => {
- rewrite_chain(expr, context, shape)
- }
+ ast::ExprKind::Try(..)
+ | ast::ExprKind::Field(..)
+ | ast::ExprKind::MethodCall(..)
+ | ast::ExprKind::Await(_) => rewrite_chain(expr, context, shape),
ast::ExprKind::MacCall(ref mac) => {
rewrite_macro(mac, None, context, shape, MacroPosition::Expression).or_else(|| {
wrap_str(
@@ -377,7 +378,6 @@ pub(crate) fn format_expr(
))
}
}
- ast::ExprKind::Await(_) => rewrite_chain(expr, context, shape),
ast::ExprKind::Underscore => Some("_".to_owned()),
ast::ExprKind::Err => None,
};
@@ -829,6 +829,7 @@ impl<'a> ControlFlow<'a> {
&format!("{}{}{}", matcher, pat_string, self.connector),
expr,
cond_shape,
+ &RhsAssignKind::Expr(&expr.kind, expr.span),
RhsTactics::Default,
comments_span,
true,
@@ -1839,6 +1840,34 @@ fn rewrite_unary_op(
rewrite_unary_prefix(context, ast::UnOp::to_string(op), expr, shape)
}
+pub(crate) enum RhsAssignKind<'ast> {
+ Expr(&'ast ast::ExprKind, Span),
+ Bounds,
+ Ty,
+}
+
+impl<'ast> RhsAssignKind<'ast> {
+ // TODO(calebcartwright)
+ // Preemptive addition for handling RHS with chains, not yet utilized.
+ // It may make more sense to construct the chain first and then check
+ // whether there are actually chain elements.
+ #[allow(dead_code)]
+ fn is_chain(&self) -> bool {
+ match self {
+ RhsAssignKind::Expr(kind, _) => {
+ matches!(
+ kind,
+ ast::ExprKind::Try(..)
+ | ast::ExprKind::Field(..)
+ | ast::ExprKind::MethodCall(..)
+ | ast::ExprKind::Await(_)
+ )
+ }
+ _ => false,
+ }
+ }
+}
+
fn rewrite_assignment(
context: &RewriteContext<'_>,
lhs: &ast::Expr,
@@ -1855,7 +1884,13 @@ fn rewrite_assignment(
let lhs_shape = shape.sub_width(operator_str.len() + 1)?;
let lhs_str = format!("{} {}", lhs.rewrite(context, lhs_shape)?, operator_str);
- rewrite_assign_rhs(context, lhs_str, rhs, shape)
+ rewrite_assign_rhs(
+ context,
+ lhs_str,
+ rhs,
+ &RhsAssignKind::Expr(&rhs.kind, rhs.span),
+ shape,
+ )
}
/// Controls where to put the rhs.
@@ -1876,9 +1911,10 @@ pub(crate) fn rewrite_assign_rhs<S: Into<String>, R: Rewrite>(
context: &RewriteContext<'_>,
lhs: S,
ex: &R,
+ rhs_kind: &RhsAssignKind<'_>,
shape: Shape,
) -> Option<String> {
- rewrite_assign_rhs_with(context, lhs, ex, shape, RhsTactics::Default)
+ rewrite_assign_rhs_with(context, lhs, ex, shape, rhs_kind, RhsTactics::Default)
}
pub(crate) fn rewrite_assign_rhs_expr<R: Rewrite>(
@@ -1886,6 +1922,7 @@ pub(crate) fn rewrite_assign_rhs_expr<R: Rewrite>(
lhs: &str,
ex: &R,
shape: Shape,
+ rhs_kind: &RhsAssignKind<'_>,
rhs_tactics: RhsTactics,
) -> Option<String> {
let last_line_width = last_line_width(lhs).saturating_sub(if lhs.contains('\n') {
@@ -1910,6 +1947,7 @@ pub(crate) fn rewrite_assign_rhs_expr<R: Rewrite>(
ex,
orig_shape,
ex.rewrite(context, orig_shape),
+ rhs_kind,
rhs_tactics,
has_rhs_comment,
)
@@ -1920,10 +1958,11 @@ pub(crate) fn rewrite_assign_rhs_with<S: Into<String>, R: Rewrite>(
lhs: S,
ex: &R,
shape: Shape,
+ rhs_kind: &RhsAssignKind<'_>,
rhs_tactics: RhsTactics,
) -> Option<String> {
let lhs = lhs.into();
- let rhs = rewrite_assign_rhs_expr(context, &lhs, ex, shape, rhs_tactics)?;
+ let rhs = rewrite_assign_rhs_expr(context, &lhs, ex, shape, rhs_kind, rhs_tactics)?;
Some(lhs + &rhs)
}
@@ -1932,6 +1971,7 @@ pub(crate) fn rewrite_assign_rhs_with_comments<S: Into<String>, R: Rewrite>(
lhs: S,
ex: &R,
shape: Shape,
+ rhs_kind: &RhsAssignKind<'_>,
rhs_tactics: RhsTactics,
between_span: Span,
allow_extend: bool,
@@ -1943,7 +1983,7 @@ pub(crate) fn rewrite_assign_rhs_with_comments<S: Into<String>, R: Rewrite>(
} else {
shape
};
- let rhs = rewrite_assign_rhs_expr(context, &lhs, ex, shape, rhs_tactics)?;
+ let rhs = rewrite_assign_rhs_expr(context, &lhs, ex, shape, rhs_kind, rhs_tactics)?;
if contains_comment {
let rhs = rhs.trim_start();
@@ -1958,6 +1998,7 @@ fn choose_rhs<R: Rewrite>(
expr: &R,
shape: Shape,
orig_rhs: Option<String>,
+ _rhs_kind: &RhsAssignKind<'_>,
rhs_tactics: RhsTactics,
has_rhs_comment: bool,
) -> Option<String> {
diff --git a/src/tools/rustfmt/src/ignore_path.rs b/src/tools/rustfmt/src/ignore_path.rs
index d8974e12b8f..7738eee0a76 100644
--- a/src/tools/rustfmt/src/ignore_path.rs
+++ b/src/tools/rustfmt/src/ignore_path.rs
@@ -37,21 +37,17 @@ mod test {
use crate::config::{Config, FileName};
use crate::ignore_path::IgnorePathSet;
+ use rustfmt_config_proc_macro::nightly_only_test;
+
+ #[nightly_only_test]
#[test]
fn test_ignore_path_set() {
- match option_env!("CFG_RELEASE_CHANNEL") {
- // this test requires nightly
- None | Some("nightly") => {
- let config =
- Config::from_toml(r#"ignore = ["foo.rs", "bar_dir/*"]"#, Path::new(""))
- .unwrap();
- let ignore_path_set = IgnorePathSet::from_ignore_list(&config.ignore()).unwrap();
-
- assert!(ignore_path_set.is_match(&FileName::Real(PathBuf::from("src/foo.rs"))));
- assert!(ignore_path_set.is_match(&FileName::Real(PathBuf::from("bar_dir/baz.rs"))));
- assert!(!ignore_path_set.is_match(&FileName::Real(PathBuf::from("src/bar.rs"))));
- }
- _ => (),
- };
+ let config =
+ Config::from_toml(r#"ignore = ["foo.rs", "bar_dir/*"]"#, Path::new("")).unwrap();
+ let ignore_path_set = IgnorePathSet::from_ignore_list(&config.ignore()).unwrap();
+
+ assert!(ignore_path_set.is_match(&FileName::Real(PathBuf::from("src/foo.rs"))));
+ assert!(ignore_path_set.is_match(&FileName::Real(PathBuf::from("bar_dir/baz.rs"))));
+ assert!(!ignore_path_set.is_match(&FileName::Real(PathBuf::from("src/bar.rs"))));
}
}
diff --git a/src/tools/rustfmt/src/items.rs b/src/tools/rustfmt/src/items.rs
index 50121a8b6b5..f36bdba26e9 100644
--- a/src/tools/rustfmt/src/items.rs
+++ b/src/tools/rustfmt/src/items.rs
@@ -18,7 +18,7 @@ use crate::config::lists::*;
use crate::config::{BraceStyle, Config, IndentStyle, Version};
use crate::expr::{
is_empty_block, is_simple_block_stmt, rewrite_assign_rhs, rewrite_assign_rhs_with,
- rewrite_assign_rhs_with_comments, RhsTactics,
+ rewrite_assign_rhs_with_comments, RhsAssignKind, RhsTactics,
};
use crate::lists::{definitive_tactic, itemize_list, write_list, ListFormatting, Separator};
use crate::macros::{rewrite_macro, MacroPosition};
@@ -28,6 +28,7 @@ use crate::shape::{Indent, Shape};
use crate::source_map::{LineRangeUtils, SpanUtils};
use crate::spanned::Spanned;
use crate::stmt::Stmt;
+use crate::types::opaque_ty;
use crate::utils::*;
use crate::vertical::rewrite_with_alignment;
use crate::visitor::FmtVisitor;
@@ -115,7 +116,13 @@ impl Rewrite for ast::Local {
// 1 = trailing semicolon;
let nested_shape = shape.sub_width(1)?;
- result = rewrite_assign_rhs(context, result, init, nested_shape)?;
+ result = rewrite_assign_rhs(
+ context,
+ result,
+ init,
+ &RhsAssignKind::Expr(&init.kind, init.span),
+ nested_shape,
+ )?;
// todo else
}
@@ -563,11 +570,13 @@ impl<'a> FmtVisitor<'a> {
let variant_body = if let Some(ref expr) = field.disr_expr {
let lhs = format!("{:1$} =", variant_body, pad_discrim_ident_to);
+ let ex = &*expr.value;
rewrite_assign_rhs_with(
&context,
lhs,
- &*expr.value,
+ ex,
shape,
+ &RhsAssignKind::Expr(&ex.kind, ex.span),
RhsTactics::AllowOverflow,
)?
} else {
@@ -579,6 +588,22 @@ impl<'a> FmtVisitor<'a> {
fn visit_impl_items(&mut self, items: &[ptr::P<ast::AssocItem>]) {
if self.get_context().config.reorder_impl_items() {
+ type TyOpt = Option<ptr::P<ast::Ty>>;
+ use crate::ast::AssocItemKind::*;
+ let is_type = |ty: &TyOpt| opaque_ty(ty).is_none();
+ let is_opaque = |ty: &TyOpt| opaque_ty(ty).is_some();
+ let both_type = |l: &TyOpt, r: &TyOpt| is_type(l) && is_type(r);
+ let both_opaque = |l: &TyOpt, r: &TyOpt| is_opaque(l) && is_opaque(r);
+ let need_empty_line = |a: &ast::AssocItemKind, b: &ast::AssocItemKind| match (a, b) {
+ (TyAlias(lty), TyAlias(rty))
+ if both_type(&lty.ty, &rty.ty) || both_opaque(&lty.ty, &rty.ty) =>
+ {
+ false
+ }
+ (Const(..), Const(..)) => false,
+ _ => true,
+ };
+
// Create visitor for each items, then reorder them.
let mut buffer = vec![];
for item in items {
@@ -587,50 +612,6 @@ impl<'a> FmtVisitor<'a> {
self.buffer.clear();
}
- fn is_type(ty: &Option<rustc_ast::ptr::P<ast::Ty>>) -> bool {
- if let Some(lty) = ty {
- if let ast::TyKind::ImplTrait(..) = lty.kind {
- return false;
- }
- }
- true
- }
-
- fn is_opaque(ty: &Option<rustc_ast::ptr::P<ast::Ty>>) -> bool {
- !is_type(ty)
- }
-
- fn both_type(
- a: &Option<rustc_ast::ptr::P<ast::Ty>>,
- b: &Option<rustc_ast::ptr::P<ast::Ty>>,
- ) -> bool {
- is_type(a) && is_type(b)
- }
-
- fn both_opaque(
- a: &Option<rustc_ast::ptr::P<ast::Ty>>,
- b: &Option<rustc_ast::ptr::P<ast::Ty>>,
- ) -> bool {
- is_opaque(a) && is_opaque(b)
- }
-
- // In rustc-ap-v638 the `OpaqueTy` AssocItemKind variant was removed but
- // we still need to differentiate to maintain sorting order.
-
- // type -> opaque -> const -> macro -> method
- use crate::ast::AssocItemKind::*;
- fn need_empty_line(a: &ast::AssocItemKind, b: &ast::AssocItemKind) -> bool {
- match (a, b) {
- (TyAlias(lty), TyAlias(rty))
- if both_type(&lty.ty, &rty.ty) || both_opaque(&lty.ty, &rty.ty) =>
- {
- false
- }
- (Const(..), Const(..)) => false,
- _ => true,
- }
- }
-
buffer.sort_by(|(_, a), (_, b)| match (&a.kind, &b.kind) {
(TyAlias(lty), TyAlias(rty))
if both_type(&lty.ty, &rty.ty) || both_opaque(&lty.ty, &rty.ty) =>
@@ -676,136 +657,133 @@ impl<'a> FmtVisitor<'a> {
pub(crate) fn format_impl(
context: &RewriteContext<'_>,
item: &ast::Item,
+ iimpl: &ast::Impl,
offset: Indent,
) -> Option<String> {
- if let ast::ItemKind::Impl(impl_kind) = &item.kind {
- let ast::Impl {
- ref generics,
- ref self_ty,
- ref items,
- ..
- } = **impl_kind;
- let mut result = String::with_capacity(128);
- let ref_and_type = format_impl_ref_and_type(context, item, offset)?;
- let sep = offset.to_string_with_newline(context.config);
- result.push_str(&ref_and_type);
+ let ast::Impl {
+ generics,
+ self_ty,
+ items,
+ ..
+ } = iimpl;
+ let mut result = String::with_capacity(128);
+ let ref_and_type = format_impl_ref_and_type(context, item, iimpl, offset)?;
+ let sep = offset.to_string_with_newline(context.config);
+ result.push_str(&ref_and_type);
- let where_budget = if result.contains('\n') {
- context.config.max_width()
- } else {
- context.budget(last_line_width(&result))
- };
+ let where_budget = if result.contains('\n') {
+ context.config.max_width()
+ } else {
+ context.budget(last_line_width(&result))
+ };
- let mut option = WhereClauseOption::snuggled(&ref_and_type);
- let snippet = context.snippet(item.span);
- let open_pos = snippet.find_uncommented("{")? + 1;
- if !contains_comment(&snippet[open_pos..])
- && items.is_empty()
- && generics.where_clause.predicates.len() == 1
- && !result.contains('\n')
- {
- option.suppress_comma();
- option.snuggle();
- option.allow_single_line();
- }
+ let mut option = WhereClauseOption::snuggled(&ref_and_type);
+ let snippet = context.snippet(item.span);
+ let open_pos = snippet.find_uncommented("{")? + 1;
+ if !contains_comment(&snippet[open_pos..])
+ && items.is_empty()
+ && generics.where_clause.predicates.len() == 1
+ && !result.contains('\n')
+ {
+ option.suppress_comma();
+ option.snuggle();
+ option.allow_single_line();
+ }
- let missing_span = mk_sp(self_ty.span.hi(), item.span.hi());
- let where_span_end = context.snippet_provider.opt_span_before(missing_span, "{");
- let where_clause_str = rewrite_where_clause(
- context,
- &generics.where_clause,
- context.config.brace_style(),
- Shape::legacy(where_budget, offset.block_only()),
- false,
- "{",
- where_span_end,
- self_ty.span.hi(),
- option,
- )?;
+ let missing_span = mk_sp(self_ty.span.hi(), item.span.hi());
+ let where_span_end = context.snippet_provider.opt_span_before(missing_span, "{");
+ let where_clause_str = rewrite_where_clause(
+ context,
+ &generics.where_clause,
+ context.config.brace_style(),
+ Shape::legacy(where_budget, offset.block_only()),
+ false,
+ "{",
+ where_span_end,
+ self_ty.span.hi(),
+ option,
+ )?;
- // If there is no where-clause, we may have missing comments between the trait name and
- // the opening brace.
- if generics.where_clause.predicates.is_empty() {
- if let Some(hi) = where_span_end {
- match recover_missing_comment_in_span(
- mk_sp(self_ty.span.hi(), hi),
- Shape::indented(offset, context.config),
- context,
- last_line_width(&result),
- ) {
- Some(ref missing_comment) if !missing_comment.is_empty() => {
- result.push_str(missing_comment);
- }
- _ => (),
+ // If there is no where-clause, we may have missing comments between the trait name and
+ // the opening brace.
+ if generics.where_clause.predicates.is_empty() {
+ if let Some(hi) = where_span_end {
+ match recover_missing_comment_in_span(
+ mk_sp(self_ty.span.hi(), hi),
+ Shape::indented(offset, context.config),
+ context,
+ last_line_width(&result),
+ ) {
+ Some(ref missing_comment) if !missing_comment.is_empty() => {
+ result.push_str(missing_comment);
}
+ _ => (),
}
}
+ }
- if is_impl_single_line(context, items.as_slice(), &result, &where_clause_str, item)? {
- result.push_str(&where_clause_str);
- if where_clause_str.contains('\n') || last_line_contains_single_line_comment(&result) {
- // if the where_clause contains extra comments AND
- // there is only one where-clause predicate
- // recover the suppressed comma in single line where_clause formatting
- if generics.where_clause.predicates.len() == 1 {
- result.push(',');
- }
- result.push_str(&format!("{}{{{}}}", sep, sep));
- } else {
- result.push_str(" {}");
+ if is_impl_single_line(context, items.as_slice(), &result, &where_clause_str, item)? {
+ result.push_str(&where_clause_str);
+ if where_clause_str.contains('\n') || last_line_contains_single_line_comment(&result) {
+ // if the where_clause contains extra comments AND
+ // there is only one where-clause predicate
+ // recover the suppressed comma in single line where_clause formatting
+ if generics.where_clause.predicates.len() == 1 {
+ result.push(',');
}
- return Some(result);
+ result.push_str(&format!("{}{{{}}}", sep, sep));
+ } else {
+ result.push_str(" {}");
}
+ return Some(result);
+ }
- result.push_str(&where_clause_str);
+ result.push_str(&where_clause_str);
- let need_newline = last_line_contains_single_line_comment(&result) || result.contains('\n');
- match context.config.brace_style() {
- _ if need_newline => result.push_str(&sep),
- BraceStyle::AlwaysNextLine => result.push_str(&sep),
- BraceStyle::PreferSameLine => result.push(' '),
- BraceStyle::SameLineWhere => {
- if !where_clause_str.is_empty() {
- result.push_str(&sep);
- } else {
- result.push(' ');
- }
+ let need_newline = last_line_contains_single_line_comment(&result) || result.contains('\n');
+ match context.config.brace_style() {
+ _ if need_newline => result.push_str(&sep),
+ BraceStyle::AlwaysNextLine => result.push_str(&sep),
+ BraceStyle::PreferSameLine => result.push(' '),
+ BraceStyle::SameLineWhere => {
+ if !where_clause_str.is_empty() {
+ result.push_str(&sep);
+ } else {
+ result.push(' ');
}
}
+ }
- result.push('{');
- // this is an impl body snippet(impl SampleImpl { /* here */ })
- let lo = max(self_ty.span.hi(), generics.where_clause.span.hi());
- let snippet = context.snippet(mk_sp(lo, item.span.hi()));
- let open_pos = snippet.find_uncommented("{")? + 1;
+ result.push('{');
+ // this is an impl body snippet(impl SampleImpl { /* here */ })
+ let lo = max(self_ty.span.hi(), generics.where_clause.span.hi());
+ let snippet = context.snippet(mk_sp(lo, item.span.hi()));
+ let open_pos = snippet.find_uncommented("{")? + 1;
- if !items.is_empty() || contains_comment(&snippet[open_pos..]) {
- let mut visitor = FmtVisitor::from_context(context);
- let item_indent = offset.block_only().block_indent(context.config);
- visitor.block_indent = item_indent;
- visitor.last_pos = lo + BytePos(open_pos as u32);
+ if !items.is_empty() || contains_comment(&snippet[open_pos..]) {
+ let mut visitor = FmtVisitor::from_context(context);
+ let item_indent = offset.block_only().block_indent(context.config);
+ visitor.block_indent = item_indent;
+ visitor.last_pos = lo + BytePos(open_pos as u32);
- visitor.visit_attrs(&item.attrs, ast::AttrStyle::Inner);
- visitor.visit_impl_items(items);
+ visitor.visit_attrs(&item.attrs, ast::AttrStyle::Inner);
+ visitor.visit_impl_items(items);
- visitor.format_missing(item.span.hi() - BytePos(1));
+ visitor.format_missing(item.span.hi() - BytePos(1));
- let inner_indent_str = visitor.block_indent.to_string_with_newline(context.config);
- let outer_indent_str = offset.block_only().to_string_with_newline(context.config);
+ let inner_indent_str = visitor.block_indent.to_string_with_newline(context.config);
+ let outer_indent_str = offset.block_only().to_string_with_newline(context.config);
- result.push_str(&inner_indent_str);
- result.push_str(visitor.buffer.trim());
- result.push_str(&outer_indent_str);
- } else if need_newline || !context.config.empty_item_single_line() {
- result.push_str(&sep);
- }
+ result.push_str(&inner_indent_str);
+ result.push_str(visitor.buffer.trim());
+ result.push_str(&outer_indent_str);
+ } else if need_newline || !context.config.empty_item_single_line() {
+ result.push_str(&sep);
+ }
- result.push('}');
+ result.push('}');
- Some(result)
- } else {
- unreachable!();
- }
+ Some(result)
}
fn is_impl_single_line(
@@ -830,111 +808,106 @@ fn is_impl_single_line(
fn format_impl_ref_and_type(
context: &RewriteContext<'_>,
item: &ast::Item,
+ iimpl: &ast::Impl,
offset: Indent,
) -> Option<String> {
- if let ast::ItemKind::Impl(impl_kind) = &item.kind {
- let ast::Impl {
- unsafety,
- polarity,
- defaultness,
- constness,
- ref generics,
- of_trait: ref trait_ref,
- ref self_ty,
- ..
- } = **impl_kind;
- let mut result = String::with_capacity(128);
+ let ast::Impl {
+ unsafety,
+ polarity,
+ defaultness,
+ constness,
+ ref generics,
+ of_trait: ref trait_ref,
+ ref self_ty,
+ ..
+ } = *iimpl;
+ let mut result = String::with_capacity(128);
- result.push_str(&format_visibility(context, &item.vis));
- result.push_str(format_defaultness(defaultness));
- result.push_str(format_unsafety(unsafety));
+ result.push_str(&format_visibility(context, &item.vis));
+ result.push_str(format_defaultness(defaultness));
+ result.push_str(format_unsafety(unsafety));
- let shape = if context.config.version() == Version::Two {
- Shape::indented(offset + last_line_width(&result), context.config)
- } else {
- generics_shape_from_config(
- context.config,
- Shape::indented(offset + last_line_width(&result), context.config),
- 0,
- )?
- };
- let generics_str = rewrite_generics(context, "impl", generics, shape)?;
- result.push_str(&generics_str);
- result.push_str(format_constness_right(constness));
+ let shape = if context.config.version() == Version::Two {
+ Shape::indented(offset + last_line_width(&result), context.config)
+ } else {
+ generics_shape_from_config(
+ context.config,
+ Shape::indented(offset + last_line_width(&result), context.config),
+ 0,
+ )?
+ };
+ let generics_str = rewrite_generics(context, "impl", generics, shape)?;
+ result.push_str(&generics_str);
+ result.push_str(format_constness_right(constness));
- let polarity_str = match polarity {
- ast::ImplPolarity::Negative(_) => "!",
- ast::ImplPolarity::Positive => "",
- };
+ let polarity_str = match polarity {
+ ast::ImplPolarity::Negative(_) => "!",
+ ast::ImplPolarity::Positive => "",
+ };
- let polarity_overhead;
- let trait_ref_overhead;
- if let Some(ref trait_ref) = *trait_ref {
- let result_len = last_line_width(&result);
- result.push_str(&rewrite_trait_ref(
- context,
- trait_ref,
- offset,
- polarity_str,
- result_len,
- )?);
- polarity_overhead = 0; // already written
- trait_ref_overhead = " for".len();
- } else {
- polarity_overhead = polarity_str.len();
- trait_ref_overhead = 0;
- }
+ let polarity_overhead;
+ let trait_ref_overhead;
+ if let Some(ref trait_ref) = *trait_ref {
+ let result_len = last_line_width(&result);
+ result.push_str(&rewrite_trait_ref(
+ context,
+ trait_ref,
+ offset,
+ polarity_str,
+ result_len,
+ )?);
+ polarity_overhead = 0; // already written
+ trait_ref_overhead = " for".len();
+ } else {
+ polarity_overhead = polarity_str.len();
+ trait_ref_overhead = 0;
+ }
- // Try to put the self type in a single line.
- let curly_brace_overhead = if generics.where_clause.predicates.is_empty() {
- // If there is no where-clause adapt budget for type formatting to take space and curly
- // brace into account.
- match context.config.brace_style() {
- BraceStyle::AlwaysNextLine => 0,
- _ => 2,
- }
- } else {
- 0
- };
- let used_space = last_line_width(&result)
- + polarity_overhead
- + trait_ref_overhead
- + curly_brace_overhead;
- // 1 = space before the type.
- let budget = context.budget(used_space + 1);
- if let Some(self_ty_str) = self_ty.rewrite(context, Shape::legacy(budget, offset)) {
- if !self_ty_str.contains('\n') {
- if trait_ref.is_some() {
- result.push_str(" for ");
- } else {
- result.push(' ');
- result.push_str(polarity_str);
- }
- result.push_str(&self_ty_str);
- return Some(result);
+ // Try to put the self type in a single line.
+ let curly_brace_overhead = if generics.where_clause.predicates.is_empty() {
+ // If there is no where-clause adapt budget for type formatting to take space and curly
+ // brace into account.
+ match context.config.brace_style() {
+ BraceStyle::AlwaysNextLine => 0,
+ _ => 2,
+ }
+ } else {
+ 0
+ };
+ let used_space =
+ last_line_width(&result) + polarity_overhead + trait_ref_overhead + curly_brace_overhead;
+ // 1 = space before the type.
+ let budget = context.budget(used_space + 1);
+ if let Some(self_ty_str) = self_ty.rewrite(context, Shape::legacy(budget, offset)) {
+ if !self_ty_str.contains('\n') {
+ if trait_ref.is_some() {
+ result.push_str(" for ");
+ } else {
+ result.push(' ');
+ result.push_str(polarity_str);
}
+ result.push_str(&self_ty_str);
+ return Some(result);
}
+ }
- // Couldn't fit the self type on a single line, put it on a new line.
- result.push('\n');
- // Add indentation of one additional tab.
- let new_line_offset = offset.block_indent(context.config);
- result.push_str(&new_line_offset.to_string(context.config));
- if trait_ref.is_some() {
- result.push_str("for ");
- } else {
- result.push_str(polarity_str);
- }
- let budget = context.budget(last_line_width(&result) + polarity_overhead);
- let type_offset = match context.config.indent_style() {
- IndentStyle::Visual => new_line_offset + trait_ref_overhead,
- IndentStyle::Block => new_line_offset,
- };
- result.push_str(&*self_ty.rewrite(context, Shape::legacy(budget, type_offset))?);
- Some(result)
+ // Couldn't fit the self type on a single line, put it on a new line.
+ result.push('\n');
+ // Add indentation of one additional tab.
+ let new_line_offset = offset.block_indent(context.config);
+ result.push_str(&new_line_offset.to_string(context.config));
+ if trait_ref.is_some() {
+ result.push_str("for ");
} else {
- unreachable!();
+ result.push_str(polarity_str);
}
+ let budget = context.budget(last_line_width(&result) + polarity_overhead);
+ let type_offset = match context.config.indent_style() {
+ IndentStyle::Visual => new_line_offset + trait_ref_overhead,
+ IndentStyle::Block => new_line_offset,
+ };
+ result.push_str(&*self_ty.rewrite(context, Shape::legacy(budget, type_offset))?);
+ Some(result)
}
fn rewrite_trait_ref(
@@ -1068,6 +1041,7 @@ pub(crate) fn format_trait(
result + ":",
bounds,
shape,
+ &RhsAssignKind::Bounds,
RhsTactics::ForceNextLineWithoutIndent,
)?;
}
@@ -1248,7 +1222,14 @@ pub(crate) fn format_trait_alias(
generic_bounds,
generics,
};
- rewrite_assign_rhs(context, lhs, &trait_alias_bounds, shape.sub_width(1)?).map(|s| s + ";")
+ rewrite_assign_rhs(
+ context,
+ lhs,
+ &trait_alias_bounds,
+ &RhsAssignKind::Bounds,
+ shape.sub_width(1)?,
+ )
+ .map(|s| s + ";")
}
fn format_unit_struct(
@@ -1541,43 +1522,38 @@ pub(crate) fn rewrite_type_alias<'a, 'b>(
ref bounds,
ref ty,
} = *ty_alias_kind;
- let ty_opt = ty.as_ref().map(|t| &**t);
+ let ty_opt = ty.as_ref();
let (ident, vis) = match visitor_kind {
Item(i) => (i.ident, &i.vis),
AssocTraitItem(i) | AssocImplItem(i) => (i.ident, &i.vis),
ForeignItem(i) => (i.ident, &i.vis),
};
let rw_info = &TyAliasRewriteInfo(context, indent, generics, ident, span);
-
+ let op_ty = opaque_ty(ty);
// Type Aliases are formatted slightly differently depending on the context
// in which they appear, whether they are opaque, and whether they are associated.
// https://rustc-dev-guide.rust-lang.org/opaque-types-type-alias-impl-trait.html
// https://github.com/rust-dev-tools/fmt-rfcs/blob/master/guide/items.md#type-aliases
- match (visitor_kind, ty_opt) {
- (Item(_), None) => {
- let op_ty = OpaqueType { bounds };
- rewrite_ty(rw_info, Some(bounds), Some(&op_ty), vis)
+ match (visitor_kind, &op_ty) {
+ (Item(_) | AssocTraitItem(_) | ForeignItem(_), Some(ref op_bounds)) => {
+ let op = OpaqueType { bounds: op_bounds };
+ rewrite_ty(rw_info, Some(bounds), Some(&op), vis)
+ }
+ (Item(_) | AssocTraitItem(_) | ForeignItem(_), None) => {
+ rewrite_ty(rw_info, Some(bounds), ty_opt, vis)
}
- (Item(_), Some(ty)) => rewrite_ty(rw_info, Some(bounds), Some(&*ty), vis),
(AssocImplItem(_), _) => {
- let result = if let Some(ast::Ty {
- kind: ast::TyKind::ImplTrait(_, ref bounds),
- ..
- }) = ty_opt
- {
- let op_ty = OpaqueType { bounds };
- rewrite_ty(rw_info, None, Some(&op_ty), &DEFAULT_VISIBILITY)
+ let result = if let Some(ref op_bounds) = op_ty {
+ let op = OpaqueType { bounds: op_bounds };
+ rewrite_ty(rw_info, Some(bounds), Some(&op), &DEFAULT_VISIBILITY)
} else {
- rewrite_ty(rw_info, None, ty.as_ref(), vis)
+ rewrite_ty(rw_info, Some(bounds), ty_opt, vis)
}?;
match defaultness {
ast::Defaultness::Default(..) => Some(format!("default {}", result)),
_ => Some(result),
}
}
- (AssocTraitItem(_), _) | (ForeignItem(_), _) => {
- rewrite_ty(rw_info, Some(bounds), ty.as_ref(), vis)
- }
}
}
@@ -1670,7 +1646,7 @@ fn rewrite_ty<R: Rewrite>(
// 1 = `;`
let shape = Shape::indented(indent, context.config).sub_width(1)?;
- rewrite_assign_rhs(context, lhs, &*ty, shape).map(|s| s + ";")
+ rewrite_assign_rhs(context, lhs, &*ty, &RhsAssignKind::Ty, shape).map(|s| s + ";")
} else {
Some(format!("{};", result))
}
@@ -1760,7 +1736,7 @@ pub(crate) fn rewrite_struct_field(
let is_prefix_empty = prefix.is_empty();
// We must use multiline. We are going to put attributes and a field on different lines.
- let field_str = rewrite_assign_rhs(context, prefix, &*field.ty, shape)?;
+ let field_str = rewrite_assign_rhs(context, prefix, &*field.ty, &RhsAssignKind::Ty, shape)?;
// Remove a leading white-space from `rewrite_assign_rhs()` when rewriting a tuple struct.
let field_str = if is_prefix_empty {
field_str.trim_start()
@@ -1890,6 +1866,7 @@ fn rewrite_static(
&lhs,
&**expr,
Shape::legacy(remaining_width, offset.block_only()),
+ &RhsAssignKind::Expr(&expr.kind, expr.span),
RhsTactics::Default,
comments_span,
true,
@@ -1900,6 +1877,12 @@ fn rewrite_static(
Some(format!("{}{};", prefix, ty_str))
}
}
+
+// FIXME(calebcartwright) - This is a hack around a bug in the handling of TyKind::ImplTrait.
+// This should be removed once that bug is resolved, with the type alias formatting using the
+// defined Ty for the RHS directly.
+// https://github.com/rust-lang/rustfmt/issues/4373
+// https://github.com/rust-lang/rustfmt/issues/5027
struct OpaqueType<'a> {
bounds: &'a ast::GenericBounds,
}
@@ -2236,18 +2219,10 @@ fn rewrite_fn_base(
result.push_str(&param_indent.to_string_with_newline(context.config));
}
- // Skip `pub(crate)`.
- let lo_after_visibility = get_bytepos_after_visibility(fn_sig.visibility, span);
- // A conservative estimation, the goal is to be over all parens in generics
- let params_start = fn_sig
- .generics
- .params
- .last()
- .map_or(lo_after_visibility, |param| param.span().hi());
let params_end = if fd.inputs.is_empty() {
context
.snippet_provider
- .span_after(mk_sp(params_start, span.hi()), ")")
+ .span_after(mk_sp(fn_sig.generics.span.hi(), span.hi()), ")")
} else {
let last_span = mk_sp(fd.inputs[fd.inputs.len() - 1].span().hi(), span.hi());
context.snippet_provider.span_after(last_span, ")")
@@ -2255,7 +2230,7 @@ fn rewrite_fn_base(
let params_span = mk_sp(
context
.snippet_provider
- .span_after(mk_sp(params_start, span.hi()), "("),
+ .span_after(mk_sp(fn_sig.generics.span.hi(), span.hi()), "("),
params_end,
);
let param_str = rewrite_params(
@@ -3181,7 +3156,14 @@ impl Rewrite for ast::ForeignItem {
rewrite_ident(context, self.ident)
);
// 1 = ;
- rewrite_assign_rhs(context, prefix, &**ty, shape.sub_width(1)?).map(|s| s + ";")
+ rewrite_assign_rhs(
+ context,
+ prefix,
+ &**ty,
+ &RhsAssignKind::Ty,
+ shape.sub_width(1)?,
+ )
+ .map(|s| s + ";")
}
ast::ForeignItemKind::TyAlias(ref ty_alias) => {
let (kind, span) = (&ItemVisitorKind::ForeignItem(&self), self.span);
diff --git a/src/tools/rustfmt/src/lists.rs b/src/tools/rustfmt/src/lists.rs
index d341ec8e6b0..3515dd17251 100644
--- a/src/tools/rustfmt/src/lists.rs
+++ b/src/tools/rustfmt/src/lists.rs
@@ -444,10 +444,15 @@ where
let offset = formatting.shape.indent + overhead;
let comment_shape = Shape::legacy(width, offset);
- // Use block-style only for the last item or multiline comments.
- let block_style = !formatting.ends_with_newline && last
- || comment.trim().contains('\n')
- || comment.trim().len() > width;
+ let block_style = if !formatting.ends_with_newline && last {
+ true
+ } else if starts_with_newline(comment) {
+ false
+ } else if comment.trim().contains('\n') || comment.trim().len() > width {
+ true
+ } else {
+ false
+ };
rewrite_comment(
comment.trim_start(),
diff --git a/src/tools/rustfmt/src/macros.rs b/src/tools/rustfmt/src/macros.rs
index ef747638e33..a52568be9ea 100644
--- a/src/tools/rustfmt/src/macros.rs
+++ b/src/tools/rustfmt/src/macros.rs
@@ -27,7 +27,7 @@ use crate::comment::{
contains_comment, CharClasses, FindUncommented, FullCodeCharKind, LineClasses,
};
use crate::config::lists::*;
-use crate::expr::rewrite_array;
+use crate::expr::{rewrite_array, rewrite_assign_rhs, RhsAssignKind};
use crate::lists::{itemize_list, write_list, ListFormatting};
use crate::overflow;
use crate::rewrite::{Rewrite, RewriteContext};
@@ -1468,10 +1468,11 @@ fn format_lazy_static(
id,
ty.rewrite(context, nested_shape)?
));
- result.push_str(&crate::expr::rewrite_assign_rhs(
+ result.push_str(&rewrite_assign_rhs(
context,
stmt,
&*expr,
+ &RhsAssignKind::Expr(&expr.kind, expr.span),
nested_shape.sub_width(1)?,
)?);
result.push(';');
diff --git a/src/tools/rustfmt/src/syntux/session.rs b/src/tools/rustfmt/src/syntux/session.rs
index cdb4893d443..dd7c7352686 100644
--- a/src/tools/rustfmt/src/syntux/session.rs
+++ b/src/tools/rustfmt/src/syntux/session.rs
@@ -286,10 +286,11 @@ impl LineRangeUtils for ParseSess {
mod tests {
use super::*;
+ use rustfmt_config_proc_macro::nightly_only_test;
+
mod emitter {
use super::*;
use crate::config::IgnoreList;
- use crate::is_nightly_channel;
use crate::utils::mk_sp;
use rustc_span::{FileName as SourceMapFileName, MultiSpan, RealFileName, DUMMY_SP};
use std::path::PathBuf;
@@ -371,11 +372,9 @@ mod tests {
assert_eq!(can_reset_errors.load(Ordering::Acquire), false);
}
+ #[nightly_only_test]
#[test]
fn handles_recoverable_parse_error_in_ignored_file() {
- if !is_nightly_channel!() {
- return;
- }
let num_emitted_errors = Lrc::new(AtomicU32::new(0));
let can_reset_errors = Lrc::new(AtomicBool::new(false));
let ignore_list = get_ignore_list(r#"ignore = ["foo.rs"]"#);
@@ -398,11 +397,9 @@ mod tests {
assert_eq!(can_reset_errors.load(Ordering::Acquire), true);
}
+ #[nightly_only_test]
#[test]
fn handles_recoverable_parse_error_in_non_ignored_file() {
- if !is_nightly_channel!() {
- return;
- }
let num_emitted_errors = Lrc::new(AtomicU32::new(0));
let can_reset_errors = Lrc::new(AtomicBool::new(false));
let source_map = Lrc::new(SourceMap::new(FilePathMapping::empty()));
@@ -424,11 +421,9 @@ mod tests {
assert_eq!(can_reset_errors.load(Ordering::Acquire), false);
}
+ #[nightly_only_test]
#[test]
fn handles_mix_of_recoverable_parse_error() {
- if !is_nightly_channel!() {
- return;
- }
let num_emitted_errors = Lrc::new(AtomicU32::new(0));
let can_reset_errors = Lrc::new(AtomicBool::new(false));
let source_map = Lrc::new(SourceMap::new(FilePathMapping::empty()));
diff --git a/src/tools/rustfmt/src/test/mod.rs b/src/tools/rustfmt/src/test/mod.rs
index e2620508c34..cceb28dfea6 100644
--- a/src/tools/rustfmt/src/test/mod.rs
+++ b/src/tools/rustfmt/src/test/mod.rs
@@ -15,6 +15,8 @@ use crate::rustfmt_diff::{make_diff, print_diff, DiffLine, Mismatch, ModifiedChu
use crate::source_file;
use crate::{is_nightly_channel, FormatReport, FormatReportFormatterBuilder, Input, Session};
+use rustfmt_config_proc_macro::nightly_only_test;
+
mod configuration_snippet;
mod mod_resolver;
mod parser;
@@ -307,14 +309,11 @@ fn assert_output(source: &Path, expected_filename: &Path) {
// Idempotence tests. Files in tests/target are checked to be unaltered by
// rustfmt.
+#[nightly_only_test]
#[test]
fn idempotence_tests() {
init_log();
run_test_with(&TestSetting::default(), || {
- // these tests require nightly
- if !is_nightly_channel!() {
- return;
- }
// Get all files in the tests/target directory.
let files = get_test_files(Path::new("tests/target"), true);
let (_reports, count, fails) = check_files(files, &None);
@@ -332,13 +331,11 @@ fn idempotence_tests() {
// Run rustfmt on itself. This operation must be idempotent. We also check that
// no warnings are emitted.
+// Issue-3443: these tests require nightly
+#[nightly_only_test]
#[test]
fn self_tests() {
init_log();
- // Issue-3443: these tests require nightly
- if !is_nightly_channel!() {
- return;
- }
let mut files = get_test_files(Path::new("tests"), false);
let bin_directories = vec!["cargo-fmt", "git-rustfmt", "bin", "format-diff"];
for dir in bin_directories {
diff --git a/src/tools/rustfmt/src/types.rs b/src/tools/rustfmt/src/types.rs
index 9ea90c5e46d..88f5dc43245 100644
--- a/src/tools/rustfmt/src/types.rs
+++ b/src/tools/rustfmt/src/types.rs
@@ -2,6 +2,7 @@ use std::iter::ExactSizeIterator;
use std::ops::Deref;
use rustc_ast::ast::{self, FnRetTy, Mutability};
+use rustc_ast::ptr;
use rustc_span::{symbol::kw, BytePos, Pos, Span};
use crate::comment::{combine_strs_with_missing_comments, contains_comment};
@@ -9,6 +10,7 @@ use crate::config::lists::*;
use crate::config::{IndentStyle, TypeDensity, Version};
use crate::expr::{
format_expr, rewrite_assign_rhs, rewrite_call, rewrite_tuple, rewrite_unary_prefix, ExprType,
+ RhsAssignKind,
};
use crate::lists::{
definitive_tactic, itemize_list, write_list, ListFormatting, ListItem, Separator,
@@ -429,7 +431,7 @@ impl Rewrite for ast::WherePredicate {
format!("{}{}", type_str, colon)
};
- rewrite_assign_rhs(context, lhs, bounds, shape)?
+ rewrite_assign_rhs(context, lhs, bounds, &RhsAssignKind::Bounds, shape)?
}
ast::WherePredicate::RegionPredicate(ast::WhereRegionPredicate {
ref lifetime,
@@ -442,7 +444,7 @@ impl Rewrite for ast::WherePredicate {
..
}) => {
let lhs_ty_str = lhs_ty.rewrite(context, shape).map(|lhs| lhs + " =")?;
- rewrite_assign_rhs(context, lhs_ty_str, &**rhs_ty, shape)?
+ rewrite_assign_rhs(context, lhs_ty_str, &**rhs_ty, &RhsAssignKind::Ty, shape)?
}
};
@@ -1031,6 +1033,13 @@ fn join_bounds_inner(
}
}
+pub(crate) fn opaque_ty(ty: &Option<ptr::P<ast::Ty>>) -> Option<&ast::GenericBounds> {
+ ty.as_ref().and_then(|t| match &t.kind {
+ ast::TyKind::ImplTrait(_, bounds) => Some(bounds),
+ _ => None,
+ })
+}
+
pub(crate) fn can_be_overflowed_type(
context: &RewriteContext<'_>,
ty: &ast::Ty,
diff --git a/src/tools/rustfmt/src/visitor.rs b/src/tools/rustfmt/src/visitor.rs
index 527042d098a..e4a7be742ab 100644
--- a/src/tools/rustfmt/src/visitor.rs
+++ b/src/tools/rustfmt/src/visitor.rs
@@ -485,9 +485,9 @@ impl<'b, 'a: 'b> FmtVisitor<'a> {
if should_visit_node_again {
match item.kind {
ast::ItemKind::Use(ref tree) => self.format_import(item, tree),
- ast::ItemKind::Impl { .. } => {
+ ast::ItemKind::Impl(ref iimpl) => {
let block_indent = self.block_indent;
- let rw = self.with_context(|ctx| format_impl(ctx, item, block_indent));
+ let rw = self.with_context(|ctx| format_impl(ctx, item, iimpl, block_indent));
self.push_rewrite(item.span, rw);
}
ast::ItemKind::Trait(..) => {
diff --git a/src/tools/rustfmt/tests/source/comments-in-lists/wrap-comments-not-normalized.rs b/src/tools/rustfmt/tests/source/comments-in-lists/wrap-comments-not-normalized.rs
new file mode 100644
index 00000000000..b96c02802d6
--- /dev/null
+++ b/src/tools/rustfmt/tests/source/comments-in-lists/wrap-comments-not-normalized.rs
@@ -0,0 +1,129 @@
+// rustfmt-wrap_comments: true
+
+// https://github.com/rust-lang/rustfmt/issues/4909
+pub enum E {
+ // Expand as needed, numbers should be ascending according to the stage
+ // through the inclusion pipeline, or according to the descriptions
+ Variant1,
+ // Expand as needed, numbers should be ascending according to the stage
+ // through the inclusion pipeline, or according to the descriptions
+ Variant2,
+ // Expand as needed, numbers should be ascending according to the stage
+ // through the inclusion pipeline, or according to the descriptions
+}
+
+pub enum E2 {
+ // This can be changed once https://github.com/rust-lang/rustfmt/issues/4854 is fixed
+// Expand as needed, numbers should be ascending according to the stage
+// through the inclusion pipeline, or according to the descriptions
+}
+
+pub enum E3 {
+ // Expand as needed, numbers should be ascending according to the stage through the inclusion pipeline, or according to the descriptions
+ Variant1,
+ // Expand as needed, numbers should be ascending according to the stage through the inclusion pipeline, or according to the descriptions
+ Variant2,
+ // Expand as needed, numbers should be ascending according to the stage through the inclusion pipeline, or according to the descriptions
+
+}
+
+pub struct S {
+ // Expand as needed, numbers should be ascending according to the stage
+ // through the inclusion pipeline, or according to the descriptions
+ some_field: usize,
+ // Expand as needed, numbers should be ascending according to the stage
+ // through the inclusion pipeline, or according to the descriptions
+ last_field: usize,
+ // Expand as needed, numbers should be ascending according to the stage
+ // through the inclusion pipeline, or according to the descriptions
+}
+
+pub struct S2 {
+ // This can be changed once https://github.com/rust-lang/rustfmt/issues/4854 is fixed
+// Expand as needed, numbers should be ascending according to the stage
+// through the inclusion pipeline, or according to the descriptions
+}
+
+pub struct S3 {
+ // Expand as needed, numbers should be ascending according to the stage through the inclusion pipeline, or according to the descriptions
+ some_field: usize,
+ // Expand as needed, numbers should be ascending according to the stage through the inclusion pipeline, or according to the descriptions
+ last_field: usize,
+ // Expand as needed, numbers should be ascending according to the stage through the inclusion pipeline, or according to the descriptions
+}
+
+fn foo(
+ // Expand as needed, numbers should be ascending according to the stage
+ // through the inclusion pipeline, or according to the descriptions
+ a: usize,
+ // Expand as needed, numbers should be ascending according to the stage
+ // through the inclusion pipeline, or according to the descriptions
+ b: usize,
+ // Expand as needed, numbers should be ascending according to the stage
+ // through the inclusion pipeline, or according to the descriptions
+) -> usize {
+ 5
+}
+
+fn foo2(// Expand as needed, numbers should be ascending according to the stage
+ // through the inclusion pipeline, or according to the descriptions
+) -> usize {
+ 5
+}
+
+fn foo3(
+ // Expand as needed, numbers should be ascending according to the stage through the inclusion pipeline, or according to the descriptions
+ a: usize,
+ // Expand as needed, numbers should be ascending according to the stage through the inclusion pipeline, or according to the descriptions
+ b: usize,
+ // Expand as needed, numbers should be ascending according to the stage through the inclusion pipeline, or according to the descriptions
+
+) -> usize {
+ 5
+}
+
+fn main() {
+ let v = vec![
+ // Expand as needed, numbers should be ascending according to the stage
+ // through the inclusion pipeline, or according to the descriptions
+ 1,
+ // Expand as needed, numbers should be ascending according to the stage
+ // through the inclusion pipeline, or according to the descriptions
+ 2,
+ // Expand as needed, numbers should be ascending according to the stage
+ // through the inclusion pipeline, or according to the descriptions
+ ];
+
+ let v2: Vec<i32> = vec![
+ // Expand as needed, numbers should be ascending according to the stage
+ // through the inclusion pipeline, or according to the descriptions
+ ];
+
+ let v3 = vec![
+ // Expand as needed, numbers should be ascending according to the stage through the inclusion pipeline, or according to the descriptions
+ 1,
+ // Expand as needed, numbers should be ascending according to the stage through the inclusion pipeline, or according to the descriptions
+ 2,
+ // Expand as needed, numbers should be ascending according to the stage through the inclusion pipeline, or according to the descriptions
+ ];
+
+ // https://github.com/rust-lang/rustfmt/issues/4430
+ match a {
+ // Expand as needed, numbers should be ascending according to the stage
+ // through the inclusion pipeline, or according to the descriptions
+ b => c,
+ // Expand as needed, numbers should be ascending according to the stage
+ // through the inclusion pipeline, or according to the descriptions
+ d => e,
+ // Expand as needed, numbers should be ascending according to the stage
+ // through the inclusion pipeline, or according to the descriptions
+ }
+
+ match a {
+ // Expand as needed, numbers should be ascending according to the stage through the inclusion pipeline, or according to the descriptions
+ b => c,
+ // Expand as needed, numbers should be ascending according to the stage through the inclusion pipeline, or according to the descriptions
+ d => e,
+ // Expand as needed, numbers should be ascending according to the stage through the inclusion pipeline, or according to the descriptions
+ }
+}
diff --git a/src/tools/rustfmt/tests/source/comments-in-lists/wrap-comments-true.rs b/src/tools/rustfmt/tests/source/comments-in-lists/wrap-comments-true.rs
new file mode 100644
index 00000000000..360b838520e
--- /dev/null
+++ b/src/tools/rustfmt/tests/source/comments-in-lists/wrap-comments-true.rs
@@ -0,0 +1,130 @@
+// rustfmt-normalize_comments: true
+// rustfmt-wrap_comments: true
+
+// https://github.com/rust-lang/rustfmt/issues/4909
+pub enum E {
+ // Expand as needed, numbers should be ascending according to the stage
+ // through the inclusion pipeline, or according to the descriptions
+ Variant1,
+ // Expand as needed, numbers should be ascending according to the stage
+ // through the inclusion pipeline, or according to the descriptions
+ Variant2,
+ // Expand as needed, numbers should be ascending according to the stage
+ // through the inclusion pipeline, or according to the descriptions
+}
+
+pub enum E2 {
+ // This can be changed once https://github.com/rust-lang/rustfmt/issues/4854 is fixed
+// Expand as needed, numbers should be ascending according to the stage
+// through the inclusion pipeline, or according to the descriptions
+}
+
+pub enum E3 {
+ // Expand as needed, numbers should be ascending according to the stage through the inclusion pipeline, or according to the descriptions
+ Variant1,
+ // Expand as needed, numbers should be ascending according to the stage through the inclusion pipeline, or according to the descriptions
+ Variant2,
+ // Expand as needed, numbers should be ascending according to the stage through the inclusion pipeline, or according to the descriptions
+
+}
+
+pub struct S {
+ // Expand as needed, numbers should be ascending according to the stage
+ // through the inclusion pipeline, or according to the descriptions
+ some_field: usize,
+ // Expand as needed, numbers should be ascending according to the stage
+ // through the inclusion pipeline, or according to the descriptions
+ last_field: usize,
+ // Expand as needed, numbers should be ascending according to the stage
+ // through the inclusion pipeline, or according to the descriptions
+}
+
+pub struct S2 {
+ // This can be changed once https://github.com/rust-lang/rustfmt/issues/4854 is fixed
+// Expand as needed, numbers should be ascending according to the stage
+// through the inclusion pipeline, or according to the descriptions
+}
+
+pub struct S3 {
+ // Expand as needed, numbers should be ascending according to the stage through the inclusion pipeline, or according to the descriptions
+ some_field: usize,
+ // Expand as needed, numbers should be ascending according to the stage through the inclusion pipeline, or according to the descriptions
+ last_field: usize,
+ // Expand as needed, numbers should be ascending according to the stage through the inclusion pipeline, or according to the descriptions
+}
+
+fn foo(
+ // Expand as needed, numbers should be ascending according to the stage
+ // through the inclusion pipeline, or according to the descriptions
+ a: usize,
+ // Expand as needed, numbers should be ascending according to the stage
+ // through the inclusion pipeline, or according to the descriptions
+ b: usize,
+ // Expand as needed, numbers should be ascending according to the stage
+ // through the inclusion pipeline, or according to the descriptions
+) -> usize {
+ 5
+}
+
+fn foo2(// Expand as needed, numbers should be ascending according to the stage
+ // through the inclusion pipeline, or according to the descriptions
+) -> usize {
+ 5
+}
+
+fn foo3(
+ // Expand as needed, numbers should be ascending according to the stage through the inclusion pipeline, or according to the descriptions
+ a: usize,
+ // Expand as needed, numbers should be ascending according to the stage through the inclusion pipeline, or according to the descriptions
+ b: usize,
+ // Expand as needed, numbers should be ascending according to the stage through the inclusion pipeline, or according to the descriptions
+
+) -> usize {
+ 5
+}
+
+fn main() {
+ let v = vec![
+ // Expand as needed, numbers should be ascending according to the stage
+ // through the inclusion pipeline, or according to the descriptions
+ 1,
+ // Expand as needed, numbers should be ascending according to the stage
+ // through the inclusion pipeline, or according to the descriptions
+ 2,
+ // Expand as needed, numbers should be ascending according to the stage
+ // through the inclusion pipeline, or according to the descriptions
+ ];
+
+ let v2: Vec<i32> = vec![
+ // Expand as needed, numbers should be ascending according to the stage
+ // through the inclusion pipeline, or according to the descriptions
+ ];
+
+ let v3 = vec![
+ // Expand as needed, numbers should be ascending according to the stage through the inclusion pipeline, or according to the descriptions
+ 1,
+ // Expand as needed, numbers should be ascending according to the stage through the inclusion pipeline, or according to the descriptions
+ 2,
+ // Expand as needed, numbers should be ascending according to the stage through the inclusion pipeline, or according to the descriptions
+ ];
+
+ // https://github.com/rust-lang/rustfmt/issues/4430
+ match a {
+ // Expand as needed, numbers should be ascending according to the stage
+ // through the inclusion pipeline, or according to the descriptions
+ b => c,
+ // Expand as needed, numbers should be ascending according to the stage
+ // through the inclusion pipeline, or according to the descriptions
+ d => e,
+ // Expand as needed, numbers should be ascending according to the stage
+ // through the inclusion pipeline, or according to the descriptions
+ }
+
+ match a {
+ // Expand as needed, numbers should be ascending according to the stage through the inclusion pipeline, or according to the descriptions
+ b => c,
+ // Expand as needed, numbers should be ascending according to the stage through the inclusion pipeline, or according to the descriptions
+ d => e,
+ // Expand as needed, numbers should be ascending according to the stage through the inclusion pipeline, or according to the descriptions
+ }
+}
diff --git a/src/tools/rustfmt/tests/source/issue-5088/deeply_nested_long_comment_wrap_comments_true.rs b/src/tools/rustfmt/tests/source/issue-5088/deeply_nested_long_comment_wrap_comments_true.rs
new file mode 100644
index 00000000000..09f68cae424
--- /dev/null
+++ b/src/tools/rustfmt/tests/source/issue-5088/deeply_nested_long_comment_wrap_comments_true.rs
@@ -0,0 +1,33 @@
+// rustfmt-wrap_comments: true
+
+fn main() {
+ {
+ {
+ {
+ {
+ {
+ {
+ {
+ {
+ {
+ {
+ {
+ // - aaaa aaaaaaaaa aaaaaaaaa aaaaaaaaa aaaaaaaaa bbbbbbbbbb bbbbbbbbb bbbbbbbbb ccc cccccccccc ccccccc cccccccc
+
+ // * aaaa aaaaaaaaa aaaaaaaaa aaaaaaaaa aaaaaaaaa bbbbbbbbbb bbbbbbbbb bbbbbbbbb ccc cccccccccc ccccccc cccccccc
+
+ /* - aaaa aaaaaaaaa aaaaaaaaa aaaaaaaaa aaaaaaaaa bbbbbbbbbb bbbbbbbbb bbbbbbbbb ccc cccccccccc ccccccc cccccccc */
+
+ /* * aaaa aaaaaaaaa aaaaaaaaa aaaaaaaaa aaaaaaaaa bbbbbbbbbb bbbbbbbbb bbbbbbbbb ccc cccccccccc ccccccc cccccccc */
+ };
+ };
+ };
+ };
+ };
+ };
+ };
+ };
+ };
+ };
+ };
+}
diff --git a/src/tools/rustfmt/tests/source/issue-5088/start_with_empty_comment_very_long_itemized_block_wrap_comments_true.rs b/src/tools/rustfmt/tests/source/issue-5088/start_with_empty_comment_very_long_itemized_block_wrap_comments_true.rs
new file mode 100644
index 00000000000..75f748000f9
--- /dev/null
+++ b/src/tools/rustfmt/tests/source/issue-5088/start_with_empty_comment_very_long_itemized_block_wrap_comments_true.rs
@@ -0,0 +1,19 @@
+// rustfmt-wrap_comments: true
+
+//
+// - Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.
+// - Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.
+
+//
+// * Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.
+// * Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.
+
+/*
+ * - Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.*/
+/*
+ * - Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.*/
+
+/*
+ * * Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.*/
+/*
+ * * Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.*/
diff --git a/src/tools/rustfmt/tests/source/issue-5088/very_long_comment_wrap_comments_true.rs b/src/tools/rustfmt/tests/source/issue-5088/very_long_comment_wrap_comments_true.rs
new file mode 100644
index 00000000000..00437f00216
--- /dev/null
+++ b/src/tools/rustfmt/tests/source/issue-5088/very_long_comment_wrap_comments_true.rs
@@ -0,0 +1,13 @@
+// rustfmt-wrap_comments: true
+
+// - Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.
+// - Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.
+
+// * Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.
+// * Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.
+
+/* - Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.*/
+/* - Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.*/
+
+/* * Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.*/
+/* * Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.*/
diff --git a/src/tools/rustfmt/tests/source/issue_4823.rs b/src/tools/rustfmt/tests/source/issue_4823.rs
new file mode 100644
index 00000000000..a008dd3d838
--- /dev/null
+++ b/src/tools/rustfmt/tests/source/issue_4823.rs
@@ -0,0 +1,5 @@
+macro_rules! m {
+() => {
+type Type;
+};
+}
diff --git a/src/tools/rustfmt/tests/source/issue_5027.rs b/src/tools/rustfmt/tests/source/issue_5027.rs
new file mode 100644
index 00000000000..67beeb23b71
--- /dev/null
+++ b/src/tools/rustfmt/tests/source/issue_5027.rs
@@ -0,0 +1,7 @@
+// rustfmt-version: Two
+
+pub type Iter<'a, D> = impl DoubleEndedIterator<Item = (SomethingSomethingSomethingLongType<D>)>+ ExactSizeIterator+ 'a;
+
+trait FOo {pub type Iter<'a, D> = impl DoubleEndedIterator<Item = (SomethingSomethingSomethingLongType<D>)>+ ExactSizeIterator+ 'a;}
+
+impl Bar {pub type Iter<'a, D> = impl DoubleEndedIterator<Item = (SomethingSomethingSomethingLongType<D>)>+ ExactSizeIterator+ 'a;} \ No newline at end of file
diff --git a/src/tools/rustfmt/tests/source/issue_5086.rs b/src/tools/rustfmt/tests/source/issue_5086.rs
new file mode 100644
index 00000000000..1644c9d2ccb
--- /dev/null
+++ b/src/tools/rustfmt/tests/source/issue_5086.rs
@@ -0,0 +1,2 @@
+#[cfg(any())]
+ type Type : Bound ; \ No newline at end of file
diff --git a/src/tools/rustfmt/tests/target/comments-in-lists/format-doc-comments.rs b/src/tools/rustfmt/tests/target/comments-in-lists/format-doc-comments.rs
new file mode 100644
index 00000000000..be31bf0a331
--- /dev/null
+++ b/src/tools/rustfmt/tests/target/comments-in-lists/format-doc-comments.rs
@@ -0,0 +1,96 @@
+// rustfmt-format_code_in_doc_comments: true
+
+// https://github.com/rust-lang/rustfmt/issues/4420
+enum Minimal {
+ Example,
+ //[thisisremoved thatsleft
+ // canbeanything
+}
+
+struct Minimal2 {
+ Example: usize,
+ //[thisisremoved thatsleft
+ // canbeanything
+}
+
+pub enum E {
+ // Expand as needed, numbers should be ascending according to the stage
+ // through the inclusion pipeline, or according to the descriptions
+ Variant1,
+ // Expand as needed, numbers should be ascending according to the stage
+ // through the inclusion pipeline, or according to the descriptions
+ Variant2,
+ // Expand as needed, numbers should be ascending according to the stage
+ // through the inclusion pipeline, or according to the descriptions
+}
+
+pub enum E2 {
+ // This can be changed once https://github.com/rust-lang/rustfmt/issues/4854 is fixed
+// Expand as needed, numbers should be ascending according to the stage
+// through the inclusion pipeline, or according to the descriptions
+}
+
+pub struct S {
+ // Expand as needed, numbers should be ascending according to the stage
+ // through the inclusion pipeline, or according to the descriptions
+ some_field: usize,
+ // Expand as needed, numbers should be ascending according to the stage
+ // through the inclusion pipeline, or according to the descriptions
+ last_field: usize,
+ // Expand as needed, numbers should be ascending according to the stage
+ // through the inclusion pipeline, or according to the descriptions
+}
+
+pub struct S2 {
+ // This can be changed once https://github.com/rust-lang/rustfmt/issues/4854 is fixed
+// Expand as needed, numbers should be ascending according to the stage
+// through the inclusion pipeline, or according to the descriptions
+}
+
+fn foo(
+ // Expand as needed, numbers should be ascending according to the stage
+ // through the inclusion pipeline, or according to the descriptions
+ a: usize,
+ // Expand as needed, numbers should be ascending according to the stage
+ // through the inclusion pipeline, or according to the descriptions
+ b: usize,
+ // Expand as needed, numbers should be ascending according to the stage
+ // through the inclusion pipeline, or according to the descriptions
+) -> usize {
+ 5
+}
+
+fn foo2(// Expand as needed, numbers should be ascending according to the stage
+ // through the inclusion pipeline, or according to the descriptions
+) -> usize {
+ 5
+}
+
+fn main() {
+ let v = vec![
+ // Expand as needed, numbers should be ascending according to the stage
+ // through the inclusion pipeline, or according to the descriptions
+ 1,
+ // Expand as needed, numbers should be ascending according to the stage
+ // through the inclusion pipeline, or according to the descriptions
+ 2,
+ // Expand as needed, numbers should be ascending according to the stage
+ // through the inclusion pipeline, or according to the descriptions
+ ];
+
+ let v2: Vec<i32> = vec![
+ // Expand as needed, numbers should be ascending according to the stage
+ // through the inclusion pipeline, or according to the descriptions
+ ];
+
+ match a {
+ // Expand as needed, numbers should be ascending according to the stage
+ // through the inclusion pipeline, or according to the descriptions
+ b => c,
+ // Expand as needed, numbers should be ascending according to the stage
+ // through the inclusion pipeline, or according to the descriptions
+ d => e,
+ // Expand as needed, numbers should be ascending according to the stage
+ // through the inclusion pipeline, or according to the descriptions
+ }
+}
diff --git a/src/tools/rustfmt/tests/target/comments-in-lists/wrap-comments-false.rs b/src/tools/rustfmt/tests/target/comments-in-lists/wrap-comments-false.rs
new file mode 100644
index 00000000000..80aea59d1b5
--- /dev/null
+++ b/src/tools/rustfmt/tests/target/comments-in-lists/wrap-comments-false.rs
@@ -0,0 +1,85 @@
+// rustfmt-normalize_comments: true
+
+// https://github.com/rust-lang/rustfmt/issues/4909
+pub enum E {
+ // Expand as needed, numbers should be ascending according to the stage
+ // through the inclusion pipeline, or according to the descriptions
+ Variant1,
+ // Expand as needed, numbers should be ascending according to the stage
+ // through the inclusion pipeline, or according to the descriptions
+ Variant2,
+ // Expand as needed, numbers should be ascending according to the stage
+ // through the inclusion pipeline, or according to the descriptions
+}
+
+pub enum E2 {
+ // This can be changed once https://github.com/rust-lang/rustfmt/issues/4854 is fixed
+// Expand as needed, numbers should be ascending according to the stage
+// through the inclusion pipeline, or according to the descriptions
+}
+
+pub struct S {
+ // Expand as needed, numbers should be ascending according to the stage
+ // through the inclusion pipeline, or according to the descriptions
+ some_field: usize,
+ // Expand as needed, numbers should be ascending according to the stage
+ // through the inclusion pipeline, or according to the descriptions
+ last_field: usize,
+ // Expand as needed, numbers should be ascending according to the stage
+ // through the inclusion pipeline, or according to the descriptions
+}
+
+pub struct S2 {
+ // This can be changed once https://github.com/rust-lang/rustfmt/issues/4854 is fixed
+// Expand as needed, numbers should be ascending according to the stage
+// through the inclusion pipeline, or according to the descriptions
+}
+
+fn foo(
+ // Expand as needed, numbers should be ascending according to the stage
+ // through the inclusion pipeline, or according to the descriptions
+ a: usize,
+ // Expand as needed, numbers should be ascending according to the stage
+ // through the inclusion pipeline, or according to the descriptions
+ b: usize,
+ // Expand as needed, numbers should be ascending according to the stage
+ // through the inclusion pipeline, or according to the descriptions
+) -> usize {
+ 5
+}
+
+fn foo2(// Expand as needed, numbers should be ascending according to the stage
+ // through the inclusion pipeline, or according to the descriptions
+) -> usize {
+ 5
+}
+
+fn main() {
+ let v = vec![
+ // Expand as needed, numbers should be ascending according to the stage
+ // through the inclusion pipeline, or according to the descriptions
+ 1,
+ // Expand as needed, numbers should be ascending according to the stage
+ // through the inclusion pipeline, or according to the descriptions
+ 2,
+ // Expand as needed, numbers should be ascending according to the stage
+ // through the inclusion pipeline, or according to the descriptions
+ ];
+
+ let v2: Vec<i32> = vec![
+ // Expand as needed, numbers should be ascending according to the stage
+ // through the inclusion pipeline, or according to the descriptions
+ ];
+
+ // https://github.com/rust-lang/rustfmt/issues/4430
+ match a {
+ // Expand as needed, numbers should be ascending according to the stage
+ // through the inclusion pipeline, or according to the descriptions
+ b => c,
+ // Expand as needed, numbers should be ascending according to the stage
+ // through the inclusion pipeline, or according to the descriptions
+ d => e,
+ // Expand as needed, numbers should be ascending according to the stage
+ // through the inclusion pipeline, or according to the descriptions
+ }
+}
diff --git a/src/tools/rustfmt/tests/target/comments-in-lists/wrap-comments-not-normalized.rs b/src/tools/rustfmt/tests/target/comments-in-lists/wrap-comments-not-normalized.rs
new file mode 100644
index 00000000000..52315f470e4
--- /dev/null
+++ b/src/tools/rustfmt/tests/target/comments-in-lists/wrap-comments-not-normalized.rs
@@ -0,0 +1,142 @@
+// rustfmt-wrap_comments: true
+
+// https://github.com/rust-lang/rustfmt/issues/4909
+pub enum E {
+ // Expand as needed, numbers should be ascending according to the stage
+ // through the inclusion pipeline, or according to the descriptions
+ Variant1,
+ // Expand as needed, numbers should be ascending according to the stage
+ // through the inclusion pipeline, or according to the descriptions
+ Variant2,
+ // Expand as needed, numbers should be ascending according to the stage
+ // through the inclusion pipeline, or according to the descriptions
+}
+
+pub enum E2 {
+ // This can be changed once https://github.com/rust-lang/rustfmt/issues/4854 is fixed
+// Expand as needed, numbers should be ascending according to the stage
+// through the inclusion pipeline, or according to the descriptions
+}
+
+pub enum E3 {
+ // Expand as needed, numbers should be ascending according to the stage through the inclusion
+ // pipeline, or according to the descriptions
+ Variant1,
+ // Expand as needed, numbers should be ascending according to the stage through the inclusion
+ // pipeline, or according to the descriptions
+ Variant2,
+ // Expand as needed, numbers should be ascending according to the stage through the inclusion
+ // pipeline, or according to the descriptions
+}
+
+pub struct S {
+ // Expand as needed, numbers should be ascending according to the stage
+ // through the inclusion pipeline, or according to the descriptions
+ some_field: usize,
+ // Expand as needed, numbers should be ascending according to the stage
+ // through the inclusion pipeline, or according to the descriptions
+ last_field: usize,
+ // Expand as needed, numbers should be ascending according to the stage
+ // through the inclusion pipeline, or according to the descriptions
+}
+
+pub struct S2 {
+ // This can be changed once https://github.com/rust-lang/rustfmt/issues/4854 is fixed
+// Expand as needed, numbers should be ascending according to the stage
+// through the inclusion pipeline, or according to the descriptions
+}
+
+pub struct S3 {
+ // Expand as needed, numbers should be ascending according to the stage through the inclusion
+ // pipeline, or according to the descriptions
+ some_field: usize,
+ // Expand as needed, numbers should be ascending according to the stage through the inclusion
+ // pipeline, or according to the descriptions
+ last_field: usize,
+ // Expand as needed, numbers should be ascending according to the stage through the inclusion
+ // pipeline, or according to the descriptions
+}
+
+fn foo(
+ // Expand as needed, numbers should be ascending according to the stage
+ // through the inclusion pipeline, or according to the descriptions
+ a: usize,
+ // Expand as needed, numbers should be ascending according to the stage
+ // through the inclusion pipeline, or according to the descriptions
+ b: usize,
+ // Expand as needed, numbers should be ascending according to the stage
+ // through the inclusion pipeline, or according to the descriptions
+) -> usize {
+ 5
+}
+
+fn foo2(// Expand as needed, numbers should be ascending according to the stage
+ // through the inclusion pipeline, or according to the descriptions
+) -> usize {
+ 5
+}
+
+fn foo3(
+ // Expand as needed, numbers should be ascending according to the stage through the inclusion
+ // pipeline, or according to the descriptions
+ a: usize,
+ // Expand as needed, numbers should be ascending according to the stage through the inclusion
+ // pipeline, or according to the descriptions
+ b: usize,
+ // Expand as needed, numbers should be ascending according to the stage through the inclusion
+ // pipeline, or according to the descriptions
+) -> usize {
+ 5
+}
+
+fn main() {
+ let v = vec![
+ // Expand as needed, numbers should be ascending according to the stage
+ // through the inclusion pipeline, or according to the descriptions
+ 1,
+ // Expand as needed, numbers should be ascending according to the stage
+ // through the inclusion pipeline, or according to the descriptions
+ 2,
+ // Expand as needed, numbers should be ascending according to the stage
+ // through the inclusion pipeline, or according to the descriptions
+ ];
+
+ let v2: Vec<i32> = vec![
+ // Expand as needed, numbers should be ascending according to the stage
+ // through the inclusion pipeline, or according to the descriptions
+ ];
+
+ let v3 = vec![
+ // Expand as needed, numbers should be ascending according to the stage through the
+ // inclusion pipeline, or according to the descriptions
+ 1,
+ // Expand as needed, numbers should be ascending according to the stage through the
+ // inclusion pipeline, or according to the descriptions
+ 2,
+ // Expand as needed, numbers should be ascending according to the stage through the
+ // inclusion pipeline, or according to the descriptions
+ ];
+
+ // https://github.com/rust-lang/rustfmt/issues/4430
+ match a {
+ // Expand as needed, numbers should be ascending according to the stage
+ // through the inclusion pipeline, or according to the descriptions
+ b => c,
+ // Expand as needed, numbers should be ascending according to the stage
+ // through the inclusion pipeline, or according to the descriptions
+ d => e,
+ // Expand as needed, numbers should be ascending according to the stage
+ // through the inclusion pipeline, or according to the descriptions
+ }
+
+ match a {
+ // Expand as needed, numbers should be ascending according to the stage through the
+ // inclusion pipeline, or according to the descriptions
+ b => c,
+ // Expand as needed, numbers should be ascending according to the stage through the
+ // inclusion pipeline, or according to the descriptions
+ d => e,
+ // Expand as needed, numbers should be ascending according to the stage through the
+ // inclusion pipeline, or according to the descriptions
+ }
+}
diff --git a/src/tools/rustfmt/tests/target/comments-in-lists/wrap-comments-true.rs b/src/tools/rustfmt/tests/target/comments-in-lists/wrap-comments-true.rs
new file mode 100644
index 00000000000..e0bfcf0b500
--- /dev/null
+++ b/src/tools/rustfmt/tests/target/comments-in-lists/wrap-comments-true.rs
@@ -0,0 +1,143 @@
+// rustfmt-normalize_comments: true
+// rustfmt-wrap_comments: true
+
+// https://github.com/rust-lang/rustfmt/issues/4909
+pub enum E {
+ // Expand as needed, numbers should be ascending according to the stage
+ // through the inclusion pipeline, or according to the descriptions
+ Variant1,
+ // Expand as needed, numbers should be ascending according to the stage
+ // through the inclusion pipeline, or according to the descriptions
+ Variant2,
+ // Expand as needed, numbers should be ascending according to the stage
+ // through the inclusion pipeline, or according to the descriptions
+}
+
+pub enum E2 {
+ // This can be changed once https://github.com/rust-lang/rustfmt/issues/4854 is fixed
+// Expand as needed, numbers should be ascending according to the stage
+// through the inclusion pipeline, or according to the descriptions
+}
+
+pub enum E3 {
+ // Expand as needed, numbers should be ascending according to the stage through the inclusion
+ // pipeline, or according to the descriptions
+ Variant1,
+ // Expand as needed, numbers should be ascending according to the stage through the inclusion
+ // pipeline, or according to the descriptions
+ Variant2,
+ // Expand as needed, numbers should be ascending according to the stage through the inclusion
+ // pipeline, or according to the descriptions
+}
+
+pub struct S {
+ // Expand as needed, numbers should be ascending according to the stage
+ // through the inclusion pipeline, or according to the descriptions
+ some_field: usize,
+ // Expand as needed, numbers should be ascending according to the stage
+ // through the inclusion pipeline, or according to the descriptions
+ last_field: usize,
+ // Expand as needed, numbers should be ascending according to the stage
+ // through the inclusion pipeline, or according to the descriptions
+}
+
+pub struct S2 {
+ // This can be changed once https://github.com/rust-lang/rustfmt/issues/4854 is fixed
+// Expand as needed, numbers should be ascending according to the stage
+// through the inclusion pipeline, or according to the descriptions
+}
+
+pub struct S3 {
+ // Expand as needed, numbers should be ascending according to the stage through the inclusion
+ // pipeline, or according to the descriptions
+ some_field: usize,
+ // Expand as needed, numbers should be ascending according to the stage through the inclusion
+ // pipeline, or according to the descriptions
+ last_field: usize,
+ // Expand as needed, numbers should be ascending according to the stage through the inclusion
+ // pipeline, or according to the descriptions
+}
+
+fn foo(
+ // Expand as needed, numbers should be ascending according to the stage
+ // through the inclusion pipeline, or according to the descriptions
+ a: usize,
+ // Expand as needed, numbers should be ascending according to the stage
+ // through the inclusion pipeline, or according to the descriptions
+ b: usize,
+ // Expand as needed, numbers should be ascending according to the stage
+ // through the inclusion pipeline, or according to the descriptions
+) -> usize {
+ 5
+}
+
+fn foo2(// Expand as needed, numbers should be ascending according to the stage
+ // through the inclusion pipeline, or according to the descriptions
+) -> usize {
+ 5
+}
+
+fn foo3(
+ // Expand as needed, numbers should be ascending according to the stage through the inclusion
+ // pipeline, or according to the descriptions
+ a: usize,
+ // Expand as needed, numbers should be ascending according to the stage through the inclusion
+ // pipeline, or according to the descriptions
+ b: usize,
+ // Expand as needed, numbers should be ascending according to the stage through the inclusion
+ // pipeline, or according to the descriptions
+) -> usize {
+ 5
+}
+
+fn main() {
+ let v = vec![
+ // Expand as needed, numbers should be ascending according to the stage
+ // through the inclusion pipeline, or according to the descriptions
+ 1,
+ // Expand as needed, numbers should be ascending according to the stage
+ // through the inclusion pipeline, or according to the descriptions
+ 2,
+ // Expand as needed, numbers should be ascending according to the stage
+ // through the inclusion pipeline, or according to the descriptions
+ ];
+
+ let v2: Vec<i32> = vec![
+ // Expand as needed, numbers should be ascending according to the stage
+ // through the inclusion pipeline, or according to the descriptions
+ ];
+
+ let v3 = vec![
+ // Expand as needed, numbers should be ascending according to the stage through the
+ // inclusion pipeline, or according to the descriptions
+ 1,
+ // Expand as needed, numbers should be ascending according to the stage through the
+ // inclusion pipeline, or according to the descriptions
+ 2,
+ // Expand as needed, numbers should be ascending according to the stage through the
+ // inclusion pipeline, or according to the descriptions
+ ];
+
+ // https://github.com/rust-lang/rustfmt/issues/4430
+ match a {
+ // Expand as needed, numbers should be ascending according to the stage
+ // through the inclusion pipeline, or according to the descriptions
+ b => c,
+ // Expand as needed, numbers should be ascending according to the stage
+ // through the inclusion pipeline, or according to the descriptions
+ d => e,
+ // Expand as needed, numbers should be ascending according to the stage
+ // through the inclusion pipeline, or according to the descriptions
+ }
+
+ match a {
+ // Expand as needed, numbers should be ascending according to the stage through the
+ // inclusion pipeline, or according to the descriptions
+ b => c,
+ // Expand as needed, numbers should be ascending according to the stage through the
+ // inclusion pipeline, or according to the descriptions
+ d => e,
+ // Expand as needed, numbers should be ascending according to the stage through the
+ // inclusion pipeline, or according to the descriptions
+ }
+}
diff --git a/src/tools/rustfmt/tests/target/issue-5088/deeply_nested_long_comment_wrap_comments_false.rs b/src/tools/rustfmt/tests/target/issue-5088/deeply_nested_long_comment_wrap_comments_false.rs
new file mode 100644
index 00000000000..f4801de0184
--- /dev/null
+++ b/src/tools/rustfmt/tests/target/issue-5088/deeply_nested_long_comment_wrap_comments_false.rs
@@ -0,0 +1,33 @@
+// rustfmt-wrap_comments: false
+
+fn main() {
+ {
+ {
+ {
+ {
+ {
+ {
+ {
+ {
+ {
+ {
+ {
+ // - aaaa aaaaaaaaa aaaaaaaaa aaaaaaaaa aaaaaaaaa bbbbbbbbbb bbbbbbbbb bbbbbbbbb ccc cccccccccc ccccccc cccccccc
+
+ // * aaaa aaaaaaaaa aaaaaaaaa aaaaaaaaa aaaaaaaaa bbbbbbbbbb bbbbbbbbb bbbbbbbbb ccc cccccccccc ccccccc cccccccc
+
+ /* - aaaa aaaaaaaaa aaaaaaaaa aaaaaaaaa aaaaaaaaa bbbbbbbbbb bbbbbbbbb bbbbbbbbb ccc cccccccccc ccccccc cccccccc */
+
+ /* * aaaa aaaaaaaaa aaaaaaaaa aaaaaaaaa aaaaaaaaa bbbbbbbbbb bbbbbbbbb bbbbbbbbb ccc cccccccccc ccccccc cccccccc */
+ };
+ };
+ };
+ };
+ };
+ };
+ };
+ };
+ };
+ };
+ };
+}
diff --git a/src/tools/rustfmt/tests/target/issue-5088/deeply_nested_long_comment_wrap_comments_true.rs b/src/tools/rustfmt/tests/target/issue-5088/deeply_nested_long_comment_wrap_comments_true.rs
new file mode 100644
index 00000000000..b289c9f859e
--- /dev/null
+++ b/src/tools/rustfmt/tests/target/issue-5088/deeply_nested_long_comment_wrap_comments_true.rs
@@ -0,0 +1,49 @@
+// rustfmt-wrap_comments: true
+
+fn main() {
+ {
+ {
+ {
+ {
+ {
+ {
+ {
+ {
+ {
+ {
+ {
+ // - aaaa aaaaaaaaa aaaaaaaaa
+ // aaaaaaaaa aaaaaaaaa
+ // bbbbbbbbbb bbbbbbbbb
+ // bbbbbbbbb ccc cccccccccc
+ // ccccccc cccccccc
+
+ // * aaaa aaaaaaaaa aaaaaaaaa
+ // aaaaaaaaa aaaaaaaaa
+ // bbbbbbbbbb bbbbbbbbb
+ // bbbbbbbbb ccc cccccccccc
+ // ccccccc cccccccc
+
+ /* - aaaa aaaaaaaaa aaaaaaaaa
+ * aaaaaaaaa aaaaaaaaa
+ * bbbbbbbbbb bbbbbbbbb
+ * bbbbbbbbb ccc cccccccccc
+ * ccccccc cccccccc */
+
+ /* * aaaa aaaaaaaaa aaaaaaaaa
+ * aaaaaaaaa aaaaaaaaa
+ * bbbbbbbbbb bbbbbbbbb
+ * bbbbbbbbb ccc cccccccccc
+ * ccccccc cccccccc */
+ };
+ };
+ };
+ };
+ };
+ };
+ };
+ };
+ };
+ };
+ };
+}
diff --git a/src/tools/rustfmt/tests/target/issue-5088/multi_line_itemized_block_wrap_comments_false.rs b/src/tools/rustfmt/tests/target/issue-5088/multi_line_itemized_block_wrap_comments_false.rs
new file mode 100644
index 00000000000..60beed1b048
--- /dev/null
+++ b/src/tools/rustfmt/tests/target/issue-5088/multi_line_itemized_block_wrap_comments_false.rs
@@ -0,0 +1,17 @@
+// rustfmt-wrap_comments: false
+
+// - some itemized block 1
+// - some itemized block 2
+
+// * some itemized block 3
+// * some itemized block 4
+
+/*
+ * - some itemized block 5
+ * - some itemized block 6
+ */
+
+/*
+ * * some itemized block 7
+ * * some itemized block 8
+ */
diff --git a/src/tools/rustfmt/tests/target/issue-5088/multi_line_itemized_block_wrap_comments_true.rs b/src/tools/rustfmt/tests/target/issue-5088/multi_line_itemized_block_wrap_comments_true.rs
new file mode 100644
index 00000000000..84fba4b7c19
--- /dev/null
+++ b/src/tools/rustfmt/tests/target/issue-5088/multi_line_itemized_block_wrap_comments_true.rs
@@ -0,0 +1,17 @@
+// rustfmt-wrap_comments: true
+
+// - some itemized block 1
+// - some itemized block 2
+
+// * some itemized block 3
+// * some itemized block 4
+
+/*
+ * - some itemized block 5
+ * - some itemized block 6
+ */
+
+/*
+ * * some itemized block 7
+ * * some itemized block 8
+ */
diff --git a/src/tools/rustfmt/tests/target/issue-5088/multi_line_text_with_itemized_block_wrap_comments_false.rs b/src/tools/rustfmt/tests/target/issue-5088/multi_line_text_with_itemized_block_wrap_comments_false.rs
new file mode 100644
index 00000000000..d1bf44f6c74
--- /dev/null
+++ b/src/tools/rustfmt/tests/target/issue-5088/multi_line_text_with_itemized_block_wrap_comments_false.rs
@@ -0,0 +1,37 @@
+// rustfmt-wrap_comments: false
+
+// Some text
+// - some itemized block 1
+// - some itemized block 2
+// Some more text
+// - some itemized block 3
+// - some itemized block 4
+// Even more text
+
+// Some text
+// * some itemized block 5
+// * some itemized block 6
+// Some more text
+// * some itemized block 7
+// * some itemized block 8
+// Even more text
+
+/*
+ * Some text
+ * - some itemized block 9
+ * - some itemized block 10
+ * Some more text
+ * - some itemized block 11
+ * - some itemized block 12
+ * Even more text
+ */
+
+/*
+ * Some text
+ * * some itemized block 13
+ * * some itemized block 14
+ * Some more text
+ * * some itemized block 15
+ * * some itemized block 16
+ * Even more text
+ */
diff --git a/src/tools/rustfmt/tests/target/issue-5088/multi_line_text_with_itemized_block_wrap_comments_true.rs b/src/tools/rustfmt/tests/target/issue-5088/multi_line_text_with_itemized_block_wrap_comments_true.rs
new file mode 100644
index 00000000000..f767491f902
--- /dev/null
+++ b/src/tools/rustfmt/tests/target/issue-5088/multi_line_text_with_itemized_block_wrap_comments_true.rs
@@ -0,0 +1,37 @@
+// rustfmt-wrap_comments: true
+
+// Some text
+// - some itemized block 1
+// - some itemized block 2
+// Some more text
+// - some itemized block 3
+// - some itemized block 4
+// Even more text
+
+// Some text
+// * some itemized block 5
+// * some itemized block 6
+// Some more text
+// * some itemized block 7
+// * some itemized block 8
+// Even more text
+
+/*
+ * Some text
+ * - some itemized block 9
+ * - some itemized block 10
+ * Some more text
+ * - some itemized block 11
+ * - some itemized block 12
+ * Even more text
+ */
+
+/*
+ * Some text
+ * * some itemized block 13
+ * * some itemized block 14
+ * Some more text
+ * * some itemized block 15
+ * * some itemized block 16
+ * Even more text
+ */
diff --git a/src/tools/rustfmt/tests/target/issue-5088/single_line_itemized_block_wrap_comments_false.rs b/src/tools/rustfmt/tests/target/issue-5088/single_line_itemized_block_wrap_comments_false.rs
new file mode 100644
index 00000000000..2cd85c787f9
--- /dev/null
+++ b/src/tools/rustfmt/tests/target/issue-5088/single_line_itemized_block_wrap_comments_false.rs
@@ -0,0 +1,9 @@
+// rustfmt-wrap_comments: false
+
+// - some itemized block 1
+
+// * some itemized block 2
+
+/* - some itemized block 3 */
+
+/* * some itemized block 4 */
diff --git a/src/tools/rustfmt/tests/target/issue-5088/single_line_itemized_block_wrap_comments_true.rs b/src/tools/rustfmt/tests/target/issue-5088/single_line_itemized_block_wrap_comments_true.rs
new file mode 100644
index 00000000000..e9f343d75d5
--- /dev/null
+++ b/src/tools/rustfmt/tests/target/issue-5088/single_line_itemized_block_wrap_comments_true.rs
@@ -0,0 +1,9 @@
+// rustfmt-wrap_comments: true
+
+// - some itemized block 1
+
+// * some itemized block 2
+
+/* - some itemized block 3 */
+
+/* * some itemized block 4 */
diff --git a/src/tools/rustfmt/tests/target/issue-5088/start_with_empty_comment_very_long_itemized_block_wrap_comments_false.rs b/src/tools/rustfmt/tests/target/issue-5088/start_with_empty_comment_very_long_itemized_block_wrap_comments_false.rs
new file mode 100644
index 00000000000..97bb7733d18
--- /dev/null
+++ b/src/tools/rustfmt/tests/target/issue-5088/start_with_empty_comment_very_long_itemized_block_wrap_comments_false.rs
@@ -0,0 +1,19 @@
+// rustfmt-wrap_comments: false
+
+//
+// - Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.
+// - Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.
+
+//
+// * Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.
+// * Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.
+
+/*
+ * - Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.*/
+/*
+ * - Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.*/
+
+/*
+ * * Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.*/
+/*
+ * * Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.*/
diff --git a/src/tools/rustfmt/tests/target/issue-5088/start_with_empty_comment_very_long_itemized_block_wrap_comments_true.rs b/src/tools/rustfmt/tests/target/issue-5088/start_with_empty_comment_very_long_itemized_block_wrap_comments_true.rs
new file mode 100644
index 00000000000..c8af8383e05
--- /dev/null
+++ b/src/tools/rustfmt/tests/target/issue-5088/start_with_empty_comment_very_long_itemized_block_wrap_comments_true.rs
@@ -0,0 +1,27 @@
+// rustfmt-wrap_comments: true
+
+//
+// - Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod
+// tempor incididunt ut labore et dolore magna aliqua.
+// - Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod
+// tempor incididunt ut labore et dolore magna aliqua.
+
+//
+// * Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod
+// tempor incididunt ut labore et dolore magna aliqua.
+// * Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod
+// tempor incididunt ut labore et dolore magna aliqua.
+
+/*
+ * - Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod
+ * tempor incididunt ut labore et dolore magna aliqua. */
+/*
+ * - Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod
+ * tempor incididunt ut labore et dolore magna aliqua. */
+
+/*
+ * * Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod
+ * tempor incididunt ut labore et dolore magna aliqua. */
+/*
+ * * Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod
+ * tempor incididunt ut labore et dolore magna aliqua. */
diff --git a/src/tools/rustfmt/tests/target/issue-5088/start_with_empty_comment_wrap_comments_false.rs b/src/tools/rustfmt/tests/target/issue-5088/start_with_empty_comment_wrap_comments_false.rs
new file mode 100644
index 00000000000..75cc42c0e66
--- /dev/null
+++ b/src/tools/rustfmt/tests/target/issue-5088/start_with_empty_comment_wrap_comments_false.rs
@@ -0,0 +1,17 @@
+// rustfmt-wrap_comments: false
+
+//
+// - some itemized block 1
+// - some itemized block 2
+
+//
+// * some itemized block 3
+// * some itemized block 4
+
+/*
+ * - some itemized block 5
+ * - some itemized block 6 */
+
+/*
+ * * some itemized block 7
+ * * some itemized block 8 */
diff --git a/src/tools/rustfmt/tests/target/issue-5088/start_with_empty_comment_wrap_comments_true.rs b/src/tools/rustfmt/tests/target/issue-5088/start_with_empty_comment_wrap_comments_true.rs
new file mode 100644
index 00000000000..ef2c8f90cd3
--- /dev/null
+++ b/src/tools/rustfmt/tests/target/issue-5088/start_with_empty_comment_wrap_comments_true.rs
@@ -0,0 +1,17 @@
+// rustfmt-wrap_comments: true
+
+//
+// - some itemized block 1
+// - some itemized block 2
+
+//
+// * some itemized block 3
+// * some itemized block 4
+
+/*
+ * - some itemized block 5
+ * - some itemized block 6 */
+
+/*
+ * * some itemized block 7
+ * * some itemized block 8 */
diff --git a/src/tools/rustfmt/tests/target/issue-5088/very_long_comment_wrap_comments_false.rs b/src/tools/rustfmt/tests/target/issue-5088/very_long_comment_wrap_comments_false.rs
new file mode 100644
index 00000000000..c826cc5d4da
--- /dev/null
+++ b/src/tools/rustfmt/tests/target/issue-5088/very_long_comment_wrap_comments_false.rs
@@ -0,0 +1,13 @@
+// rustfmt-wrap_comments: false
+
+// - Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.
+// - Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.
+
+// * Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.
+// * Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.
+
+/* - Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.*/
+/* - Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.*/
+
+/* * Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.*/
+/* * Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.*/
diff --git a/src/tools/rustfmt/tests/target/issue-5088/very_long_comment_wrap_comments_true.rs b/src/tools/rustfmt/tests/target/issue-5088/very_long_comment_wrap_comments_true.rs
new file mode 100644
index 00000000000..7f764dbd8a2
--- /dev/null
+++ b/src/tools/rustfmt/tests/target/issue-5088/very_long_comment_wrap_comments_true.rs
@@ -0,0 +1,21 @@
+// rustfmt-wrap_comments: true
+
+// - Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod
+// tempor incididunt ut labore et dolore magna aliqua.
+// - Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod
+// tempor incididunt ut labore et dolore magna aliqua.
+
+// * Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod
+// tempor incididunt ut labore et dolore magna aliqua.
+// * Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod
+// tempor incididunt ut labore et dolore magna aliqua.
+
+/* - Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod
+ * tempor incididunt ut labore et dolore magna aliqua. */
+/* - Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod
+ * tempor incididunt ut labore et dolore magna aliqua. */
+
+/* * Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod
+ * tempor incididunt ut labore et dolore magna aliqua. */
+/* * Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod
+ * tempor incididunt ut labore et dolore magna aliqua. */
diff --git a/src/tools/rustfmt/tests/target/issue-5095.rs b/src/tools/rustfmt/tests/target/issue-5095.rs
new file mode 100644
index 00000000000..6981a65808c
--- /dev/null
+++ b/src/tools/rustfmt/tests/target/issue-5095.rs
@@ -0,0 +1,27 @@
+// rustfmt-wrap_comments: true
+
+pub mod a_long_name {
+ pub mod b_long_name {
+ pub mod c_long_name {
+ pub mod d_long_name {
+ pub mod e_long_name {
+ pub struct Bananas;
+ impl Bananas {
+ pub fn fantastic() {}
+ }
+
+ pub mod f_long_name {
+ pub struct Apples;
+ }
+ }
+ }
+ }
+ }
+}
+
+/// Check out [my other struct] ([`Bananas`]) and [the method it has].
+///
+/// [my other struct]: a_long_name::b_long_name::c_long_name::d_long_name::e_long_name::f_long_name::Apples
+/// [`Bananas`]: a_long_name::b_long_name::c_long_name::d_long_name::e_long_name::Bananas::fantastic()
+/// [the method it has]: a_long_name::b_long_name::c_long_name::d_long_name::e_long_name::Bananas::fantastic()
+pub struct A;
diff --git a/src/tools/rustfmt/tests/target/issue_4823.rs b/src/tools/rustfmt/tests/target/issue_4823.rs
new file mode 100644
index 00000000000..de17467c0ef
--- /dev/null
+++ b/src/tools/rustfmt/tests/target/issue_4823.rs
@@ -0,0 +1,5 @@
+macro_rules! m {
+ () => {
+ type Type;
+ };
+}
diff --git a/src/tools/rustfmt/tests/target/issue_5027.rs b/src/tools/rustfmt/tests/target/issue_5027.rs
new file mode 100644
index 00000000000..26d771720b6
--- /dev/null
+++ b/src/tools/rustfmt/tests/target/issue_5027.rs
@@ -0,0 +1,17 @@
+// rustfmt-version: Two
+
+pub type Iter<'a, D> = impl DoubleEndedIterator<Item = (SomethingSomethingSomethingLongType<D>)>
+ + ExactSizeIterator
+ + 'a;
+
+trait FOo {
+ pub type Iter<'a, D> = impl DoubleEndedIterator<Item = (SomethingSomethingSomethingLongType<D>)>
+ + ExactSizeIterator
+ + 'a;
+}
+
+impl Bar {
+ type Iter<'a, D> = impl DoubleEndedIterator<Item = (SomethingSomethingSomethingLongType<D>)>
+ + ExactSizeIterator
+ + 'a;
+}
diff --git a/src/tools/rustfmt/tests/target/issue_5086.rs b/src/tools/rustfmt/tests/target/issue_5086.rs
new file mode 100644
index 00000000000..7a0be06f791
--- /dev/null
+++ b/src/tools/rustfmt/tests/target/issue_5086.rs
@@ -0,0 +1,2 @@
+#[cfg(any())]
+type Type: Bound;
diff --git a/src/tools/tidy/src/deps.rs b/src/tools/tidy/src/deps.rs
index c1719a9ffe8..d27afa497f6 100644
--- a/src/tools/tidy/src/deps.rs
+++ b/src/tools/tidy/src/deps.rs
@@ -15,6 +15,7 @@ const LICENSES: &[&str] = &[
"Apache-2.0 OR MIT",
"Apache-2.0 WITH LLVM-exception OR Apache-2.0 OR MIT", // wasi license
"MIT",
+ "ISC",
"Unlicense/MIT",
"Unlicense OR MIT",
"0BSD OR MIT OR Apache-2.0", // adler license
@@ -53,7 +54,6 @@ const EXCEPTIONS_CRANELIFT: &[(&str, &str)] = &[
("cranelift-module", "Apache-2.0 WITH LLVM-exception"),
("cranelift-native", "Apache-2.0 WITH LLVM-exception"),
("cranelift-object", "Apache-2.0 WITH LLVM-exception"),
- ("libloading", "ISC"),
("mach", "BSD-2-Clause"),
("regalloc", "Apache-2.0 WITH LLVM-exception"),
("target-lexicon", "Apache-2.0 WITH LLVM-exception"),
@@ -82,8 +82,8 @@ const PERMITTED_DEPENDENCIES: &[&str] = &[
"bitflags",
"block-buffer",
"block-padding",
- "byteorder",
"byte-tools",
+ "byteorder",
"cc",
"cfg-if",
"chalk-derive",
@@ -129,6 +129,7 @@ const PERMITTED_DEPENDENCIES: &[&str] = &[
"jobserver",
"lazy_static",
"libc",
+ "libloading",
"libz-sys",
"lock_api",
"log",
@@ -140,9 +141,9 @@ const PERMITTED_DEPENDENCIES: &[&str] = &[
"memmap2",
"memoffset",
"miniz_oxide",
- "num_cpus",
"num-integer",
"num-traits",
+ "num_cpus",
"object",
"odht",
"once_cell",
@@ -190,8 +191,8 @@ const PERMITTED_DEPENDENCIES: &[&str] = &[
"serde_json",
"sha-1",
"sha2",
- "smallvec",
"sharded-slab",
+ "smallvec",
"snap",
"stable_deref_trait",
"stacker",
@@ -211,6 +212,11 @@ const PERMITTED_DEPENDENCIES: &[&str] = &[
"tracing-subscriber",
"tracing-tree",
"typenum",
+ "unic-char-property",
+ "unic-char-range",
+ "unic-common",
+ "unic-emoji-char",
+ "unic-ucd-version",
"unicode-normalization",
"unicode-script",
"unicode-security",
diff --git a/src/tools/tidy/src/edition.rs b/src/tools/tidy/src/edition.rs
index 3f59fefd041..f610dbd806a 100644
--- a/src/tools/tidy/src/edition.rs
+++ b/src/tools/tidy/src/edition.rs
@@ -23,8 +23,10 @@ pub fn check(path: &Path, bad: &mut bool) {
return;
}
- // Library crates are not yet ready to migrate to 2021.
- if path.components().any(|c| c.as_os_str() == "library") {
+ // Not all library crates are ready to migrate to 2021.
+ if file.components().any(|c| c.as_os_str() == "library")
+ && file.components().all(|c| c.as_os_str() != "std")
+ {
let has = contents.lines().any(is_edition_2018);
if !has {
tidy_error!(
diff --git a/src/tools/tidy/src/ui_tests.rs b/src/tools/tidy/src/ui_tests.rs
index 7fae9bf0f69..203e33e8b1f 100644
--- a/src/tools/tidy/src/ui_tests.rs
+++ b/src/tools/tidy/src/ui_tests.rs
@@ -7,9 +7,8 @@ use std::path::Path;
const ENTRY_LIMIT: usize = 1000;
// FIXME: The following limits should be reduced eventually.
-const ROOT_ENTRY_LIMIT: usize = 983;
+const ROOT_ENTRY_LIMIT: usize = 982;
const ISSUES_ENTRY_LIMIT: usize = 2310;
-const PARSER_LIMIT: usize = 1012;
fn check_entries(path: &Path, bad: &mut bool) {
let dirs = walkdir::WalkDir::new(&path.join("test/ui"))
@@ -22,13 +21,10 @@ fn check_entries(path: &Path, bad: &mut bool) {
// Use special values for these dirs.
let is_root = path.join("test/ui") == dir_path;
let is_issues_dir = path.join("test/ui/issues") == dir_path;
- let is_parser = path.join("test/ui/parser") == dir_path;
let limit = if is_root {
ROOT_ENTRY_LIMIT
} else if is_issues_dir {
ISSUES_ENTRY_LIMIT
- } else if is_parser {
- PARSER_LIMIT
} else {
ENTRY_LIMIT
};
diff --git a/src/version b/src/version
index 79f82f6b8e0..bb120e876c6 100644
--- a/src/version
+++ b/src/version
@@ -1 +1 @@
-1.58.0
+1.59.0
diff --git a/triagebot.toml b/triagebot.toml
index 7a9908fe8c0..b484c25ea51 100644
--- a/triagebot.toml
+++ b/triagebot.toml
@@ -91,6 +91,38 @@ exclude_labels = [
"requires-nightly",
]
+[autolabel."T-rustdoc"]
+trigger_files = [
+ # Source code
+ "src/librustdoc",
+ "src/tools/rustdoc",
+ "src/rustdoc-json-types",
+
+ # Tests
+ "src/test/rustdoc",
+ "src/test/rustdoc-ui",
+ "src/test/rustdoc-gui",
+ "src/test/rustdoc-js",
+ "src/test/rustdoc-js-std",
+ "src/test/rustdoc-json",
+
+ # Internal tooling
+ "src/etc/htmldocck.py",
+ "src/tools/jsondocck",
+ "src/tools/rustdoc-gui",
+ "src/tools/rustdoc-js",
+ "src/tools/rustdoc-themes",
+]
+
+[autolabel."T-compiler"]
+trigger_files = [
+ # Source code
+ "compiler",
+
+ # Tests
+ "src/test/ui",
+]
+
[notify-zulip."I-prioritize"]
zulip_stream = 245100 # #t-compiler/wg-prioritization/alerts
topic = "#{number} {title}"